summaryrefslogtreecommitdiff
path: root/daemon/graphdriver/devmapper
diff options
context:
space:
mode:
authorTonis Tiigi <tonistiigi@gmail.com>2016-03-23 00:33:02 -0700
committerTonis Tiigi <tonistiigi@gmail.com>2016-03-23 00:33:02 -0700
commite91de9fb9d175541acc95834de486d33feef552a (patch)
tree610bab6174675f30408c87644e864f1c58bce10c /daemon/graphdriver/devmapper
parentf668e36652e26f92c0f1a7fa3f648e5ed444b68e (diff)
downloaddocker-e91de9fb9d175541acc95834de486d33feef552a.tar.gz
Revert "Move layer mount refcounts to mountedLayer"
This reverts commit 563d0711f83952e561a0d7d5c48fef9810b4f010. Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
Diffstat (limited to 'daemon/graphdriver/devmapper')
-rw-r--r--daemon/graphdriver/devmapper/deviceset.go84
-rw-r--r--daemon/graphdriver/devmapper/driver.go2
2 files changed, 55 insertions, 31 deletions
diff --git a/daemon/graphdriver/devmapper/deviceset.go b/daemon/graphdriver/devmapper/deviceset.go
index cb3bf742a0..71c214d5d8 100644
--- a/daemon/graphdriver/devmapper/deviceset.go
+++ b/daemon/graphdriver/devmapper/deviceset.go
@@ -69,6 +69,9 @@ type devInfo struct {
Deleted bool `json:"deleted"`
devices *DeviceSet
+ mountCount int
+ mountPath string
+
// The global DeviceSet lock guarantees that we serialize all
// the calls to libdevmapper (which is not threadsafe), but we
// sometimes release that lock while sleeping. In that case
@@ -1988,6 +1991,13 @@ func (devices *DeviceSet) DeleteDevice(hash string, syncDelete bool) error {
devices.Lock()
defer devices.Unlock()
+ // If mountcount is not zero, that means devices is still in use
+ // or has not been Put() properly. Fail device deletion.
+
+ if info.mountCount != 0 {
+ return fmt.Errorf("devmapper: Can't delete device %v as it is still mounted. mntCount=%v", info.Hash, info.mountCount)
+ }
+
return devices.deleteDevice(info, syncDelete)
}
@@ -2106,11 +2116,13 @@ func (devices *DeviceSet) cancelDeferredRemoval(info *devInfo) error {
}
// Shutdown shuts down the device by unmounting the root.
-func (devices *DeviceSet) Shutdown(home string) error {
+func (devices *DeviceSet) Shutdown() error {
logrus.Debugf("devmapper: [deviceset %s] Shutdown()", devices.devicePrefix)
logrus.Debugf("devmapper: Shutting down DeviceSet: %s", devices.root)
defer logrus.Debugf("devmapper: [deviceset %s] Shutdown() END", devices.devicePrefix)
+ var devs []*devInfo
+
// Stop deletion worker. This should start delivering new events to
// ticker channel. That means no new instance of cleanupDeletedDevice()
// will run after this call. If one instance is already running at
@@ -2127,46 +2139,30 @@ func (devices *DeviceSet) Shutdown(home string) error {
// metadata. Hence save this early before trying to deactivate devices.
devices.saveDeviceSetMetaData()
- // ignore the error since it's just a best effort to not try to unmount something that's mounted
- mounts, _ := mount.GetMounts()
- mounted := make(map[string]bool, len(mounts))
- for _, mnt := range mounts {
- mounted[mnt.Mountpoint] = true
+ for _, info := range devices.Devices {
+ devs = append(devs, info)
}
+ devices.Unlock()
- if err := filepath.Walk(path.Join(home, "mnt"), func(p string, info os.FileInfo, err error) error {
- if err != nil {
- return err
- }
- if !info.IsDir() {
- return nil
- }
-
- if mounted[p] {
+ for _, info := range devs {
+ info.lock.Lock()
+ if info.mountCount > 0 {
// We use MNT_DETACH here in case it is still busy in some running
// container. This means it'll go away from the global scope directly,
// and the device will be released when that container dies.
- if err := syscall.Unmount(p, syscall.MNT_DETACH); err != nil {
- logrus.Debugf("devmapper: Shutdown unmounting %s, error: %s", p, err)
+ if err := syscall.Unmount(info.mountPath, syscall.MNT_DETACH); err != nil {
+ logrus.Debugf("devmapper: Shutdown unmounting %s, error: %s", info.mountPath, err)
}
- }
- if devInfo, err := devices.lookupDevice(path.Base(p)); err != nil {
- logrus.Debugf("devmapper: Shutdown lookup device %s, error: %s", path.Base(p), err)
- } else {
- if err := devices.deactivateDevice(devInfo); err != nil {
- logrus.Debugf("devmapper: Shutdown deactivate %s , error: %s", devInfo.Hash, err)
+ devices.Lock()
+ if err := devices.deactivateDevice(info); err != nil {
+ logrus.Debugf("devmapper: Shutdown deactivate %s , error: %s", info.Hash, err)
}
+ devices.Unlock()
}
-
- return nil
- }); err != nil && !os.IsNotExist(err) {
- devices.Unlock()
- return err
+ info.lock.Unlock()
}
- devices.Unlock()
-
info, _ := devices.lookupDeviceWithLock("")
if info != nil {
info.lock.Lock()
@@ -2206,6 +2202,15 @@ func (devices *DeviceSet) MountDevice(hash, path, mountLabel string) error {
devices.Lock()
defer devices.Unlock()
+ if info.mountCount > 0 {
+ if path != info.mountPath {
+ return fmt.Errorf("devmapper: Trying to mount devmapper device in multiple places (%s, %s)", info.mountPath, path)
+ }
+
+ info.mountCount++
+ return nil
+ }
+
if err := devices.activateDeviceIfNeeded(info, false); err != nil {
return fmt.Errorf("devmapper: Error activating devmapper device for '%s': %s", hash, err)
}
@@ -2229,6 +2234,9 @@ func (devices *DeviceSet) MountDevice(hash, path, mountLabel string) error {
return fmt.Errorf("devmapper: Error mounting '%s' on '%s': %s", info.DevName(), path, err)
}
+ info.mountCount = 1
+ info.mountPath = path
+
return nil
}
@@ -2248,6 +2256,20 @@ func (devices *DeviceSet) UnmountDevice(hash, mountPath string) error {
devices.Lock()
defer devices.Unlock()
+ // If there are running containers when daemon crashes, during daemon
+ // restarting, it will kill running containers and will finally call
+ // Put() without calling Get(). So info.MountCount may become negative.
+ // if info.mountCount goes negative, we do the unmount and assign
+ // it to 0.
+
+ info.mountCount--
+ if info.mountCount > 0 {
+ return nil
+ } else if info.mountCount < 0 {
+ logrus.Warnf("devmapper: Mount count of device went negative. Put() called without matching Get(). Resetting count to 0")
+ info.mountCount = 0
+ }
+
logrus.Debugf("devmapper: Unmount(%s)", mountPath)
if err := syscall.Unmount(mountPath, syscall.MNT_DETACH); err != nil {
return err
@@ -2258,6 +2280,8 @@ func (devices *DeviceSet) UnmountDevice(hash, mountPath string) error {
return err
}
+ info.mountPath = ""
+
return nil
}
diff --git a/daemon/graphdriver/devmapper/driver.go b/daemon/graphdriver/devmapper/driver.go
index 7de6907c80..c03a7730ed 100644
--- a/daemon/graphdriver/devmapper/driver.go
+++ b/daemon/graphdriver/devmapper/driver.go
@@ -108,7 +108,7 @@ func (d *Driver) GetMetadata(id string) (map[string]string, error) {
// Cleanup unmounts a device.
func (d *Driver) Cleanup() error {
- err := d.DeviceSet.Shutdown(d.home)
+ err := d.DeviceSet.Shutdown()
if err2 := mount.Unmount(d.home); err == nil {
err = err2