浏览代码

devmapper: Provide a new parameter dm.deferred_device_removal

Provide a new command line knob dm.deferred_device_removal which will enable
deferred device deactivation if driver and library support it.

This patch also checks for library support and driver version.

Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
Vivek Goyal 10 年之前
父节点
当前提交
15c158b207
共有 2 个文件被更改,包括 83 次插入2 次删除
  1. 20 0
      daemon/graphdriver/devmapper/README.md
  2. 63 2
      daemon/graphdriver/devmapper/deviceset.go

+ 20 - 0
daemon/graphdriver/devmapper/README.md

@@ -252,3 +252,23 @@ Here is the list of supported options:
     > Otherwise, set this flag for migrating existing Docker daemons to a
     > daemon with a supported environment.
 
+ *  `dm.use_deferred_removal`
+
+    Enables use of deferred device removal if libdm and kernel driver
+    support the mechanism.
+
+    Deferred device removal means that if device is busy when devices is
+    being removed/deactivated, then a deferred removal is scheduled on
+    device. And devices automatically goes away when last user of device
+    exits.
+
+    For example, when contianer exits, its associated thin device is
+    removed. If that devices has leaked into some other mount namespace
+    can can't be removed now, container exit will still be successful
+    and this option will just schedule device for deferred removal and
+    will not wait in a loop trying to remove a busy device.
+
+    Example use:
+
+    ``docker -d --storage-opt dm.use_deferred_device_removal=true``
+

+ 63 - 2
daemon/graphdriver/devmapper/deviceset.go

@@ -37,7 +37,9 @@ var (
 	// We retry device removal so many a times that even error messages
 	// will fill up console during normal operation. So only log Fatal
 	// messages by default.
-	DMLogLevel int = devicemapper.LogLevelFatal
+	DMLogLevel                   int  = devicemapper.LogLevelFatal
+	DriverDeferredRemovalSupport bool = false
+	EnableDeferredRemoval        bool = false
 )
 
 const deviceSetMetaFile string = "deviceset-metadata"
@@ -103,6 +105,7 @@ type DeviceSet struct {
 	thinPoolDevice        string
 	Transaction           `json:"-"`
 	overrideUdevSyncCheck bool
+	deferredRemove        bool // use deferred removal
 }
 
 type DiskUsage struct {
@@ -960,16 +963,67 @@ func (devices *DeviceSet) closeTransaction() error {
 	return nil
 }
 
+func determineDriverCapabilities(version string) error {
+	/*
+	 * Driver version 4.27.0 and greater support deferred activation
+	 * feature.
+	 */
+
+	logrus.Debugf("devicemapper: driver version is %s", version)
+
+	versionSplit := strings.Split(version, ".")
+	major, err := strconv.Atoi(versionSplit[0])
+	if err != nil {
+		return graphdriver.ErrNotSupported
+	}
+
+	if major > 4 {
+		DriverDeferredRemovalSupport = true
+		return nil
+	}
+
+	if major < 4 {
+		return nil
+	}
+
+	minor, err := strconv.Atoi(versionSplit[1])
+	if err != nil {
+		return graphdriver.ErrNotSupported
+	}
+
+	/*
+	 * If major is 4 and minor is 27, then there is no need to
+	 * check for patch level as it can not be less than 0.
+	 */
+	if minor >= 27 {
+		DriverDeferredRemovalSupport = true
+		return nil
+	}
+
+	return nil
+}
+
 func (devices *DeviceSet) initDevmapper(doInit bool) error {
 	// give ourselves to libdm as a log handler
 	devicemapper.LogInit(devices)
 
-	_, err := devicemapper.GetDriverVersion()
+	version, err := devicemapper.GetDriverVersion()
 	if err != nil {
 		// Can't even get driver version, assume not supported
 		return graphdriver.ErrNotSupported
 	}
 
+	if err := determineDriverCapabilities(version); err != nil {
+		return graphdriver.ErrNotSupported
+	}
+
+	// If user asked for deferred removal and both library and driver
+	// supports deferred removal use it.
+	if EnableDeferredRemoval && DriverDeferredRemovalSupport && devicemapper.LibraryDeferredRemovalSupport == true {
+		logrus.Debugf("devmapper: Deferred removal support enabled.")
+		devices.deferredRemove = true
+	}
+
 	// https://github.com/docker/docker/issues/4036
 	if supported := devicemapper.UdevSetSyncSupport(true); !supported {
 		logrus.Errorf("Udev sync is not supported. This will lead to unexpected behavior, data loss and errors. For more information, see https://docs.docker.com/reference/commandline/cli/#daemon-storage-driver-option")
@@ -1671,6 +1725,13 @@ func NewDeviceSet(root string, doInit bool, options []string) (*DeviceSet, error
 			if err != nil {
 				return nil, err
 			}
+
+		case "dm.use_deferred_removal":
+			EnableDeferredRemoval, err = strconv.ParseBool(val)
+			if err != nil {
+				return nil, err
+			}
+
 		default:
 			return nil, fmt.Errorf("Unknown option %s\n", key)
 		}