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.
This commit is contained in:
Yu Watanabe
2025-05-10 02:44:54 +09:00
parent e8f017c421
commit 6a04c1e518
+22 -2
View File
@@ -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");