pid1: update manager settings on reload too

Most complexity of this patch is due to the fact that some manager settings
(basically the watchdog properties) can be set at runtime and in this case the
runtime values must be retained over daemon-reload or daemon-reexec.

For consistency sake, all watchdog properties behaves now the same way, that
is:

  - Values defined by config files can be overridden by writing the new value
    through their respective D-BUS properties. In this case, these values are
    preserved over reload/reexec until the special value '0' or USEC_INFINITY
    is written, which will then restore the last values loaded from the config
    files. If the restored value is '0' or 'USEC_INFINITY', the watchdogs will
    be disabled and the corresponding device will be closed.

  - Reading the properties from a user instance will return the USEC_INFINITY
    value as these properties are only meaningful for PID1.

  - Writing to one of the watchdog properties of a user instance's will be a
    NOP.

Fixes: #15453
This commit is contained in:
Franck Bui 2020-04-22 16:16:47 +02:00
parent 34d16bad2d
commit 986935cf6a
4 changed files with 226 additions and 33 deletions

View File

@ -244,6 +244,76 @@ static int property_get_show_status(
return sd_bus_message_append_basic(reply, 'b', &b);
}
static int property_get_runtime_watchdog(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
Manager *m = userdata;
assert(m);
assert(bus);
assert(reply);
return sd_bus_message_append(reply, "t", manager_get_watchdog(m, WATCHDOG_RUNTIME));
}
static int property_get_reboot_watchdog(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
Manager *m = userdata;
assert(m);
assert(bus);
assert(reply);
return sd_bus_message_append(reply, "t", manager_get_watchdog(m, WATCHDOG_REBOOT));
}
static int property_get_kexec_watchdog(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
Manager *m = userdata;
assert(m);
assert(bus);
assert(reply);
return sd_bus_message_append(reply, "t", manager_get_watchdog(m, WATCHDOG_KEXEC));
}
static int property_set_watchdog(Manager *m, WatchdogType type, sd_bus_message *value) {
usec_t timeout;
int r;
assert(m);
assert(value);
assert_cc(sizeof(usec_t) == sizeof(uint64_t));
r = sd_bus_message_read(value, "t", &timeout);
if (r < 0)
return r;
return manager_set_watchdog_overridden(m, type, timeout);
}
static int property_set_runtime_watchdog(
sd_bus *bus,
const char *path,
@ -253,19 +323,37 @@ static int property_set_runtime_watchdog(
void *userdata,
sd_bus_error *error) {
usec_t *t = userdata;
int r;
return property_set_watchdog(userdata, WATCHDOG_RUNTIME, value);
}
static int property_set_reboot_watchdog(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *value,
void *userdata,
sd_bus_error *error) {
return property_set_watchdog(userdata, WATCHDOG_REBOOT, value);
}
static int property_set_kexec_watchdog(
sd_bus *bus,
const char *path,
const char *interface,
const char *property,
sd_bus_message *value,
void *userdata,
sd_bus_error *error) {
Manager *m = userdata;
assert(m);
assert(bus);
assert(value);
assert_cc(sizeof(usec_t) == sizeof(uint64_t));
r = sd_bus_message_read(value, "t", t);
if (r < 0)
return r;
return watchdog_set_timeout(t);
return property_set_watchdog(userdata, WATCHDOG_KEXEC, value);
}
static int bus_get_unit_by_name(Manager *m, sd_bus_message *message, const char *name, Unit **ret_unit, sd_bus_error *error) {
@ -2404,11 +2492,11 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_PROPERTY("UnitPath", "as", NULL, offsetof(Manager, lookup_paths.search_path), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultStandardOutput", "s", bus_property_get_exec_output, offsetof(Manager, default_std_output), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultStandardError", "s", bus_property_get_exec_output, offsetof(Manager, default_std_output), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_WRITABLE_PROPERTY("RuntimeWatchdogUSec", "t", bus_property_get_usec, property_set_runtime_watchdog, offsetof(Manager, runtime_watchdog), 0),
SD_BUS_WRITABLE_PROPERTY("RebootWatchdogUSec", "t", bus_property_get_usec, bus_property_set_usec, offsetof(Manager, reboot_watchdog), 0),
SD_BUS_WRITABLE_PROPERTY("RuntimeWatchdogUSec", "t", property_get_runtime_watchdog, property_set_runtime_watchdog, 0, 0),
SD_BUS_WRITABLE_PROPERTY("RebootWatchdogUSec", "t", property_get_reboot_watchdog, property_set_reboot_watchdog, 0, 0),
/* The following item is an obsolete alias */
SD_BUS_WRITABLE_PROPERTY("ShutdownWatchdogUSec", "t", bus_property_get_usec, bus_property_set_usec, offsetof(Manager, reboot_watchdog), SD_BUS_VTABLE_HIDDEN),
SD_BUS_WRITABLE_PROPERTY("KExecWatchdogUSec", "t", bus_property_get_usec, bus_property_set_usec, offsetof(Manager, kexec_watchdog), 0),
SD_BUS_WRITABLE_PROPERTY("ShutdownWatchdogUSec", "t", property_get_reboot_watchdog, property_set_reboot_watchdog, 0, SD_BUS_VTABLE_HIDDEN),
SD_BUS_WRITABLE_PROPERTY("KExecWatchdogUSec", "t", property_get_kexec_watchdog, property_set_kexec_watchdog, 0, 0),
SD_BUS_WRITABLE_PROPERTY("ServiceWatchdogs", "b", bus_property_get_bool, bus_property_set_bool, offsetof(Manager, service_watchdogs), 0),
SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Manager, cgroup_root), 0),
SD_BUS_PROPERTY("SystemState", "s", property_get_system_state, 0, 0),

View File

@ -703,16 +703,18 @@ static void set_manager_settings(Manager *m) {
assert(m);
/* Propagates the various manager settings into the manager object, i.e. properties that effect the manager
* itself (as opposed to just being inherited into newly allocated units, see set_manager_defaults() above). */
/* Propagates the various manager settings into the manager object, i.e. properties that
* effect the manager itself (as opposed to just being inherited into newly allocated
* units, see set_manager_defaults() above). */
m->confirm_spawn = arg_confirm_spawn;
m->service_watchdogs = arg_service_watchdogs;
m->runtime_watchdog = arg_runtime_watchdog;
m->reboot_watchdog = arg_reboot_watchdog;
m->kexec_watchdog = arg_kexec_watchdog;
m->cad_burst_action = arg_cad_burst_action;
manager_set_watchdog(m, WATCHDOG_RUNTIME, arg_runtime_watchdog);
manager_set_watchdog(m, WATCHDOG_REBOOT, arg_reboot_watchdog);
manager_set_watchdog(m, WATCHDOG_KEXEC, arg_kexec_watchdog);
manager_set_show_status(m, arg_show_status, "commandline");
m->status_unit_format = arg_status_unit_format;
}
@ -1784,6 +1786,7 @@ static int invoke_main_loop(
(void) parse_configuration(saved_rlimit_nofile, saved_rlimit_memlock);
set_manager_defaults(m);
set_manager_settings(m);
update_cpu_affinity(false);
update_numa_policy(false);
@ -1974,9 +1977,6 @@ static int initialize_runtime(
if (r < 0)
log_warning_errno(r, "Failed to set watchdog device to %s, ignoring: %m", arg_watchdog_device);
}
if (timestamp_is_set(arg_runtime_watchdog))
watchdog_set_timeout(&arg_runtime_watchdog);
}
if (arg_timer_slack_nsec != NSEC_INFINITY)
@ -2250,6 +2250,10 @@ static int parse_configuration(const struct rlimit *saved_rlimit_nofile,
/* Note that this also parses bits from the kernel command line, including "debug". */
log_parse_environment();
/* Initialize the show status setting if it hasn't been set explicitly yet */
if (arg_show_status == _SHOW_STATUS_INVALID)
arg_show_status = SHOW_STATUS_YES;
return 0;
}
@ -2273,10 +2277,6 @@ static int load_configuration(
return r;
}
/* Initialize the show status setting if it hasn't been set explicitly yet */
if (arg_show_status == _SHOW_STATUS_INVALID)
arg_show_status = SHOW_STATUS_YES;
return 0;
}
@ -2753,8 +2753,8 @@ finish:
pager_close();
if (m) {
arg_reboot_watchdog = m->reboot_watchdog;
arg_kexec_watchdog = m->kexec_watchdog;
arg_reboot_watchdog = manager_get_watchdog(m, WATCHDOG_REBOOT);
arg_kexec_watchdog = manager_get_watchdog(m, WATCHDOG_KEXEC);
m = manager_free(m);
}

