From 6a04c1e518008bb81b41a94f56b015801fd399b2 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sat, 26 Apr 2025 15:37:25 +0900 Subject: [PATCH] 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. --- src/udev/udev-manager.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) 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"); -- 2.47.3