fadump: isolate fadump initramfs image within the default one

From: Hari Bathini <hbathini@linux.ibm.com>

In case of fadump, the initramfs image has to be built to boot into
the production environment as well as to offload the active crash dump
to the specified dump target (for boot after crash). As the same image
would be used for both boot scenarios, it could not be built optimally
while accommodating both cases.

Use --include to include the initramfs image built for offloading
active crash dump to the specified dump target. Also, introduce a new
out-of-tree dracut module (99zz-fadumpinit) that installs a customized
init program while moving the default /init to /init.dracut.

Thus, the customized init program is leveraged to isolate fadump image
within the default initramfs image by kicking off default boot process
(exec /init.dracut) for regular boot scenario and activating squash'ed
image only when an active crash dump would be available.

Signed-off-by: Hari Bathini <hbathini@linux.ibm.com>
---
 dracut-fadump-init-fadump.sh  |   27 +++++++++++++++++++++++++++
 dracut-fadump-module-setup.sh |   18 ++++++++++++++++++
 kdumpctl                      |    8 +++++++-
 kexec-tools.spec              |   11 +++++++++++
 4 files changed, 63 insertions(+), 1 deletion(-)
 create mode 100644 dracut-fadump-init-fadump.sh
 create mode 100644 dracut-fadump-module-setup.sh

