reset kernel crashkernel for the special case where the kernel is updated right after kexec-tools

When kexec-tools updates the default crashkernel value, it will try to
reset the existing installed kernels including the currently running
kernel. So the running kernel could have different kernel cmdline
parameters from /proc/cmdline. When installing a kernel after updating
kexec-tools, /usr/lib/kernel/install.d/20-grub.install would be called
by kernel-install [1] which would use /proc/cmdline to set up new kernel's
cmdline. To address this special case, reset the new kernel's crashkernel
and fadump value to the value that would be used by running kernel after
rebooting by the installation hook. One side effect of this commit is it
would reset the installed kernel's crashkernel even currently running kernel
don't use the default crashkernel value after rebooting. But I think this
side effect is a benefit for the user.

The implementation depends on kernel-install which run the scripts in
/usr/lib/kernel/install.d passing the following arguments,

  add KERNEL-VERSION $BOOT/MACHINE-ID/KERNEL-VERSION/ KERNEL-IMAGE [INITRD-FILE ...]

An concrete example is given as follows,
  add 5.11.12-300.fc34.x86_64 /boot/e986846f63134c7295458cf36300ba5b/5.11.12-300.fc34.x86_64 /lib/modules/5.11.12-300.fc34.x86_64/vmlinuz

kernel-install could be started by the kernel package's RPM scriplet [2].
As mentioned in previous commit "try to reset kernel crashkernel when
kexec-tools updates the default crashkernel value", kdumpctl has difficulty
running in RPM scriptlet fore CoreOS. But rpm-ostree ignores all kernel hooks,
there is no need to disable the kernel hook for CoreOS/Atomic/Silverblue. But a
collaboration between rpm-ostree and kexec-tools is needed [3] to take care
of this special case.

Note the crashkernel.default support is dropped.

[1] https://www.freedesktop.org/software/systemd/man/kernel-install.html
[2] https://src.fedoraproject.org/rpms/kernel/blob/rawhide/f/kernel.spec#_2680
[3] https://github.com/coreos/rpm-ostree/issues/2894

Reviewed-by: Pingfan Liu <piliu@redhat.com>
Reviewed-by: Philipp Rudo <prudo@redhat.com>
Signed-off-by: Coiby Xu <coxu@redhat.com>
This commit is contained in:
Coiby Xu 2021-12-02 17:19:50 +08:00
parent 0adb0f4a8c
commit 5e8c751c39
2 changed files with 32 additions and 134 deletions

View File

@ -5,142 +5,9 @@ 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
exit 0
;;
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
kdumpctl reset-crashkernel-for-installed_kernel "$KERNEL_VERSION"
exit 0
;;
esac

View File

@ -1576,6 +1576,32 @@ reset_crashkernel_after_update()
done
}
reset_crashkernel_for_installed_kernel()
{
local _installed_kernel _running_kernel _crashkernel _crashkernel_running
local _dump_mode_running _fadump_val_running
if ! _installed_kernel=$(_find_kernel_path_by_release "$1"); then
exit 1
fi
if ! _running_kernel=$(_get_current_running_kernel_path); then
derror "Couldn't find current running kernel"
exit
fi
_crashkernel=$(get_grub_kernel_boot_parameter "$_installed_kernel" crashkernel)
_crashkernel_running=$(get_grub_kernel_boot_parameter "$_running_kernel" crashkernel)
_dump_mode_running=$(get_dump_mode_by_kernel "$_running_kernel")
_fadump_val_running=$(get_grub_kernel_boot_parameter "$_kernel" fadump)
if [[ $_crashkernel != "$_crashkernel_running" ]]; then
if _update_grub "$_installed_kernel" "$_crashkernel_running" "$_dump_mode_running" "$_fadump_val_running"; then
echo "kexec-tools has reset $_installed_kernel to use the new default crashkernel value $_crashkernel_running"
fi
fi
}
if [[ ! -f $KDUMP_CONFIG_FILE ]]; then
derror "Error: No kdump config file found!"
exit 1
@ -1641,6 +1667,11 @@ main()
reset_crashkernel_after_update
fi
;;
reset-crashkernel-for-installed_kernel)
if [[ $(kdump_get_conf_val auto_reset_crashkernel) != no ]]; then
reset_crashkernel_for_installed_kernel "$2"
fi
;;
*)
dinfo $"Usage: $0 {estimate|start|stop|status|restart|reload|rebuild|reset-crashkernel|propagate|showmem}"
exit 1