1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

libdm: fix races with udev

On modern systems udev manages nodes in /dev/mapper directory.
It creates, deletes and renames the nodes according to the
state of the kernel driver.

When the dmsetup is compiled without udev support (--enable-udev_sync)
and runs on the system with running udevd it tries to manage nodes in
/dev/mapper too, so it can race with udev.
dmsetup checks if the node was created/deleted/renamed with the stat
syscall, and skips the operation if it was. However, if udev
creates/deletes/renames the node after the stat syscall and before the
mknod/unlink/rename syscall, dmsetup reports an error.

Since in the system everything happened as expected, skip reporting
error for such case.

These races can be easily provoked by inserting sleep at appropriate
places.

Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
This commit is contained in:
Mikulas Patocka 2013-09-16 15:23:54 -04:00 committed by Zdenek Kabelac
parent 3ac7f927e1
commit ed30145f4a
2 changed files with 8 additions and 3 deletions

View File

@ -1,5 +1,6 @@
Version 1.02.83 Version 1.02.83
================================== ==================================
Skip race errors when non-udev dmsetup build runs on udev-enabled system.
Skip error message when holders are not present in sysfs. Skip error message when holders are not present in sysfs.
Use __linux__ instead of linux define to make libdevmapper.h C compliant. Use __linux__ instead of linux define to make libdevmapper.h C compliant.

View File

@ -966,7 +966,9 @@ static int _add_dev_node(const char *dev_name, uint32_t major, uint32_t minor,
(void) dm_prepare_selinux_context(path, S_IFBLK); (void) dm_prepare_selinux_context(path, S_IFBLK);
old_mask = umask(0); old_mask = umask(0);
if (mknod(path, S_IFBLK | mode, dev) < 0) {
/* The node may already have been created by udev. So ignore EEXIST. */
if (mknod(path, S_IFBLK | mode, dev) < 0 && errno != EEXIST) {
log_error("%s: mknod for %s failed: %s", path, dev_name, strerror(errno)); log_error("%s: mknod for %s failed: %s", path, dev_name, strerror(errno));
umask(old_mask); umask(old_mask);
(void) dm_prepare_selinux_context(NULL, 0); (void) dm_prepare_selinux_context(NULL, 0);
@ -998,7 +1000,8 @@ static int _rm_dev_node(const char *dev_name, int warn_if_udev_failed)
log_warn("Node %s was not removed by udev. " log_warn("Node %s was not removed by udev. "
"Falling back to direct node removal.", path); "Falling back to direct node removal.", path);
if (unlink(path) < 0) { /* udev may already have deleted the node. Ignore ENOENT. */
if (unlink(path) < 0 && errno != ENOENT) {
log_error("Unable to unlink device node for '%s'", dev_name); log_error("Unable to unlink device node for '%s'", dev_name);
return 0; return 0;
} }
@ -1054,7 +1057,8 @@ static int _rename_dev_node(const char *old_name, const char *new_name,
"Falling back to direct node rename.", "Falling back to direct node rename.",
oldpath, newpath); oldpath, newpath);
if (rename(oldpath, newpath) < 0) { /* udev may already have renamed the node. Ignore ENOENT. */
if (rename(oldpath, newpath) < 0 && errno != ENOENT) {
log_error("Unable to rename device node from '%s' to '%s'", log_error("Unable to rename device node from '%s' to '%s'",
old_name, new_name); old_name, new_name);
return 0; return 0;