Skip to content

Commit

Permalink
Add a Shutdown() method to the Store
Browse files Browse the repository at this point in the history
Add a method for calling the underlying driver's Cleanup() method,
preferably when it's not going to disrupt another user of the same data
store, and try to give other users of the store a way to notice that the
driver's been cleaned up, so they need to reinitialize things before
continuing to use them.

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
  • Loading branch information
nalind committed Oct 26, 2016
1 parent 9b06332 commit b046fb5
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 34 deletions.
46 changes: 46 additions & 0 deletions cmd/oci-storage/shutdown.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package main

import (
"encoding/json"
"fmt"
"os"

"github.com/containers/storage/pkg/mflag"
"github.com/containers/storage/storage"
)

var (
forceShutdown = false
)

func shutdown(flags *mflag.FlagSet, action string, m storage.Store, args []string) int {
_, err := m.Shutdown(forceShutdown)
if jsonOutput {
if err == nil {
json.NewEncoder(os.Stdout).Encode(string(""))
} else {
json.NewEncoder(os.Stdout).Encode(err)
}
} else {
if err != nil {
fmt.Fprintf(os.Stderr, "%s: %v\n", action, err)
}
}
if err != nil {
return 1
}
return 0
}

func init() {
commands = append(commands, command{
names: []string{"shutdown"},
usage: "Shut down layer storage",
minArgs: 0,
action: shutdown,
addFlags: func(flags *mflag.FlagSet, cmd *command) {
flags.BoolVar(&jsonOutput, []string{"-json", "j"}, jsonOutput, "Prefer JSON output")
flags.BoolVar(&forceShutdown, []string{"-force", "f"}, forceShutdown, "Unmount mounted layers first")
},
})
}
18 changes: 0 additions & 18 deletions docs/oci-storage-list-deps.md

This file was deleted.

20 changes: 20 additions & 0 deletions docs/oci-storage-shutdown.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
## oci-storage-shutdown 1 "October 2016"

## NAME
oci-storage shutdown - Shut down layer storage

## SYNOPSIS
**oci-storage** **shutdown** [*options* [...]]

## DESCRIPTION
Shuts down the layer storage driver, which may be using kernel resources.

## OPTIONS
**-f | --force**

Attempt to unmount any mounted layers before attempting to shut down the
driver. If this option is not specified, if any layers are mounted, shutdown
will not be attempted.

## EXAMPLE
**oci-storage shutdown**
2 changes: 1 addition & 1 deletion docs/oci-storage.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,14 @@ The *oci-storage* command's features are broken down into several subcommands:
**oci-storage images(1)** List images
**oci-storage layers(1)** List layers
**oci-storage list-container-data(1)** List data items that are attached to a container
**oci-storage list-deps(1)** List referrers to a layer, image, or container
**oci-storage list-image-data(1)** List data items that are attached to an image
**oci-storage metadata(1)** Retrieve layer, image, or container metadata
**oci-storage mount(1)** Mount a layer or container
**oci-storage set-container-data(1)** Set data that is attached to a container
**oci-storage set-image-data(1)** Set data that is attached to an image
**oci-storage set-metadata(1)** Set layer, image, or container metadata
**oci-storage set-names(1)** Set layer, image, or container name or names
**oci-storage shutdown(1)** Shut down graph driver
**oci-storage status(1)** Check on graph driver status
**oci-storage unmount(1)** Unmount a layer or container
**oci-storage version(1)** Return oci-storage version information
Expand Down
125 changes: 110 additions & 15 deletions storage/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"os"
"path/filepath"
"strings"
"sync"
"time"

