From 4f294ffdf18ab9f187400dbbab593a980e60be89 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 26 Aug 2022 00:16:17 +0900 Subject: [PATCH] udev: certainly restart event for previously locked device If udevd receives a uevent for a locked block device, then the event is requeued. However, the queued event will be processed only when at least one sd_event_source is processed. Hence, if udevd has no event under processing, or receives no new uevent, etc., then the requeued event will be never processed. Follow-up for 400e3d21f8cae53a8ba9f9567f244fbf6f3e076c. Fixes #24439. Reference:https://github.com/systemd/systemd/commit/4f294ffdf18ab9f187400dbbab593a980e60be89 Conflict:adaption because previous commits in https://github.com/systemd/systemd/pull/23088 are not introduced --- src/udev/udevd.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/udev/udevd.c b/src/udev/udevd.c index a979d43..b15a9d4 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -129,8 +129,11 @@ typedef struct Event { sd_device_action_t action; uint64_t seqnum; uint64_t blocker_seqnum; + + /* Used when the device is locked by another program. */ usec_t retry_again_next_usec; usec_t retry_again_timeout_usec; + sd_event_source *retry_event_source; sd_event_source *timeout_warning_event; sd_event_source *timeout_event; @@ -172,6 +175,7 @@ static Event *event_free(Event *event) { LIST_REMOVE(event, event->manager->events, event); sd_device_unref(event->dev); + sd_event_source_unref(event->retry_event_source); sd_event_source_unref(event->timeout_warning_event); sd_event_source_unref(event->timeout_event); @@ -749,6 +753,8 @@ static int event_run(Event *event) { log_device_uevent(event->dev, "Device ready for processing"); + (void) event_source_disable(event->retry_event_source); + manager = event->manager; HASHMAP_FOREACH(worker, manager->workers) { if (worker->state != WORKER_IDLE) @@ -995,6 +1001,11 @@ static int event_queue_start(Manager *manager) { return 0; } +static int on_event_retry(sd_event_source *s, uint64_t usec, void *userdata) { + /* This does nothing. The on_post() callback will start the event if there exists an idle worker. */ + return 1; +} + static int event_requeue(Event *event) { usec_t now_usec; int r; @@ -1025,6 +1036,15 @@ static int event_requeue(Event *event) { if (event->retry_again_timeout_usec == 0) event->retry_again_timeout_usec = usec_add(now_usec, EVENT_RETRY_TIMEOUT_USEC); + r = event_reset_time_relative(event->manager->event, &event->retry_event_source, + CLOCK_MONOTONIC, EVENT_RETRY_INTERVAL_USEC, 0, + on_event_retry, NULL, + 0, "retry-event", true); + if (r < 0) + return log_device_warning_errno(event->dev, r, "Failed to reset timer event source for retrying event, " + "skipping event (SEQNUM=%"PRIu64", ACTION=%s): %m", + event->seqnum, strna(device_action_to_string(event->action))); + if (event->worker && event->worker->event == event) event->worker->event = NULL; event->worker = NULL; -- 2.33.0