浏览代码

replace pkg/locker with github.com/moby/locker

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Sebastiaan van Stijn 4 年之前
父节点
当前提交
5ca758199d

+ 1 - 1
daemon/daemon.go

@@ -55,7 +55,6 @@ import (
 	"github.com/docker/docker/libcontainerd"
 	libcontainerdtypes "github.com/docker/docker/libcontainerd/types"
 	"github.com/docker/docker/pkg/idtools"
-	"github.com/docker/docker/pkg/locker"
 	"github.com/docker/docker/pkg/plugingetter"
 	"github.com/docker/docker/pkg/system"
 	"github.com/docker/docker/pkg/truncindex"
@@ -68,6 +67,7 @@ import (
 	"github.com/docker/libnetwork"
 	"github.com/docker/libnetwork/cluster"
 	nwconfig "github.com/docker/libnetwork/config"
+	"github.com/moby/locker"
 	"github.com/pkg/errors"
 	"golang.org/x/sync/semaphore"
 )

+ 1 - 1
daemon/graphdriver/aufs/aufs.go

@@ -42,8 +42,8 @@ import (
 	"github.com/docker/docker/pkg/containerfs"
 	"github.com/docker/docker/pkg/directory"
 	"github.com/docker/docker/pkg/idtools"
-	"github.com/docker/docker/pkg/locker"
 	"github.com/docker/docker/pkg/system"
+	"github.com/moby/locker"
 	"github.com/moby/sys/mount"
 	"github.com/opencontainers/selinux/go-selinux/label"
 	"github.com/pkg/errors"

+ 1 - 1
daemon/graphdriver/devmapper/driver.go

@@ -13,8 +13,8 @@ import (
 	"github.com/docker/docker/pkg/containerfs"
 	"github.com/docker/docker/pkg/devicemapper"
 	"github.com/docker/docker/pkg/idtools"
-	"github.com/docker/docker/pkg/locker"
 	units "github.com/docker/go-units"
+	"github.com/moby/locker"
 	"github.com/moby/sys/mount"
 	"github.com/sirupsen/logrus"
 	"golang.org/x/sys/unix"

+ 1 - 1
daemon/graphdriver/fuse-overlayfs/fuseoverlayfs.go

@@ -22,9 +22,9 @@ import (
 	"github.com/docker/docker/pkg/containerfs"
 	"github.com/docker/docker/pkg/directory"
 	"github.com/docker/docker/pkg/idtools"
-	"github.com/docker/docker/pkg/locker"
 	"github.com/docker/docker/pkg/parsers/kernel"
 	"github.com/docker/docker/pkg/system"
+	"github.com/moby/locker"
 	"github.com/moby/sys/mount"
 	"github.com/opencontainers/selinux/go-selinux/label"
 	"github.com/pkg/errors"

+ 1 - 1
daemon/graphdriver/overlay/overlay.go

@@ -19,9 +19,9 @@ import (
 	"github.com/docker/docker/pkg/containerfs"
 	"github.com/docker/docker/pkg/fsutils"
 	"github.com/docker/docker/pkg/idtools"
-	"github.com/docker/docker/pkg/locker"
 	"github.com/docker/docker/pkg/parsers"
 	"github.com/docker/docker/pkg/system"
+	"github.com/moby/locker"
 	"github.com/moby/sys/mount"
 	"github.com/opencontainers/selinux/go-selinux/label"
 	"github.com/sirupsen/logrus"

+ 1 - 1
daemon/graphdriver/overlay2/overlay.go

@@ -25,10 +25,10 @@ import (
 	"github.com/docker/docker/pkg/directory"
 	"github.com/docker/docker/pkg/fsutils"
 	"github.com/docker/docker/pkg/idtools"
-	"github.com/docker/docker/pkg/locker"
 	"github.com/docker/docker/pkg/parsers"
 	"github.com/docker/docker/pkg/system"
 	units "github.com/docker/go-units"
+	"github.com/moby/locker"
 	"github.com/moby/sys/mount"
 	"github.com/opencontainers/selinux/go-selinux/label"
 	"github.com/sirupsen/logrus"

+ 1 - 1
integration/plugin/logging/helpers_test.go

@@ -9,8 +9,8 @@ import (
 	"time"
 
 	"github.com/docker/docker/api/types"
-	"github.com/docker/docker/pkg/locker"
 	"github.com/docker/docker/testutil/fixtures/plugin"
+	"github.com/moby/locker"
 	"github.com/pkg/errors"
 )
 

+ 1 - 1
integration/plugin/volumes/helpers_test.go

@@ -9,8 +9,8 @@ import (
 	"time"
 
 	"github.com/docker/docker/api/types"
-	"github.com/docker/docker/pkg/locker"
 	"github.com/docker/docker/testutil/fixtures/plugin"
+	"github.com/moby/locker"
 	"github.com/pkg/errors"
 	"gotest.tools/v3/assert"
 )

+ 1 - 1
layer/layer_store.go

@@ -12,10 +12,10 @@ import (
 	"github.com/docker/distribution"
 	"github.com/docker/docker/daemon/graphdriver"
 	"github.com/docker/docker/pkg/idtools"
-	"github.com/docker/docker/pkg/locker"
 	"github.com/docker/docker/pkg/plugingetter"
 	"github.com/docker/docker/pkg/stringid"
 	"github.com/docker/docker/pkg/system"
+	"github.com/moby/locker"
 	digest "github.com/opencontainers/go-digest"
 	"github.com/sirupsen/logrus"
 	"github.com/vbatts/tar-split/tar/asm"

+ 7 - 89
pkg/locker/locker.go

@@ -14,99 +14,17 @@ waiting for the lock.
 package locker // import "github.com/docker/docker/pkg/locker"
 
 import (
-	"errors"
-	"sync"
-	"sync/atomic"
+	"github.com/moby/locker"
 )
 
 // ErrNoSuchLock is returned when the requested lock does not exist
-var ErrNoSuchLock = errors.New("no such lock")
+// Deprecated: use github.com/moby/locker.ErrNoSuchLock
+var ErrNoSuchLock = locker.ErrNoSuchLock
 
 // Locker provides a locking mechanism based on the passed in reference name
-type Locker struct {
-	mu    sync.Mutex
-	locks map[string]*lockCtr
-}
-
-// lockCtr is used by Locker to represent a lock with a given name.
-type lockCtr struct {
-	mu sync.Mutex
-	// waiters is the number of waiters waiting to acquire the lock
-	// this is int32 instead of uint32 so we can add `-1` in `dec()`
-	waiters int32
-}
-
-// inc increments the number of waiters waiting for the lock
-func (l *lockCtr) inc() {
-	atomic.AddInt32(&l.waiters, 1)
-}
-
-// dec decrements the number of waiters waiting on the lock
-func (l *lockCtr) dec() {
-	atomic.AddInt32(&l.waiters, -1)
-}
-
-// count gets the current number of waiters
-func (l *lockCtr) count() int32 {
-	return atomic.LoadInt32(&l.waiters)
-}
-
-// Lock locks the mutex
-func (l *lockCtr) Lock() {
-	l.mu.Lock()
-}
-
-// Unlock unlocks the mutex
-func (l *lockCtr) Unlock() {
-	l.mu.Unlock()
-}
+// Deprecated: use github.com/moby/locker.Locker
+type Locker = locker.Locker
 
 // New creates a new Locker
-func New() *Locker {
-	return &Locker{
-		locks: make(map[string]*lockCtr),
-	}
-}
-
-// Lock locks a mutex with the given name. If it doesn't exist, one is created
-func (l *Locker) Lock(name string) {
-	l.mu.Lock()
-	if l.locks == nil {
-		l.locks = make(map[string]*lockCtr)
-	}
-
-	nameLock, exists := l.locks[name]
-	if !exists {
-		nameLock = &lockCtr{}
-		l.locks[name] = nameLock
-	}
-
-	// increment the nameLock waiters while inside the main mutex
-	// this makes sure that the lock isn't deleted if `Lock` and `Unlock` are called concurrently
-	nameLock.inc()
-	l.mu.Unlock()
-
-	// Lock the nameLock outside the main mutex so we don't block other operations
-	// once locked then we can decrement the number of waiters for this lock
-	nameLock.Lock()
-	nameLock.dec()
-}
-
-// Unlock unlocks the mutex with the given name
-// If the given lock is not being waited on by any other callers, it is deleted
-func (l *Locker) Unlock(name string) error {
-	l.mu.Lock()
-	nameLock, exists := l.locks[name]
-	if !exists {
-		l.mu.Unlock()
-		return ErrNoSuchLock
-	}
-
-	if nameLock.count() == 0 {
-		delete(l.locks, name)
-	}
-	nameLock.Unlock()
-
-	l.mu.Unlock()
-	return nil
-}
+// Deprecated: use github.com/moby/locker.New
+var New = locker.New

+ 0 - 161
pkg/locker/locker_test.go

@@ -1,161 +0,0 @@
-package locker // import "github.com/docker/docker/pkg/locker"
-
-import (
-	"math/rand"
-	"strconv"
-	"sync"
-	"testing"
-	"time"
-)
-
-func TestLockCounter(t *testing.T) {
-	l := &lockCtr{}
-	l.inc()
-
-	if l.waiters != 1 {
-		t.Fatal("counter inc failed")
-	}
-
-	l.dec()
-	if l.waiters != 0 {
-		t.Fatal("counter dec failed")
-	}
-}
-
-func TestLockerLock(t *testing.T) {
-	l := New()
-	l.Lock("test")
-	ctr := l.locks["test"]
-
-	if ctr.count() != 0 {
-		t.Fatalf("expected waiters to be 0, got :%d", ctr.waiters)
-	}
-
-	chDone := make(chan struct{})
-	go func() {
-		l.Lock("test")
-		close(chDone)
-	}()
-
-	chWaiting := make(chan struct{})
-	go func() {
-		for range time.Tick(1 * time.Millisecond) {
-			if ctr.count() == 1 {
-				close(chWaiting)
-				break
-			}
-		}
-	}()
-
-	select {
-	case <-chWaiting:
-	case <-time.After(3 * time.Second):
-		t.Fatal("timed out waiting for lock waiters to be incremented")
-	}
-
-	select {
-	case <-chDone:
-		t.Fatal("lock should not have returned while it was still held")
-	default:
-	}
-
-	if err := l.Unlock("test"); err != nil {
-		t.Fatal(err)
-	}
-
-	select {
-	case <-chDone:
-	case <-time.After(3 * time.Second):
-		t.Fatalf("lock should have completed")
-	}
-
-	if ctr.count() != 0 {
-		t.Fatalf("expected waiters to be 0, got: %d", ctr.count())
-	}
-}
-
-func TestLockerUnlock(t *testing.T) {
-	l := New()
-
-	l.Lock("test")
-	l.Unlock("test")
-
-	chDone := make(chan struct{})
-	go func() {
-		l.Lock("test")
-		close(chDone)
-	}()
-
-	select {
-	case <-chDone:
-	case <-time.After(3 * time.Second):
-		t.Fatalf("lock should not be blocked")
-	}
-}
-
-func TestLockerConcurrency(t *testing.T) {
-	l := New()
-
-	var wg sync.WaitGroup
-	for i := 0; i <= 10000; i++ {
-		wg.Add(1)
-		go func() {
-			l.Lock("test")
-			// if there is a concurrency issue, will very likely panic here
-			l.Unlock("test")
-			wg.Done()
-		}()
-	}
-
-	chDone := make(chan struct{})
-	go func() {
-		wg.Wait()
-		close(chDone)
-	}()
-
-	select {
-	case <-chDone:
-	case <-time.After(10 * time.Second):
-		t.Fatal("timeout waiting for locks to complete")
-	}
-
-	// Since everything has unlocked this should not exist anymore
-	if ctr, exists := l.locks["test"]; exists {
-		t.Fatalf("lock should not exist: %v", ctr)
-	}
-}
-
-func BenchmarkLocker(b *testing.B) {
-	l := New()
-	for i := 0; i < b.N; i++ {
-		l.Lock("test")
-		l.Unlock("test")
-	}
-}
-
-func BenchmarkLockerParallel(b *testing.B) {
-	l := New()
-	b.SetParallelism(128)
-	b.RunParallel(func(pb *testing.PB) {
-		for pb.Next() {
-			l.Lock("test")
-			l.Unlock("test")
-		}
-	})
-}
-
-func BenchmarkLockerMoreKeys(b *testing.B) {
-	l := New()
-	var keys []string
-	for i := 0; i < 64; i++ {
-		keys = append(keys, strconv.Itoa(i))
-	}
-	b.SetParallelism(128)
-	b.RunParallel(func(pb *testing.PB) {
-		for pb.Next() {
-			k := keys[rand.Intn(len(keys))]
-			l.Lock(k)
-			l.Unlock(k)
-		}
-	})
-}

+ 1 - 0
vendor.conf

@@ -6,6 +6,7 @@ github.com/golang/gddo                              72a348e765d293ed6d1ded7b6995
 github.com/google/uuid                              0cd6bf5da1e1c83f8b45653022c74f71af0538a4 # v1.1.1
 github.com/gorilla/mux                              98cb6bf42e086f6af920b965c38cacc07402d51b # v1.8.0
 github.com/Microsoft/opengcs                        a10967154e143a36014584a6f664344e3bb0aa64
+github.com/moby/locker                              281af2d563954745bea9d1487c965f24d30742fe # v1.0.1
 github.com/moby/term                                73f35e472e8f0a3f91347164138ce6bd73b756a9
 
 github.com/creack/pty                               3a6a957789163cacdfe0e291617a1c8e80612c11 # v1.1.9

+ 190 - 0
vendor/github.com/moby/locker/LICENSE

@@ -0,0 +1,190 @@
+                                 Apache License
+                           Version 2.0, January 2004
+                        https://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   Copyright 2013-2018 Docker, Inc.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       https://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.

+ 1 - 1
pkg/locker/README.md → vendor/github.com/moby/locker/README.md

@@ -23,7 +23,7 @@ import (
 	"sync"
 	"time"
 
-	"github.com/docker/docker/pkg/locker"
+	"github.com/moby/locker"
 )
 
 type important struct {

+ 3 - 0
vendor/github.com/moby/locker/go.mod

@@ -0,0 +1,3 @@
+module github.com/moby/locker
+
+go 1.13

+ 112 - 0
vendor/github.com/moby/locker/locker.go

@@ -0,0 +1,112 @@
+/*
+Package locker provides a mechanism for creating finer-grained locking to help
+free up more global locks to handle other tasks.
+
+The implementation looks close to a sync.Mutex, however the user must provide a
+reference to use to refer to the underlying lock when locking and unlocking,
+and unlock may generate an error.
+
+If a lock with a given name does not exist when `Lock` is called, one is
+created.
+Lock references are automatically cleaned up on `Unlock` if nothing else is
+waiting for the lock.
+*/
+package locker
+
+import (
+	"errors"
+	"sync"
+	"sync/atomic"
+)
+
+// ErrNoSuchLock is returned when the requested lock does not exist
+var ErrNoSuchLock = errors.New("no such lock")
+
+// Locker provides a locking mechanism based on the passed in reference name
+type Locker struct {
+	mu    sync.Mutex
+	locks map[string]*lockCtr
+}
+
+// lockCtr is used by Locker to represent a lock with a given name.
+type lockCtr struct {
+	mu sync.Mutex
+	// waiters is the number of waiters waiting to acquire the lock
+	// this is int32 instead of uint32 so we can add `-1` in `dec()`
+	waiters int32
+}
+
+// inc increments the number of waiters waiting for the lock
+func (l *lockCtr) inc() {
+	atomic.AddInt32(&l.waiters, 1)
+}
+
+// dec decrements the number of waiters waiting on the lock
+func (l *lockCtr) dec() {
+	atomic.AddInt32(&l.waiters, -1)
+}
+
+// count gets the current number of waiters
+func (l *lockCtr) count() int32 {
+	return atomic.LoadInt32(&l.waiters)
+}
+
+// Lock locks the mutex
+func (l *lockCtr) Lock() {
+	l.mu.Lock()
+}
+
+// Unlock unlocks the mutex
+func (l *lockCtr) Unlock() {
+	l.mu.Unlock()
+}
+
+// New creates a new Locker
+func New() *Locker {
+	return &Locker{
+		locks: make(map[string]*lockCtr),
+	}
+}
+
+// Lock locks a mutex with the given name. If it doesn't exist, one is created
+func (l *Locker) Lock(name string) {
+	l.mu.Lock()
+	if l.locks == nil {
+		l.locks = make(map[string]*lockCtr)
+	}
+
+	nameLock, exists := l.locks[name]
+	if !exists {
+		nameLock = &lockCtr{}
+		l.locks[name] = nameLock
+	}
+
+	// increment the nameLock waiters while inside the main mutex
+	// this makes sure that the lock isn't deleted if `Lock` and `Unlock` are called concurrently
+	nameLock.inc()
+	l.mu.Unlock()
+
+	// Lock the nameLock outside the main mutex so we don't block other operations
+	// once locked then we can decrement the number of waiters for this lock
+	nameLock.Lock()
+	nameLock.dec()
+}
+
+// Unlock unlocks the mutex with the given name
+// If the given lock is not being waited on by any other callers, it is deleted
+func (l *Locker) Unlock(name string) error {
+	l.mu.Lock()
+	nameLock, exists := l.locks[name]
+	if !exists {
+		l.mu.Unlock()
+		return ErrNoSuchLock
+	}
+
+	if nameLock.count() == 0 {
+		delete(l.locks, name)
+	}
+	nameLock.Unlock()
+
+	l.mu.Unlock()
+	return nil
+}

+ 1 - 1
volume/drivers/extpoint.go

@@ -8,10 +8,10 @@ import (
 	"sync"
 
 	"github.com/docker/docker/errdefs"
-	"github.com/docker/docker/pkg/locker"
 	getter "github.com/docker/docker/pkg/plugingetter"
 	"github.com/docker/docker/pkg/plugins"
 	"github.com/docker/docker/volume"
+	"github.com/moby/locker"
 	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
 )

+ 2 - 3
volume/service/store.go

@@ -10,14 +10,13 @@ import (
 	"sync"
 	"time"
 
-	"github.com/pkg/errors"
-
 	"github.com/docker/docker/errdefs"
-	"github.com/docker/docker/pkg/locker"
 	"github.com/docker/docker/volume"
 	"github.com/docker/docker/volume/drivers"
 	volumemounts "github.com/docker/docker/volume/mounts"
 	"github.com/docker/docker/volume/service/opts"
+	"github.com/moby/locker"
+	"github.com/pkg/errors"
 	"github.com/sirupsen/logrus"
 	bolt "go.etcd.io/bbolt"
 )