From: Yu Watanabe Date: Wed, 5 Jul 2023 02:44:00 +0000 (+0900) Subject: sd-device: do not read uevent file in device_clone_with_db() X-Git-Tag: v254-rc1~27^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=35e49f2856dc7e80cfc6c9af3dca4e3aad9b8cb5;p=thirdparty%2Fsystemd.git sd-device: do not read uevent file in device_clone_with_db() Follow-up for 381f6d4ba5551898e7ff19189485072b94879281. When the function is called, the device may be already removed, and another device has the same syspath. Such situation can occur when a partition removed and another is created. In that case, the sysfs paths of the removed and newly created partitions can be same, but their devnums are different, and thus the database files corresponding to the devices are also different. Fixes #27981. --- diff --git a/src/libsystemd/sd-device/device-private.c b/src/libsystemd/sd-device/device-private.c index 9ded8c17a17..52cf9f2ab8c 100644 --- a/src/libsystemd/sd-device/device-private.c +++ b/src/libsystemd/sd-device/device-private.c @@ -620,51 +620,56 @@ int device_get_devlink_priority(sd_device *device, int *ret) { return 0; } -static int device_shallow_clone(sd_device *device, sd_device **ret) { +int device_clone_with_db(sd_device *device, sd_device **ret) { _cleanup_(sd_device_unrefp) sd_device *dest = NULL; - const char *val = NULL; + const char *key, *val; int r; assert(device); assert(ret); + /* The device may be already removed. Let's copy minimal set of information that was obtained through + * netlink socket. */ + r = device_new_aux(&dest); if (r < 0) return r; + /* Seal device to prevent reading the uevent file, as the device may have been already removed. */ + dest->sealed = true; + + /* Copy syspath, then also devname, sysname or sysnum can be obtained. */ r = device_set_syspath(dest, device->syspath, false); if (r < 0) return r; - (void) sd_device_get_subsystem(device, &val); - r = device_set_subsystem(dest, val); - if (r < 0) - return r; - if (streq_ptr(val, "drivers")) { - r = free_and_strdup(&dest->driver_subsystem, device->driver_subsystem); + /* Copy other information stored in database. Here, do not use FOREACH_DEVICE_PROPERTY() and + * sd_device_get_property_value(), as they calls device_properties_prepare() -> + * device_read_uevent_file(), but as commented in the above, the device may be already removed and + * reading uevent file may fail. */ + ORDERED_HASHMAP_FOREACH_KEY(val, key, device->properties) { + if (streq(key, "MINOR")) + continue; + + if (streq(key, "MAJOR")) { + const char *minor = NULL; + + minor = ordered_hashmap_get(device->properties, "MINOR"); + r = device_set_devnum(dest, val, minor); + } else + r = device_amend(dest, key, val); if (r < 0) return r; - } - - /* The device may be already removed. Let's copy minimal set of information to make - * device_get_device_id() work without uevent file. */ - if (sd_device_get_property_value(device, "IFINDEX", &val) >= 0) { - r = device_set_ifindex(dest, val); - if (r < 0) - return r; - } - - if (sd_device_get_property_value(device, "MAJOR", &val) >= 0) { - const char *minor = NULL; - - (void) sd_device_get_property_value(device, "MINOR", &minor); - r = device_set_devnum(dest, val, minor); - if (r < 0) - return r; + if (streq(key, "SUBSYSTEM") && streq(val, "drivers")) { + r = free_and_strdup(&dest->driver_subsystem, device->driver_subsystem); + if (r < 0) + return r; + } } - r = device_read_uevent_file(dest); + /* Finally, read the udev database. */ + r = device_read_db_internal(dest, /* force = */ true); if (r < 0) return r; @@ -672,27 +677,6 @@ static int device_shallow_clone(sd_device *device, sd_device **ret) { return 0; } -int device_clone_with_db(sd_device *device, sd_device **ret) { - _cleanup_(sd_device_unrefp) sd_device *dest = NULL; - int r; - - assert(device); - assert(ret); - - r = device_shallow_clone(device, &dest); - if (r < 0) - return r; - - r = device_read_db(dest); - if (r < 0) - return r; - - dest->sealed = true; - - *ret = TAKE_PTR(dest); - return 0; -} - void device_cleanup_tags(sd_device *device) { assert(device);