From 64ffdbc701e470881023256b408c2d369717ac00 Mon Sep 17 00:00:00 2001 From: Vivek Goyal Date: Tue, 21 Apr 2015 18:14:59 -0400 Subject: [PATCH] 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 --- devicemapper/devmapper.go | 20 +++++++++++++++++++ devicemapper/devmapper_wrapper.go | 1 + .../devmapper_wrapper_deferred_remove.go | 15 ++++++++++++++ .../devmapper_wrapper_no_deferred_remove.go | 10 ++++++++++ 4 files changed, 46 insertions(+) create mode 100644 devicemapper/devmapper_wrapper_deferred_remove.go create mode 100644 devicemapper/devmapper_wrapper_no_deferred_remove.go diff --git a/devicemapper/devmapper.go b/devicemapper/devmapper.go index bb89f7f..42876d6 100644 --- a/devicemapper/devmapper.go +++ b/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 { diff --git a/devicemapper/devmapper_wrapper.go b/devicemapper/devmapper_wrapper.go index e436cca..fc841d9 100644 --- a/devicemapper/devmapper_wrapper.go +++ b/devicemapper/devmapper_wrapper.go @@ -112,6 +112,7 @@ var ( DmUdevGetSyncSupport = dmUdevGetSyncSupportFct DmCookieSupported = dmCookieSupportedFct LogWithErrnoInit = logWithErrnoInitFct + DmTaskDeferredRemove = dmTaskDeferredRemoveFct ) func free(p *C.char) { diff --git a/devicemapper/devmapper_wrapper_deferred_remove.go b/devicemapper/devmapper_wrapper_deferred_remove.go new file mode 100644 index 0000000..3d52f3f --- /dev/null +++ b/devicemapper/devmapper_wrapper_deferred_remove.go @@ -0,0 +1,15 @@ +// +build linux,!libdm_no_deferred_remove + +package devicemapper + +/* +#cgo LDFLAGS: -L. -ldevmapper +#include +*/ +import "C" + +const LibraryDeferredRemovalSupport = true + +func dmTaskDeferredRemoveFct(task *CDmTask) int { + return int(C.dm_task_deferred_remove((*C.struct_dm_task)(task))) +} diff --git a/devicemapper/devmapper_wrapper_no_deferred_remove.go b/devicemapper/devmapper_wrapper_no_deferred_remove.go new file mode 100644 index 0000000..6366065 --- /dev/null +++ b/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 +}