View File

@ -779,6 +779,10 @@ int manager_new(UnitFileScope scope, ManagerTestRunFlags test_run_flags, Manager
.original_log_level = -1,
.original_log_target = _LOG_TARGET_INVALID,
.watchdog_overridden[WATCHDOG_RUNTIME] = USEC_INFINITY,
.watchdog_overridden[WATCHDOG_REBOOT] = USEC_INFINITY,
.watchdog_overridden[WATCHDOG_KEXEC] = USEC_INFINITY,
.notify_fd = -1,
.cgroups_agent_fd = -1,
.signal_fd = -1,
@ -2922,9 +2926,10 @@ int manager_loop(Manager *m) {
return log_error_errno(r, "Failed to enable SIGCHLD event source: %m");
while (m->objective == MANAGER_OK) {
usec_t wait_usec;
usec_t wait_usec, watchdog_usec;
if (timestamp_is_set(m->runtime_watchdog) && MANAGER_IS_SYSTEM(m))
watchdog_usec = manager_get_watchdog(m, WATCHDOG_RUNTIME);
if (timestamp_is_set(watchdog_usec))
watchdog_ping();
if (!ratelimit_below(&rl)) {
@ -2955,7 +2960,7 @@ int manager_loop(Manager *m) {
continue;
/* Sleep for watchdog runtime wait time */
if (MANAGER_IS_SYSTEM(m))
if (timestamp_is_set(watchdog_usec))
wait_usec = watchdog_runtime_wait();
else
wait_usec = USEC_INFINITY;
@ -3196,6 +3201,10 @@ int manager_serialize(
if (m->log_target_overridden)
(void) serialize_item(f, "log-target-override", log_target_to_string(log_get_target()));
(void) serialize_usec(f, "runtime-watchdog-overridden", m->watchdog_overridden[WATCHDOG_RUNTIME]);
(void) serialize_usec(f, "reboot-watchdog-overridden", m->watchdog_overridden[WATCHDOG_REBOOT]);
(void) serialize_usec(f, "kexec-watchdog-overridden", m->watchdog_overridden[WATCHDOG_KEXEC]);
for (q = 0; q < _MANAGER_TIMESTAMP_MAX; q++) {
_cleanup_free_ char *joined = NULL;
@ -3328,6 +3337,68 @@ static int manager_deserialize_units(Manager *m, FILE *f, FDSet *fds) {
return 0;
}
usec_t manager_get_watchdog(Manager *m, WatchdogType t) {
assert(m);
if (MANAGER_IS_USER(m))
return USEC_INFINITY;
if (timestamp_is_set(m->watchdog_overridden[t]))
return m->watchdog_overridden[t];
return m->watchdog[t];
}
void manager_set_watchdog(Manager *m, WatchdogType t, usec_t timeout) {
int r = 0;
assert(m);
if (MANAGER_IS_USER(m))
return;
if (m->watchdog[t] == timeout)
return;
if (t == WATCHDOG_RUNTIME)
if (!timestamp_is_set(m->watchdog_overridden[WATCHDOG_RUNTIME])) {
if (timestamp_is_set(timeout))
r = watchdog_set_timeout(&timeout);
else
watchdog_close(true);
}
if (r >= 0)
m->watchdog[t] = timeout;
}
int manager_set_watchdog_overridden(Manager *m, WatchdogType t, usec_t timeout) {
int r = 0;
assert(m);
if (MANAGER_IS_USER(m))
return 0;
if (m->watchdog_overridden[t] == timeout)
return 0;
if (t == WATCHDOG_RUNTIME) {
usec_t *p;
p = timestamp_is_set(timeout) ? &timeout : &m->watchdog[t];
if (timestamp_is_set(*p))
r = watchdog_set_timeout(p);
else
watchdog_close(true);
}
if (r >= 0)
m->watchdog_overridden[t] = timeout;
return 0;
}
int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
int r = 0;
@ -3451,6 +3522,30 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
else
manager_override_log_target(m, target);
} else if ((val = startswith(l, "runtime-watchdog-overridden="))) {
usec_t t;
if (deserialize_usec(val, &t) < 0)
log_notice("Failed to parse runtime-watchdog-overridden value '%s', ignoring.", val);
else
manager_set_watchdog_overridden(m, WATCHDOG_RUNTIME, t);
} else if ((val = startswith(l, "reboot-watchdog-overridden="))) {
usec_t t;
if (deserialize_usec(val, &t) < 0)
log_notice("Failed to parse reboot-watchdog-overridden value '%s', ignoring.", val);
else
manager_set_watchdog_overridden(m, WATCHDOG_REBOOT, t);
} else if ((val = startswith(l, "kexec-watchdog-overridden="))) {
usec_t t;
if (deserialize_usec(val, &t) < 0)
log_notice("Failed to parse kexec-watchdog-overridden value '%s', ignoring.", val);
else
manager_set_watchdog_overridden(m, WATCHDOG_KEXEC, t);
} else if (startswith(l, "env=")) {
r = deserialize_environment(l + 4, &m->client_environment);
if (r < 0)

View File

@ -114,6 +114,13 @@ typedef enum ManagerTimestamp {
_MANAGER_TIMESTAMP_INVALID = -1,
} ManagerTimestamp;
typedef enum WatchdogType {
WATCHDOG_RUNTIME,
WATCHDOG_REBOOT,
WATCHDOG_KEXEC,
_WATCHDOG_TYPE_MAX,
} WatchdogType;
#include "execute.h"
#include "job.h"
#include "path-lookup.h"
@ -231,9 +238,8 @@ struct Manager {
char **transient_environment; /* The environment, as determined from config files, kernel cmdline and environment generators */
char **client_environment; /* Environment variables created by clients through the bus API */
usec_t runtime_watchdog;
usec_t reboot_watchdog;
usec_t kexec_watchdog;
usec_t watchdog[_WATCHDOG_TYPE_MAX];
usec_t watchdog_overridden[_WATCHDOG_TYPE_MAX];
dual_timestamp timestamps[_MANAGER_TIMESTAMP_MAX];
@ -555,5 +561,9 @@ const char *manager_timestamp_to_string(ManagerTimestamp m) _const_;
ManagerTimestamp manager_timestamp_from_string(const char *s) _pure_;
ManagerTimestamp manager_timestamp_initrd_mangle(ManagerTimestamp s);
usec_t manager_get_watchdog(Manager *m, WatchdogType t);
void manager_set_watchdog(Manager *m, WatchdogType t, usec_t timeout);
int manager_set_watchdog_overridden(Manager *m, WatchdogType t, usec_t timeout);
const char* oom_policy_to_string(OOMPolicy i) _const_;
OOMPolicy oom_policy_from_string(const char *s) _pure_;