github.com/wozhu6104/docker@v20.10.10+incompatible/volume/service/store.go (about) 1 package service // import "github.com/docker/docker/volume/service" 2 3 import ( 4 "context" 5 "fmt" 6 "net" 7 "os" 8 "path/filepath" 9 "runtime" 10 "sync" 11 "time" 12 13 "github.com/docker/docker/errdefs" 14 "github.com/docker/docker/volume" 15 "github.com/docker/docker/volume/drivers" 16 volumemounts "github.com/docker/docker/volume/mounts" 17 "github.com/docker/docker/volume/service/opts" 18 "github.com/moby/locker" 19 "github.com/pkg/errors" 20 "github.com/sirupsen/logrus" 21 bolt "go.etcd.io/bbolt" 22 ) 23 24 const ( 25 volumeDataDir = "volumes" 26 ) 27 28 type volumeWrapper struct { 29 volume.Volume 30 labels map[string]string 31 scope string 32 options map[string]string 33 } 34 35 func (v volumeWrapper) Options() map[string]string { 36 if v.options == nil { 37 return nil 38 } 39 options := make(map[string]string, len(v.options)) 40 for key, value := range v.options { 41 options[key] = value 42 } 43 return options 44 } 45 46 func (v volumeWrapper) Labels() map[string]string { 47 if v.labels == nil { 48 return nil 49 } 50 51 labels := make(map[string]string, len(v.labels)) 52 for key, value := range v.labels { 53 labels[key] = value 54 } 55 return labels 56 } 57 58 func (v volumeWrapper) Scope() string { 59 return v.scope 60 } 61 62 func (v volumeWrapper) CachedPath() string { 63 if vv, ok := v.Volume.(interface { 64 CachedPath() string 65 }); ok { 66 return vv.CachedPath() 67 } 68 return v.Volume.Path() 69 } 70 71 // NewStore creates a new volume store at the given path 72 func NewStore(rootPath string, drivers *drivers.Store) (*VolumeStore, error) { 73 vs := &VolumeStore{ 74 locks: &locker.Locker{}, 75 names: make(map[string]volume.Volume), 76 refs: make(map[string]map[string]struct{}), 77 labels: make(map[string]map[string]string), 78 options: make(map[string]map[string]string), 79 drivers: drivers, 80 } 81 82 if rootPath != "" { 83 // initialize metadata store 84 volPath := filepath.Join(rootPath, volumeDataDir) 85 if err := os.MkdirAll(volPath, 0750); err != nil { 86 return nil, err 87 } 88 89 var err error 90 vs.db, err = bolt.Open(filepath.Join(volPath, "metadata.db"), 0600, &bolt.Options{Timeout: 1 * time.Second}) 91 if err != nil { 92 return nil, errors.Wrap(err, "error while opening volume store metadata database") 93 } 94 95 // initialize volumes bucket 96 if err := vs.db.Update(func(tx *bolt.Tx) error { 97 if _, err := tx.CreateBucketIfNotExists(volumeBucketName); err != nil { 98 return errors.Wrap(err, "error while setting up volume store metadata database") 99 } 100 return nil 101 }); err != nil { 102 return nil, err 103 } 104 } 105 106 vs.restore() 107 108 return vs, nil 109 } 110 111 func (s *VolumeStore) getNamed(name string) (volume.Volume, bool) { 112 s.globalLock.RLock() 113 v, exists := s.names[name] 114 s.globalLock.RUnlock() 115 return v, exists 116 } 117 118 func (s *VolumeStore) setNamed(v volume.Volume, ref string) { 119 name := v.Name() 120 121 s.globalLock.Lock() 122 s.names[name] = v 123 if len(ref) > 0 { 124 if s.refs[name] == nil { 125 s.refs[name] = make(map[string]struct{}) 126 } 127 s.refs[name][ref] = struct{}{} 128 } 129 s.globalLock.Unlock() 130 } 131 132 // hasRef returns true if the given name has at least one ref. 133 // Callers of this function are expected to hold the name lock. 134 func (s *VolumeStore) hasRef(name string) bool { 135 s.globalLock.RLock() 136 l := len(s.refs[name]) 137 s.globalLock.RUnlock() 138 return l > 0 139 } 140 141 // getRefs gets the list of refs for a given name 142 // Callers of this function are expected to hold the name lock. 143 func (s *VolumeStore) getRefs(name string) []string { 144 s.globalLock.RLock() 145 defer s.globalLock.RUnlock() 146 147 refs := make([]string, 0, len(s.refs[name])) 148 for r := range s.refs[name] { 149 refs = append(refs, r) 150 } 151 152 return refs 153 } 154 155 // purge allows the cleanup of internal data on docker in case 156 // the internal data is out of sync with volumes driver plugins. 157 func (s *VolumeStore) purge(ctx context.Context, name string) error { 158 s.globalLock.Lock() 159 defer s.globalLock.Unlock() 160 161 select { 162 case <-ctx.Done(): 163 return ctx.Err() 164 default: 165 } 166 167 v, exists := s.names[name] 168 if exists { 169 driverName := v.DriverName() 170 if _, err := s.drivers.ReleaseDriver(driverName); err != nil { 171 logrus.WithError(err).WithField("driver", driverName).Error("Error releasing reference to volume driver") 172 } 173 } 174 if err := s.removeMeta(name); err != nil { 175 logrus.Errorf("Error removing volume metadata for volume %q: %v", name, err) 176 } 177 delete(s.names, name) 178 delete(s.refs, name) 179 delete(s.labels, name) 180 delete(s.options, name) 181 return nil 182 } 183 184 // VolumeStore is responsible for storing and reference counting volumes. 185 type VolumeStore struct { 186 // locks ensures that only one action is being performed on a particular volume at a time without locking the entire store 187 // since actions on volumes can be quite slow, this ensures the store is free to handle requests for other volumes. 188 locks *locker.Locker 189 drivers *drivers.Store 190 // globalLock is used to protect access to mutable structures used by the store object 191 globalLock sync.RWMutex 192 // names stores the volume name -> volume relationship. 193 // This is used for making lookups faster so we don't have to probe all drivers 194 names map[string]volume.Volume 195 // refs stores the volume name and the list of things referencing it 196 refs map[string]map[string]struct{} 197 // labels stores volume labels for each volume 198 labels map[string]map[string]string 199 // options stores volume options for each volume 200 options map[string]map[string]string 201 db *bolt.DB 202 } 203 204 func filterByDriver(names []string) filterFunc { 205 return func(v volume.Volume) bool { 206 for _, name := range names { 207 if name == v.DriverName() { 208 return true 209 } 210 } 211 return false 212 } 213 } 214 215 func (s *VolumeStore) byReferenced(referenced bool) filterFunc { 216 return func(v volume.Volume) bool { 217 return s.hasRef(v.Name()) == referenced 218 } 219 } 220 221 func (s *VolumeStore) filter(ctx context.Context, vols *[]volume.Volume, by By) (warnings []string, err error) { 222 // note that this specifically does not support the `FromList` By type. 223 switch f := by.(type) { 224 case nil: 225 if *vols == nil { 226 var ls []volume.Volume 227 ls, warnings, err = s.list(ctx) 228 if err != nil { 229 return warnings, err 230 } 231 *vols = ls 232 } 233 case byDriver: 234 if *vols != nil { 235 filter(vols, filterByDriver([]string(f))) 236 return nil, nil 237 } 238 var ls []volume.Volume 239 ls, warnings, err = s.list(ctx, []string(f)...) 240 if err != nil { 241 return nil, err 242 } 243 *vols = ls 244 case ByReferenced: 245 // TODO(@cpuguy83): It would be nice to optimize this by looking at the list 246 // of referenced volumes, however the locking strategy makes this difficult 247 // without either providing inconsistent data or deadlocks. 248 if *vols == nil { 249 var ls []volume.Volume 250 ls, warnings, err = s.list(ctx) 251 if err != nil { 252 return nil, err 253 } 254 *vols = ls 255 } 256 filter(vols, s.byReferenced(bool(f))) 257 case andCombinator: 258 for _, by := range f { 259 w, err := s.filter(ctx, vols, by) 260 if err != nil { 261 return warnings, err 262 } 263 warnings = append(warnings, w...) 264 } 265 case orCombinator: 266 for _, by := range f { 267 switch by.(type) { 268 case byDriver: 269 var ls []volume.Volume 270 w, err := s.filter(ctx, &ls, by) 271 if err != nil { 272 return warnings, err 273 } 274 warnings = append(warnings, w...) 275 default: 276 ls, w, err := s.list(ctx) 277 if err != nil { 278 return warnings, err 279 } 280 warnings = append(warnings, w...) 281 w, err = s.filter(ctx, &ls, by) 282 if err != nil { 283 return warnings, err 284 } 285 warnings = append(warnings, w...) 286 *vols = append(*vols, ls...) 287 } 288 } 289 unique(vols) 290 case CustomFilter: 291 if *vols == nil { 292 var ls []volume.Volume 293 ls, warnings, err = s.list(ctx) 294 if err != nil { 295 return nil, err 296 } 297 *vols = ls 298 } 299 filter(vols, filterFunc(f)) 300 default: 301 return nil, errdefs.InvalidParameter(errors.Errorf("unsupported filter: %T", f)) 302 } 303 return warnings, nil 304 } 305 306 func unique(ls *[]volume.Volume) { 307 names := make(map[string]bool, len(*ls)) 308 filter(ls, func(v volume.Volume) bool { 309 if names[v.Name()] { 310 return false 311 } 312 names[v.Name()] = true 313 return true 314 }) 315 } 316 317 // Find lists volumes filtered by the past in filter. 318 // If a driver returns a volume that has name which conflicts with another volume from a different driver, 319 // the first volume is chosen and the conflicting volume is dropped. 320 func (s *VolumeStore) Find(ctx context.Context, by By) (vols []volume.Volume, warnings []string, err error) { 321 logrus.WithField("ByType", fmt.Sprintf("%T", by)).WithField("ByValue", fmt.Sprintf("%+v", by)).Debug("VolumeStore.Find") 322 switch f := by.(type) { 323 case nil, orCombinator, andCombinator, byDriver, ByReferenced, CustomFilter: 324 warnings, err = s.filter(ctx, &vols, by) 325 case fromList: 326 warnings, err = s.filter(ctx, f.ls, f.by) 327 default: 328 // Really shouldn't be possible, but makes sure that any new By's are added to this check. 329 err = errdefs.InvalidParameter(errors.Errorf("unsupported filter type: %T", f)) 330 } 331 if err != nil { 332 return nil, nil, &OpErr{Err: err, Op: "list"} 333 } 334 335 var out []volume.Volume 336 337 for _, v := range vols { 338 name := normalizeVolumeName(v.Name()) 339 340 s.locks.Lock(name) 341 storedV, exists := s.getNamed(name) 342 // Note: it's not safe to populate the cache here because the volume may have been 343 // deleted before we acquire a lock on its name 344 if exists && storedV.DriverName() != v.DriverName() { 345 logrus.Warnf("Volume name %s already exists for driver %s, not including volume returned by %s", v.Name(), storedV.DriverName(), v.DriverName()) 346 s.locks.Unlock(v.Name()) 347 continue 348 } 349 350 out = append(out, v) 351 s.locks.Unlock(v.Name()) 352 } 353 return out, warnings, nil 354 } 355 356 type filterFunc func(volume.Volume) bool 357 358 func filter(vols *[]volume.Volume, fn filterFunc) { 359 var evict []int 360 for i, v := range *vols { 361 if !fn(v) { 362 evict = append(evict, i) 363 } 364 } 365 366 for n, i := range evict { 367 copy((*vols)[i-n:], (*vols)[i-n+1:]) 368 (*vols)[len(*vols)-1] = nil 369 *vols = (*vols)[:len(*vols)-1] 370 } 371 } 372 373 // list goes through each volume driver and asks for its list of volumes. 374 // TODO(@cpuguy83): plumb context through 375 func (s *VolumeStore) list(ctx context.Context, driverNames ...string) ([]volume.Volume, []string, error) { 376 var ( 377 ls = []volume.Volume{} // do not return a nil value as this affects filtering 378 warnings []string 379 ) 380 381 var dls []volume.Driver 382 383 all, err := s.drivers.GetAllDrivers() 384 if err != nil { 385 return nil, nil, err 386 } 387 if len(driverNames) == 0 { 388 dls = all 389 } else { 390 idx := make(map[string]bool, len(driverNames)) 391 for _, name := range driverNames { 392 idx[name] = true 393 } 394 for _, d := range all { 395 if idx[d.Name()] { 396 dls = append(dls, d) 397 } 398 } 399 } 400 401 type vols struct { 402 vols []volume.Volume 403 err error 404 driverName string 405 } 406 chVols := make(chan vols, len(dls)) 407 408 for _, vd := range dls { 409 go func(d volume.Driver) { 410 vs, err := d.List() 411 if err != nil { 412 chVols <- vols{driverName: d.Name(), err: &OpErr{Err: err, Name: d.Name(), Op: "list"}} 413 return 414 } 415 for i, v := range vs { 416 s.globalLock.RLock() 417 vs[i] = volumeWrapper{v, s.labels[v.Name()], d.Scope(), s.options[v.Name()]} 418 s.globalLock.RUnlock() 419 } 420 421 chVols <- vols{vols: vs} 422 }(vd) 423 } 424 425 badDrivers := make(map[string]struct{}) 426 for i := 0; i < len(dls); i++ { 427 vs := <-chVols 428 429 if vs.err != nil { 430 warnings = append(warnings, vs.err.Error()) 431 badDrivers[vs.driverName] = struct{}{} 432 } 433 ls = append(ls, vs.vols...) 434 } 435 436 if len(badDrivers) > 0 { 437 s.globalLock.RLock() 438 for _, v := range s.names { 439 if _, exists := badDrivers[v.DriverName()]; exists { 440 ls = append(ls, v) 441 } 442 } 443 s.globalLock.RUnlock() 444 } 445 return ls, warnings, nil 446 } 447 448 // Create creates a volume with the given name and driver 449 // If the volume needs to be created with a reference to prevent race conditions 450 // with volume cleanup, make sure to use the `CreateWithReference` option. 451 func (s *VolumeStore) Create(ctx context.Context, name, driverName string, createOpts ...opts.CreateOption) (volume.Volume, error) { 452 var cfg opts.CreateConfig 453 for _, o := range createOpts { 454 o(&cfg) 455 } 456 457 name = normalizeVolumeName(name) 458 s.locks.Lock(name) 459 defer s.locks.Unlock(name) 460 461 select { 462 case <-ctx.Done(): 463 return nil, ctx.Err() 464 default: 465 } 466 467 v, err := s.create(ctx, name, driverName, cfg.Options, cfg.Labels) 468 if err != nil { 469 if _, ok := err.(*OpErr); ok { 470 return nil, err 471 } 472 return nil, &OpErr{Err: err, Name: name, Op: "create"} 473 } 474 475 s.setNamed(v, cfg.Reference) 476 return v, nil 477 } 478 479 // checkConflict checks the local cache for name collisions with the passed in name, 480 // for existing volumes with the same name but in a different driver. 481 // This is used by `Create` as a best effort to prevent name collisions for volumes. 482 // If a matching volume is found that is not a conflict that is returned so the caller 483 // does not need to perform an additional lookup. 484 // When no matching volume is found, both returns will be nil 485 // 486 // Note: This does not probe all the drivers for name collisions because v1 plugins 487 // are very slow, particularly if the plugin is down, and cause other issues, 488 // particularly around locking the store. 489 // TODO(cpuguy83): With v2 plugins this shouldn't be a problem. Could also potentially 490 // use a connect timeout for this kind of check to ensure we aren't blocking for a 491 // long time. 492 func (s *VolumeStore) checkConflict(ctx context.Context, name, driverName string) (volume.Volume, error) { 493 // check the local cache 494 v, _ := s.getNamed(name) 495 if v == nil { 496 return nil, nil 497 } 498 499 vDriverName := v.DriverName() 500 var conflict bool 501 if driverName != "" { 502 // Retrieve canonical driver name to avoid inconsistencies (for example 503 // "plugin" vs. "plugin:latest") 504 vd, err := s.drivers.GetDriver(driverName) 505 if err != nil { 506 return nil, err 507 } 508 509 if vDriverName != vd.Name() { 510 conflict = true 511 } 512 } 513 514 // let's check if the found volume ref 515 // is stale by checking with the driver if it still exists 516 exists, err := volumeExists(ctx, s.drivers, v) 517 if err != nil { 518 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) 519 } 520 521 if exists { 522 if conflict { 523 return nil, errors.Wrapf(errNameConflict, "driver '%s' already has volume '%s'", vDriverName, name) 524 } 525 return v, nil 526 } 527 528 if s.hasRef(v.Name()) { 529 // Containers are referencing this volume but it doesn't seem to exist anywhere. 530 // Return a conflict error here, the user can fix this with `docker volume rm -f` 531 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) 532 } 533 534 // doesn't exist, so purge it from the cache 535 s.purge(ctx, name) 536 return nil, nil 537 } 538 539 // volumeExists returns if the volume is still present in the driver. 540 // An error is returned if there was an issue communicating with the driver. 541 func volumeExists(ctx context.Context, store *drivers.Store, v volume.Volume) (bool, error) { 542 exists, err := lookupVolume(ctx, store, v.DriverName(), v.Name()) 543 if err != nil { 544 return false, err 545 } 546 return exists != nil, nil 547 } 548 549 // create asks the given driver to create a volume with the name/opts. 550 // If a volume with the name is already known, it will ask the stored driver for the volume. 551 // If the passed in driver name does not match the driver name which is stored 552 // for the given volume name, an error is returned after checking if the reference is stale. 553 // If the reference is stale, it will be purged and this create can continue. 554 // It is expected that callers of this function hold any necessary locks. 555 func (s *VolumeStore) create(ctx context.Context, name, driverName string, opts, labels map[string]string) (volume.Volume, error) { 556 // Validate the name in a platform-specific manner 557 558 // volume name validation is specific to the host os and not on container image 559 // windows/lcow should have an equivalent volumename validation logic so we create a parser for current host OS 560 parser := volumemounts.NewParser(runtime.GOOS) 561 err := parser.ValidateVolumeName(name) 562 if err != nil { 563 return nil, err 564 } 565 566 v, err := s.checkConflict(ctx, name, driverName) 567 if err != nil { 568 return nil, err 569 } 570 571 if v != nil { 572 // there is an existing volume, if we already have this stored locally, return it. 573 // TODO: there could be some inconsistent details such as labels here 574 if vv, _ := s.getNamed(v.Name()); vv != nil { 575 return vv, nil 576 } 577 } 578 579 // Since there isn't a specified driver name, let's see if any of the existing drivers have this volume name 580 if driverName == "" { 581 v, _ = s.getVolume(ctx, name, "") 582 if v != nil { 583 return v, nil 584 } 585 } 586 587 if driverName == "" { 588 driverName = volume.DefaultDriverName 589 } 590 vd, err := s.drivers.CreateDriver(driverName) 591 if err != nil { 592 return nil, &OpErr{Op: "create", Name: name, Err: err} 593 } 594 595 logrus.Debugf("Registering new volume reference: driver %q, name %q", vd.Name(), name) 596 if v, _ = vd.Get(name); v == nil { 597 v, err = vd.Create(name, opts) 598 if err != nil { 599 if _, err := s.drivers.ReleaseDriver(driverName); err != nil { 600 logrus.WithError(err).WithField("driver", driverName).Error("Error releasing reference to volume driver") 601 } 602 return nil, err 603 } 604 } 605 606 s.globalLock.Lock() 607 s.labels[name] = labels 608 s.options[name] = opts 609 s.refs[name] = make(map[string]struct{}) 610 s.globalLock.Unlock() 611 612 metadata := volumeMetadata{ 613 Name: name, 614 Driver: vd.Name(), 615 Labels: labels, 616 Options: opts, 617 } 618 619 if err := s.setMeta(name, metadata); err != nil { 620 return nil, err 621 } 622 return volumeWrapper{v, labels, vd.Scope(), opts}, nil 623 } 624 625 // Get looks if a volume with the given name exists and returns it if so 626 func (s *VolumeStore) Get(ctx context.Context, name string, getOptions ...opts.GetOption) (volume.Volume, error) { 627 var cfg opts.GetConfig 628 for _, o := range getOptions { 629 o(&cfg) 630 } 631 name = normalizeVolumeName(name) 632 s.locks.Lock(name) 633 defer s.locks.Unlock(name) 634 635 v, err := s.getVolume(ctx, name, cfg.Driver) 636 if err != nil { 637 return nil, &OpErr{Err: err, Name: name, Op: "get"} 638 } 639 if cfg.Driver != "" && v.DriverName() != cfg.Driver { 640 return nil, &OpErr{Name: name, Op: "get", Err: errdefs.Conflict(errors.New("found volume driver does not match passed in driver"))} 641 } 642 s.setNamed(v, cfg.Reference) 643 return v, nil 644 } 645 646 // getVolume requests the volume, if the driver info is stored it just accesses that driver, 647 // if the driver is unknown it probes all drivers until it finds the first volume with that name. 648 // it is expected that callers of this function hold any necessary locks 649 func (s *VolumeStore) getVolume(ctx context.Context, name, driverName string) (volume.Volume, error) { 650 var meta volumeMetadata 651 meta, err := s.getMeta(name) 652 if err != nil { 653 return nil, err 654 } 655 656 if driverName != "" { 657 if meta.Driver == "" { 658 meta.Driver = driverName 659 } 660 if driverName != meta.Driver { 661 return nil, errdefs.Conflict(errors.New("provided volume driver does not match stored driver")) 662 } 663 } 664 665 if driverName == "" { 666 driverName = meta.Driver 667 } 668 if driverName == "" { 669 s.globalLock.RLock() 670 select { 671 case <-ctx.Done(): 672 s.globalLock.RUnlock() 673 return nil, ctx.Err() 674 default: 675 } 676 v, exists := s.names[name] 677 s.globalLock.RUnlock() 678 if exists { 679 meta.Driver = v.DriverName() 680 if err := s.setMeta(name, meta); err != nil { 681 return nil, err 682 } 683 } 684 } 685 686 if meta.Driver != "" { 687 vol, err := lookupVolume(ctx, s.drivers, meta.Driver, name) 688 if err != nil { 689 return nil, err 690 } 691 if vol == nil { 692 s.purge(ctx, name) 693 return nil, errNoSuchVolume 694 } 695 696 var scope string 697 vd, err := s.drivers.GetDriver(meta.Driver) 698 if err == nil { 699 scope = vd.Scope() 700 } 701 return volumeWrapper{vol, meta.Labels, scope, meta.Options}, nil 702 } 703 704 logrus.Debugf("Probing all drivers for volume with name: %s", name) 705 drivers, err := s.drivers.GetAllDrivers() 706 if err != nil { 707 return nil, err 708 } 709 710 for _, d := range drivers { 711 select { 712 case <-ctx.Done(): 713 return nil, ctx.Err() 714 default: 715 } 716 v, err := d.Get(name) 717 if err != nil || v == nil { 718 continue 719 } 720 meta.Driver = v.DriverName() 721 if err := s.setMeta(name, meta); err != nil { 722 return nil, err 723 } 724 return volumeWrapper{v, meta.Labels, d.Scope(), meta.Options}, nil 725 } 726 return nil, errNoSuchVolume 727 } 728 729 // lookupVolume gets the specified volume from the specified driver. 730 // This will only return errors related to communications with the driver. 731 // If the driver returns an error that is not communication related the 732 // error is logged but not returned. 733 // If the volume is not found it will return `nil, nil`` 734 // TODO(@cpuguy83): plumb through the context to lower level components 735 func lookupVolume(ctx context.Context, store *drivers.Store, driverName, volumeName string) (volume.Volume, error) { 736 if driverName == "" { 737 driverName = volume.DefaultDriverName 738 } 739 vd, err := store.GetDriver(driverName) 740 if err != nil { 741 return nil, errors.Wrapf(err, "error while checking if volume %q exists in driver %q", volumeName, driverName) 742 } 743 v, err := vd.Get(volumeName) 744 if err != nil { 745 var nErr net.Error 746 if errors.As(err, &nErr) { 747 if v != nil { 748 volumeName = v.Name() 749 driverName = v.DriverName() 750 } 751 return nil, errors.Wrapf(err, "error while checking if volume %q exists in driver %q", volumeName, driverName) 752 } 753 754 // At this point, the error could be anything from the driver, such as "no such volume" 755 // Let's not check an error here, and instead check if the driver returned a volume 756 logrus.WithError(err).WithField("driver", driverName).WithField("volume", volumeName).Debug("Error while looking up volume") 757 } 758 return v, nil 759 } 760 761 // Remove removes the requested volume. A volume is not removed if it has any refs 762 func (s *VolumeStore) Remove(ctx context.Context, v volume.Volume, rmOpts ...opts.RemoveOption) error { 763 var cfg opts.RemoveConfig 764 for _, o := range rmOpts { 765 o(&cfg) 766 } 767 768 name := v.Name() 769 s.locks.Lock(name) 770 defer s.locks.Unlock(name) 771 772 select { 773 case <-ctx.Done(): 774 return ctx.Err() 775 default: 776 } 777 778 if s.hasRef(name) { 779 return &OpErr{Err: errVolumeInUse, Name: name, Op: "remove", Refs: s.getRefs(name)} 780 } 781 782 v, err := s.getVolume(ctx, name, v.DriverName()) 783 if err != nil { 784 return err 785 } 786 787 vd, err := s.drivers.GetDriver(v.DriverName()) 788 if err != nil { 789 return &OpErr{Err: err, Name: v.DriverName(), Op: "remove"} 790 } 791 792 logrus.Debugf("Removing volume reference: driver %s, name %s", v.DriverName(), name) 793 vol := unwrapVolume(v) 794 795 err = vd.Remove(vol) 796 if err != nil { 797 err = &OpErr{Err: err, Name: name, Op: "remove"} 798 } 799 800 if err == nil || cfg.PurgeOnError { 801 if e := s.purge(ctx, name); e != nil && err == nil { 802 err = e 803 } 804 } 805 return err 806 } 807 808 // Release releases the specified reference to the volume 809 func (s *VolumeStore) Release(ctx context.Context, name string, ref string) error { 810 s.locks.Lock(name) 811 defer s.locks.Unlock(name) 812 select { 813 case <-ctx.Done(): 814 return ctx.Err() 815 default: 816 } 817 818 s.globalLock.Lock() 819 defer s.globalLock.Unlock() 820 821 select { 822 case <-ctx.Done(): 823 return ctx.Err() 824 default: 825 } 826 827 if s.refs[name] != nil { 828 delete(s.refs[name], ref) 829 } 830 return nil 831 } 832 833 // CountReferences gives a count of all references for a given volume. 834 func (s *VolumeStore) CountReferences(v volume.Volume) int { 835 name := normalizeVolumeName(v.Name()) 836 837 s.locks.Lock(name) 838 defer s.locks.Unlock(name) 839 s.globalLock.Lock() 840 defer s.globalLock.Unlock() 841 842 return len(s.refs[name]) 843 } 844 845 func unwrapVolume(v volume.Volume) volume.Volume { 846 if vol, ok := v.(volumeWrapper); ok { 847 return vol.Volume 848 } 849 850 return v 851 } 852 853 // Shutdown releases all resources used by the volume store 854 // It does not make any changes to volumes, drivers, etc. 855 func (s *VolumeStore) Shutdown() error { 856 return s.db.Close() 857 }