mirror of
https://github.com/morgan9e/systemd
synced 2026-04-14 16:37:19 +09:00
udev: scan partitions and trigger synthetic change events in child process
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.
This commit is contained in:
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user