This makes sure fsdiff doesn't try to unmount things that shouldn't be.
**Note**: This is intended as a temporary solution to have as minor a
change as possible for 1.11.1. A bigger change will be required in order
to support container re-attach.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
(cherry picked from commit 7342060b070df67481f8da4f394a57cac1671d56)
1 | 1 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,32 @@ |
0 |
+package graphdriver |
|
1 |
+ |
|
2 |
+import "sync" |
|
3 |
+ |
|
4 |
+// RefCounter is a generic counter for use by graphdriver Get/Put calls |
|
5 |
+type RefCounter struct { |
|
6 |
+ counts map[string]int |
|
7 |
+ mu sync.Mutex |
|
8 |
+} |
|
9 |
+ |
|
10 |
+// NewRefCounter returns a new RefCounter |
|
11 |
+func NewRefCounter() *RefCounter { |
|
12 |
+ return &RefCounter{counts: make(map[string]int)} |
|
13 |
+} |
|
14 |
+ |
|
15 |
+// Increment increaes the ref count for the given id and returns the current count |
|
16 |
+func (c *RefCounter) Increment(id string) int { |
|
17 |
+ c.mu.Lock() |
|
18 |
+ c.counts[id]++ |
|
19 |
+ count := c.counts[id] |
|
20 |
+ c.mu.Unlock() |
|
21 |
+ return count |
|
22 |
+} |
|
23 |
+ |
|
24 |
+// Decrement decreases the ref count for the given id and returns the current count |
|
25 |
+func (c *RefCounter) Decrement(id string) int { |
|
26 |
+ c.mu.Lock() |
|
27 |
+ c.counts[id]-- |
|
28 |
+ count := c.counts[id] |
|
29 |
+ c.mu.Unlock() |
|
30 |
+ return count |
|
31 |
+} |
... | ... |
@@ -28,6 +28,7 @@ type Driver struct { |
28 | 28 |
home string |
29 | 29 |
uidMaps []idtools.IDMap |
30 | 30 |
gidMaps []idtools.IDMap |
31 |
+ ctr *graphdriver.RefCounter |
|
31 | 32 |
} |
32 | 33 |
|
33 | 34 |
// Init creates a driver with the given home and the set of options. |
... | ... |
@@ -46,6 +47,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap |
46 | 46 |
home: home, |
47 | 47 |
uidMaps: uidMaps, |
48 | 48 |
gidMaps: gidMaps, |
49 |
+ ctr: graphdriver.NewRefCounter(), |
|
49 | 50 |
} |
50 | 51 |
|
51 | 52 |
return graphdriver.NewNaiveDiffDriver(d, uidMaps, gidMaps), nil |
... | ... |
@@ -151,26 +153,35 @@ func (d *Driver) Remove(id string) error { |
151 | 151 |
// Get mounts a device with given id into the root filesystem |
152 | 152 |
func (d *Driver) Get(id, mountLabel string) (string, error) { |
153 | 153 |
mp := path.Join(d.home, "mnt", id) |
154 |
+ if count := d.ctr.Increment(id); count > 1 { |
|
155 |
+ return mp, nil |
|
156 |
+ } |
|
154 | 157 |
|
155 | 158 |
uid, gid, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps) |
156 | 159 |
if err != nil { |
160 |
+ d.ctr.Decrement(id) |
|
157 | 161 |
return "", err |
158 | 162 |
} |
163 |
+ |
|
159 | 164 |
// Create the target directories if they don't exist |
160 | 165 |
if err := idtools.MkdirAllAs(path.Join(d.home, "mnt"), 0755, uid, gid); err != nil && !os.IsExist(err) { |
166 |
+ d.ctr.Decrement(id) |
|
161 | 167 |
return "", err |
162 | 168 |
} |
163 | 169 |
if err := idtools.MkdirAs(mp, 0755, uid, gid); err != nil && !os.IsExist(err) { |
170 |
+ d.ctr.Decrement(id) |
|
164 | 171 |
return "", err |
165 | 172 |
} |
166 | 173 |
|
167 | 174 |
// Mount the device |
168 | 175 |
if err := d.DeviceSet.MountDevice(id, mp, mountLabel); err != nil { |
176 |
+ d.ctr.Decrement(id) |
|
169 | 177 |
return "", err |
170 | 178 |
} |
171 | 179 |
|
172 | 180 |
rootFs := path.Join(mp, "rootfs") |
173 | 181 |
if err := idtools.MkdirAllAs(rootFs, 0755, uid, gid); err != nil && !os.IsExist(err) { |
182 |
+ d.ctr.Decrement(id) |
|
174 | 183 |
d.DeviceSet.UnmountDevice(id, mp) |
175 | 184 |
return "", err |
176 | 185 |
} |
... | ... |
@@ -180,6 +191,7 @@ func (d *Driver) Get(id, mountLabel string) (string, error) { |
180 | 180 |
// Create an "id" file with the container/image id in it to help reconstruct this in case |
181 | 181 |
// of later problems |
182 | 182 |
if err := ioutil.WriteFile(idFile, []byte(id), 0600); err != nil { |
183 |
+ d.ctr.Decrement(id) |
|
183 | 184 |
d.DeviceSet.UnmountDevice(id, mp) |
184 | 185 |
return "", err |
185 | 186 |
} |
... | ... |
@@ -190,6 +202,9 @@ func (d *Driver) Get(id, mountLabel string) (string, error) { |
190 | 190 |
|
191 | 191 |
// Put unmounts a device and removes it. |
192 | 192 |
func (d *Driver) Put(id string) error { |
193 |
+ if count := d.ctr.Decrement(id); count > 0 { |
|
194 |
+ return nil |
|
195 |
+ } |
|
193 | 196 |
mp := path.Join(d.home, "mnt", id) |
194 | 197 |
err := d.DeviceSet.UnmountDevice(id, mp) |
195 | 198 |
if err != nil { |
... | ... |
@@ -95,6 +95,7 @@ type Driver struct { |
95 | 95 |
pathCache map[string]string |
96 | 96 |
uidMaps []idtools.IDMap |
97 | 97 |
gidMaps []idtools.IDMap |
98 |
+ ctr *graphdriver.RefCounter |
|
98 | 99 |
} |
99 | 100 |
|
100 | 101 |
var backingFs = "<unknown>" |
... | ... |
@@ -147,6 +148,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap |
147 | 147 |
pathCache: make(map[string]string), |
148 | 148 |
uidMaps: uidMaps, |
149 | 149 |
gidMaps: gidMaps, |
150 |
+ ctr: graphdriver.NewRefCounter(), |
|
150 | 151 |
} |
151 | 152 |
|
152 | 153 |
return NaiveDiffDriverWithApply(d, uidMaps, gidMaps), nil |
... | ... |
@@ -348,28 +350,39 @@ func (d *Driver) Get(id string, mountLabel string) (string, error) { |
348 | 348 |
workDir := path.Join(dir, "work") |
349 | 349 |
mergedDir := path.Join(dir, "merged") |
350 | 350 |
|
351 |
+ if count := d.ctr.Increment(id); count > 1 { |
|
352 |
+ return mergedDir, nil |
|
353 |
+ } |
|
354 |
+ |
|
351 | 355 |
opts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", lowerDir, upperDir, workDir) |
352 | 356 |
|
353 | 357 |
// if it's mounted already, just return |
354 | 358 |
mounted, err := d.mounted(mergedDir) |
355 | 359 |
if err != nil { |
360 |
+ d.ctr.Decrement(id) |
|
356 | 361 |
return "", err |
357 | 362 |
} |
358 | 363 |
if mounted { |
364 |
+ d.ctr.Decrement(id) |
|
359 | 365 |
return mergedDir, nil |
360 | 366 |
} |
361 | 367 |
|
362 | 368 |
if err := syscall.Mount("overlay", mergedDir, "overlay", 0, label.FormatMountLabel(opts, mountLabel)); err != nil { |
369 |
+ d.ctr.Decrement(id) |
|
363 | 370 |
return "", fmt.Errorf("error creating overlay mount to %s: %v", mergedDir, err) |
364 | 371 |
} |
365 | 372 |
// chown "workdir/work" to the remapped root UID/GID. Overlay fs inside a |
366 | 373 |
// user namespace requires this to move a directory from lower to upper. |
367 | 374 |
rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps) |
368 | 375 |
if err != nil { |
376 |
+ d.ctr.Decrement(id) |
|
377 |
+ syscall.Unmount(mergedDir, 0) |
|
369 | 378 |
return "", err |
370 | 379 |
} |
371 | 380 |
|
372 | 381 |
if err := os.Chown(path.Join(workDir, "work"), rootUID, rootGID); err != nil { |
382 |
+ d.ctr.Decrement(id) |
|
383 |
+ syscall.Unmount(mergedDir, 0) |
|
373 | 384 |
return "", err |
374 | 385 |
} |
375 | 386 |
|
... | ... |
@@ -386,6 +399,9 @@ func (d *Driver) mounted(dir string) (bool, error) { |
386 | 386 |
|
387 | 387 |
// Put unmounts the mount path created for the give id. |
388 | 388 |
func (d *Driver) Put(id string) error { |
389 |
+ if count := d.ctr.Decrement(id); count > 0 { |
|
390 |
+ return nil |
|
391 |
+ } |
|
389 | 392 |
d.pathCacheLock.Lock() |
390 | 393 |
mountpoint, exists := d.pathCache[id] |
391 | 394 |
d.pathCacheLock.Unlock() |
... | ... |
@@ -105,6 +105,7 @@ func Init(base string, opt []string, uidMaps, gidMaps []idtools.IDMap) (graphdri |
105 | 105 |
filesystemsCache: filesystemsCache, |
106 | 106 |
uidMaps: uidMaps, |
107 | 107 |
gidMaps: gidMaps, |
108 |
+ ctr: graphdriver.NewRefCounter(), |
|
108 | 109 |
} |
109 | 110 |
return graphdriver.NewNaiveDiffDriver(d, uidMaps, gidMaps), nil |
110 | 111 |
} |
... | ... |
@@ -161,6 +162,7 @@ type Driver struct { |
161 | 161 |
filesystemsCache map[string]bool |
162 | 162 |
uidMaps []idtools.IDMap |
163 | 163 |
gidMaps []idtools.IDMap |
164 |
+ ctr *graphdriver.RefCounter |
|
164 | 165 |
} |
165 | 166 |
|
166 | 167 |
func (d *Driver) String() string { |
... | ... |
@@ -295,25 +297,35 @@ func (d *Driver) Remove(id string) error { |
295 | 295 |
// Get returns the mountpoint for the given id after creating the target directories if necessary. |
296 | 296 |
func (d *Driver) Get(id, mountLabel string) (string, error) { |
297 | 297 |
mountpoint := d.mountPath(id) |
298 |
+ if count := d.ctr.Increment(id); count > 1 { |
|
299 |
+ return mountpoint, nil |
|
300 |
+ } |
|
301 |
+ |
|
298 | 302 |
filesystem := d.zfsPath(id) |
299 | 303 |
options := label.FormatMountLabel("", mountLabel) |
300 | 304 |
logrus.Debugf(`[zfs] mount("%s", "%s", "%s")`, filesystem, mountpoint, options) |
301 | 305 |
|
302 | 306 |
rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps) |
303 | 307 |
if err != nil { |
308 |
+ d.ctr.Decrement(id) |
|
304 | 309 |
return "", err |
305 | 310 |
} |
306 | 311 |
// Create the target directories if they don't exist |
307 | 312 |
if err := idtools.MkdirAllAs(mountpoint, 0755, rootUID, rootGID); err != nil { |
313 |
+ d.ctr.Decrement(id) |
|
308 | 314 |
return "", err |
309 | 315 |
} |
310 | 316 |
|
311 | 317 |
if err := mount.Mount(filesystem, mountpoint, "zfs", options); err != nil { |
318 |
+ d.ctr.Decrement(id) |
|
312 | 319 |
return "", fmt.Errorf("error creating zfs mount of %s to %s: %v", filesystem, mountpoint, err) |
313 | 320 |
} |
321 |
+ |
|
314 | 322 |
// this could be our first mount after creation of the filesystem, and the root dir may still have root |
315 | 323 |
// permissions instead of the remapped root uid:gid (if user namespaces are enabled): |
316 | 324 |
if err := os.Chown(mountpoint, rootUID, rootGID); err != nil { |
325 |
+ mount.Unmount(mountpoint) |
|
326 |
+ d.ctr.Decrement(id) |
|
317 | 327 |
return "", fmt.Errorf("error modifying zfs mountpoint (%s) directory ownership: %v", mountpoint, err) |
318 | 328 |
} |
319 | 329 |
|
... | ... |
@@ -322,6 +334,9 @@ func (d *Driver) Get(id, mountLabel string) (string, error) { |
322 | 322 |
|
323 | 323 |
// Put removes the existing mountpoint for the given id if it exists. |
324 | 324 |
func (d *Driver) Put(id string) error { |
325 |
+ if count := d.ctr.Decrement(id); count > 0 { |
|
326 |
+ return nil |
|
327 |
+ } |
|
325 | 328 |
mountpoint := d.mountPath(id) |
326 | 329 |
mounted, err := graphdriver.Mounted(graphdriver.FsMagicZfs, mountpoint) |
327 | 330 |
if err != nil || !mounted { |