From 5e505d101f0201a4d045510d0a9b0c66697dedfe Mon Sep 17 00:00:00 2001 From: "Ji.Zhilong" Date: Fri, 15 Jul 2016 22:47:31 +0800 Subject: [PATCH] devmapper: prevent libdevmapper from deleting device symlinks in RemoveDeviceDeferred if there is no cookie set in dm task, or flag DM_UDEV_DISABLE_LIBRARY_FALLBACK is cleared for a DM_DEV_REMOVE task, libdevmapper will fallback to clean up the symlink under /dev/mapper by itself, no matter the device removal is executed immediately or deferred by the kernel.In some cases, the removal is deferred by the kernel, while the symlink is deleted directly by libdevmapper, when docker tries to activate the device again, the deferred removal will be canceld, but the symlink will not show up again, so docker's attempt to mount the device by the symlink will fail, and it will eventually leads to a `docker start/diff` error. Fixes #24671 Signed-off-by: Ji.Zhilong --- pkg/devicemapper/devmapper.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/pkg/devicemapper/devmapper.go b/pkg/devicemapper/devmapper.go index d6b17ad976..94b55306f1 100644 --- a/pkg/devicemapper/devmapper.go +++ b/pkg/devicemapper/devmapper.go @@ -358,6 +358,27 @@ func RemoveDeviceDeferred(name string) error { return ErrTaskDeferredRemove } + // set a task cookie and disable library fallback, or else libdevmapper will + // disable udev dm rules and delete the symlink under /dev/mapper by itself, + // even if the removal is deferred by the kernel. + var cookie uint + var flags uint16 + flags = DmUdevDisableLibraryFallback + if err := task.setCookie(&cookie, flags); err != nil { + return fmt.Errorf("devicemapper: Can not set cookie: %s", err) + } + + // libdevmapper and udev relies on System V semaphore for synchronization, + // semaphores created in `task.setCookie` will be cleaned up in `UdevWait`. + // So these two function call must come in pairs, otherwise semaphores will + // be leaked, and the limit of number of semaphores defined in `/proc/sys/kernel/sem` + // will be reached, which will eventually make all follwing calls to 'task.SetCookie' + // fail. + // this call will not wait for the deferred removal's final executing, since no + // udev event will be generated, and the semaphore's value will not be incremented + // by udev, what UdevWait is just cleaning up the semaphore. + defer UdevWait(&cookie) + if err = task.run(); err != nil { return fmt.Errorf("devicemapper: Error running RemoveDeviceDeferred %s", err) }