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);
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;
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) {
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;
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);