From e7f781e473f5119bf9246208a6de9f6b76a39c5d Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Sun, 7 Mar 2021 15:35:33 +0900 Subject: udev,sd_device: also save map from device ID to watch handle in /run/udev/watch Previously, watch handle is saved in the udev databse. But in most cases, the handle saved in the database is not updated. Especially, when udevd is restarted, the inotify watch is restarted, but the database is not updated. Moreover, it is not necessary to save watch handle in the database, as the handle is only take a effect during udevd is running, and the value is meaningless when udevd is restarted. So, this makes the opposite map from device ID to watch handle is saved in /run/udev/watch as a symbolic link, and the handle not saved in the database anymore. Fixes #18525. --- src/udev/udev-event.c | 19 +++------ src/udev/udev-watch.c | 105 +++++++++++++++++--------------------------------- src/udev/udev-watch.h | 1 - src/udev/udevd.c | 12 ++++-- 4 files changed, 49 insertions(+), 88 deletions(-) (limited to 'src/udev') diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c index c613916d18..f40b3120ca 100644 --- a/src/udev/udev-event.c +++ b/src/udev/udev-event.c @@ -997,6 +997,9 @@ int udev_event_execute_rules( if (action == SD_DEVICE_REMOVE) return event_execute_rules_on_remove(event, inotify_fd, timeout_usec, timeout_signal, properties_list, rules); + /* Disable watch during event processing. */ + (void) udev_watch_end(inotify_fd, event->dev); + r = device_clone_with_db(dev, &event->dev_db_clone); if (r < 0) return log_device_debug_errno(dev, r, "Failed to clone sd_device object: %m"); @@ -1005,9 +1008,6 @@ int udev_event_execute_rules( if (r < 0) log_device_warning_errno(dev, r, "Failed to copy all tags from old database entry, ignoring: %m"); - /* Disable watch during event processing. */ - (void) udev_watch_end(inotify_fd, event->dev_db_clone); - if (action == SD_DEVICE_MOVE) { r = udev_event_on_move(event->dev); if (r < 0) @@ -1083,7 +1083,6 @@ void udev_event_execute_run(UdevEvent *event, usec_t timeout_usec, int timeout_s int udev_event_process_inotify_watch(UdevEvent *event, int inotify_fd) { sd_device *dev; - int r; assert(event); assert(inotify_fd >= 0); @@ -1095,16 +1094,10 @@ int udev_event_process_inotify_watch(UdevEvent *event, int inotify_fd) { if (device_for_action(dev, SD_DEVICE_REMOVE)) return 0; - if (!event->inotify_watch) { + if (event->inotify_watch) + (void) udev_watch_begin(inotify_fd, dev); + else (void) udev_watch_end(inotify_fd, dev); - return 0; - } - - (void) udev_watch_begin(inotify_fd, dev); - - r = device_update_db(dev); - if (r < 0) - return log_device_debug_errno(dev, r, "Failed to update database under /run/udev/data/: %m"); return 0; } diff --git a/src/udev/udev-watch.c b/src/udev/udev-watch.c index f5085107be..7f15c87870 100644 --- a/src/udev/udev-watch.c +++ b/src/udev/udev-watch.c @@ -5,52 +5,55 @@ */ #include -#include #include "alloc-util.h" #include "device-private.h" #include "device-util.h" #include "dirent-util.h" #include "fs-util.h" -#include "mkdir.h" -#include "stdio-util.h" +#include "parse-util.h" #include "udev-watch.h" -/* Move any old watches directory out of the way, and then restore the watches. */ int udev_watch_restore(int inotify_fd) { struct dirent *ent; DIR *dir; int r; + /* Move any old watches directory out of the way, and then restore the watches. */ + assert(inotify_fd >= 0); if (rename("/run/udev/watch", "/run/udev/watch.old") < 0) { if (errno != ENOENT) - return log_warning_errno(errno, "Failed to move watches directory /run/udev/watch. Old watches will not be restored: %m"); + return log_warning_errno(errno, "Failed to move watches directory /run/udev/watch. " + "Old watches will not be restored: %m"); return 0; } dir = opendir("/run/udev/watch.old"); if (!dir) - return log_warning_errno(errno, "Failed to open old watches directory /run/udev/watch.old. Old watches will not be restored: %m"); + return log_warning_errno(errno, "Failed to open old watches directory /run/udev/watch.old. " + "Old watches will not be restored: %m"); FOREACH_DIRENT_ALL(ent, dir, break) { _cleanup_(sd_device_unrefp) sd_device *dev = NULL; - _cleanup_free_ char *id = NULL; + int wd; if (ent->d_name[0] == '.') continue; - r = readlinkat_malloc(dirfd(dir), ent->d_name, &id); - if (r < 0) { - log_debug_errno(r, "Failed to read link '/run/udev/watch.old/%s', ignoring: %m", ent->d_name); + /* For backward compatibility, read symlink from watch handle to device id, and ignore + * the opposite direction symlink. */ + + if (safe_atoi(ent->d_name, &wd) < 0) goto unlink; - } - r = sd_device_new_from_device_id(&dev, id); + r = device_new_from_watch_handle_at(&dev, dirfd(dir), wd); if (r < 0) { - log_debug_errno(r, "Failed to create sd_device object for '%s', ignoring: %m", id); + log_full_errno(r == -ENODEV ? LOG_DEBUG : LOG_WARNING, r, + "Failed to create sd_device object from saved watch handle '%s', ignoring: %m", + ent->d_name); goto unlink; } @@ -67,8 +70,7 @@ unlink: } int udev_watch_begin(int inotify_fd, sd_device *dev) { - char filename[STRLEN("/run/udev/watch/") + DECIMAL_STR_MAX(int)]; - const char *devnode, *id; + const char *devnode; int wd, r; assert(inotify_fd >= 0); @@ -76,35 +78,27 @@ int udev_watch_begin(int inotify_fd, sd_device *dev) { r = sd_device_get_devname(dev, &devnode); if (r < 0) - return log_device_error_errno(dev, r, "Failed to get device name: %m"); + return log_device_debug_errno(dev, r, "Failed to get device name: %m"); log_device_debug(dev, "Adding watch on '%s'", devnode); wd = inotify_add_watch(inotify_fd, devnode, IN_CLOSE_WRITE); - if (wd < 0) - return log_device_full_errno(dev, errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno, - "Failed to add device '%s' to watch: %m", devnode); - - device_set_watch_handle(dev, wd); + if (wd < 0) { + r = log_device_full_errno(dev, errno == ENOENT ? LOG_DEBUG : LOG_WARNING, + errno, "Failed to add device '%s' to watch: %m", devnode); - xsprintf(filename, "/run/udev/watch/%d", wd); - r = mkdir_parents(filename, 0755); - if (r < 0) - return log_device_error_errno(dev, r, "Failed to create parent directory of '%s': %m", filename); - (void) unlink(filename); + (void) device_set_watch_handle(dev, -1); + return r; + } - r = device_get_device_id(dev, &id); + r = device_set_watch_handle(dev, wd); if (r < 0) - return log_device_error_errno(dev, r, "Failed to get device id-filename: %m"); - - if (symlink(id, filename) < 0) - return log_device_error_errno(dev, errno, "Failed to create symlink %s: %m", filename); + return log_device_warning_errno(dev, r, "Failed to save watch handle in /run/udev/watch: %m"); return 0; } int udev_watch_end(int inotify_fd, sd_device *dev) { - char filename[STRLEN("/run/udev/watch/") + DECIMAL_STR_MAX(int)]; - int wd, r; + int wd; assert(dev); @@ -115,43 +109,14 @@ int udev_watch_end(int inotify_fd, sd_device *dev) { if (sd_device_get_devname(dev, NULL) < 0) return 0; - r = device_get_watch_handle(dev, &wd); - if (r == -ENOENT) - return 0; - if (r < 0) - return log_device_debug_errno(dev, r, "Failed to get watch handle, ignoring: %m"); - - log_device_debug(dev, "Removing watch"); - (void) inotify_rm_watch(inotify_fd, wd); - - xsprintf(filename, "/run/udev/watch/%d", wd); - (void) unlink(filename); - - device_set_watch_handle(dev, -1); + wd = device_get_watch_handle(dev); + if (wd < 0) + log_device_debug_errno(dev, wd, "Failed to get watch handle, ignoring: %m"); + else { + log_device_debug(dev, "Removing watch"); + (void) inotify_rm_watch(inotify_fd, wd); + } + (void) device_set_watch_handle(dev, -1); return 0; } - -int udev_watch_lookup(int wd, sd_device **ret) { - char filename[STRLEN("/run/udev/watch/") + DECIMAL_STR_MAX(int)]; - _cleanup_free_ char *id = NULL; - int r; - - assert(wd >= 0); - assert(ret); - - xsprintf(filename, "/run/udev/watch/%d", wd); - r = readlink_malloc(filename, &id); - if (r == -ENOENT) - return 0; - if (r < 0) - return log_debug_errno(r, "Failed to read link '%s': %m", filename); - - r = sd_device_new_from_device_id(ret, id); - if (r == -ENODEV) - return 0; - if (r < 0) - return log_debug_errno(r, "Failed to create sd_device object for '%s': %m", id); - - return 1; -} diff --git a/src/udev/udev-watch.h b/src/udev/udev-watch.h index f5c55794c4..d211d99f49 100644 --- a/src/udev/udev-watch.h +++ b/src/udev/udev-watch.h @@ -6,4 +6,3 @@ 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); -int udev_watch_lookup(int wd, sd_device **ret); diff --git a/src/udev/udevd.c b/src/udev/udevd.c index 9689e15b1c..5574abce9d 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -1302,17 +1302,21 @@ static int on_inotify(sd_event_source *s, int fd, uint32_t revents, void *userda _cleanup_(sd_device_unrefp) sd_device *dev = NULL; const char *devnode; - if (udev_watch_lookup(e->wd, &dev) <= 0) + r = device_new_from_watch_handle(&dev, e->wd); + if (r < 0) { + log_debug_errno(r, "Failed to create sd_device object from watch handle, ignoring: %m"); continue; + } if (sd_device_get_devname(dev, &devnode) < 0) continue; log_device_debug(dev, "Inotify event: %x for %s", e->mask, devnode); if (e->mask & IN_CLOSE_WRITE) - synthesize_change(dev); - else if (e->mask & IN_IGNORED) - udev_watch_end(manager->inotify_fd, dev); + (void) synthesize_change(dev); + + /* Do not handle IN_IGNORED here. It should be handled by worker in 'remove' uevent; + * udev_event_execute_rules() -> event_execute_rules_on_remove() -> udev_watch_end(). */ } return 1; -- cgit v1.2.1