diff --git a/dracut-fadump-init-fadump.sh b/dracut-fadump-init-fadump.sh
new file mode 100644
index 0000000..7e7562d
--- /dev/null
+++ b/dracut-fadump-init-fadump.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+PATH=/bin:/sbin
+
+[ -e /proc/self/mounts ] \
+    || (mkdir -p /proc && mount -t proc -o nosuid,noexec,nodev proc /proc)
+
+grep -q '^sysfs /sys sysfs' /proc/self/mounts \
+    || (mkdir -p /sys && mount -t sysfs -o nosuid,noexec,nodev sysfs /sys)
+
+grep -q '^devtmpfs /dev devtmpfs' /proc/self/mounts \
+	    || (mkdir -p /dev && mount -t devtmpfs -o mode=755,noexec,nosuid,strictatime devtmpfs /dev)
+
+grep -q '^tmpfs /run tmpfs' /proc/self/mounts \
+	    || (mkdir -p /run && mount -t tmpfs -o mode=755,noexec,nosuid,strictatime tmpfs /run)
+
+# Check if system is booting after a crash
+if [ -f /proc/device-tree/rtas/ibm,kernel-dump ] || [ -f /proc/device-tree/ibm,opal/dump/mpipl-boot ]; then
+    mount -t ramfs ramfs /fadumproot
+    CAT="cat"
+    #CAT="gzip -cd"
+    $CAT /fadump-initrd.img | cpio -idm --quiet -D /fadumproot
+
+    # Jump to new root and clean setup files
+    SYSTEMD_IN_INITRD=lenient exec switch_root /fadumproot /init
+else
+    exec /init.dracut
+fi
diff --git a/dracut-fadump-module-setup.sh b/dracut-fadump-module-setup.sh
new file mode 100644
index 0000000..99d1230
--- /dev/null
+++ b/dracut-fadump-module-setup.sh
@@ -0,0 +1,18 @@
+#!/bin/bash
+
+check() {
+    return 255
+}
+
+depends() {
+    return 0
+}
+
+install() {
+    mv -f "$initdir/init" "$initdir/init.dracut"
+    inst_dir "/fadumproot"
+    inst_script "$moddir/init-fadump.sh" /init
+
+    # Install required binaries for the init script (init-fadump.sh)
+    inst_multiple sh grep mkdir mount switch_root cat gzip cpio
+}
diff --git a/kdumpctl b/kdumpctl
index 978dae5..902bb3d 100755
--- a/kdumpctl
+++ b/kdumpctl
@@ -105,6 +105,7 @@ save_core()
 rebuild_fadump_initrd()
 {
 	local target_initrd_tmp
+	local _dracut_isolate_args
 
 	# this file tells the initrd is fadump enabled
 	touch /tmp/fadump.initramfs
@@ -119,6 +120,11 @@ rebuild_fadump_initrd()
 	fi
 	rm -f /tmp/fadump.initramfs
 
+       _dracut_isolate_args=" --rebuild $DEFAULT_INITRD_BAK --add zz-fadumpinit -i $target_initrd_tmp /fadump-initrd.img"
+	if ! dracut --force --quiet $_dracut_isolate_args $target_initrd_tmp; then
+		dwarn "WARNING: Could not isolate the dump capture initramfs image."
+	fi
+
 	# updating fadump initrd
 	ddebug "updating fadump initrd: $target_initrd_tmp $TARGET_INITRD"
 	mv $target_initrd_tmp $TARGET_INITRD
@@ -612,7 +618,7 @@ check_rebuild()
 		#in case of fadump mode, check whether the default/target
 		#initrd is already built with dump capture capability
 		if [ "$DEFAULT_DUMP_MODE" == "fadump" ]; then
-			capture_capable_initrd=$(lsinitrd -f $DRACUT_MODULES_FILE $TARGET_INITRD | grep ^kdumpbase$ | wc -l)
+			capture_capable_initrd=$(lsinitrd -f $DRACUT_MODULES_FILE $TARGET_INITRD | grep -e ^kdumpbase$ -e ^zz-fadumpinit$ | wc -l)
 		fi
 	fi
 
diff --git a/kexec-tools.spec b/kexec-tools.spec
index e94ed02..4d160b8 100644
--- a/kexec-tools.spec
+++ b/kexec-tools.spec
@@ -54,6 +54,9 @@ Source107: dracut-kdump-emergency.target
 Source108: dracut-early-kdump.sh
 Source109: dracut-early-kdump-module-setup.sh
 
+Source200: dracut-fadump-init-fadump.sh
+Source201: dracut-fadump-module-setup.sh
+
 Requires(post): systemd-units
 Requires(preun): systemd-units
 Requires(postun): systemd-units
@@ -211,6 +214,7 @@ install -m 644 makedumpfile-%{mkdf_ver}/eppic_scripts/* $RPM_BUILD_ROOT/usr/shar
 
 %define remove_dracut_prefix() %(echo -n %1|sed 's/.*dracut-//g')
 %define remove_dracut_early_kdump_prefix() %(echo -n %1|sed 's/.*dracut-early-kdump-//g')
+%define remove_dracut_fadump_prefix() %(echo -n %1|sed 's/.*dracut-fadump-//g')
 
 # deal with dracut modules
 mkdir -p -m755 $RPM_BUILD_ROOT/etc/kdump-adv-conf/kdump_dracut_modules/99kdumpbase
@@ -228,6 +232,13 @@ cp %{SOURCE108} $RPM_BUILD_ROOT/etc/kdump-adv-conf/kdump_dracut_modules/99earlyk
 cp %{SOURCE109} $RPM_BUILD_ROOT/etc/kdump-adv-conf/kdump_dracut_modules/99earlykdump/%{remove_dracut_early_kdump_prefix %{SOURCE109}}
 chmod 755 $RPM_BUILD_ROOT/etc/kdump-adv-conf/kdump_dracut_modules/99earlykdump/%{remove_dracut_prefix %{SOURCE108}}
 chmod 755 $RPM_BUILD_ROOT/etc/kdump-adv-conf/kdump_dracut_modules/99earlykdump/%{remove_dracut_early_kdump_prefix %{SOURCE109}}
+%ifarch ppc64 ppc64le
+mkdir -p -m755 $RPM_BUILD_ROOT/etc/kdump-adv-conf/kdump_dracut_modules/99zz-fadumpinit
+cp %{SOURCE200} $RPM_BUILD_ROOT/etc/kdump-adv-conf/kdump_dracut_modules/99zz-fadumpinit/%{remove_dracut_fadump_prefix %{SOURCE200}}
+cp %{SOURCE201} $RPM_BUILD_ROOT/etc/kdump-adv-conf/kdump_dracut_modules/99zz-fadumpinit/%{remove_dracut_fadump_prefix %{SOURCE201}}
+chmod 755 $RPM_BUILD_ROOT/etc/kdump-adv-conf/kdump_dracut_modules/99zz-fadumpinit/%{remove_dracut_fadump_prefix %{SOURCE200}}
+chmod 755 $RPM_BUILD_ROOT/etc/kdump-adv-conf/kdump_dracut_modules/99zz-fadumpinit/%{remove_dracut_fadump_prefix %{SOURCE201}}
+%endif
 
 
 %define dracutlibdir %{_prefix}/lib/dracut
