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>
This commit is contained in:
Vivek Goyal 2015-04-21 18:14:59 -04:00
parent 1b9b5095ac
commit 64ffdbc701
4 changed files with 46 additions and 0 deletions

View file

@ -55,6 +55,7 @@ var (
ErrTaskGetDeps = errors.New("dm_task_get_deps failed") ErrTaskGetDeps = errors.New("dm_task_get_deps failed")
ErrTaskGetInfo = errors.New("dm_task_get_info failed") ErrTaskGetInfo = errors.New("dm_task_get_info failed")
ErrTaskGetDriverVersion = errors.New("dm_task_get_driver_version 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") ErrTaskSetCookie = errors.New("dm_task_set_cookie failed")
ErrNilCookie = errors.New("cookie ptr can't be nil") ErrNilCookie = errors.New("cookie ptr can't be nil")
ErrAttachLoopbackDevice = errors.New("loopback mounting failed") ErrAttachLoopbackDevice = errors.New("loopback mounting failed")
@ -371,6 +372,25 @@ func RemoveDevice(name string) error {
return nil 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) { func GetBlockDeviceSize(file *os.File) (uint64, error) {
size, err := ioctlBlkGetSize64(file.Fd()) size, err := ioctlBlkGetSize64(file.Fd())
if err != nil { if err != nil {

View file

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

View file

@ -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)))
}

View file

@ -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
}