github.com/fabiokung/docker@v0.11.2-0.20170222101415-4534dcd49497/volume/store/store.go (about)

     1  package store
     2  
     3  import (
     4  	"net"
     5  	"os"
     6  	"path/filepath"
     7  	"sync"
     8  	"time"
     9  
    10  	"github.com/pkg/errors"
    11  
    12  	"github.com/Sirupsen/logrus"
    13  	"github.com/boltdb/bolt"
    14  	"github.com/docker/docker/pkg/locker"
    15  	"github.com/docker/docker/volume"
    16  	"github.com/docker/docker/volume/drivers"
    17  )
    18  
    19  const (
    20  	volumeDataDir = "volumes"
    21  )
    22  
    23  type volumeWrapper struct {
    24  	volume.Volume
    25  	labels  map[string]string
    26  	scope   string
    27  	options map[string]string
    28  }
    29  
    30  func (v volumeWrapper) Options() map[string]string {
    31  	options := map[string]string{}
    32  	for key, value := range v.options {
    33  		options[key] = value
    34  	}
    35  	return options
    36  }
    37  
    38  func (v volumeWrapper) Labels() map[string]string {
    39  	return v.labels
    40  }
    41  
    42  func (v volumeWrapper) Scope() string {
    43  	return v.scope
    44  }
    45  
    46  func (v volumeWrapper) CachedPath() string {
    47  	if vv, ok := v.Volume.(interface {
    48  		CachedPath() string
    49  	}); ok {
    50  		return vv.CachedPath()
    51  	}
    52  	return v.Volume.Path()
    53  }
    54  
    55  // New initializes a VolumeStore to keep
    56  // reference counting of volumes in the system.
    57  func New(rootPath string) (*VolumeStore, error) {
    58  	vs := &VolumeStore{
    59  		locks:   &locker.Locker{},
    60  		names:   make(map[string]volume.Volume),
    61  		refs:    make(map[string]map[string]struct{}),
    62  		labels:  make(map[string]map[string]string),
    63  		options: make(map[string]map[string]string),
    64  	}
    65  
    66  	if rootPath != "" {
    67  		// initialize metadata store
    68  		volPath := filepath.Join(rootPath, volumeDataDir)
    69  		if err := os.MkdirAll(volPath, 750); err != nil {
    70  			return nil, err
    71  		}
    72  
    73  		dbPath := filepath.Join(volPath, "metadata.db")
    74  
    75  		var err error
    76  		vs.db, err = bolt.Open(dbPath, 0600, &bolt.Options{Timeout: 1 * time.Second})
    77  		if err != nil {
    78  			return nil, errors.Wrap(err, "error while opening volume store metadata database")
    79  		}
    80  
    81  		// initialize volumes bucket
    82  		if err := vs.db.Update(func(tx *bolt.Tx) error {
    83  			if _, err := tx.CreateBucketIfNotExists(volumeBucketName); err != nil {
    84  				return errors.Wrap(err, "error while setting up volume store metadata database")
    85  			}
    86  			return nil
    87  		}); err != nil {
    88  			return nil, err
    89  		}
    90  	}
    91  
    92  	vs.restore()
    93  
    94  	return vs, nil
    95  }
    96  
    97  func (s *VolumeStore) getNamed(name string) (volume.Volume, bool) {
    98  	s.globalLock.RLock()
    99  	v, exists := s.names[name]
   100  	s.globalLock.RUnlock()
   101  	return v, exists
   102  }
   103  
   104  func (s *VolumeStore) setNamed(v volume.Volume, ref string) {
   105  	name := v.Name()
   106  
   107  	s.globalLock.Lock()
   108  	s.names[name] = v
   109  	if len(ref) > 0 {
   110  		if s.refs[name] == nil {
   111  			s.refs[name] = make(map[string]struct{})
   112  		}
   113  		s.refs[name][ref] = struct{}{}
   114  	}
   115  	s.globalLock.Unlock()
   116  }
   117  
   118  // hasRef returns true if the given name has at least one ref.
   119  // Callers of this function are expected to hold the name lock.
   120  func (s *VolumeStore) hasRef(name string) bool {
   121  	s.globalLock.RLock()
   122  	l := len(s.refs[name])
   123  	s.globalLock.RUnlock()
   124  	return l > 0
   125  }
   126  
   127  // getRefs gets the list of refs for a given name
   128  // Callers of this function are expected to hold the name lock.
   129  func (s *VolumeStore) getRefs(name string) []string {
   130  	s.globalLock.RLock()
   131  	defer s.globalLock.RUnlock()
   132  
   133  	refs := make([]string, 0, len(s.refs[name]))
   134  	for r := range s.refs[name] {
   135  		refs = append(refs, r)
   136  	}
   137  
   138  	return refs
   139  }
   140  
   141  // Purge allows the cleanup of internal data on docker in case
   142  // the internal data is out of sync with volumes driver plugins.
   143  func (s *VolumeStore) Purge(name string) {
   144  	s.globalLock.Lock()
   145  	v, exists := s.names[name]
   146  	if exists {
   147  		if _, err := volumedrivers.RemoveDriver(v.DriverName()); err != nil {
   148  			logrus.Errorf("Error dereferencing volume driver: %v", err)
   149  		}
   150  	}
   151  	if err := s.removeMeta(name); err != nil {
   152  		logrus.Errorf("Error removing volume metadata for volume %q: %v", name, err)
   153  	}
   154  	delete(s.names, name)
   155  	delete(s.refs, name)
   156  	delete(s.labels, name)
   157  	delete(s.options, name)
   158  	s.globalLock.Unlock()
   159  }
   160  
   161  // VolumeStore is a struct that stores the list of volumes available and keeps track of their usage counts
   162  type VolumeStore struct {
   163  	// locks ensures that only one action is being performed on a particular volume at a time without locking the entire store
   164  	// since actions on volumes can be quite slow, this ensures the store is free to handle requests for other volumes.
   165  	locks *locker.Locker
   166  	// globalLock is used to protect access to mutable structures used by the store object
   167  	globalLock sync.RWMutex
   168  	// names stores the volume name -> volume relationship.
   169  	// This is used for making lookups faster so we don't have to probe all drivers
   170  	names map[string]volume.Volume
   171  	// refs stores the volume name and the list of things referencing it
   172  	refs map[string]map[string]struct{}
   173  	// labels stores volume labels for each volume
   174  	labels map[string]map[string]string
   175  	// options stores volume options for each volume
   176  	options map[string]map[string]string
   177  	db      *bolt.DB
   178  }
   179  
   180  // List proxies to all registered volume drivers to get the full list of volumes
   181  // If a driver returns a volume that has name which conflicts with another volume from a different driver,
   182  // the first volume is chosen and the conflicting volume is dropped.
   183  func (s *VolumeStore) List() ([]volume.Volume, []string, error) {
   184  	vols, warnings, err := s.list()
   185  	if err != nil {
   186  		return nil, nil, &OpErr{Err: err, Op: "list"}
   187  	}
   188  	var out []volume.Volume
   189  
   190  	for _, v := range vols {
   191  		name := normaliseVolumeName(v.Name())
   192  
   193  		s.locks.Lock(name)
   194  		storedV, exists := s.getNamed(name)
   195  		// Note: it's not safe to populate the cache here because the volume may have been
   196  		// deleted before we acquire a lock on its name
   197  		if exists && storedV.DriverName() != v.DriverName() {
   198  			logrus.Warnf("Volume name %s already exists for driver %s, not including volume returned by %s", v.Name(), storedV.DriverName(), v.DriverName())
   199  			s.locks.Unlock(v.Name())
   200  			continue
   201  		}
   202  
   203  		out = append(out, v)
   204  		s.locks.Unlock(v.Name())
   205  	}
   206  	return out, warnings, nil
   207  }
   208  
   209  // list goes through each volume driver and asks for its list of volumes.
   210  func (s *VolumeStore) list() ([]volume.Volume, []string, error) {
   211  	var (
   212  		ls       []volume.Volume
   213  		warnings []string
   214  	)
   215  
   216  	drivers, err := volumedrivers.GetAllDrivers()
   217  	if err != nil {
   218  		return nil, nil, err
   219  	}
   220  
   221  	type vols struct {
   222  		vols       []volume.Volume
   223  		err        error
   224  		driverName string
   225  	}
   226  	chVols := make(chan vols, len(drivers))
   227  
   228  	for _, vd := range drivers {
   229  		go func(d volume.Driver) {
   230  			vs, err := d.List()
   231  			if err != nil {
   232  				chVols <- vols{driverName: d.Name(), err: &OpErr{Err: err, Name: d.Name(), Op: "list"}}
   233  				return
   234  			}
   235  			for i, v := range vs {
   236  				s.globalLock.RLock()
   237  				vs[i] = volumeWrapper{v, s.labels[v.Name()], d.Scope(), s.options[v.Name()]}
   238  				s.globalLock.RUnlock()
   239  			}
   240  
   241  			chVols <- vols{vols: vs}
   242  		}(vd)
   243  	}
   244  
   245  	badDrivers := make(map[string]struct{})
   246  	for i := 0; i < len(drivers); i++ {
   247  		vs := <-chVols
   248  
   249  		if vs.err != nil {
   250  			warnings = append(warnings, vs.err.Error())
   251  			badDrivers[vs.driverName] = struct{}{}
   252  			logrus.Warn(vs.err)
   253  		}
   254  		ls = append(ls, vs.vols...)
   255  	}
   256  
   257  	if len(badDrivers) > 0 {
   258  		s.globalLock.RLock()
   259  		for _, v := range s.names {
   260  			if _, exists := badDrivers[v.DriverName()]; exists {
   261  				ls = append(ls, v)
   262  			}
   263  		}
   264  		s.globalLock.RUnlock()
   265  	}
   266  	return ls, warnings, nil
   267  }
   268  
   269  // CreateWithRef creates a volume with the given name and driver and stores the ref
   270  // This ensures there's no race between creating a volume and then storing a reference.
   271  func (s *VolumeStore) CreateWithRef(name, driverName, ref string, opts, labels map[string]string) (volume.Volume, error) {
   272  	name = normaliseVolumeName(name)
   273  	s.locks.Lock(name)
   274  	defer s.locks.Unlock(name)
   275  
   276  	v, err := s.create(name, driverName, opts, labels)
   277  	if err != nil {
   278  		if _, ok := err.(*OpErr); ok {
   279  			return nil, err
   280  		}
   281  		return nil, &OpErr{Err: err, Name: name, Op: "create"}
   282  	}
   283  
   284  	s.setNamed(v, ref)
   285  	return v, nil
   286  }
   287  
   288  // Create creates a volume with the given name and driver.
   289  // This is just like CreateWithRef() except we don't store a reference while holding the lock.
   290  func (s *VolumeStore) Create(name, driverName string, opts, labels map[string]string) (volume.Volume, error) {
   291  	return s.CreateWithRef(name, driverName, "", opts, labels)
   292  }
   293  
   294  // checkConflict checks the local cache for name collisions with the passed in name,
   295  // for existing volumes with the same name but in a different driver.
   296  // This is used by `Create` as a best effort to prevent name collisions for volumes.
   297  // If a matching volume is found that is not a conflict that is returned so the caller
   298  // does not need to perform an additional lookup.
   299  // When no matching volume is found, both returns will be nil
   300  //
   301  // Note: This does not probe all the drivers for name collisions because v1 plugins
   302  // are very slow, particularly if the plugin is down, and cause other issues,
   303  // particularly around locking the store.
   304  // TODO(cpuguy83): With v2 plugins this shouldn't be a problem. Could also potentially
   305  // use a connect timeout for this kind of check to ensure we aren't blocking for a
   306  // long time.
   307  func (s *VolumeStore) checkConflict(name, driverName string) (volume.Volume, error) {
   308  	// check the local cache
   309  	v, _ := s.getNamed(name)
   310  	if v == nil {
   311  		return nil, nil
   312  	}
   313  
   314  	vDriverName := v.DriverName()
   315  	var conflict bool
   316  	if driverName != "" {
   317  		// Retrieve canonical driver name to avoid inconsistencies (for example
   318  		// "plugin" vs. "plugin:latest")
   319  		vd, err := volumedrivers.GetDriver(driverName)
   320  		if err != nil {
   321  			return nil, err
   322  		}
   323  
   324  		if vDriverName != vd.Name() {
   325  			conflict = true
   326  		}
   327  	}
   328  
   329  	// let's check if the found volume ref
   330  	// is stale by checking with the driver if it still exists
   331  	exists, err := volumeExists(v)
   332  	if err != nil {
   333  		return nil, errors.Wrapf(errNameConflict, "found reference to volume '%s' in driver '%s', but got an error while checking the driver: %v", name, vDriverName, err)
   334  	}
   335  
   336  	if exists {
   337  		if conflict {
   338  			return nil, errors.Wrapf(errNameConflict, "driver '%s' already has volume '%s'", vDriverName, name)
   339  		}
   340  		return v, nil
   341  	}
   342  
   343  	if s.hasRef(v.Name()) {
   344  		// Containers are referencing this volume but it doesn't seem to exist anywhere.
   345  		// Return a conflict error here, the user can fix this with `docker volume rm -f`
   346  		return nil, errors.Wrapf(errNameConflict, "found references to volume '%s' in driver '%s' but the volume was not found in the driver -- you may need to remove containers referencing this volume or force remove the volume to re-create it", name, vDriverName)
   347  	}
   348  
   349  	// doesn't exist, so purge it from the cache
   350  	s.Purge(name)
   351  	return nil, nil
   352  }
   353  
   354  // volumeExists returns if the volume is still present in the driver.
   355  // An error is returned if there was an issue communicating with the driver.
   356  func volumeExists(v volume.Volume) (bool, error) {
   357  	exists, err := lookupVolume(v.DriverName(), v.Name())
   358  	if err != nil {
   359  		return false, err
   360  	}
   361  	return exists != nil, nil
   362  }
   363  
   364  // create asks the given driver to create a volume with the name/opts.
   365  // If a volume with the name is already known, it will ask the stored driver for the volume.
   366  // If the passed in driver name does not match the driver name which is stored
   367  //  for the given volume name, an error is returned after checking if the reference is stale.
   368  // If the reference is stale, it will be purged and this create can continue.
   369  // It is expected that callers of this function hold any necessary locks.
   370  func (s *VolumeStore) create(name, driverName string, opts, labels map[string]string) (volume.Volume, error) {
   371  	// Validate the name in a platform-specific manner
   372  	valid, err := volume.IsVolumeNameValid(name)
   373  	if err != nil {
   374  		return nil, err
   375  	}
   376  	if !valid {
   377  		return nil, &OpErr{Err: errInvalidName, Name: name, Op: "create"}
   378  	}
   379  
   380  	v, err := s.checkConflict(name, driverName)
   381  	if err != nil {
   382  		return nil, err
   383  	}
   384  
   385  	if v != nil {
   386  		return v, nil
   387  	}
   388  
   389  	// Since there isn't a specified driver name, let's see if any of the existing drivers have this volume name
   390  	if driverName == "" {
   391  		v, _ := s.getVolume(name)
   392  		if v != nil {
   393  			return v, nil
   394  		}
   395  	}
   396  
   397  	vd, err := volumedrivers.CreateDriver(driverName)
   398  
   399  	if err != nil {
   400  		return nil, &OpErr{Op: "create", Name: name, Err: err}
   401  	}
   402  
   403  	logrus.Debugf("Registering new volume reference: driver %q, name %q", vd.Name(), name)
   404  
   405  	if v, _ := vd.Get(name); v != nil {
   406  		return v, nil
   407  	}
   408  	v, err = vd.Create(name, opts)
   409  	if err != nil {
   410  		return nil, err
   411  	}
   412  	s.globalLock.Lock()
   413  	s.labels[name] = labels
   414  	s.options[name] = opts
   415  	s.refs[name] = make(map[string]struct{})
   416  	s.globalLock.Unlock()
   417  
   418  	metadata := volumeMetadata{
   419  		Name:    name,
   420  		Driver:  vd.Name(),
   421  		Labels:  labels,
   422  		Options: opts,
   423  	}
   424  
   425  	if err := s.setMeta(name, metadata); err != nil {
   426  		return nil, err
   427  	}
   428  	return volumeWrapper{v, labels, vd.Scope(), opts}, nil
   429  }
   430  
   431  // GetWithRef gets a volume with the given name from the passed in driver and stores the ref
   432  // This is just like Get(), but we store the reference while holding the lock.
   433  // This makes sure there are no races between checking for the existence of a volume and adding a reference for it
   434  func (s *VolumeStore) GetWithRef(name, driverName, ref string) (volume.Volume, error) {
   435  	name = normaliseVolumeName(name)
   436  	s.locks.Lock(name)
   437  	defer s.locks.Unlock(name)
   438  
   439  	vd, err := volumedrivers.GetDriver(driverName)
   440  	if err != nil {
   441  		return nil, &OpErr{Err: err, Name: name, Op: "get"}
   442  	}
   443  
   444  	v, err := vd.Get(name)
   445  	if err != nil {
   446  		return nil, &OpErr{Err: err, Name: name, Op: "get"}
   447  	}
   448  
   449  	s.setNamed(v, ref)
   450  
   451  	s.globalLock.RLock()
   452  	defer s.globalLock.RUnlock()
   453  	return volumeWrapper{v, s.labels[name], vd.Scope(), s.options[name]}, nil
   454  }
   455  
   456  // Get looks if a volume with the given name exists and returns it if so
   457  func (s *VolumeStore) Get(name string) (volume.Volume, error) {
   458  	name = normaliseVolumeName(name)
   459  	s.locks.Lock(name)
   460  	defer s.locks.Unlock(name)
   461  
   462  	v, err := s.getVolume(name)
   463  	if err != nil {
   464  		return nil, &OpErr{Err: err, Name: name, Op: "get"}
   465  	}
   466  	s.setNamed(v, "")
   467  	return v, nil
   468  }
   469  
   470  // getVolume requests the volume, if the driver info is stored it just accesses that driver,
   471  // if the driver is unknown it probes all drivers until it finds the first volume with that name.
   472  // it is expected that callers of this function hold any necessary locks
   473  func (s *VolumeStore) getVolume(name string) (volume.Volume, error) {
   474  	var meta volumeMetadata
   475  	meta, err := s.getMeta(name)
   476  	if err != nil {
   477  		return nil, err
   478  	}
   479  
   480  	driverName := meta.Driver
   481  	if driverName == "" {
   482  		s.globalLock.RLock()
   483  		v, exists := s.names[name]
   484  		s.globalLock.RUnlock()
   485  		if exists {
   486  			meta.Driver = v.DriverName()
   487  			if err := s.setMeta(name, meta); err != nil {
   488  				return nil, err
   489  			}
   490  		}
   491  	}
   492  
   493  	if meta.Driver != "" {
   494  		vol, err := lookupVolume(meta.Driver, name)
   495  		if err != nil {
   496  			return nil, err
   497  		}
   498  		if vol == nil {
   499  			s.Purge(name)
   500  			return nil, errNoSuchVolume
   501  		}
   502  
   503  		var scope string
   504  		vd, err := volumedrivers.GetDriver(meta.Driver)
   505  		if err == nil {
   506  			scope = vd.Scope()
   507  		}
   508  		return volumeWrapper{vol, meta.Labels, scope, meta.Options}, nil
   509  	}
   510  
   511  	logrus.Debugf("Probing all drivers for volume with name: %s", name)
   512  	drivers, err := volumedrivers.GetAllDrivers()
   513  	if err != nil {
   514  		return nil, err
   515  	}
   516  
   517  	for _, d := range drivers {
   518  		v, err := d.Get(name)
   519  		if err != nil || v == nil {
   520  			continue
   521  		}
   522  		meta.Driver = v.DriverName()
   523  		if err := s.setMeta(name, meta); err != nil {
   524  			return nil, err
   525  		}
   526  		return volumeWrapper{v, meta.Labels, d.Scope(), meta.Options}, nil
   527  	}
   528  	return nil, errNoSuchVolume
   529  }
   530  
   531  // lookupVolume gets the specified volume from the specified driver.
   532  // This will only return errors related to communications with the driver.
   533  // If the driver returns an error that is not communication related the
   534  //   error is logged but not returned.
   535  // If the volume is not found it will return `nil, nil``
   536  func lookupVolume(driverName, volumeName string) (volume.Volume, error) {
   537  	vd, err := volumedrivers.GetDriver(driverName)
   538  	if err != nil {
   539  		return nil, errors.Wrapf(err, "error while checking if volume %q exists in driver %q", volumeName, driverName)
   540  	}
   541  	v, err := vd.Get(volumeName)
   542  	if err != nil {
   543  		err = errors.Cause(err)
   544  		if _, ok := err.(net.Error); ok {
   545  			return nil, errors.Wrapf(err, "error while checking if volume %q exists in driver %q", v.Name(), v.DriverName())
   546  		}
   547  
   548  		// At this point, the error could be anything from the driver, such as "no such volume"
   549  		// Let's not check an error here, and instead check if the driver returned a volume
   550  		logrus.WithError(err).WithField("driver", driverName).WithField("volume", volumeName).Warnf("Error while looking up volume")
   551  	}
   552  	return v, nil
   553  }
   554  
   555  // Remove removes the requested volume. A volume is not removed if it has any refs
   556  func (s *VolumeStore) Remove(v volume.Volume) error {
   557  	name := normaliseVolumeName(v.Name())
   558  	s.locks.Lock(name)
   559  	defer s.locks.Unlock(name)
   560  
   561  	if s.hasRef(name) {
   562  		return &OpErr{Err: errVolumeInUse, Name: v.Name(), Op: "remove", Refs: s.getRefs(name)}
   563  	}
   564  
   565  	vd, err := volumedrivers.GetDriver(v.DriverName())
   566  	if err != nil {
   567  		return &OpErr{Err: err, Name: vd.Name(), Op: "remove"}
   568  	}
   569  
   570  	logrus.Debugf("Removing volume reference: driver %s, name %s", v.DriverName(), name)
   571  	vol := unwrapVolume(v)
   572  	if err := vd.Remove(vol); err != nil {
   573  		return &OpErr{Err: err, Name: name, Op: "remove"}
   574  	}
   575  
   576  	s.Purge(name)
   577  	return nil
   578  }
   579  
   580  // Dereference removes the specified reference to the volume
   581  func (s *VolumeStore) Dereference(v volume.Volume, ref string) {
   582  	name := v.Name()
   583  
   584  	s.locks.Lock(name)
   585  	defer s.locks.Unlock(name)
   586  
   587  	s.globalLock.Lock()
   588  	defer s.globalLock.Unlock()
   589  
   590  	if s.refs[name] != nil {
   591  		delete(s.refs[name], ref)
   592  	}
   593  }
   594  
   595  // Refs gets the current list of refs for the given volume
   596  func (s *VolumeStore) Refs(v volume.Volume) []string {
   597  	name := v.Name()
   598  
   599  	s.locks.Lock(name)
   600  	defer s.locks.Unlock(name)
   601  
   602  	return s.getRefs(name)
   603  }
   604  
   605  // FilterByDriver returns the available volumes filtered by driver name
   606  func (s *VolumeStore) FilterByDriver(name string) ([]volume.Volume, error) {
   607  	vd, err := volumedrivers.GetDriver(name)
   608  	if err != nil {
   609  		return nil, &OpErr{Err: err, Name: name, Op: "list"}
   610  	}
   611  	ls, err := vd.List()
   612  	if err != nil {
   613  		return nil, &OpErr{Err: err, Name: name, Op: "list"}
   614  	}
   615  	for i, v := range ls {
   616  		options := map[string]string{}
   617  		s.globalLock.RLock()
   618  		for key, value := range s.options[v.Name()] {
   619  			options[key] = value
   620  		}
   621  		ls[i] = volumeWrapper{v, s.labels[v.Name()], vd.Scope(), options}
   622  		s.globalLock.RUnlock()
   623  	}
   624  	return ls, nil
   625  }
   626  
   627  // FilterByUsed returns the available volumes filtered by if they are in use or not.
   628  // `used=true` returns only volumes that are being used, while `used=false` returns
   629  // only volumes that are not being used.
   630  func (s *VolumeStore) FilterByUsed(vols []volume.Volume, used bool) []volume.Volume {
   631  	return s.filter(vols, func(v volume.Volume) bool {
   632  		s.locks.Lock(v.Name())
   633  		hasRef := s.hasRef(v.Name())
   634  		s.locks.Unlock(v.Name())
   635  		return used == hasRef
   636  	})
   637  }
   638  
   639  // filterFunc defines a function to allow filter volumes in the store
   640  type filterFunc func(vol volume.Volume) bool
   641  
   642  // filter returns the available volumes filtered by a filterFunc function
   643  func (s *VolumeStore) filter(vols []volume.Volume, f filterFunc) []volume.Volume {
   644  	var ls []volume.Volume
   645  	for _, v := range vols {
   646  		if f(v) {
   647  			ls = append(ls, v)
   648  		}
   649  	}
   650  	return ls
   651  }
   652  
   653  func unwrapVolume(v volume.Volume) volume.Volume {
   654  	if vol, ok := v.(volumeWrapper); ok {
   655  		return vol.Volume
   656  	}
   657  
   658  	return v
   659  }
   660  
   661  // Shutdown releases all resources used by the volume store
   662  // It does not make any changes to volumes, drivers, etc.
   663  func (s *VolumeStore) Shutdown() error {
   664  	return s.db.Close()
   665  }