Browse code

Fix potential race in volume creation

Docker-DCO-1.1-Signed-off-by: Brian Goff <cpuguy83@gmail.com> (github: cpuguy83)

Brian Goff authored on 2014/09/27 09:42:24
Showing 2 changed files
... ...
@@ -111,12 +111,9 @@ func (container *Container) parseVolumeMountConfig() (map[string]*Mount, error)
111 111
 			return nil, err
112 112
 		}
113 113
 		// Check if a volume already exists for this and use it
114
-		vol := container.daemon.volumes.Get(path)
115
-		if vol == nil {
116
-			vol, err = container.daemon.volumes.NewVolume(path, writable)
117
-			if err != nil {
118
-				return nil, err
119
-			}
114
+		vol, err := container.daemon.volumes.FindOrCreateVolume(path, writable)
115
+		if err != nil {
116
+			return nil, err
120 117
 		}
121 118
 		mounts[mountToPath] = &Mount{container: container, volume: vol, MountToPath: mountToPath, Writable: writable}
122 119
 	}
... ...
@@ -128,7 +125,7 @@ func (container *Container) parseVolumeMountConfig() (map[string]*Mount, error)
128 128
 			continue
129 129
 		}
130 130
 
131
-		vol, err := container.daemon.volumes.NewVolume("", true)
131
+		vol, err := container.daemon.volumes.FindOrCreateVolume("", true)
132 132
 		if err != nil {
133 133
 			return nil, err
134 134
 		}
... ...
@@ -38,7 +38,7 @@ func NewRepository(configPath string, driver graphdriver.Driver) (*Repository, e
38 38
 	return repo, repo.restore()
39 39
 }
40 40
 
41
-func (r *Repository) NewVolume(path string, writable bool) (*Volume, error) {
41
+func (r *Repository) newVolume(path string, writable bool) (*Volume, error) {
42 42
 	var (
43 43
 		isBindMount bool
44 44
 		err         error
... ...
@@ -73,10 +73,8 @@ func (r *Repository) NewVolume(path string, writable bool) (*Volume, error) {
73 73
 	if err := v.initialize(); err != nil {
74 74
 		return nil, err
75 75
 	}
76
-	if err := r.Add(v); err != nil {
77
-		return nil, err
78
-	}
79
-	return v, nil
76
+
77
+	return v, r.add(v)
80 78
 }
81 79
 
82 80
 func (r *Repository) restore() error {
... ...
@@ -113,6 +111,10 @@ func (r *Repository) get(path string) *Volume {
113 113
 func (r *Repository) Add(volume *Volume) error {
114 114
 	r.lock.Lock()
115 115
 	defer r.lock.Unlock()
116
+	return r.add(volume)
117
+}
118
+
119
+func (r *Repository) add(volume *Volume) error {
116 120
 	if vol := r.get(volume.Path); vol != nil {
117 121
 		return fmt.Errorf("Volume exists: %s", volume.ID)
118 122
 	}
... ...
@@ -175,3 +177,18 @@ func (r *Repository) createNewVolumePath(id string) (string, error) {
175 175
 
176 176
 	return path, nil
177 177
 }
178
+
179
+func (r *Repository) FindOrCreateVolume(path string, writable bool) (*Volume, error) {
180
+	r.lock.Lock()
181
+	defer r.lock.Unlock()
182
+
183
+	if path == "" {
184
+		return r.newVolume(path, writable)
185
+	}
186
+
187
+	if v := r.get(path); v != nil {
188
+		return v, nil
189
+	}
190
+
191
+	return r.newVolume(path, writable)
192
+}