Przeglądaj źródła

devicemapper: Add helper functions to allow deferred device removal

A lot of time device mapper devices leak across mount namespace which docker
does not know about and when docker tries to deactivate/delete device,
operation fails as device is open in some mount namespace.

Create a mechanism where one can defer the device deactivation/deletion
so that docker operation does not fail and device automatically goes
away when last reference to it is dropped.

Signed-off-by: Vivek Goyal <vgoyal@redhat.com>
Vivek Goyal 10 lat temu
rodzic
commit
6964ab94be

+ 20 - 0
pkg/devicemapper/devmapper.go

@@ -55,6 +55,7 @@ var (
 	ErrTaskGetDeps            = errors.New("dm_task_get_deps failed")
 	ErrTaskGetInfo            = errors.New("dm_task_get_info failed")
 	ErrTaskGetDriverVersion   = errors.New("dm_task_get_driver_version failed")
+	ErrTaskDeferredRemove     = errors.New("dm_task_deferred_remove failed")
 	ErrTaskSetCookie          = errors.New("dm_task_set_cookie failed")
 	ErrNilCookie              = errors.New("cookie ptr can't be nil")
 	ErrAttachLoopbackDevice   = errors.New("loopback mounting failed")
@@ -371,6 +372,25 @@ func RemoveDevice(name string) error {
 	return nil
 }
 
+func RemoveDeviceDeferred(name string) error {
+	logrus.Debugf("[devmapper] RemoveDeviceDeferred START(%s)", name)
+	defer logrus.Debugf("[devmapper] RemoveDeviceDeferred END(%s)", name)
+	task, err := TaskCreateNamed(DeviceRemove, name)
+	if task == nil {
+		return err
+	}
+
+	if err := DmTaskDeferredRemove(task.unmanaged); err != 1 {
+		return ErrTaskDeferredRemove
+	}
+
+	if err = task.Run(); err != nil {
+		return fmt.Errorf("Error running RemoveDeviceDeferred %s", err)
+	}
+
+	return nil
+}
+
 func GetBlockDeviceSize(file *os.File) (uint64, error) {
 	size, err := ioctlBlkGetSize64(file.Fd())
 	if err != nil {

+ 1 - 0
pkg/devicemapper/devmapper_wrapper.go

@@ -112,6 +112,7 @@ var (
 	DmUdevGetSyncSupport   = dmUdevGetSyncSupportFct
 	DmCookieSupported      = dmCookieSupportedFct
 	LogWithErrnoInit       = logWithErrnoInitFct
+	DmTaskDeferredRemove   = dmTaskDeferredRemoveFct
 )
 
 func free(p *C.char) {

+ 15 - 0
pkg/devicemapper/devmapper_wrapper_deferred_remove.go

@@ -0,0 +1,15 @@
+// +build linux,!libdm_no_deferred_remove
+
+package devicemapper
+
+/*
+#cgo LDFLAGS: -L. -ldevmapper
+#include <libdevmapper.h>
+*/
+import "C"
+
+const LibraryDeferredRemovalSupport = true
+
+func dmTaskDeferredRemoveFct(task *CDmTask) int {
+	return int(C.dm_task_deferred_remove((*C.struct_dm_task)(task)))
+}

+ 10 - 0
pkg/devicemapper/devmapper_wrapper_no_deferred_remove.go

@@ -0,0 +1,10 @@
+// +build linux,libdm_no_deferred_remove
+
+package devicemapper
+
+const LibraryDeferredRemovalSupport = false
+
+func dmTaskDeferredRemoveFct(task *CDmTask) int {
+	// Error. Nobody should be calling it.
+	return -1
+}