diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2021-09-01 02:20:33 +0900 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2021-09-02 09:06:24 +0900 |
commit | 242d39ebc1391f4734f6e63ff13764de92bc5f70 (patch) | |
tree | 6822460da66fecdb92d3b6f8aa2157cfb9d74a27 | |
parent | 8f27311eb2aec2411d1fb7d62e6c9d75d21ae8df (diff) | |
download | systemd-242d39ebc1391f4734f6e63ff13764de92bc5f70.tar.gz |
udev-node: always atomically create symlink to device node
By the previous commit, it is not necessary to distinguish if the devlink
already exists. Also, I cannot find any significant advantages of the
previous complecated logic, that is, first try to create directly, and then
fallback to atomically creation. Moreover, such logic increases the chance
of conflicts between multiple udev workers.
This makes devlinks always created atomically. Hopefully, this reduces the
conflicts between the workers.
-rw-r--r-- | src/udev/udev-node.c | 42 |
1 files changed, 9 insertions, 33 deletions
diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c index 1a34ea8128..46c04fe00b 100644 --- a/src/udev/udev-node.c +++ b/src/udev/udev-node.c @@ -71,6 +71,13 @@ static int node_symlink(sd_device *dev, const char *node, const char *slink) { assert(node); assert(slink); + if (lstat(slink, &stats) >= 0) { + if (!S_ISLNK(stats.st_mode)) + return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EEXIST), + "Conflicting inode '%s' found, link to '%s' will not be created.", slink, node); + } else if (errno != ENOENT) + return log_device_debug_errno(dev, errno, "Failed to lstat() '%s': %m", slink); + r = path_extract_directory(slink, &slink_dirname); if (r < 0) return log_device_debug_errno(dev, r, "Failed to get parent directory of '%s': %m", slink); @@ -80,41 +87,11 @@ static int node_symlink(sd_device *dev, const char *node, const char *slink) { if (r < 0) return log_device_debug_errno(dev, r, "Failed to get relative path from '%s' to '%s': %m", slink, node); - if (lstat(slink, &stats) >= 0) { - _cleanup_free_ char *buf = NULL; - - if (!S_ISLNK(stats.st_mode)) - return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EEXIST), - "Conflicting inode '%s' found, link to '%s' will not be created.", slink, node); - - if (readlink_malloc(slink, &buf) >= 0 && - path_equal(target, buf)) { - /* preserve link with correct target, do not replace node of other device */ - log_device_debug(dev, "Preserve already existing symlink '%s' to '%s'", slink, target); - - (void) label_fix(slink, LABEL_IGNORE_ENOENT); - (void) utimensat(AT_FDCWD, slink, NULL, AT_SYMLINK_NOFOLLOW); - - return 0; - } - } else if (errno == ENOENT) { - log_device_debug(dev, "Creating symlink '%s' to '%s'", slink, target); - - r = create_symlink(target, slink); - if (r >= 0) - return 0; - - log_device_debug_errno(dev, r, "Failed to create symlink '%s' to '%s', trying to replace '%s': %m", slink, target, slink); - } else - return log_device_debug_errno(dev, errno, "Failed to lstat() '%s': %m", slink); - - log_device_debug(dev, "Atomically replace '%s'", slink); - r = device_get_device_id(dev, &id); if (r < 0) return log_device_debug_errno(dev, r, "Failed to get device id: %m"); - slink_tmp = strjoina(slink, ".tmp-", id); + slink_tmp = strjoina(slink, ".tmp-", id); (void) unlink(slink_tmp); r = create_symlink(target, slink_tmp); @@ -127,8 +104,7 @@ static int node_symlink(sd_device *dev, const char *node, const char *slink) { return r; } - /* Tell caller that we replaced already existing symlink. */ - return 1; + return 0; } static int link_find_prioritized(sd_device *dev, bool add, const char *stackdir, char **ret) { |