From b3ad0ff48c154ed056a6bded2adac609395a9439 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Sat, 28 Jan 2017 21:18:31 -0500 Subject: [PATCH 1/4] systemctl: always avoid being killed when doing switch-root The same logic as described in acc28e2e3037d689d6481e applies to any time we are switching root, to just set the flag unconditionally. --- src/systemctl/systemctl.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 41e8d6075a..6eed921ecf 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -5655,11 +5655,9 @@ static int switch_root(int argc, char *argv[], void *userdata) { } /* Instruct PID1 to exclude us from its killing spree applied during - * the transition from the initrd to the main system otherwise we would - * exit with a failure status even though the switch to the new root - * has succeed. */ - if (in_initrd()) - argv_cmdline[0] = '@'; + * the transition. Otherwise we would exit with a failure status even + * though the switch to the new root has succeed. */ + argv_cmdline[0] = '@'; r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) From 0af9a194ca0243fcb206499116e28612f571bd91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Sun, 29 Jan 2017 12:45:51 -0500 Subject: [PATCH 2/4] units: drop KillMode= from initrd-switch-root.service The service already has DefaultDeps disabled, so systemd should not try to stop it. And if it *does* get stopped, we don't want the zombie process around. KillMode=none does not change anything in the killall() phase, and we already use argv[0][0] = '@' to protect against that anyway. KillMode=none should not be useful in normal operation, so let's leave it out. --- units/initrd-switch-root.service.in | 1 - 1 file changed, 1 deletion(-) diff --git a/units/initrd-switch-root.service.in b/units/initrd-switch-root.service.in index 219748d19b..d31497f5e3 100644 --- a/units/initrd-switch-root.service.in +++ b/units/initrd-switch-root.service.in @@ -16,4 +16,3 @@ AllowIsolate=yes [Service] Type=oneshot ExecStart=@rootbindir@/systemctl --no-block switch-root /sysroot -KillMode=none From 8a7a9ceab204fb02fd5d93a765b36b31efeb9beb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Mon, 30 Jan 2017 13:06:10 -0500 Subject: [PATCH 3/4] systemctl: ignore SIGTERM after switch root https://bugzilla.redhat.com/show_bug.cgi?id=1414904#c14 and #c15. --- src/systemctl/systemctl.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 6eed921ecf..a20ca1bcb5 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -5663,6 +5663,14 @@ static int switch_root(int argc, char *argv[], void *userdata) { if (r < 0) return r; + /* If we are slow to exit after the root switch, the new systemd instance + * will send us a signal to terminate. Just ignore it and exit normally. + * This way the unit does not end up as failed. + */ + r = ignore_signals(SIGTERM, -1); + if (r < 0) + log_warning_errno(r, "Failed to change disposition of SIGTERM to ignore: %m"); + log_debug("Switching root - root: %s; init: %s", root, strna(init)); r = sd_bus_call_method( @@ -5674,8 +5682,11 @@ static int switch_root(int argc, char *argv[], void *userdata) { &error, NULL, "ss", root, init); - if (r < 0) + if (r < 0) { + (void) default_signals(SIGTERM, -1); + return log_error_errno(r, "Failed to switch root: %s", bus_error_message(&error, r)); + } return 0; } From 750e550eba362096d56a35104c6a32631aa67b8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Tue, 31 Jan 2017 00:34:33 -0500 Subject: [PATCH 4/4] units: restore Before dependencies for systemd-vconsole-setup.service When the service is run in the initramfs, it is possible for it to get started and not be fast enough to exit before the root switch happens. It is started multiple times (depending on the consoles being detected), and runs asynchronously, so this is quite likely. It'll then get killed by killall(), and systemd will consider the service failed. To avoid all this, just wait for the service to terminate on it's own. Before=initrd-switch-root.target should be good for the initramfs, and Before=shutdown.tuarget should be good for the real system, although it's unlikely to make any difference there. --- units/systemd-vconsole-setup.service.in | 1 + 1 file changed, 1 insertion(+) diff --git a/units/systemd-vconsole-setup.service.in b/units/systemd-vconsole-setup.service.in index 2bd1fd1a5d..8bb75c6a4f 100644 --- a/units/systemd-vconsole-setup.service.in +++ b/units/systemd-vconsole-setup.service.in @@ -9,6 +9,7 @@ Description=Setup Virtual Console Documentation=man:systemd-vconsole-setup.service(8) man:vconsole.conf(5) DefaultDependencies=no +Before=initrd-switch-root.target shutdown.target ConditionPathExists=/dev/tty0 [Service]