src: die during shutdown with everything else

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
This commit is contained in:
Ray Strode 2020-07-17 16:06:44 -04:00
parent ab986a9582
commit 00df82fea8
12 changed files with 134 additions and 13 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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)

View file

@ -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;
}

View file

@ -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 \

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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