From 5e4bb476c0cc46dedc020a802f045d479e483857 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Tue, 21 Mar 2017 15:58:13 -0600 Subject: [PATCH] kexec-tools: bump version and add support for crashdump kernel split kexec-tools into two packages, kexec and kdump. * kexec to simply execute a new kernel * kdump is for loading and collecting debris of a crashed kernel with support for kdump forensics. In order to properly support booting into a crashkernel, an init script as well as UCI configuration has been added. As modifying the kernel cmdline is required for this to work in x86 platforms use an uci-defaults script to modify /boot/grub/grub.cfg. To test collecting crash information, use the 'c' sysrq-trigger, ie. echo c > /proc/sysrq-trigger This should result in the crash kernel being executed and (depending on the configution) dmesg and/or vmcore getting saved. To check if the crash kernel was loaded properly, use the 'status' command of the kdump init script. Signed-off-by: Daniel Golle --- package/boot/kexec-tools/Config.in | 9 +- package/boot/kexec-tools/Makefile | 80 ++++++-- package/boot/kexec-tools/files/kdump.config | 7 + package/boot/kexec-tools/files/kdump.defaults | 11 ++ package/boot/kexec-tools/files/kdump.init | 182 ++++++++++++++++++ 5 files changed, 265 insertions(+), 24 deletions(-) create mode 100644 package/boot/kexec-tools/files/kdump.config create mode 100644 package/boot/kexec-tools/files/kdump.defaults create mode 100755 package/boot/kexec-tools/files/kdump.init diff --git a/package/boot/kexec-tools/Config.in b/package/boot/kexec-tools/Config.in index 03bc6ee804..068c27e417 100644 --- a/package/boot/kexec-tools/Config.in +++ b/package/boot/kexec-tools/Config.in @@ -1,12 +1,5 @@ menu "Configuration" - depends on PACKAGE_kexec-tools - -config KEXEC_TOOLS_kdump - bool - prompt "kdump support" - default n - help - Include the kdump utility. + depends on PACKAGE_kexec config KEXEC_ZLIB bool diff --git a/package/boot/kexec-tools/Makefile b/package/boot/kexec-tools/Makefile index ecd2a6ea11..1c686a2540 100644 --- a/package/boot/kexec-tools/Makefile +++ b/package/boot/kexec-tools/Makefile @@ -8,12 +8,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=kexec-tools -PKG_VERSION:=2.0.14-rc1 +PKG_VERSION:=2.0.14 PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz PKG_SOURCE_URL:=@KERNEL/linux/utils/kernel/kexec -PKG_HASH:=3fc505ff8d8a2d24c68aac5e6b4783997d5a086966ff3de8b05a0ceb27e5e23b +PKG_HASH:=ffb2e7e99d9d08754c6bc1922aed3c000094f318665d82a72ecc76c4ff1c0dc6 PKG_FIXUP:=autoreconf @@ -21,22 +21,49 @@ PKG_CONFIG_DEPENDS := CONFIG_KEXEC_ZLIB CONFIG_KEXEC_LZMA include $(INCLUDE_DIR)/package.mk -define Package/kexec-tools +define Package/kexec-tools/Default SECTION:=utils CATEGORY:=Utilities - DEPENDS:=@armeb||@arm||@i386||@x86_64||@powerpc64||@mipsel||@mips +KEXEC_ZLIB:zlib +KEXEC_LZMA:liblzma - TITLE:=Kernel boots kernel URL:=http://kernel.org/pub/linux/kernel/people/horms/kexec-tools/ MAINTAINER:=Florian Fainelli - MENU:=1 +endef + +define Package/kexec-tools + $(call Package/kexec-tools/Default) + TITLE:=kexec-tools transition meta package + DEPENDS:=+kexec endef define Package/kexec-tools/description - kexec is a set of systems call that allows you to load + kexec is a set of system calls that allows you to load another kernel from the currently executing Linux kernel. + The kexec utility allows to load and boot another kernel. endef -define Package/kexec-tools/config +define Package/kexec + $(call Package/kexec-tools/Default) + TITLE:=Kernel boots kernel + DEPENDS:=\ + @armeb||@arm||@i386||@x86_64||@powerpc64||@mipsel||@mips \ + +KEXEC_ZLIB:zlib +KEXEC_LZMA:liblzma @KERNEL_KEXEC +endef + +define Package/kexec/description + The kexec utility allows to load and boot another kernel. +endef + +define Package/kdump + $(call Package/kexec-tools/Default) + TITLE:=Kernel crash analysis + DEPENDS:=+kexec @i386||@x86_64||@arm @KERNEL_CRASH_DUMP +endef + +define Package/kdump/description + The kdump package allows to automatically boot into a + special kernel for analyzing kernel crashes using kdump. +endef + +define Package/kexec/config source "$(SOURCE)/Config.in" endef @@ -65,24 +92,45 @@ CONFIGURE_VARS += \ BUILD_CC="$(HOSTCC)" \ TARGET_CC="$(TARGET_CC)" -kexec-extra-sbin-$(CONFIG_KEXEC_TOOLS_kdump) += kdump - define Build/Compile $(MAKE) -C $(PKG_BUILD_DIR) DESTDIR="$(PKG_INSTALL_DIR)" all install endef define Package/kexec-tools/install + : +endef + +define Package/kexec/install $(INSTALL_DIR) $(1)/usr/sbin - $(INSTALL_BIN) \ - $(addprefix $(PKG_INSTALL_DIR)/usr/sbin/, \ - $(kexec-extra-sbin-y)) \ - $(kexec-extra-bin-y) \ - $(PKG_INSTALL_DIR)/usr/sbin/kexec \ - $(1)/usr/sbin + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/kexec $(1)/usr/sbin # make a link for compatability with other distros $(INSTALL_DIR) $(1)/sbin $(LN) ../usr/sbin/kexec $(1)/sbin/kexec endef +define Package/kdump/install + $(INSTALL_DIR) $(1)/usr/sbin $(1)/etc/init.d $(1)/etc/config $(1)/etc/uci-defaults + $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/kdump $(PKG_INSTALL_DIR)/usr/sbin/vmcore-dmesg $(1)/usr/sbin + $(INSTALL_BIN) ./files/kdump.init $(1)/etc/init.d/kdump + $(INSTALL_BIN) ./files/kdump.defaults $(1)/etc/uci-defaults/kdump + $(INSTALL_CONF) ./files/kdump.config $(1)/etc/config/kdump +endef + +define Package/kdump/prerm +#!/bin/sh + +case $$(uname -m) in + i?86|x86_64) + if grep -q " crashkernel=" /boot/grub/grub.cfg; then + mount /boot -o remount,rw + sed -i 's/ crashkernel=[^ ]*//' /boot/grub/grub.cfg + mount /boot -o remount,ro + fi + ;; +esac +endef + $(eval $(call BuildPackage,kexec-tools)) +$(eval $(call BuildPackage,kexec)) +$(eval $(call BuildPackage,kdump)) diff --git a/package/boot/kexec-tools/files/kdump.config b/package/boot/kexec-tools/files/kdump.config new file mode 100644 index 0000000000..dc6054ffdf --- /dev/null +++ b/package/boot/kexec-tools/files/kdump.config @@ -0,0 +1,7 @@ + +config kdump + option enabled '1' + option save_dmesg '1' + option save_vmcore '0' +# using an external partition to store vmcore is highly recommended! +# option path '/mnt/crashdump' diff --git a/package/boot/kexec-tools/files/kdump.defaults b/package/boot/kexec-tools/files/kdump.defaults new file mode 100644 index 0000000000..2f15e757bf --- /dev/null +++ b/package/boot/kexec-tools/files/kdump.defaults @@ -0,0 +1,11 @@ +#!/bin/sh + +case $(uname -m) in + i?86|x86_64) + if ! grep -q crashkernel /boot/grub/grub.cfg; then + mount /boot -o remount,rw + sed -i 's/linux.*/& crashkernel=32M@32M/' /boot/grub/grub.cfg + mount /boot -o remount,ro + fi + ;; +esac diff --git a/package/boot/kexec-tools/files/kdump.init b/package/boot/kexec-tools/files/kdump.init new file mode 100755 index 0000000000..057b8cc17a --- /dev/null +++ b/package/boot/kexec-tools/files/kdump.init @@ -0,0 +1,182 @@ +#!/bin/sh /etc/rc.common + +START=41 +STOP=98 + +EXTRA_COMMANDS="status" +EXTRA_HELP=" status Print crashkernel status" + +verify_kdump() { + local cfg="$1" + local enabled + local path + local save_vmcore + local save_dmesg + + config_get_bool enabled "$cfg" enabled 1 + config_get_bool save_dmesg "$cfg" save_dmesg 1 + config_get_bool save_vmcore "$cfg" save_vmcore 0 + + [ "$enabled" -gt 0 ] || return 2 + + [ "$save_dmesg" -gt 0 ] || [ "$save_vmcore" -gt 0 ] || return 2 + + config_get path "$cfg" path "/" + + [ -d "$path" ] || mkdir -p "$path" 2>/dev/null || return 1 +} + +run_kdump() { + local cfg="$1" + local enabled + local path + local save_vmcore + local save_dmesg + + config_get_bool enabled "$cfg" enabled 1 + [ "$enabled" -gt 0 ] || return + + config_get_bool save_dmesg "$cfg" save_dmesg 1 + config_get_bool save_vmcore "$cfg" save_vmcore 0 + config_get path "$cfg" path "/" + + timestamp=$(date "+%Y%m%dT%H%M%S") + + if [ "$save_vmcore" -eq 1 ]; then + # would like 'sparse' but busybox doesn't support it + dd if=/proc/vmcore of="$path/vmcore-$timestamp" conv=fsync bs=1M + fi + + if [ "$save_dmesg" -eq 1 ]; then + vmcore-dmesg /proc/vmcore > "$path/dmesg-$timestamp" + fi + + sync + reboot -f +} + +find_kernel() { + . /lib/functions.sh + local kernel + + kernel="$BOOT_IMAGE" + if [ -r "$kernel" ]; then + echo $kernel + return 0 + fi + + kernel="$(find_mtd_part kernel)" + if [ -r "$kernel" ]; then + echo $kernel + return 0 + fi + + for voldir in /sys/class/ubi/ubi*_*; do + [ ! -e "$voldir" ] && continue + if [ "$(cat "${voldir}/name")" = "kernel" ]; then + kernel="/dev/$(basename "$voldir")" + echo $kernel + return 0 + fi + done + + return 1 +} + +load_crashkernel() { + local append_cmdline + local kernel + + kernel="$(find_kernel)" + [ $? -gt 0 ] && return 1 + + case "$(uname -m)" in + i?86|x86_64) + grep -q "crashkernel=" /proc/cmdline || return 1 + append_cmdline="1 irqpoll reset_devices maxcpus=1" + ;; + arm*) + append_cmdline="1 maxcpus=1 reset_devices" + ;; + esac + kexec -p "$kernel" --reuse-cmdline --append="$append_cmdline" + return $? +} + +start() { + local retval + + if [ ! -e /sys/kernel/kexec_crash_loaded ]; then + return 1 + fi + + if [ -e /proc/vmcore ]; then + config_load kdump + config_foreach run_kdump kdump + else + config_load kdump + config_foreach verify_kdump kdump + retval=$? + [ $retval = 1 ] && return 1 + [ $retval = 0 ] && load_crashkernel + return $? + fi +} + +stop() { + [ "$(cat /sys/kernel/kexec_crash_loaded)" = "1" ] || return + + if [ -e "$BOOT_IMAGE" ]; then + kexec -p -u "$BOOT_IMAGE" + fi +} + +status() { + local retval kernel + + if [ ! -e /sys/kernel/kexec_crash_loaded ]; then + echo "crashdump not supported by kernel" + return + fi + + if [ $(cat /sys/kernel/kexec_crash_size) -eq 0 ]; then + echo "memory for crashdump kernel not reserved!" + echo "check crashkernel= kernel cmdline parameter" + echo "(a reboot is required after installing kdump)" + return + fi + + kernel="$(find_kernel)" + if [ $? -gt 0 ]; then + echo "cannot find kernel image" + return + else + echo "using kernel image $kernel" + fi + + echo -n "kdump configuration is " + config_load kdump + retval=$? + if [ $retval = 0 ]; then + if [ "$(config_foreach echo kdump)" ]; then + config_foreach verify_kdump kdump + retval=$? + else + retval=1 + fi + fi + + if [ $retval = 0 ]; then + echo "valid" + elif [ $retval = 2 ]; then + echo "disabled" + else + echo "BROKEN" + fi + + echo -n "kexec crash kernel " + if [ "$(cat /sys/kernel/kexec_crash_loaded)" = "0" ]; then + echo -n "not " + fi + echo "loaded" +}