Merge pull request #22271 from keszybz/manager-reexec-freeze
Freeze manager if reexec fails
This commit is contained in:
+65
-54
@@ -1751,11 +1751,11 @@ static void update_cpu_affinity(bool skip_setup) {
|
||||
|
||||
assert(arg_cpu_affinity.allocated > 0);
|
||||
|
||||
mask = cpu_set_to_string(&arg_cpu_affinity);
|
||||
log_debug("Setting CPU affinity to %s.", strnull(mask));
|
||||
mask = cpu_set_to_range_string(&arg_cpu_affinity);
|
||||
log_debug("Setting CPU affinity to {%s}.", strnull(mask));
|
||||
|
||||
if (sched_setaffinity(0, arg_cpu_affinity.allocated, arg_cpu_affinity.set) < 0)
|
||||
log_warning_errno(errno, "Failed to set CPU affinity: %m");
|
||||
log_warning_errno(errno, "Failed to set CPU affinity, ignoring: %m");
|
||||
}
|
||||
|
||||
static void update_numa_policy(bool skip_setup) {
|
||||
@@ -1769,14 +1769,14 @@ static void update_numa_policy(bool skip_setup) {
|
||||
if (DEBUG_LOGGING) {
|
||||
policy = mpol_to_string(numa_policy_get_type(&arg_numa_policy));
|
||||
nodes = cpu_set_to_range_string(&arg_numa_policy.nodes);
|
||||
log_debug("Setting NUMA policy to %s, with nodes %s.", strnull(policy), strnull(nodes));
|
||||
log_debug("Setting NUMA policy to %s, with nodes {%s}.", strnull(policy), strnull(nodes));
|
||||
}
|
||||
|
||||
r = apply_numa_policy(&arg_numa_policy);
|
||||
if (r == -EOPNOTSUPP)
|
||||
log_debug_errno(r, "NUMA support not available, ignoring.");
|
||||
else if (r < 0)
|
||||
log_warning_errno(r, "Failed to set NUMA memory policy: %m");
|
||||
log_warning_errno(r, "Failed to set NUMA memory policy, ignoring: %m");
|
||||
}
|
||||
|
||||
static void filter_args(
|
||||
@@ -1824,7 +1824,8 @@ static void filter_args(
|
||||
}
|
||||
}
|
||||
|
||||
static void do_reexecute(
|
||||
static int do_reexecute(
|
||||
ManagerObjective objective,
|
||||
int argc,
|
||||
char* argv[],
|
||||
const struct rlimit *saved_rlimit_nofile,
|
||||
@@ -1838,6 +1839,7 @@ static void do_reexecute(
|
||||
const char **args;
|
||||
int r;
|
||||
|
||||
assert(IN_SET(objective, MANAGER_REEXECUTE, MANAGER_SWITCH_ROOT));
|
||||
assert(argc >= 0);
|
||||
assert(saved_rlimit_nofile);
|
||||
assert(saved_rlimit_memlock);
|
||||
@@ -1901,6 +1903,12 @@ static void do_reexecute(
|
||||
|
||||
args[0] = SYSTEMD_BINARY_PATH;
|
||||
(void) execv(args[0], (char* const*) args);
|
||||
|
||||
if (objective == MANAGER_REEXECUTE) {
|
||||
*ret_error_message = "Failed to execute our own binary";
|
||||
return log_error_errno(errno, "Failed to execute our own binary %s: %m", args[0]);
|
||||
}
|
||||
|
||||
log_debug_errno(errno, "Failed to execute our own binary %s, trying fallback: %m", args[0]);
|
||||
}
|
||||
|
||||
@@ -1938,24 +1946,22 @@ static void do_reexecute(
|
||||
ANSI_HIGHLIGHT_RED " !! " ANSI_NORMAL,
|
||||
"Failed to execute /sbin/init");
|
||||
|
||||
*ret_error_message = "Failed to execute fallback shell";
|
||||
if (r == -ENOENT) {
|
||||
log_warning("No /sbin/init, trying fallback");
|
||||
|
||||
args[0] = "/bin/sh";
|
||||
args[1] = NULL;
|
||||
(void) execve(args[0], (char* const*) args, saved_env);
|
||||
log_error_errno(errno, "Failed to execute /bin/sh, giving up: %m");
|
||||
return log_error_errno(errno, "Failed to execute /bin/sh, giving up: %m");
|
||||
} else
|
||||
log_warning_errno(r, "Failed to execute /sbin/init, giving up: %m");
|
||||
|
||||
*ret_error_message = "Failed to execute fallback shell";
|
||||
return log_error_errno(r, "Failed to execute /sbin/init, giving up: %m");
|
||||
}
|
||||
|
||||
static int invoke_main_loop(
|
||||
Manager *m,
|
||||
const struct rlimit *saved_rlimit_nofile,
|
||||
const struct rlimit *saved_rlimit_memlock,
|
||||
bool *ret_reexecute,
|
||||
int *ret_retval, /* Return parameters relevant for shutting down */
|
||||
const char **ret_shutdown_verb, /* … */
|
||||
FDSet **ret_fds, /* Return parameters for reexecuting */
|
||||
@@ -1968,7 +1974,6 @@ static int invoke_main_loop(
|
||||
assert(m);
|
||||
assert(saved_rlimit_nofile);
|
||||
assert(saved_rlimit_memlock);
|
||||
assert(ret_reexecute);
|
||||
assert(ret_retval);
|
||||
assert(ret_shutdown_verb);
|
||||
assert(ret_fds);
|
||||
@@ -1977,13 +1982,13 @@ static int invoke_main_loop(
|
||||
assert(ret_error_message);
|
||||
|
||||
for (;;) {
|
||||
r = manager_loop(m);
|
||||
if (r < 0) {
|
||||
int objective = manager_loop(m);
|
||||
if (objective < 0) {
|
||||
*ret_error_message = "Failed to run main loop";
|
||||
return log_emergency_errno(r, "Failed to run main loop: %m");
|
||||
return log_emergency_errno(objective, "Failed to run main loop: %m");
|
||||
}
|
||||
|
||||
switch ((ManagerObjective) r) {
|
||||
switch (objective) {
|
||||
|
||||
case MANAGER_RELOAD: {
|
||||
LogTarget saved_log_target;
|
||||
@@ -2010,17 +2015,15 @@ static int invoke_main_loop(
|
||||
if (saved_log_target >= 0)
|
||||
manager_override_log_target(m, saved_log_target);
|
||||
|
||||
r = manager_reload(m);
|
||||
if (r < 0)
|
||||
if (manager_reload(m) < 0)
|
||||
/* Reloading failed before the point of no return.
|
||||
* Let's continue running as if nothing happened. */
|
||||
m->objective = MANAGER_OK;
|
||||
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
case MANAGER_REEXECUTE:
|
||||
|
||||
r = prepare_reexecute(m, &arg_serialization, ret_fds, false);
|
||||
if (r < 0) {
|
||||
*ret_error_message = "Failed to prepare for reexecution";
|
||||
@@ -2029,12 +2032,11 @@ static int invoke_main_loop(
|
||||
|
||||
log_notice("Reexecuting.");
|
||||
|
||||
*ret_reexecute = true;
|
||||
*ret_retval = EXIT_SUCCESS;
|
||||
*ret_shutdown_verb = NULL;
|
||||
*ret_switch_root_dir = *ret_switch_root_init = NULL;
|
||||
|
||||
return 0;
|
||||
return objective;
|
||||
|
||||
case MANAGER_SWITCH_ROOT:
|
||||
if (!m->switch_root_init) {
|
||||
@@ -2048,7 +2050,6 @@ static int invoke_main_loop(
|
||||
|
||||
log_notice("Switching root.");
|
||||
|
||||
*ret_reexecute = true;
|
||||
*ret_retval = EXIT_SUCCESS;
|
||||
*ret_shutdown_verb = NULL;
|
||||
|
||||
@@ -2056,20 +2057,18 @@ static int invoke_main_loop(
|
||||
*ret_switch_root_dir = TAKE_PTR(m->switch_root);
|
||||
*ret_switch_root_init = TAKE_PTR(m->switch_root_init);
|
||||
|
||||
return 0;
|
||||
return objective;
|
||||
|
||||
case MANAGER_EXIT:
|
||||
|
||||
if (MANAGER_IS_USER(m)) {
|
||||
log_debug("Exit.");
|
||||
|
||||
*ret_reexecute = false;
|
||||
*ret_retval = m->return_value;
|
||||
*ret_shutdown_verb = NULL;
|
||||
*ret_fds = NULL;
|
||||
*ret_switch_root_dir = *ret_switch_root_init = NULL;
|
||||
|
||||
return 0;
|
||||
return objective;
|
||||
}
|
||||
|
||||
_fallthrough_;
|
||||
@@ -2077,7 +2076,7 @@ static int invoke_main_loop(
|
||||
case MANAGER_POWEROFF:
|
||||
case MANAGER_HALT:
|
||||
case MANAGER_KEXEC: {
|
||||
static const char * const table[_MANAGER_OBJECTIVE_MAX] = {
|
||||
static const char* const table[_MANAGER_OBJECTIVE_MAX] = {
|
||||
[MANAGER_EXIT] = "exit",
|
||||
[MANAGER_REBOOT] = "reboot",
|
||||
[MANAGER_POWEROFF] = "poweroff",
|
||||
@@ -2087,13 +2086,12 @@ static int invoke_main_loop(
|
||||
|
||||
log_notice("Shutting down.");
|
||||
|
||||
*ret_reexecute = false;
|
||||
*ret_retval = m->return_value;
|
||||
assert_se(*ret_shutdown_verb = table[m->objective]);
|
||||
*ret_fds = NULL;
|
||||
*ret_switch_root_dir = *ret_switch_root_init = NULL;
|
||||
|
||||
return 0;
|
||||
return objective;
|
||||
}
|
||||
|
||||
default:
|
||||
@@ -2259,7 +2257,7 @@ static int initialize_runtime(
|
||||
if (!arg_system)
|
||||
/* Become reaper of our children */
|
||||
if (prctl(PR_SET_CHILD_SUBREAPER, 1) < 0)
|
||||
log_warning_errno(errno, "Failed to make us a subreaper: %m");
|
||||
log_warning_errno(errno, "Failed to make us a subreaper, ignoring: %m");
|
||||
|
||||
/* Bump up RLIMIT_NOFILE for systemd itself */
|
||||
(void) bump_rlimit_nofile(saved_rlimit_nofile);
|
||||
@@ -2709,15 +2707,18 @@ static int save_env(void) {
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
dual_timestamp initrd_timestamp = DUAL_TIMESTAMP_NULL, userspace_timestamp = DUAL_TIMESTAMP_NULL, kernel_timestamp = DUAL_TIMESTAMP_NULL,
|
||||
security_start_timestamp = DUAL_TIMESTAMP_NULL, security_finish_timestamp = DUAL_TIMESTAMP_NULL;
|
||||
dual_timestamp
|
||||
initrd_timestamp = DUAL_TIMESTAMP_NULL,
|
||||
userspace_timestamp = DUAL_TIMESTAMP_NULL,
|
||||
kernel_timestamp = DUAL_TIMESTAMP_NULL,
|
||||
security_start_timestamp = DUAL_TIMESTAMP_NULL,
|
||||
security_finish_timestamp = DUAL_TIMESTAMP_NULL;
|
||||
struct rlimit saved_rlimit_nofile = RLIMIT_MAKE_CONST(0),
|
||||
saved_rlimit_memlock = RLIMIT_MAKE_CONST(RLIM_INFINITY); /* The original rlimits we passed
|
||||
* in. Note we use different values
|
||||
* for the two that indicate whether
|
||||
* these fields are initialized! */
|
||||
bool skip_setup, loaded_policy = false, queue_default_job = false, first_boot = false, reexecute = false;
|
||||
bool skip_setup, loaded_policy = false, queue_default_job = false, first_boot = false;
|
||||
char *switch_root_dir = NULL, *switch_root_init = NULL;
|
||||
usec_t before_startup, after_startup;
|
||||
static char systemd[] = "systemd";
|
||||
@@ -3023,16 +3024,23 @@ int main(int argc, char *argv[]) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
(void) invoke_main_loop(m,
|
||||
&saved_rlimit_nofile,
|
||||
&saved_rlimit_memlock,
|
||||
&reexecute,
|
||||
&retval,
|
||||
&shutdown_verb,
|
||||
&fds,
|
||||
&switch_root_dir,
|
||||
&switch_root_init,
|
||||
&error_message);
|
||||
r = invoke_main_loop(m,
|
||||
&saved_rlimit_nofile,
|
||||
&saved_rlimit_memlock,
|
||||
&retval,
|
||||
&shutdown_verb,
|
||||
&fds,
|
||||
&switch_root_dir,
|
||||
&switch_root_init,
|
||||
&error_message);
|
||||
assert(r < 0 || IN_SET(r, MANAGER_EXIT, /* MANAGER_OK is not expected here. */
|
||||
MANAGER_RELOAD,
|
||||
MANAGER_REEXECUTE,
|
||||
MANAGER_REBOOT,
|
||||
MANAGER_POWEROFF,
|
||||
MANAGER_HALT,
|
||||
MANAGER_KEXEC,
|
||||
MANAGER_SWITCH_ROOT));
|
||||
|
||||
finish:
|
||||
pager_close();
|
||||
@@ -3045,14 +3053,15 @@ finish:
|
||||
|
||||
mac_selinux_finish();
|
||||
|
||||
if (reexecute)
|
||||
do_reexecute(argc, argv,
|
||||
&saved_rlimit_nofile,
|
||||
&saved_rlimit_memlock,
|
||||
fds,
|
||||
switch_root_dir,
|
||||
switch_root_init,
|
||||
&error_message); /* This only returns if reexecution failed */
|
||||
if (IN_SET(r, MANAGER_REEXECUTE, MANAGER_SWITCH_ROOT))
|
||||
r = do_reexecute(r,
|
||||
argc, argv,
|
||||
&saved_rlimit_nofile,
|
||||
&saved_rlimit_memlock,
|
||||
fds,
|
||||
switch_root_dir,
|
||||
switch_root_init,
|
||||
&error_message); /* This only returns if reexecution failed */
|
||||
|
||||
arg_serialization = safe_fclose(arg_serialization);
|
||||
fds = fdset_free(fds);
|
||||
@@ -3078,7 +3087,9 @@ finish:
|
||||
__lsan_do_leak_check();
|
||||
#endif
|
||||
|
||||
if (shutdown_verb) {
|
||||
/* Try to invoke the shutdown binary unless we already failed.
|
||||
* If we failed above, we want to freeze after finishing cleanup. */
|
||||
if (r >= 0 && shutdown_verb) {
|
||||
r = become_shutdown(shutdown_verb, retval);
|
||||
log_error_errno(r, "Failed to execute shutdown binary, %s: %m", getpid_cached() == 1 ? "freezing" : "quitting");
|
||||
error_message = "Failed to execute shutdown binary";
|
||||
|
||||
@@ -181,7 +181,7 @@ else
|
||||
echo "PID1 NUMAPolicy support - Bind policy w/o mask"
|
||||
writePID1NUMAPolicy "bind"
|
||||
pid1ReloadWithJournal
|
||||
grep "Failed to set NUMA memory policy: Invalid argument" "$journalLog"
|
||||
grep "Failed to set NUMA memory policy, ignoring: Invalid argument" "$journalLog"
|
||||
|
||||
echo "PID1 NUMAPolicy support - Bind policy w/ mask"
|
||||
writePID1NUMAPolicy "bind" "0"
|
||||
@@ -191,7 +191,7 @@ else
|
||||
echo "PID1 NUMAPolicy support - Interleave policy w/o mask"
|
||||
writePID1NUMAPolicy "interleave"
|
||||
pid1ReloadWithJournal
|
||||
grep "Failed to set NUMA memory policy: Invalid argument" "$journalLog"
|
||||
grep "Failed to set NUMA memory policy, ignoring: Invalid argument" "$journalLog"
|
||||
|
||||
echo "PID1 NUMAPolicy support - Interleave policy w/ mask"
|
||||
writePID1NUMAPolicy "interleave" "0"
|
||||
@@ -202,7 +202,7 @@ else
|
||||
writePID1NUMAPolicy "preferred"
|
||||
pid1ReloadWithJournal
|
||||
# Preferred policy with empty node mask is actually allowed and should reset allocation policy to default
|
||||
grep "Failed to set NUMA memory policy: Invalid argument" "$journalLog" && { echo >&2 "unexpected pass"; exit 1; }
|
||||
grep "Failed to set NUMA memory policy, ignoring: Invalid argument" "$journalLog" && { echo >&2 "unexpected pass"; exit 1; }
|
||||
|
||||
echo "PID1 NUMAPolicy support - Preferred policy w/ mask"
|
||||
writePID1NUMAPolicy "preferred" "0"
|
||||
|
||||
Reference in New Issue
Block a user