From: Yu Watanabe Date: Wed, 13 Jul 2022 02:52:37 +0000 (+0900) Subject: udev: reload rules and builtins only when mtime of a config changed X-Git-Tag: v252-rc1~589^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=e9d1fae3bbf4e4ee6a5416f8ed0e498f034f4d98;p=thirdparty%2Fsystemd.git udev: reload rules and builtins only when mtime of a config changed This makes udevd reload rules only when the timestamp is updated, even on SIGHUP or `udevadm control --reload`. So, we can call `udevadm control --reload` without huge performance penalty when no rules, .link files, and so on are changed. --- diff --git a/src/udev/udev-rules.h b/src/udev/udev-rules.h index 704f690b676..860fe7c8e4e 100644 --- a/src/udev/udev-rules.h +++ b/src/udev/udev-rules.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ #pragma once +#include "alloc-util.h" #include "hashmap.h" #include "time-util.h" #include "udev-util.h" @@ -21,6 +22,7 @@ UdevRules* udev_rules_new(ResolveNameTiming resolve_name_timing); int udev_rules_load(UdevRules **ret_rules, ResolveNameTiming resolve_name_timing); UdevRules *udev_rules_free(UdevRules *rules); DEFINE_TRIVIAL_CLEANUP_FUNC(UdevRules*, udev_rules_free); +#define udev_rules_free_and_replace(a, b) free_and_replace_full(a, b, udev_rules_free) bool udev_rules_should_reload(UdevRules *rules); int udev_rules_apply_to_event(UdevRules *rules, UdevEvent *event, diff --git a/src/udev/udevd.c b/src/udev/udevd.c index a457ebcc9a3..0a68b7e6ac1 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -351,16 +351,40 @@ static void notify_ready(void) { } /* reload requested, HUP signal received, rules changed, builtin changed */ -static void manager_reload(Manager *manager) { +static void manager_reload(Manager *manager, bool force) { + _cleanup_(udev_rules_freep) UdevRules *rules = NULL; + usec_t now_usec; + int r; + assert(manager); + assert_se(sd_event_now(manager->event, CLOCK_MONOTONIC, &now_usec) >= 0); + if (!force && now_usec < usec_add(manager->last_usec, 3 * USEC_PER_SEC)) + /* check for changed config, every 3 seconds at most */ + return; + manager->last_usec = now_usec; + + /* Reload SELinux label database, to make the child inherit the up-to-date database. */ + mac_selinux_maybe_reload(); + + /* Nothing changed. It is not necessary to reload. */ + if (!udev_rules_should_reload(manager->rules) && !udev_builtin_validate()) + return; + sd_notify(false, "RELOADING=1\n" "STATUS=Flushing configuration..."); manager_kill_workers(manager, false); - manager->rules = udev_rules_free(manager->rules); + udev_builtin_exit(); + udev_builtin_init(); + + r = udev_rules_load(&rules, arg_resolve_name_timing); + if (r < 0) + log_warning_errno(r, "Failed to read udev rules, using the previously loaded rules, ignoring: %m"); + else + udev_rules_free_and_replace(manager->rules, rules); notify_ready(); } @@ -937,7 +961,6 @@ no_blocker: } static int event_queue_start(Manager *manager) { - usec_t usec; int r; assert(manager); @@ -945,32 +968,11 @@ static int event_queue_start(Manager *manager) { if (!manager->events || manager->exit || manager->stop_exec_queue) return 0; - assert_se(sd_event_now(manager->event, CLOCK_MONOTONIC, &usec) >= 0); - /* check for changed config, every 3 seconds at most */ - if (manager->last_usec == 0 || - usec > usec_add(manager->last_usec, 3 * USEC_PER_SEC)) { - if (udev_rules_should_reload(manager->rules) || - udev_builtin_validate()) - manager_reload(manager); - - manager->last_usec = usec; - } - r = event_source_disable(manager->kill_workers_event); if (r < 0) log_warning_errno(r, "Failed to disable event source for cleaning up idle workers, ignoring: %m"); - udev_builtin_init(); - - if (!manager->rules) { - r = udev_rules_load(&manager->rules, arg_resolve_name_timing); - if (r < 0) - return log_warning_errno(r, "Failed to read udev rules: %m"); - } - - /* fork with up-to-date SELinux label database, so the child inherits the up-to-date db - * and, until the next SELinux policy changes, we safe further reloads in future children */ - mac_selinux_maybe_reload(); + manager_reload(manager, /* force = */ false); LIST_FOREACH(event, event, manager->events) { if (event->state != EVENT_QUEUED) @@ -1252,7 +1254,7 @@ static int on_ctrl_msg(UdevCtrl *uctrl, UdevCtrlMessageType type, const UdevCtrl break; case UDEV_CTRL_RELOAD: log_debug("Received udev control message (RELOAD)"); - manager_reload(manager); + manager_reload(manager, /* force = */ true); break; case UDEV_CTRL_SET_ENV: { _unused_ _cleanup_free_ char *old_val = NULL; @@ -1501,7 +1503,7 @@ static int on_sighup(sd_event_source *s, const struct signalfd_siginfo *si, void assert(manager); - manager_reload(manager); + manager_reload(manager, /* force = */ true); return 1; } @@ -2011,6 +2013,8 @@ static int main_loop(Manager *manager) { if (r < 0) return log_error_errno(r, "Failed to create post event source: %m"); + manager->last_usec = now(CLOCK_MONOTONIC); + udev_builtin_init(); r = udev_rules_load(&manager->rules, arg_resolve_name_timing);