From: Yu Watanabe Date: Mon, 7 Apr 2025 19:33:14 +0000 (+0900) Subject: udev-config: serialize/deserialize dynamical configurations X-Git-Tag: v258-rc1~842^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=49120a7a8fdf772483f907c0bc4111b141185ac2;p=thirdparty%2Fsystemd.git udev-config: serialize/deserialize dynamical configurations Previously, configurations set by 'udevadm control' such as log level, maximum number of childrens, global properties, and so on were discarded on restart. This makes udevd serialize those configurations on stop, and deserialize them in the next invocation. --- diff --git a/src/udev/udev-config.c b/src/udev/udev-config.c index d88c18ba15d..52855145da7 100644 --- a/src/udev/udev-config.c +++ b/src/udev/udev-config.c @@ -5,10 +5,14 @@ #include "conf-parser.h" #include "cpu-set-util.h" +#include "daemon-util.h" +#include "fd-util.h" +#include "fileio.h" #include "limits-util.h" #include "parse-util.h" #include "pretty-print.h" #include "proc-cmdline.h" +#include "serialize.h" #include "signal-util.h" #include "syslog-util.h" #include "udev-config.h" @@ -512,6 +516,115 @@ UdevReloadFlags manager_revert_config(Manager *manager) { return flags | manager_needs_reload(manager, &old); } +int manager_serialize_config(Manager *manager) { + int r; + + assert(manager); + + _cleanup_fclose_ FILE *f = NULL; + r = open_serialization_file("systemd-udevd", &f); + if (r < 0) + return log_warning_errno(r, "Failed to open new serialization file: %m"); + + if (manager->config_by_control.log_level >= 0) { + r = serialize_item_format(f, "log-level", "%i", manager->config_by_control.log_level); + if (r < 0) + return r; + } + + if (manager->config_by_control.children_max > 0) { + r = serialize_item_format(f, "children-max", "%u", manager->config_by_control.children_max); + if (r < 0) + return r; + } + + r = serialize_bool_elide(f, "trace", manager->config_by_control.trace); + if (r < 0) + return r; + + const char *k, *v; + HASHMAP_FOREACH_KEY(v, k, manager->properties) { + r = serialize_item_format(f, "property", "%s=%s", k, v); + if (r < 0) + return r; + } + + r = finish_serialization_file(f); + if (r < 0) + return log_warning_errno(r, "Failed to finalize serialization file: %m"); + + /* Remove the previous serialization to make it replaced with the new one. */ + (void) notify_remove_fd_warn("config-serialization"); + + r = notify_push_fd(fileno(f), "config-serialization"); + if (r < 0) + return log_warning_errno(r, "Failed to push serialization fd to service manager: %m"); + + log_debug("Serialized configurations."); + return 0; +} + +int manager_deserialize_config(Manager *manager, int *fd) { + int r; + + assert(manager); + assert(fd); + assert(*fd >= 0); + + /* This may invalidate passed file descriptor even on failure. */ + + _cleanup_fclose_ FILE *f = take_fdopen(fd, "r"); + if (!f) + return log_warning_errno(errno, "Failed to open serialization fd: %m"); + + for (;;) { + _cleanup_free_ char *l = NULL; + const char *val; + + r = deserialize_read_line(f, &l); + if (r < 0) + return r; + if (r == 0) /* eof or end marker */ + break; + + if ((val = startswith(l, "log-level="))) { + r = log_level_from_string(val); + if (r < 0) + log_debug_errno(r, "Failed to parse serialized log level (%s), ignoring: %m", val); + else + manager->config_by_control.log_level = r; + + } else if ((val = startswith(l, "children-max="))) { + r = safe_atou(val, &manager->config_by_control.children_max); + if (r < 0) + log_debug_errno(r, "Failed to parse serialized children max (%s), ignoring: %m", val); + + } else if ((val = startswith(l, "trace="))) { + r = parse_boolean(val); + if (r < 0) + log_debug_errno(r, "Failed to parse serialized trace (%s), ignoring: %m", val); + else + manager->config_by_control.trace = r; + + } else if ((val = startswith(l, "property="))) { + if (!udev_property_assignment_is_valid(val)) + r = -EINVAL; + else + r = manager_set_environment_one(manager, val); + if (r < 0) + log_debug_errno(r, "Failed to deserialize property (%s), ignoring: %m", val); + + } else + log_debug("Unknown serialization item, ignoring: %s", l); + } + + manager_merge_config(manager); + manager_adjust_config(&manager->config); + + log_debug("Deserialized configurations."); + return 0; +} + static usec_t extra_timeout_usec(void) { static usec_t saved = 10 * USEC_PER_SEC; static bool parsed = false; diff --git a/src/udev/udev-config.h b/src/udev/udev-config.h index 72ac3920ab4..127b3b9a1be 100644 --- a/src/udev/udev-config.h +++ b/src/udev/udev-config.h @@ -36,4 +36,7 @@ int manager_load(Manager *manager, int argc, char *argv[]); UdevReloadFlags manager_reload_config(Manager *manager); UdevReloadFlags manager_revert_config(Manager *manager); +int manager_serialize_config(Manager *manager); +int manager_deserialize_config(Manager *manager, int *fd); + usec_t manager_kill_worker_timeout(Manager *manager); diff --git a/src/udev/udev-manager.c b/src/udev/udev-manager.c index 919314b5468..d35100198bf 100644 --- a/src/udev/udev-manager.c +++ b/src/udev/udev-manager.c @@ -237,6 +237,7 @@ void manager_exit(Manager *manager) { /* close sources of new events and discard buffered events */ manager->ctrl = udev_ctrl_unref(manager->ctrl); manager->varlink_server = sd_varlink_server_unref(manager->varlink_server); + (void) manager_serialize_config(manager); /* Disable the event source, but does not close the inotify fd here, as we may still receive * notification messages about requests to add or remove inotify watches. */ @@ -1178,6 +1179,8 @@ static int manager_listen_fds(Manager *manager) { r = manager_init_device_monitor(manager, fd); else if (streq(names[i], "inotify")) r = manager_init_inotify(manager, fd); + else if (streq(names[i], "config-serialization")) + r = manager_deserialize_config(manager, &fd); else r = log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Received unexpected fd (%s), ignoring.", names[i]);