From 96be8707ef42785f5dfba8e98284835f6689a18b Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Mon, 12 Oct 2026 09:29:57 +0900 Subject: [PATCH] udev-node: chase devlink on remove event Previously, readlink_malloc() was used to find the target device. However, devlink is a relative symbolic link, hence the path obtained by readlink_malloc() never matched with the one by sd_device_get_devname(). Also path_startswith(target, "/dev/") was always negative. Let's use chase_and_stat() to obtain the absolute path to the target device that the devlink currently points to. Fixes the following spurious logs on remove event: (udev-worker)[2338]: loop1p1: Processing device (SEQNUM=2231, ACTION=remove) (udev-worker)[2338]: Notify message sent to '@4814750286313953891': "INOTIFY_WATCH_REMOVE=1" (udev-worker)[2338]: loop1p1: Symbolic link '/dev/udevtest/x2' points to '../loop1p1' which is outside of '/dev/', updating it. (udev-worker)[2338]: loop1p1: No reference left for '/dev/udevtest/x2', removing (udev-worker)[2338]: loop1p1: Symbolic link '/dev/disk/by-diskseq/9-part1' points to '../../loop1p1' which is outside of '/dev/', updating it. (udev-worker)[2338]: loop1p1: No reference left for '/dev/disk/by-diskseq/9-part1', removing (udev-worker)[2338]: loop1p1: Symbolic link '/dev/disk/by-label/udevtest-b-fs1' points to '../../loop1p1' which is outside of '/dev/', updating it. (udev-worker)[2338]: loop1p1: No reference left for '/dev/disk/by-label/udevtest-b-fs1', removing (udev-worker)[2338]: loop1p1: Symbolic link '/dev/disk/by-uuid/221d135f-7bf7-45b8-abeb-d9b3afb2c215' points to '../../loop1p1' which is outside of '/dev/', updating it. (udev-worker)[2338]: loop1p1: No reference left for '/dev/disk/by-uuid/221d135f-7bf7-45b8-abeb-d9b3afb2c215', removing (udev-worker)[2338]: loop1p1: Symbolic link '/dev/disk/by-partlabel/udevtest-b-part1' points to '../../loop1p1' which is outside of '/dev/', updating it. (udev-worker)[2338]: loop1p1: No reference left for '/dev/disk/by-partlabel/udevtest-b-part1', removing (udev-worker)[2338]: loop1p1: Symbolic link '/dev/udevtest/b1' points to '../loop1p1' which is outside of '/dev/', updating it. (udev-worker)[2338]: loop1p1: No reference left for '/dev/udevtest/b1', removing (udev-worker)[2338]: loop1p1: Symbolic link '/dev/udevtest/x1' points to '../loop1p1' which is outside of '/dev/', updating it. (udev-worker)[2338]: loop1p1: No reference left for '/dev/udevtest/x1', removing (udev-worker)[2338]: loop1p1: Symbolic link '/dev/disk/by-partuuid/5ef627b6-95f1-a942-8d7a-bd4ac53485ac' points to '../../loop1p1' which is outside of '/dev/', updating it. (udev-worker)[2338]: loop1p1: No reference left for '/dev/disk/by-partuuid/5ef627b6-95f1-a942-8d7a-bd4ac53485ac', removing (udev-worker)[2338]: loop1p1: Symbolic link '/dev/udevtest/b3' points to '../loop1p1' which is outside of '/dev/', updating it. (udev-worker)[2338]: loop1p1: No reference left for '/dev/udevtest/b3', removing (udev-worker)[2338]: loop1p1: Symbolic link '/dev/disk/by-loop-inode/0:36-13-part1' points to '../../loop1p1' which is outside of '/dev/', updating it. (udev-worker)[2338]: loop1p1: No reference left for '/dev/disk/by-loop-inode/0:36-13-part1', removing (udev-worker)[2338]: loop1p1: Symbolic link '/dev/disk/by-loop-ref/\x2ftmp\x2fudevtest-b.img-part1' points to '../../loop1p1' which is outside of '/dev/', updating it. (udev-worker)[2338]: loop1p1: No reference left for '/dev/disk/by-loop-ref/\x2ftmp\x2fudevtest-b.img-part1', removing (udev-worker)[2338]: loop1p1: Device processed (SEQNUM=2231, ACTION=remove) (cherry picked from commit 03a65741d77d61929b98977d1bfdf2b470e14b55) --- src/udev/udev-node.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c index 09154c8895..9512f9cbcc 100644 --- a/src/udev/udev-node.c +++ b/src/udev/udev-node.c @@ -7,6 +7,7 @@ #include "sd-id128.h" #include "alloc-util.h" +#include "chase.h" #include "device-private.h" #include "device-util.h" #include "devnum-util.h" @@ -423,22 +424,21 @@ static int link_update(sd_device *dev, const char *slink, bool add) { return log_device_debug_errno(dev, r, "Failed to update stack directory for '%s': %m", slink); if (!add) { - _cleanup_free_ char *target = NULL; - /* Especially on 'remove' event, the device ID obtained by node_get_current() may not be * reliable, as the device node and/or device number may be reused. Hence, let's read the * devlink here and if it points to our device node, then we need to update the devlink. If * it points to another device node, then it is already owned by another device, hence we * should not touch it and keep it as is. */ - r = readlink_malloc(slink, &target); + _cleanup_free_ char *target = NULL; + struct stat st; + r = chase_and_stat(slink, /* root= */ NULL, /* chase_flags= */ 0, &target, &st); if (r < 0) { if (r != -ENOENT) - log_device_debug_errno(dev, r, "Failed to read symbolic link '%s', ignoring: %m", slink); + log_device_debug_errno(dev, r, "Failed to chase and stat '%s', ignoring: %m", slink); - /* The devlink does not exist. Let's find the most suitable owner, and create the - * devlink. This is typically not necessary and does nothing, but for safety in the - * case that the devlink is removed manually. */ + /* The devlink or its target device does not exist. Let's find the most suitable + * owner, and create or update the devlink. */ return link_search_and_update(dev, slink, dirfd, add); } @@ -458,15 +458,6 @@ static int link_update(sd_device *dev, const char *slink, bool add) { return link_search_and_update(dev, slink, dirfd, add); } - struct stat st; - if (lstat(target, &st) < 0) { - if (errno != ENOENT) - log_device_debug_errno(dev, errno, "Failed to stat '%s', ignoring: %m", target); - - /* The current target device is also already removed? Let's update. */ - return link_search_and_update(dev, slink, dirfd, add); - } - if (!IN_SET(st.st_mode & S_IFMT, S_IFBLK, S_IFCHR)) { log_device_debug(dev, "Symbolic link '%s' points to '%s' which is not a device node, updating it.", slink, target); return link_search_and_update(dev, slink, dirfd, add);