diff options
author | Ray Strode <rstrode@redhat.com> | 2020-07-17 16:06:44 -0400 |
---|---|---|
committer | Ray Strode <rstrode@redhat.com> | 2020-07-20 15:48:31 -0400 |
commit | 00df82fea8f7e6c6e441e30166191fdd682e328f (patch) | |
tree | 812644bdcdda86aa011bae6fea11575ecb1f9a59 | |
parent | ab986a95824e2a701a77dd9405d411a5c022c613 (diff) |
src: die during shutdown with everything elsewip/fix-remount-failure
plymouthd currently avoids getting killed at shutdown. This causes
filesystems to fail to remount read-only in some cases.
This commit changes things up so that plymouthd dies with everyone else,
but spawns a process to hold open the drm device that can keep the splash
up until the very end.
In order to keep this process alive until the very end, it gets run
from within the initramfs (if available). This requires adding service
files to jump back into the initramfs at shutdown
-rw-r--r-- | configure.ac | 1 | ||||
-rwxr-xr-x | scripts/plymouth-populate-initrd.in | 2 | ||||
-rw-r--r-- | src/Makefile.am | 7 | ||||
-rw-r--r-- | src/main.c | 11 | ||||
-rw-r--r-- | src/plugins/renderers/drm/Makefile.am | 3 | ||||
-rw-r--r-- | src/plugins/renderers/drm/plugin.c | 62 | ||||
-rw-r--r-- | src/plymouthd-drm-escrow.c | 18 | ||||
-rw-r--r-- | systemd-units/Makefile.am | 28 | ||||
-rw-r--r-- | systemd-units/plymouth-halt.service.in | 1 | ||||
-rw-r--r-- | systemd-units/plymouth-poweroff.service.in | 1 | ||||
-rw-r--r-- | systemd-units/plymouth-reboot.service.in | 1 | ||||
-rw-r--r-- | systemd-units/plymouth-switch-root-initramfs.service.in | 12 |
12 files changed, 134 insertions, 13 deletions
diff --git a/configure.ac b/configure.ac index 1a2314bb..d2d62287 100644 --- a/configure.ac +++ b/configure.ac @@ -341,6 +341,7 @@ AC_CONFIG_FILES([Makefile po/Makefile.in systemd-units/plymouth-reboot.service systemd-units/plymouth-start.service systemd-units/plymouth-switch-root.service + systemd-units/plymouth-switch-root-initramfs.service systemd-units/systemd-ask-password-plymouth.path systemd-units/systemd-ask-password-plymouth.service systemd-units/Makefile diff --git a/scripts/plymouth-populate-initrd.in b/scripts/plymouth-populate-initrd.in index 616ecc4e..4e35186b 100755 --- a/scripts/plymouth-populate-initrd.in +++ b/scripts/plymouth-populate-initrd.in @@ -22,6 +22,7 @@ [ -z "$PLYMOUTH_POLICYDIR" ] && PLYMOUTH_POLICYDIR="@PLYMOUTH_POLICY_DIR@" [ -z "$PLYMOUTH_DAEMON_PATH" ] && PLYMOUTH_DAEMON_PATH="@PLYMOUTH_DAEMON_DIR@/plymouthd" [ -z "$PLYMOUTH_CLIENT_PATH" ] && PLYMOUTH_CLIENT_PATH="@PLYMOUTH_CLIENT_DIR@/plymouth" +[ -z "$PLYMOUTH_DRM_ESCROW_PATH" ] && PLYMOUTH_DRM_ESCROW_PATH="@PLYMOUTH_LIBEXECDIR@/plymouth/plymouth-drm-escrow" [ -z "$SYSTEMD_UNIT_DIR" ] && SYSTEMD_UNIT_DIR="@SYSTEMD_UNIT_DIR@" # Generic substring function. If $2 is in $1, return 0. @@ -416,6 +417,7 @@ ddebug "Running with PLYMOUTH_LDD_PATH=$PLYMOUTH_LDD_PATH" mkdir -p ${INITRDDIR}${PLYMOUTH_DATADIR}/plymouth/themes inst ${PLYMOUTH_DAEMON_PATH} $INITRDDIR inst ${PLYMOUTH_CLIENT_PATH} $INITRDDIR +inst ${PLYMOUTH_DRM_ESCROW_PATH} $INITRDDIR inst ${PLYMOUTH_DATADIR}/plymouth/themes/text/text.plymouth $INITRDDIR inst ${PLYMOUTH_PLUGIN_PATH}/text.so $INITRDDIR inst ${PLYMOUTH_DATADIR}/plymouth/themes/details/details.plymouth $INITRDDIR diff --git a/src/Makefile.am b/src/Makefile.am index 95ed0192..78f3f788 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -6,6 +6,7 @@ AM_CPPFLAGS = -I$(top_srcdir) \ -I$(srcdir)/libply \ -I$(srcdir)/libply-splash-core \ -I$(srcdir) \ + -DPLYMOUTH_DRM_ESCROW_DIRECTORY=\"$(libexecdir)/plymouth\" \ -DPLYMOUTH_LOG_DIRECTORY=\"$(localstatedir)/log\" \ -DPLYMOUTH_SPOOL_DIRECTORY=\"$(localstatedir)/spool/plymouth\" \ -DPLYMOUTH_TIME_DIRECTORY=\"$(localstatedir)/lib/plymouth/\" \ @@ -30,6 +31,12 @@ plymouthd_SOURCES = \ plugins/splash/details/plugin.c \ main.c +escrowdir = $(libexecdir)/plymouth +escrow_PROGRAMS = plymouthd-drm-escrow + +plymouthd_drm_escrow_LDFLAGS = -all-static +plymouthd_drm_escrow_SOURCES = plymouthd-drm-escrow.c + plymouthdrundir = $(localstatedir)/run/plymouth plymouthdspooldir = $(localstatedir)/spool/plymouth plymouthdtimedir = $(localstatedir)/lib/plymouth @@ -2208,11 +2208,16 @@ main (int argc, } /* Make the first byte in argv be '@' so that we can survive systemd's killing - * spree when going from initrd to /, and so we stay alive all the way until - * the power is killed at shutdown. + * spree when going from initrd to / * http://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons + * + * If the system is shutting down, we let systemd slay us because otherwise we + * may prevent the root fs from getting remounted read-only. */ - argv[0][0] = '@'; + if (state.mode != PLY_BOOT_SPLASH_MODE_SHUTDOWN && + state.mode != PLY_BOOT_SPLASH_MODE_REBOOT) { + argv[0][0] = '@'; + } state.boot_server = start_boot_server (&state); diff --git a/src/plugins/renderers/drm/Makefile.am b/src/plugins/renderers/drm/Makefile.am index 271b17f4..22a819b6 100644 --- a/src/plugins/renderers/drm/Makefile.am +++ b/src/plugins/renderers/drm/Makefile.am @@ -5,7 +5,8 @@ AM_CPPFLAGS = -I$(top_srcdir) \ -I$(srcdir)/../../.. \ -I$(srcdir)/../.. \ -I$(srcdir)/.. \ - -I$(srcdir) + -I$(srcdir) \ + -DPLYMOUTH_DRM_ESCROW_DIRECTORY=\"$(libexecdir)/plymouth\" plugindir = $(libdir)/plymouth/renderers plugin_LTLIBRARIES = drm.la diff --git a/src/plugins/renderers/drm/plugin.c b/src/plugins/renderers/drm/plugin.c index 4dbf8da8..38bae367 100644 --- a/src/plugins/renderers/drm/plugin.c +++ b/src/plugins/renderers/drm/plugin.c @@ -158,6 +158,7 @@ struct _ply_renderer_backend uint32_t is_active : 1; uint32_t requires_explicit_flushing : 1; uint32_t use_preferred_mode : 1; + uint32_t watching_for_termination : 1; int panel_width; int panel_height; @@ -171,6 +172,11 @@ static bool open_input_source (ply_renderer_backend_t *backend, static void flush_head (ply_renderer_backend_t *backend, ply_renderer_head_t *head); +static void close_device (ply_renderer_backend_t *backend); + +static void watch_for_termination (ply_renderer_backend_t *backend); +static void stop_watching_for_termination (ply_renderer_backend_t *backend); + /* A small helper to determine if we should try to keep the current mode * or pick the best mode ourselves, we keep the current mode only if the * user specified a specific mode using video= on the commandline. @@ -945,6 +951,8 @@ activate (ply_renderer_backend_t *backend) flush_head (backend, head); node = ply_list_get_next_node (backend->heads, node); } + + watch_for_termination (backend); } static void @@ -953,6 +961,8 @@ deactivate (ply_renderer_backend_t *backend) ply_trace ("dropping master"); drmDropMaster (backend->device_fd); backend->is_active = false; + + stop_watching_for_termination (backend); } static void @@ -1005,6 +1015,54 @@ unload_backend (ply_renderer_backend_t *backend) } +static void +on_term_signal (ply_renderer_backend_t *backend) +{ + pid_t pid; + + ply_trace ("got SIGTERM, launching drm escrow to protect splash, and dying"); + + pid = fork(); + + if (pid == 0) { + const char *argv[] = { PLYMOUTH_DRM_ESCROW_DIRECTORY "/plymouthd-drm-escrow", NULL }; + + dup (backend->device_fd); + execve (argv[0], (char * const *) argv, NULL); + + ply_trace ("could not launch drm escrow process: %m"); + + _exit (1); + } + + + close_device (backend); + + exit (0); +} + +static void +watch_for_termination (ply_renderer_backend_t *backend) +{ + if (backend->watching_for_termination) + return; + + ply_trace ("watching for termination signal"); + ply_event_loop_watch_signal (backend->loop, SIGTERM, (ply_event_handler_t) on_term_signal, backend); + backend->watching_for_termination = true; +} + +static void +stop_watching_for_termination (ply_renderer_backend_t *backend) +{ + if (!backend->watching_for_termination) + return; + + ply_trace ("stopping watching for termination signal"); + ply_event_loop_stop_watching_signal (backend->loop, SIGTERM); + backend->watching_for_termination = false; +} + static bool open_device (ply_renderer_backend_t *backend) { @@ -1033,6 +1091,8 @@ open_device (ply_renderer_backend_t *backend) on_active_vt_changed, backend); + watch_for_termination (backend); + return true; } @@ -1043,6 +1103,8 @@ close_device (ply_renderer_backend_t *backend) free_heads (backend); + stop_watching_for_termination (backend); + if (backend->terminal != NULL) { ply_terminal_stop_watching_for_active_vt_change (backend->terminal, (ply_terminal_active_vt_changed_handler_t) diff --git a/src/plymouthd-drm-escrow.c b/src/plymouthd-drm-escrow.c new file mode 100644 index 00000000..9097db91 --- /dev/null +++ b/src/plymouthd-drm-escrow.c @@ -0,0 +1,18 @@ +#include <signal.h> +#include <unistd.h> + +int +main(int argc, char **argv) +{ + signal (SIGTERM, SIG_IGN); + + /* Make the first byte in argv be '@' so that we can survive systemd's killing + * spree until the power is killed at shutdown. + * http://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons + */ + argv[0][0] = '@'; + + while (pause()); + + return 0; +} diff --git a/systemd-units/Makefile.am b/systemd-units/Makefile.am index b1d843b6..bfede172 100644 --- a/systemd-units/Makefile.am +++ b/systemd-units/Makefile.am @@ -1,5 +1,6 @@ systemd_unit_templates = \ plymouth-switch-root.service.in \ + plymouth-switch-root-initramfs.service.in \ plymouth-start.service.in \ plymouth-read-write.service.in \ plymouth-quit.service.in \ @@ -37,17 +38,23 @@ install-data-hook: $(LN_S) ../plymouth-quit.service && \ $(LN_S) ../plymouth-quit-wait.service) (cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/reboot.target.wants && \ - rm -f plymouth-reboot.service && \ - $(LN_S) ../plymouth-reboot.service) + rm -f plymouth-reboot.service \ + plymouth-switch-root-initramfs.service && \ + $(LN_S) ../plymouth-reboot.service && \ + $(LN_S) ../plymouth-switch-root-initramfs.service) (cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/kexec.target.wants && \ rm -f plymouth-kexec.service && \ $(LN_S) ../plymouth-kexec.service) (cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/poweroff.target.wants && \ - rm -f plymouth-poweroff.service && \ - $(LN_S) ../plymouth-poweroff.service) + rm -f plymouth-poweroff.service \ + plymouth-switch-root-initramfs.service && \ + $(LN_S) ../plymouth-poweroff.service && \ + $(LN_S) ../plymouth-switch-root-initramf.services) (cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/halt.target.wants && \ - rm -f plymouth-halt.service && \ - $(LN_S) ../plymouth-halt.service) + rm -f plymouth-halt.service \ + plymouth-switch-root-initramfs.service && \ + $(LN_S) ../plymouth-halt.service && \ + $(LN_S) ../plymouth-switch-root-initramfs.service) uninstall-hook: (cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/initrd-switch-root.target.wants && \ @@ -57,13 +64,16 @@ uninstall-hook: (cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/multi-user.target.wants && \ rm -f plymouth-quit.service plymouth-quit-wait.service) (cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/reboot.target.wants && \ - rm -f plymouth-reboot.service) + rm -f plymouth-reboot.service \ + plymouth-switch-root-initramfs.service) (cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/kexec.target.wants && \ rm -f plymouth-kexec.service) (cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/poweroff.target.wants && \ - rm -f plymouth-poweroff.service) + rm -f plymouth-poweroff.service \ + plymouth-switch-root-initramfs.service) (cd $(DESTDIR)$(SYSTEMD_UNIT_DIR)/halt.target.wants && \ - rm -f plymouth-halt.service) + rm -f plymouth-halt.service \ + plymouth-switch-root-initramfs.service) rmdir --ignore-fail-on-non-empty \ $(DESTDIR)$(SYSTEMD_UNIT_DIR)/sysinit.target.wants \ $(DESTDIR)$(SYSTEMD_UNIT_DIR)/multi-user.target.wants \ diff --git a/systemd-units/plymouth-halt.service.in b/systemd-units/plymouth-halt.service.in index cb87c1f4..00f7eed9 100644 --- a/systemd-units/plymouth-halt.service.in +++ b/systemd-units/plymouth-halt.service.in @@ -9,5 +9,6 @@ ConditionVirtualization=!container [Service] ExecStart=@PLYMOUTH_DAEMON_DIR@/plymouthd --mode=shutdown --attach-to-session ExecStartPost=-@PLYMOUTH_CLIENT_DIR@/plymouth show-splash +KillMode=none Type=forking RemainAfterExit=yes diff --git a/systemd-units/plymouth-poweroff.service.in b/systemd-units/plymouth-poweroff.service.in index cf05e47f..a1f78eb4 100644 --- a/systemd-units/plymouth-poweroff.service.in +++ b/systemd-units/plymouth-poweroff.service.in @@ -9,5 +9,6 @@ ConditionVirtualization=!container [Service] ExecStart=@PLYMOUTH_DAEMON_DIR@/plymouthd --mode=shutdown --attach-to-session ExecStartPost=-@PLYMOUTH_CLIENT_DIR@/plymouth show-splash +KillMode=none Type=forking RemainAfterExit=yes diff --git a/systemd-units/plymouth-reboot.service.in b/systemd-units/plymouth-reboot.service.in index 3624550d..8fff576f 100644 --- a/systemd-units/plymouth-reboot.service.in +++ b/systemd-units/plymouth-reboot.service.in @@ -9,5 +9,6 @@ ConditionVirtualization=!container [Service] ExecStart=@PLYMOUTH_DAEMON_DIR@/plymouthd --mode=reboot --attach-to-session ExecStartPost=-@PLYMOUTH_CLIENT_DIR@/plymouth show-splash +KillMode=none Type=forking RemainAfterExit=yes diff --git a/systemd-units/plymouth-switch-root-initramfs.service.in b/systemd-units/plymouth-switch-root-initramfs.service.in new file mode 100644 index 00000000..cb20459d --- /dev/null +++ b/systemd-units/plymouth-switch-root-initramfs.service.in @@ -0,0 +1,12 @@ +[Unit] +Description=Tell Plymouth To Jump To initramfs +DefaultDependencies=no +After=plymouth-halt.service plymouth-reboot.service plymouth-poweroff.service dracut-shutdown.service +ConditionPathExists=/run/initramfs/bin/sh + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=-@PLYMOUTH_CLIENT_DIR@/plymouth update-root-fs --new-root-dir=/run/initramfs +Type=oneshot +RemainAfterExit=yes |