Skip to content

Commit f9a8c82

Browse files
yuwatabluca
authored andcommitted
sd-device: do not read uevent file in device_clone_with_db()
Follow-up for 381f6d4. 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. (cherry picked from commit 35e49f2)
1 parent 49fa773 commit f9a8c82

File tree

1 file changed

+31
-47
lines changed

1 file changed

+31
-47
lines changed

src/libsystemd/sd-device/device-private.c

Lines changed: 31 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -618,79 +618,63 @@ int device_get_devlink_priority(sd_device *device, int *ret) {
618618
return 0;
619619
}
620620

621-
static int device_shallow_clone(sd_device *device, sd_device **ret) {
621+
int device_clone_with_db(sd_device *device, sd_device **ret) {
622622
_cleanup_(sd_device_unrefp) sd_device *dest = NULL;
623-
const char *val = NULL;
623+
const char *key, *val;
624624
int r;
625625

626626
assert(device);
627627
assert(ret);
628628

629+
/* The device may be already removed. Let's copy minimal set of information that was obtained through
630+
* netlink socket. */
631+
629632
r = device_new_aux(&dest);
630633
if (r < 0)
631634
return r;
632635

636+
/* Seal device to prevent reading the uevent file, as the device may have been already removed. */
637+
dest->sealed = true;
638+
639+
/* Copy syspath, then also devname, sysname or sysnum can be obtained. */
633640
r = device_set_syspath(dest, device->syspath, false);
634641
if (r < 0)
635642
return r;
636643

637-
(void) sd_device_get_subsystem(device, &val);
638-
r = device_set_subsystem(dest, val);
639-
if (r < 0)
640-
return r;
641-
if (streq_ptr(val, "drivers")) {
642-
r = free_and_strdup(&dest->driver_subsystem, device->driver_subsystem);
644+
/* Copy other information stored in database. Here, do not use FOREACH_DEVICE_PROPERTY() and
645+
* sd_device_get_property_value(), as they calls device_properties_prepare() ->
646+
* device_read_uevent_file(), but as commented in the above, the device may be already removed and
647+
* reading uevent file may fail. */
648+
ORDERED_HASHMAP_FOREACH_KEY(val, key, device->properties) {
649+
if (streq(key, "MINOR"))
650+
continue;
651+
652+
if (streq(key, "MAJOR")) {
653+
const char *minor = NULL;
654+
655+
minor = ordered_hashmap_get(device->properties, "MINOR");
656+
r = device_set_devnum(dest, val, minor);
657+
} else
658+
r = device_amend(dest, key, val);
643659
if (r < 0)
644660
return r;
645-
}
646-
647-
/* The device may be already removed. Let's copy minimal set of information to make
648-
* device_get_device_id() work without uevent file. */
649661

650-
if (sd_device_get_property_value(device, "IFINDEX", &val) >= 0) {
651-
r = device_set_ifindex(dest, val);
652-
if (r < 0)
653-
return r;
654-
}
655-
656-
if (sd_device_get_property_value(device, "MAJOR", &val) >= 0) {
657-
const char *minor = NULL;
658-
659-
(void) sd_device_get_property_value(device, "MINOR", &minor);
660-
r = device_set_devnum(dest, val, minor);
661-
if (r < 0)
662-
return r;
662+
if (streq(key, "SUBSYSTEM") && streq(val, "drivers")) {
663+
r = free_and_strdup(&dest->driver_subsystem, device->driver_subsystem);
664+
if (r < 0)
665+
return r;
666+
}
663667
}
664668

665-
r = device_read_uevent_file(dest);
669+
/* Finally, read the udev database. */
670+
r = device_read_db_internal(dest, /* force = */ true);
666671
if (r < 0)
667672
return r;
668673

669674
*ret = TAKE_PTR(dest);
670675
return 0;
671676
}
672677

673-
int device_clone_with_db(sd_device *device, sd_device **ret) {
674-
_cleanup_(sd_device_unrefp) sd_device *dest = NULL;
675-
int r;
676-
677-
assert(device);
678-
assert(ret);
679-
680-
r = device_shallow_clone(device, &dest);
681-
if (r < 0)
682-
return r;
683-
684-
r = device_read_db(dest);
685-
if (r < 0)
686-
return r;
687-
688-
dest->sealed = true;
689-
690-
*ret = TAKE_PTR(dest);
691-
return 0;
692-
}
693-
694678
void device_cleanup_tags(sd_device *device) {
695679
assert(device);
696680

0 commit comments

Comments
 (0)