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.
This commit is contained in:
Yu Watanabe
2025-04-12 05:08:20 +09:00
parent 8b078c5b86
commit 49120a7a8f
3 changed files with 119 additions and 0 deletions
+113
View File
@@ -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;
+3
View File
@@ -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);
+3
View File
@@ -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]);