Browse code

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 authored on 2015/04/22 07:14:59
Showing 4 changed files
... ...
@@ -55,6 +55,7 @@ var (
55 55
 	ErrTaskGetDeps            = errors.New("dm_task_get_deps failed")
56 56
 	ErrTaskGetInfo            = errors.New("dm_task_get_info failed")
57 57
 	ErrTaskGetDriverVersion   = errors.New("dm_task_get_driver_version failed")
58
+	ErrTaskDeferredRemove     = errors.New("dm_task_deferred_remove failed")
58 59
 	ErrTaskSetCookie          = errors.New("dm_task_set_cookie failed")
59 60
 	ErrNilCookie              = errors.New("cookie ptr can't be nil")
60 61
 	ErrAttachLoopbackDevice   = errors.New("loopback mounting failed")
... ...
@@ -371,6 +372,25 @@ func RemoveDevice(name string) error {
371 371
 	return nil
372 372
 }
373 373
 
374
+func RemoveDeviceDeferred(name string) error {
375
+	logrus.Debugf("[devmapper] RemoveDeviceDeferred START(%s)", name)
376
+	defer logrus.Debugf("[devmapper] RemoveDeviceDeferred END(%s)", name)
377
+	task, err := TaskCreateNamed(DeviceRemove, name)
378
+	if task == nil {
379
+		return err
380
+	}
381
+
382
+	if err := DmTaskDeferredRemove(task.unmanaged); err != 1 {
383
+		return ErrTaskDeferredRemove
384
+	}
385
+
386
+	if err = task.Run(); err != nil {
387
+		return fmt.Errorf("Error running RemoveDeviceDeferred %s", err)
388
+	}
389
+
390
+	return nil
391
+}
392
+
374 393
 func GetBlockDeviceSize(file *os.File) (uint64, error) {
375 394
 	size, err := ioctlBlkGetSize64(file.Fd())
376 395
 	if err != nil {
... ...
@@ -112,6 +112,7 @@ var (
112 112
 	DmUdevGetSyncSupport   = dmUdevGetSyncSupportFct
113 113
 	DmCookieSupported      = dmCookieSupportedFct
114 114
 	LogWithErrnoInit       = logWithErrnoInitFct
115
+	DmTaskDeferredRemove   = dmTaskDeferredRemoveFct
115 116
 )
116 117
 
117 118
 func free(p *C.char) {
118 119
new file mode 100644
... ...
@@ -0,0 +1,15 @@
0
+// +build linux,!libdm_no_deferred_remove
1
+
2
+package devicemapper
3
+
4
+/*
5
+#cgo LDFLAGS: -L. -ldevmapper
6
+#include <libdevmapper.h>
7
+*/
8
+import "C"
9
+
10
+const LibraryDeferredRemovalSupport = true
11
+
12
+func dmTaskDeferredRemoveFct(task *CDmTask) int {
13
+	return int(C.dm_task_deferred_remove((*C.struct_dm_task)(task)))
14
+}
0 15
new file mode 100644
... ...
@@ -0,0 +1,10 @@
0
+// +build linux,libdm_no_deferred_remove
1
+
2
+package devicemapper
3
+
4
+const LibraryDeferredRemovalSupport = false
5
+
6
+func dmTaskDeferredRemoveFct(task *CDmTask) int {
7
+	// Error. Nobody should be calling it.
8
+	return -1
9
+}