From 646364193597401a55eb2485ef7840bb5eef7d88 Mon Sep 17 00:00:00 2001 From: Kairui Song Date: Thu, 10 Jun 2021 13:06:23 +0800 Subject: [PATCH] Add a new hook: 92-crashkernel.install To track and manage kernel's crashkernel usage by kernel version, each kernel package will include a crashkernel.default containing the default `crashkernel=` value of that kernel. So we can use a hook to update the kernel cmdline of new installed kernel accordingly. Put it after all other grub boot loader setup hooks, so it can simply call grubby to modify the kernel cmdline. Signed-off-by: Kairui Song Acked-by: Baoquan He --- 92-crashkernel.install | 143 +++++++++++++++++++++++++++++++++++++++++ kexec-tools.spec | 4 ++ 2 files changed, 147 insertions(+) create mode 100755 92-crashkernel.install diff --git a/92-crashkernel.install b/92-crashkernel.install new file mode 100755 index 0000000..7613bc6 --- /dev/null +++ b/92-crashkernel.install @@ -0,0 +1,143 @@ +#!/usr/bin/bash + +COMMAND="$1" +KERNEL_VERSION="$2" +KDUMP_INITRD_DIR_ABS="$3" +KERNEL_IMAGE="$4" + +grub_etc_default="/etc/default/grub" + +ver_lt() { + [[ "$(echo -e "$1\n$2" | sort -V)" == $1$'\n'* ]] && [[ $1 != "$2" ]] +} + +# Read crashkernel= value in /etc/default/grub +get_grub_etc_ck() { + [[ -e $grub_etc_default ]] && \ + sed -n -e "s/^GRUB_CMDLINE_LINUX=.*\(crashkernel=[^\ \"]*\)[\ \"].*$/\1/p" $grub_etc_default +} + +# Read crashkernel.default value of specified kernel +get_ck_default() { + ck_file="/usr/lib/modules/$1/crashkernel.default" + [[ -f "$ck_file" ]] && cat "$ck_file" +} + +# Iterate installed kernels, find the kernel with the highest version that has a +# valid crashkernel.default file, exclude current installing/removing kernel +# +# $1: a string representing a crashkernel= cmdline. If given, will also check the +# content of crashkernel.default, only crashkernel.default with the same value will match +get_highest_ck_default_kver() { + for kernel in $(find /usr/lib/modules -maxdepth 1 -mindepth 1 -printf "%f\n" | sort --version-sort -r); do + [[ $kernel == "$KERNEL_VERSION" ]] && continue + [[ -s "/usr/lib/modules/$kernel/crashkernel.default" ]] || continue + + echo "$kernel" + return 0 + done + + return 1 +} + +set_grub_ck() { + sed -i -e "s/^\(GRUB_CMDLINE_LINUX=.*\)crashkernel=[^\ \"]*\([\ \"].*\)$/\1$1\2/" "$grub_etc_default" +} + +# Set specified kernel's crashkernel cmdline value +set_kernel_ck() { + kernel=$1 + ck_cmdline=$2 + + entry=$(grubby --info ALL | grep "^kernel=.*$kernel") + entry=${entry#kernel=} + entry=${entry#\"} + entry=${entry%\"} + + if [[ -z "$entry" ]]; then + echo "$0: failed to find boot entry for kernel $kernel" + return 1 + fi + + [[ -f /etc/zipl.conf ]] && zipl_arg="--zipl" + grubby --args "$ck_cmdline" --update-kernel "$entry" $zipl_arg + [[ $zipl_arg ]] && zipl > /dev/null +} + +case "$COMMAND" in +add) + # - If current boot kernel is using default crashkernel value, update + # installing kernel's crashkernel value to its default value, + # - If intalling a higher version kernel, and /etc/default/grub's + # crashkernel value is using default value, update it to installing + # kernel's default value. + inst_ck_default=$(get_ck_default "$KERNEL_VERSION") + # If installing kernel doesn't have crashkernel.default, just exit. + [[ -z "$inst_ck_default" ]] && exit 0 + + boot_kernel=$(uname -r) + boot_ck_cmdline=$(sed -n -e "s/^.*\(crashkernel=\S*\).*$/\1/p" /proc/cmdline) + highest_ck_default_kver=$(get_highest_ck_default_kver) + highest_ck_default=$(get_ck_default "$highest_ck_default_kver") + + # Try update /etc/default/grub if present, else grub2-mkconfig could + # override crashkernel value. + grub_etc_ck=$(get_grub_etc_ck) + if [[ -n "$grub_etc_ck" ]]; then + if [[ -z "$highest_ck_default_kver" ]]; then + # None of installed kernel have a crashkernel.default, + # check for 'crashkernel=auto' in case of legacy kernel + [[ "$grub_etc_ck" == "crashkernel=auto" ]] && \ + set_grub_ck "$inst_ck_default" + else + # There is a valid crashkernel.default, check if installing kernel + # have a higher version and grub config is using default value + ver_lt "$highest_ck_default_kver" "$KERNEL_VERSION" && \ + [[ "$grub_etc_ck" == "$highest_ck_default" ]] && \ + [[ "$grub_etc_ck" != "$inst_ck_default" ]] && \ + set_grub_ck "$inst_ck_default" + fi + fi + + # Exit if crashkernel is not used in current cmdline + [[ -z $boot_ck_cmdline ]] && exit 0 + + # Get current boot kernel's default value + boot_ck_default=$(get_ck_default "$boot_kernel") + if [[ $boot_ck_cmdline == "crashkernel=auto" ]]; then + # Legacy RHEL kernel defaults to "auto" + boot_ck_default="$boot_ck_cmdline" + fi + + # If boot kernel doesn't have a crashkernel.default, check + # if it's using any installed kernel's crashkernel.default + if [[ -z $boot_ck_default ]]; then + [[ $(get_highest_ck_default_kver "$boot_ck_cmdline") ]] && boot_ck_default="$boot_ck_cmdline" + fi + + # If boot kernel is using a default crashkernel, update + # installing kernel's crashkernel to new default value + if [[ "$boot_ck_cmdline" != "$inst_ck_default" ]] && [[ "$boot_ck_cmdline" == "$boot_ck_default" ]]; then + set_kernel_ck "$KERNEL_VERSION" "$inst_ck_default" + fi + ;; + +remove) + # If grub default value is upgraded when this kernel was installed, try downgrade it + grub_etc_ck=$(get_grub_etc_ck) + [[ $grub_etc_ck ]] || exit 0 + + removing_ck_conf=$(get_ck_default "$KERNEL_VERSION") + [[ $removing_ck_conf ]] || exit 0 + + highest_ck_default_kver=$(get_highest_ck_default_kver) || exit 0 + highest_ck_default=$(get_ck_default "$highest_ck_default_kver") + [[ $highest_ck_default ]] || exit 0 + + if ver_lt "$highest_ck_default_kver" "$KERNEL_VERSION"; then + if [[ $grub_etc_ck == "$removing_ck_conf" ]] && [[ $grub_etc_ck != "$highest_ck_default" ]]; then + set_grub_ck "$highest_ck_default" + fi + fi + ;; +esac diff --git a/kexec-tools.spec b/kexec-tools.spec index 8fed959..9848c2d 100644 --- a/kexec-tools.spec +++ b/kexec-tools.spec @@ -40,6 +40,7 @@ Source29: kdump.sysconfig.aarch64 Source30: 60-kdump.install Source31: kdump-logger.sh Source32: mkfadumprd +Source33: 92-crashkernel.install ####################################### # These are sources for mkdumpramfs @@ -66,6 +67,7 @@ Requires: dracut >= 050 Requires: dracut-network >= 050 Requires: dracut-squash >= 050 Requires: ethtool +Requires: grubby BuildRequires: make BuildRequires: zlib-devel elfutils-devel glib2-devel bzip2-devel ncurses-devel bison flex lzo-devel snappy-devel BuildRequires: pkgconfig intltool gettext @@ -210,6 +212,7 @@ install -m 644 %{SOURCE15} $RPM_BUILD_ROOT%{_mandir}/man5/kdump.conf.5 install -m 644 %{SOURCE16} $RPM_BUILD_ROOT%{_unitdir}/kdump.service install -m 755 -D %{SOURCE22} $RPM_BUILD_ROOT%{_prefix}/lib/systemd/system-generators/kdump-dep-generator.sh install -m 755 -D %{SOURCE30} $RPM_BUILD_ROOT%{_prefix}/lib/kernel/install.d/60-kdump.install +install -m 755 -D %{SOURCE33} $RPM_BUILD_ROOT%{_prefix}/lib/kernel/install.d/92-crashkernel.install %ifarch %{ix86} x86_64 ppc64 s390x ppc64le aarch64 install -m 755 makedumpfile-%{mkdf_ver}/makedumpfile $RPM_BUILD_ROOT/usr/sbin/makedumpfile @@ -360,6 +363,7 @@ done %{_unitdir}/kdump.service %{_prefix}/lib/systemd/system-generators/kdump-dep-generator.sh %{_prefix}/lib/kernel/install.d/60-kdump.install +%{_prefix}/lib/kernel/install.d/92-crashkernel.install %doc News %license COPYING %doc TODO