From: Yu Watanabe Date: Sat, 26 Apr 2025 06:37:25 +0000 (+0900) Subject: udev: sort queued events by their seqnum X-Git-Tag: v258-rc1~646^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=refs%2Fpull%2F37314%2Fhead;p=thirdparty%2Fsystemd.git udev: sort queued events by their seqnum Unfortunately, the kernel may send events in a random order: ``` [ 25.769624] systemd-udevd[194]: sdi7: Device is queued (SEQNUM=2843, ACTION=add) [ 25.769893] systemd-udevd[194]: sda5: Device is queued (SEQNUM=2842, ACTION=add) [ 25.770517] systemd-udevd[194]: sdi8: Device is queued (SEQNUM=2844, ACTION=add) ``` As you can see, udevd receives the event with SEQNUM=2843 earlier than one with SEQNUM=2842. Let's make queued events sorted, as our logic of determining which event is ready for being processed assumes that queued events are sorted. See event_build_dependencies(). Also, refuse to queue an event if another event with the same seqnum is already queued. --- diff --git a/src/udev/udev-manager.c b/src/udev/udev-manager.c index 38ab906af20..fe26496618d 100644 --- a/src/udev/udev-manager.c +++ b/src/udev/udev-manager.c @@ -930,8 +930,28 @@ static int event_queue_insert(Manager *manager, sd_device *dev) { .locked_event_prioq_index = PRIOQ_IDX_NULL, }; - LIST_INSERT_AFTER(event, manager->events, manager->last_event, event); - manager->last_event = event; + Event *prev = NULL; + LIST_FOREACH_BACKWARDS(event, e, manager->last_event) { + if (e->seqnum < event->seqnum) { + prev = e; + break; + } + if (e->seqnum == event->seqnum) + return log_device_warning_errno(dev, SYNTHETIC_ERRNO(EALREADY), + "The event (SEQNUM=%"PRIu64") has been already queued.", + event->seqnum); + + /* Inserting an event in an earlier place may change dependency tree. Let's rebuild it later. */ + event_clear_dependencies(e); + } + + LIST_INSERT_AFTER(event, manager->events, prev, event); + if (prev == manager->last_event) + manager->last_event = event; + else + log_device_debug(dev, "Unordered event is received (last queued event seqnum=%"PRIu64", newly received event seqnum=%"PRIu64"), reordering.", + manager->last_event->seqnum, event->seqnum); + event->manager = manager; TAKE_PTR(event); log_device_uevent(dev, "Device is queued");