]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
udev: scan partitions and trigger synthetic change events in child process 36685/head
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 10 Mar 2025 13:44:02 +0000 (22:44 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 10 Mar 2025 20:55:51 +0000 (05:55 +0900)
Rereading partition table may take longer on slow disk. The main process
should not be blocked by the operation. Let's fork a child process and
do that on the child.

Prompted by #36624 and #36269.

src/udev/udev-manager.c
src/udev/udev-manager.h

index a696f6a69e42b41be3280387eb5f4fd7daa5c8e7..adfe8540b21c7f5c55f21bd6eaf67f5526680a57 100644 (file)
@@ -153,6 +153,7 @@ Manager* manager_free(Manager *manager) {
         sd_varlink_server_unref(manager->varlink_server);
 
         sd_event_source_unref(manager->inotify_event);
+        set_free(manager->synthesize_change_child_event_sources);
         sd_event_source_unref(manager->kill_workers_event);
         sd_event_unref(manager->event);
 
@@ -895,9 +896,18 @@ static int synthesize_change_all(sd_device *dev) {
         return r;
 }
 
-static int synthesize_change(sd_device *dev) {
+static int synthesize_change_child_handler(sd_event_source *s, const siginfo_t *si, void *userdata) {
+        Manager *manager = ASSERT_PTR(userdata);
+        assert(s);
+
+        sd_event_source_unref(set_remove(manager->synthesize_change_child_event_sources, s));
+        return 0;
+}
+
+static int synthesize_change(Manager *manager, sd_device *dev) {
         int r;
 
+        assert(manager);
         assert(dev);
 
         const char *sysname;
@@ -908,7 +918,37 @@ static int synthesize_change(sd_device *dev) {
         if (startswith(sysname, "dm-") || block_device_is_whole_disk(dev) <= 0)
                 return synthesize_change_one(dev, dev);
 
-        return synthesize_change_all(dev);
+        _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
+        r = pidref_safe_fork(
+                        "(udev-synth)",
+                        FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_LOG|FORK_RLIMIT_NOFILE_SAFE,
+                        &pidref);
+        if (r < 0)
+                return r;
+        if (r == 0) {
+                /* child */
+                (void) synthesize_change_all(dev);
+                _exit(EXIT_SUCCESS);
+        }
+
+        _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
+        r = event_add_child_pidref(manager->event, &s, &pidref, WEXITED, synthesize_change_child_handler, manager);
+        if (r < 0) {
+                log_debug_errno(r, "Failed to add child event source for "PID_FMT", ignoring: %m", pidref.pid);
+                return 0;
+        }
+
+        r = sd_event_source_set_child_pidfd_own(s, true);
+        if (r < 0)
+                return r;
+        TAKE_PIDREF(pidref);
+
+        r = set_ensure_put(&manager->synthesize_change_child_event_sources, &event_source_hash_ops, s);
+        if (r < 0)
+                return r;
+        TAKE_PTR(s);
+
+        return 0;
 }
 
 static int on_inotify(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
@@ -955,7 +995,7 @@ static int on_inotify(sd_event_source *s, int fd, uint32_t revents, void *userda
                 log_device_debug(dev, "Received inotify event for %s.", devnode);
 
                 (void) event_queue_assume_block_device_unlocked(manager, dev);
-                (void) synthesize_change(dev);
+                (void) synthesize_change(manager, dev);
         }
 
         return 0;
@@ -1055,7 +1095,7 @@ static int on_post(sd_event_source *s, void *userdata) {
         if (manager->exit)
                 return sd_event_exit(manager->event, 0);
 
-        if (manager->cgroup)
+        if (manager->cgroup && set_isempty(manager->synthesize_change_child_event_sources))
                 /* cleanup possible left-over processes in our cgroup */
                 (void) cg_kill(manager->cgroup, SIGKILL, CGROUP_IGNORE_SELF, /* set=*/ NULL, /* kill_log= */ NULL, /* userdata= */ NULL);
 
index 808f75d3e155280cb7c71db06801d71927dae80d..168156053315e5892490fd221e2528b6eceacc28 100644 (file)
@@ -35,6 +35,7 @@ typedef struct Manager {
         /* used by udev-watch */
         int inotify_fd;
         sd_event_source *inotify_event;
+        Set *synthesize_change_child_event_sources;
 
         sd_event_source *kill_workers_event;