// register all of the built-in drivers
_ "github.com/containers/storage/drivers/register"
Expand Down Expand Up @@ -309,6 +309,12 @@ type Store interface {
// name or ID.
Lookup(name string) (string, error)

// Shutdown attempts to free any kernel resources which are being used
// by the underlying driver. If "force" is true, any mounted (i.e., in
// use) layers are unmounted beforehand. If "force" is not true, then
// layers being in use is considered to be an error condition. A list
// of still-mounted layers is returned along with possible errors.
Shutdown(force bool) (layers []string, err error)

// Version returns version information, in the form of key-value pairs, from
// the storage package.
Expand Down Expand Up @@ -338,8 +344,9 @@ type Users struct {
}

type store struct {
lastLoaded time.Time
runRoot string
graphLock sync.Locker
graphLock Locker
graphRoot string
graphDriverName string
graphOptions []string
Expand Down Expand Up @@ -427,27 +434,20 @@ func (s *store) GetGraphOptions() []string {
}

func (s *store) load() error {
driver, err := drivers.New(s.graphRoot, s.graphDriverName, s.graphOptions, s.uidMap, s.gidMap)
driver, err := s.GetGraphDriver()
if err != nil {
return err
}
s.graphDriver = driver
s.graphDriverName = driver.String()
driverPrefix := s.graphDriverName + "-"

rlpath := filepath.Join(s.runRoot, driverPrefix+"layers")
if err := os.MkdirAll(rlpath, 0700); err != nil {
return err
}
glpath := filepath.Join(s.graphRoot, driverPrefix+"layers")
if err := os.MkdirAll(glpath, 0700); err != nil {
return err
}
rls, err := newLayerStore(rlpath, glpath, driver)
rls, err := s.GetLayerStore()
if err != nil {
return err
}
s.layerStore = rls

gipath := filepath.Join(s.graphRoot, driverPrefix+"images")
if err := os.MkdirAll(gipath, 0700); err != nil {
return err
Expand All @@ -473,18 +473,60 @@ func (s *store) load() error {
return nil
}

func (s *store) GetGraphDriver() (drivers.Driver, error) {
func (s *store) getGraphDriver() (drivers.Driver, error) {
if s.graphDriver != nil {
return s.graphDriver, nil
}
return nil, ErrLoadError
driver, err := drivers.New(s.graphRoot, s.graphDriverName, s.graphOptions, s.uidMap, s.gidMap)
if err != nil {
return nil, err
}
s.graphDriver = driver
s.graphDriverName = driver.String()
return driver, nil
}

func (s *store) GetGraphDriver() (drivers.Driver, error) {
s.graphLock.Lock()
defer s.graphLock.Unlock()
if s.graphLock.TouchedSince(s.lastLoaded) {
s.graphDriver = nil
s.layerStore = nil
s.lastLoaded = time.Now()
}
return s.getGraphDriver()
}

func (s *store) GetLayerStore() (LayerStore, error) {
s.graphLock.Lock()
defer s.graphLock.Unlock()
if s.graphLock.TouchedSince(s.lastLoaded) {
s.graphDriver = nil
s.layerStore = nil
s.lastLoaded = time.Now()
}
if s.layerStore != nil {
return s.layerStore, nil
}
return nil, ErrLoadError
driver, err := s.getGraphDriver()
if err != nil {
return nil, err
}
driverPrefix := s.graphDriverName + "-"
rlpath := filepath.Join(s.runRoot, driverPrefix+"layers")
if err := os.MkdirAll(rlpath, 0700); err != nil {
return nil, err
}
glpath := filepath.Join(s.graphRoot, driverPrefix+"layers")
if err := os.MkdirAll(glpath, 0700); err != nil {
return nil, err
}
rls, err := newLayerStore(rlpath, glpath, driver)
if err != nil {
return nil, err
}
s.layerStore = rls
return s.layerStore, nil
}

func (s *store) GetImageStore() (ImageStore, error) {
Expand Down Expand Up @@ -1939,6 +1981,59 @@ func (s *store) GetContainerRunDirectoryFile(id, file string) ([]byte, error) {
return ioutil.ReadFile(filepath.Join(dir, file))
}

func (s *store) Shutdown(force bool) ([]string, error) {
mounted := []string{}
modified := false

rlstore, err := s.GetLayerStore()
if err != nil {
return mounted, err
}

rlstore.Lock()
defer rlstore.Unlock()
if modified, err := rlstore.Modified(); modified || err != nil {
rlstore.Load()
}

s.graphLock.Lock()
defer s.graphLock.Unlock()
layers, err := rlstore.Layers()
if err != nil {
return mounted, err
}
for _, layer := range layers {
if layer.MountCount == 0 {
continue
}
mounted = append(mounted, layer.ID)
if force {
for layer.MountCount > 0 {
err2 := rlstore.Unmount(layer.ID)
if err2 != nil {
if err == nil {
err = err2
}
break
}
modified = true
}
}
}
if len(mounted) > 0 && err == nil {
err = ErrLayerUsedByContainer
}
if err == nil {
err = s.graphDriver.Cleanup()
s.graphLock.Touch()
modified = true
}
if modified {
rlstore.Touch()
}
return mounted, err
}

// MakeMall was the old name of MakeStore. It will be dropped at some point.
func MakeMall(runRoot, graphRoot, graphDriverName string, graphOptions []string) (Mall, error) {
return MakeStore(runRoot, graphRoot, graphDriverName, graphOptions, nil, nil)
Expand Down

0 comments on commit b046fb5

Please sign in to comment.