Browse code

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 <zhilongji@gmail.com>

Ji.Zhilong authored on 2016/07/15 23:47:31
Showing 1 changed files
... ...
@@ -358,6 +358,27 @@ func RemoveDeviceDeferred(name string) error {
358 358
 		return ErrTaskDeferredRemove
359 359
 	}
360 360
 
361
+	// set a task cookie and disable library fallback, or else libdevmapper will
362
+	// disable udev dm rules and delete the symlink under /dev/mapper by itself,
363
+	// even if the removal is deferred by the kernel.
364
+	var cookie uint
365
+	var flags uint16
366
+	flags = DmUdevDisableLibraryFallback
367
+	if err := task.setCookie(&cookie, flags); err != nil {
368
+		return fmt.Errorf("devicemapper: Can not set cookie: %s", err)
369
+	}
370
+
371
+	// libdevmapper and udev relies on System V semaphore for synchronization,
372
+	// semaphores created in `task.setCookie` will be cleaned up in `UdevWait`.
373
+	// So these two function call must come in pairs, otherwise semaphores will
374
+	// be leaked, and the  limit of number of semaphores defined in `/proc/sys/kernel/sem`
375
+	// will be reached, which will eventually make all follwing calls to 'task.SetCookie'
376
+	// fail.
377
+	// this call will not wait for the deferred removal's final executing, since no
378
+	// udev event will be generated, and the semaphore's value will not be incremented
379
+	// by udev, what UdevWait is just cleaning up the semaphore.
380
+	defer UdevWait(&cookie)
381
+
361 382
 	if err = task.run(); err != nil {
362 383
 		return fmt.Errorf("devicemapper: Error running RemoveDeviceDeferred %s", err)
363 384
 	}