From: Yu Watanabe Date: Wed, 2 Apr 2025 17:55:36 +0000 (+0900) Subject: udev: move inotify watch related functions to udev-watch.c X-Git-Tag: v258-rc1~904^2~5 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ef0f8397a57d963b86082aaeb50dca5bdbbc5f98;p=thirdparty%2Fsystemd.git udev: move inotify watch related functions to udev-watch.c --- diff --git a/src/udev/udev-manager.c b/src/udev/udev-manager.c index e319277c2bd..5303c4d2536 100644 --- a/src/udev/udev-manager.c +++ b/src/udev/udev-manager.c @@ -1,6 +1,5 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#include "blockdev-util.h" #include "cgroup-util.h" #include "common-signal.h" #include "daemon-util.h" @@ -12,7 +11,6 @@ #include "fd-util.h" #include "fs-util.h" #include "hashmap.h" -#include "inotify-util.h" #include "iovec-util.h" #include "list.h" #include "mkdir.h" @@ -705,7 +703,7 @@ fail: event_free(event); } -static int event_queue_assume_block_device_unlocked(Manager *manager, sd_device *dev) { +int event_queue_assume_block_device_unlocked(Manager *manager, sd_device *dev) { const char *devname; int r; @@ -858,162 +856,6 @@ static int on_worker_notify(sd_event_source *s, int fd, uint32_t revents, void * return 0; } -static int synthesize_change_one(sd_device *dev, sd_device *target) { - int r; - - assert(dev); - assert(target); - - if (DEBUG_LOGGING) { - const char *syspath = NULL; - (void) sd_device_get_syspath(target, &syspath); - log_device_debug(dev, "device is closed, synthesising 'change' on %s", strna(syspath)); - } - - r = sd_device_trigger(target, SD_DEVICE_CHANGE); - if (r < 0) - return log_device_debug_errno(target, r, "Failed to trigger 'change' uevent: %m"); - - DEVICE_TRACE_POINT(synthetic_change_event, dev); - - return 0; -} - -static int synthesize_change_all(sd_device *dev) { - int r; - - assert(dev); - - r = blockdev_reread_partition_table(dev); - if (r < 0) - log_device_debug_errno(dev, r, "Failed to re-read partition table, ignoring: %m"); - bool part_table_read = r >= 0; - - /* search for partitions */ - _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; - r = partition_enumerator_new(dev, &e); - if (r < 0) - return log_device_debug_errno(dev, r, "Failed to initialize partition enumerator, ignoring: %m"); - - /* We have partitions and re-read the table, the kernel already sent out a "change" - * event for the disk, and "remove/add" for all partitions. */ - if (part_table_read && sd_device_enumerator_get_device_first(e)) - return 0; - - /* We have partitions but re-reading the partition table did not work, synthesize - * "change" for the disk and all partitions. */ - r = synthesize_change_one(dev, dev); - FOREACH_DEVICE(e, d) - RET_GATHER(r, synthesize_change_one(dev, d)); - - return r; -} - -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; - r = sd_device_get_sysname(dev, &sysname); - if (r < 0) - return r; - - if (startswith(sysname, "dm-") || block_device_is_whole_disk(dev) <= 0) - return synthesize_change_one(dev, 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) { - Manager *manager = ASSERT_PTR(userdata); - union inotify_event_buffer buffer; - ssize_t l; - int r; - - l = read(fd, &buffer, sizeof(buffer)); - if (l < 0) { - if (ERRNO_IS_TRANSIENT(errno)) - return 0; - - return log_error_errno(errno, "Failed to read inotify fd: %m"); - } - - FOREACH_INOTIFY_EVENT_WARN(e, buffer, l) { - _cleanup_(sd_device_unrefp) sd_device *dev = NULL; - const char *devnode; - - /* Do not handle IN_IGNORED here. Especially, do not try to call udev_watch_end() from the - * main process. Otherwise, the pair of the symlinks may become inconsistent, and several - * garbage may remain. The old symlinks are removed by a worker that processes the - * corresponding 'remove' uevent; - * udev_event_execute_rules() -> event_execute_rules_on_remove() -> udev_watch_end(). */ - - if (!FLAGS_SET(e->mask, IN_CLOSE_WRITE)) - continue; - - r = device_new_from_watch_handle(&dev, e->wd); - if (r < 0) { - /* Device may be removed just after closed. */ - log_debug_errno(r, "Failed to create sd_device object from watch handle, ignoring: %m"); - continue; - } - - r = sd_device_get_devname(dev, &devnode); - if (r < 0) { - /* Also here, device may be already removed. */ - log_device_debug_errno(dev, r, "Failed to get device node, ignoring: %m"); - continue; - } - - log_device_debug(dev, "Received inotify event for %s.", devnode); - - (void) event_queue_assume_block_device_unlocked(manager, dev); - (void) synthesize_change(manager, dev); - } - - return 0; -} - static int on_sigterm(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { Manager *manager = ASSERT_PTR(userdata); @@ -1252,31 +1094,6 @@ static int manager_start_device_monitor(Manager *manager) { return 0; } -static int manager_start_inotify(Manager *manager) { - _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL; - _cleanup_close_ int fd = -EBADF; - int r; - - assert(manager); - assert(manager->event); - - fd = inotify_init1(IN_CLOEXEC); - if (fd < 0) - return log_error_errno(errno, "Failed to create inotify descriptor: %m"); - - udev_watch_restore(fd); - - r = sd_event_add_io(manager->event, &s, fd, EPOLLIN, on_inotify, manager); - if (r < 0) - return log_error_errno(r, "Failed to create inotify event source: %m"); - - (void) sd_event_source_set_description(s, "manager-inotify"); - - manager->inotify_fd = TAKE_FD(fd); - manager->inotify_event = TAKE_PTR(s); - return 0; -} - static int manager_start_worker_notify(Manager *manager) { int r; diff --git a/src/udev/udev-manager.h b/src/udev/udev-manager.h index dab271abaa8..3ed393c1f00 100644 --- a/src/udev/udev-manager.h +++ b/src/udev/udev-manager.h @@ -66,3 +66,5 @@ void notify_ready(Manager *manager); void manager_kill_workers(Manager *manager, bool force); bool devpath_conflict(const char *a, const char *b); + +int event_queue_assume_block_device_unlocked(Manager *manager, sd_device *dev); diff --git a/src/udev/udev-watch.c b/src/udev/udev-watch.c index 0254cf6ed96..c4b63a4d2f8 100644 --- a/src/udev/udev-watch.c +++ b/src/udev/udev-watch.c @@ -4,23 +4,25 @@ * Copyright © 2009 Scott James Remnant */ -#include - #include "alloc-util.h" -#include "device-private.h" +#include "blockdev-util.h" #include "device-util.h" #include "dirent-util.h" +#include "event-util.h" #include "fd-util.h" #include "fs-util.h" +#include "inotify-util.h" #include "mkdir.h" #include "parse-util.h" #include "rm-rf.h" #include "stdio-util.h" #include "string-util.h" +#include "udev-manager.h" +#include "udev-trace.h" #include "udev-util.h" #include "udev-watch.h" -int device_new_from_watch_handle_at(sd_device **ret, int dirfd, int wd) { +static int device_new_from_watch_handle_at(sd_device **ret, int dirfd, int wd) { char path_wd[STRLEN("/run/udev/watch/") + DECIMAL_STR_MAX(int)]; _cleanup_free_ char *id = NULL; int r; @@ -43,7 +45,163 @@ int device_new_from_watch_handle_at(sd_device **ret, int dirfd, int wd) { return sd_device_new_from_device_id(ret, id); } -int udev_watch_restore(int inotify_fd) { +static int synthesize_change_one(sd_device *dev, sd_device *target) { + int r; + + assert(dev); + assert(target); + + if (DEBUG_LOGGING) { + const char *syspath = NULL; + (void) sd_device_get_syspath(target, &syspath); + log_device_debug(dev, "device is closed, synthesising 'change' on %s", strna(syspath)); + } + + r = sd_device_trigger(target, SD_DEVICE_CHANGE); + if (r < 0) + return log_device_debug_errno(target, r, "Failed to trigger 'change' uevent: %m"); + + DEVICE_TRACE_POINT(synthetic_change_event, dev); + + return 0; +} + +static int synthesize_change_all(sd_device *dev) { + int r; + + assert(dev); + + r = blockdev_reread_partition_table(dev); + if (r < 0) + log_device_debug_errno(dev, r, "Failed to re-read partition table, ignoring: %m"); + bool part_table_read = r >= 0; + + /* search for partitions */ + _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; + r = partition_enumerator_new(dev, &e); + if (r < 0) + return log_device_debug_errno(dev, r, "Failed to initialize partition enumerator, ignoring: %m"); + + /* We have partitions and re-read the table, the kernel already sent out a "change" + * event for the disk, and "remove/add" for all partitions. */ + if (part_table_read && sd_device_enumerator_get_device_first(e)) + return 0; + + /* We have partitions but re-reading the partition table did not work, synthesize + * "change" for the disk and all partitions. */ + r = synthesize_change_one(dev, dev); + FOREACH_DEVICE(e, d) + RET_GATHER(r, synthesize_change_one(dev, d)); + + return r; +} + +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; + r = sd_device_get_sysname(dev, &sysname); + if (r < 0) + return r; + + if (startswith(sysname, "dm-") || block_device_is_whole_disk(dev) <= 0) + return synthesize_change_one(dev, 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) { + Manager *manager = ASSERT_PTR(userdata); + union inotify_event_buffer buffer; + ssize_t l; + int r; + + l = read(fd, &buffer, sizeof(buffer)); + if (l < 0) { + if (ERRNO_IS_TRANSIENT(errno)) + return 0; + + return log_error_errno(errno, "Failed to read inotify fd: %m"); + } + + FOREACH_INOTIFY_EVENT_WARN(e, buffer, l) { + _cleanup_(sd_device_unrefp) sd_device *dev = NULL; + const char *devnode; + + /* Do not handle IN_IGNORED here. Especially, do not try to call udev_watch_end() from the + * main process. Otherwise, the pair of the symlinks may become inconsistent, and several + * garbage may remain. The old symlinks are removed by a worker that processes the + * corresponding 'remove' uevent; + * udev_event_execute_rules() -> event_execute_rules_on_remove() -> udev_watch_end(). */ + + if (!FLAGS_SET(e->mask, IN_CLOSE_WRITE)) + continue; + + r = device_new_from_watch_handle_at(&dev, -EBADF, e->wd); + if (r < 0) { + /* Device may be removed just after closed. */ + log_debug_errno(r, "Failed to create sd_device object from watch handle, ignoring: %m"); + continue; + } + + r = sd_device_get_devname(dev, &devnode); + if (r < 0) { + /* Also here, device may be already removed. */ + log_device_debug_errno(dev, r, "Failed to get device node, ignoring: %m"); + continue; + } + + log_device_debug(dev, "Received inotify event for %s.", devnode); + + (void) event_queue_assume_block_device_unlocked(manager, dev); + (void) synthesize_change(manager, dev); + } + + return 0; +} + +static int udev_watch_restore(int inotify_fd) { _cleanup_(rm_rf_safep) const char *old = "/run/udev/watch.old/"; int r; @@ -88,6 +246,31 @@ int udev_watch_restore(int inotify_fd) { return 0; } +int manager_start_inotify(Manager *manager) { + _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL; + _cleanup_close_ int fd = -EBADF; + int r; + + assert(manager); + assert(manager->event); + + fd = inotify_init1(IN_CLOEXEC); + if (fd < 0) + return log_error_errno(errno, "Failed to create inotify descriptor: %m"); + + udev_watch_restore(fd); + + r = sd_event_add_io(manager->event, &s, fd, EPOLLIN, on_inotify, manager); + if (r < 0) + return log_error_errno(r, "Failed to create inotify event source: %m"); + + (void) sd_event_source_set_description(s, "manager-inotify"); + + manager->inotify_fd = TAKE_FD(fd); + manager->inotify_event = TAKE_PTR(s); + return 0; +} + static int udev_watch_clear(sd_device *dev, int dirfd, int *ret_wd) { _cleanup_free_ char *wd_str = NULL, *buf = NULL; const char *id; diff --git a/src/udev/udev-watch.h b/src/udev/udev-watch.h index c454deead3c..3976a835a1d 100644 --- a/src/udev/udev-watch.h +++ b/src/udev/udev-watch.h @@ -3,11 +3,9 @@ #include "sd-device.h" -int device_new_from_watch_handle_at(sd_device **ret, int dirfd, int wd); -static inline int device_new_from_watch_handle(sd_device **ret, int wd) { - return device_new_from_watch_handle_at(ret, -1, wd); -} +typedef struct Manager Manager; + +int manager_start_inotify(Manager *manager); -int udev_watch_restore(int inotify_fd); int udev_watch_begin(int inotify_fd, sd_device *dev); int udev_watch_end(int inotify_fd, sd_device *dev);