#! /bin/sh # # Copyright 2005 Red Hat, Inc. # Author: Jeff Moyer # Modifications for SUSE from Chris Mason # Takashi Iwai # # kdump # # Description: The kdump init script provides the support necessary for # loading a kdump kernel into memory at system bootup time, # and for copying away a vmcore at system panic time. # # # /etc/init.d/kexec ### BEGIN INIT INFO # Provides: kdump # Required-Start: boot.localfs $remote_fs # Should-Start: # Required-Stop: # Default-Start: 1 2 3 5 # Default-Stop: # Description: kdump core saving and boot configuration ### END INIT INFO . /etc/sysconfig/kdump . /etc/rc.status KEXEC=/sbin/kexec KDUMP_HELPER=/usr/sbin/kdump-helper BOOTDIR="/boot" # purge old dump directories if the number of directories # exceeds $KDUMP_KEEP_OLD_DUMPS purge_old_dumps() { dirs=`ls -d $KDUMP_SAVEDIR/*-*-*-*:* 2>/dev/null | sort` numdirs=`echo $dirs | wc -w` for d in $dirs; do if [ $numdirs -le $KDUMP_KEEP_OLD_DUMPS ]; then break; fi echo " Expiring old dump $d" rm -rf $d numdirs=`expr $numdirs - 1` done } # get the free disk space of the given directory in MB parse_rest_size() { test -d "$1" || mkdir -p "$1" hdread="" df -P "$1" | while read fs bl us av rest; do test -n "$hdread" && expr $av / 1024 hdread="$fs" done } # get vmcore size in MB get_mem_size() { s=`stat -c '%s' /proc/vmcore` expr \( $s + 1048575 \) / 1048576 } # The default dumper # # Clean up old stuff if necessary, check the free size # and save the vmcore save_core() { if [ $KDUMP_KEEP_OLD_DUMPS -gt 0 ]; then purge_old_dumps fi if [ $KDUMP_FREE_DISK_SIZE -gt 0 ]; then restsize=`parse_rest_size "$KDUMP_SAVEDIR"` needsize=`get_mem_size` needsize=`expr $needsize + $KDUMP_FREE_DISK_SIZE` if [ $restsize -lt $needsize ]; then echo -n " No enough space left on dump device ($restsize MB)" rc_status -s rc_failed 6 return fi fi coredir="${KDUMP_SAVEDIR}/`date +"%Y-%m-%d-%H:%M"`" mkdir -p $coredir echo -n "Saving crash dump to $coredir" cp --sparse=always /proc/vmcore $coredir/vmcore rc_status -v } # print the available kdump kernel path # empty if no matching file is found check_boot_kernel () { local kstr kstr="${BOOTDIR}/vmlinux-$1$2" if [ -f $kstr ]; then echo $kstr return fi kstr="$kstr.gz" if [ -f $kstr ]; then echo $kstr return fi case `uname -i` in ia64) # ia64 uses vmlinuz as of vmlinux.gz kstr="${BOOTDIR}/vmlinuz-$1$2" if [ -f $kstr ]; then echo $kstr return fi ;; esac } # Load the kdump kerel specified in /etc/sysconfig/kdump # If none is specified, try to load a kdump kernel with the same version # as the currently running kernel. load_kdump() { echo -n "Loading kdump " if [ -z "$KDUMP_KERNELVER" ]; then kdump_kver=`uname -r | sed -e's/-[^-]*$//g'` kdump_kernel=`check_boot_kernel $kdump_kver -kdump` if [ -n "$kdump_kernel" ]; then kdump_kver="${kdump_kver}-kdump" elif [ -z "$kdump_kernel" ]; then kdump_kver=`uname -r` kdump_kernel=`check_boot_kernel $kdump_kver` fi else kdump_kver="$KDUMP_KERNELVER" kdump_kernel=`check_boot_kernel $kdump_kver` fi if [ -z "$kdump_kernel" -o ! -f "$kdump_kernel" ]; then echo -n ": No kdump kernel image found for kernel $kdump_kver." rc_status -s rc_failed 6 rc_exit fi kdump_initrd="${BOOTDIR}/initrd-${kdump_kver}" if [ ! -f $kdump_initrd ]; then echo -n ": No kdump initial ramdisk found." echo "Tried to locate ${kdump_initrd}" rc_status -s rc_failed 6 rc_exit fi if [ -z "$KDUMP_COMMANDLINE" ]; then KDUMP_COMMANDLINE=`cat /proc/cmdline | \ sed -e 's/crashkernel=[0-9]\+[mM]\(@[0-9]\+[Mm]\?\)\?//g' \ -e 's/ *splash=[^ ]*/ /g' \ -e 's/ *BOOT_IMAGE=[^ ]* / /g' \ -e 's/ *showopts/ /g'` # Use deadline for saving the memory footprint KDUMP_COMMANDLINE="$KDUMP_COMMANDLINE elevator=deadline sysrq=1" case `uname -i` in i?86|x86_64|ia64) KDUMP_COMMANDLINE="$KDUMP_COMMANDLINE irqpoll" ;; esac fi KDUMP_COMMANDLINE="CRASH=1 $KDUMP_COMMANDLINE" if [ -n "$KDUMP_COMMANDLINE_APPEND" ] ; then KDUMP_COMMANDLINE="$KDUMP_COMMANDLINE $KDUMP_COMMANDLINE_APPEND" fi if [ -n "$KDUMP_RUNLEVEL" ]; then case "$KDUMP_RUNLEVEL" in [1-5s]) KDUMP_COMMANDLINE="$KDUMP_COMMANDLINE $KDUMP_RUNLEVEL" ;; *) echo " : Invalid KDUMP_RUNLEVEL=$KDUMP_RUNLEVEL, ignored" ;; esac fi # add the dump device if [ -n "$KDUMP_DUMPDEV" ] ; then KDUMP_COMMANDLINE="dumpdev=$KDUMP_DUMPDEV $KDUMP_COMMANDLINE" fi echo 1 > /proc/sys/kernel/panic_on_oops $KEXEC -p $kdump_kernel \ --append="$KDUMP_COMMANDLINE" \ --initrd=$kdump_initrd \ $KEXEC_OPTIONS rc_status -v } # return success if running in a crash environemnt is_crash_kernel () { test -f /proc/vmcore || return 1 # FIXME: any better way to detect crash environment? test -n "$CRASH" && return 0 case `uname -i` in ia64) # ia64 has no kdump kernel return 1;; esac return 0 } # return success if we have a valid dump on the dump device have_valid_dump_in_dumpdev () { if [ ! -b "$KDUMP_DUMPDEV" ] ; then return 1 fi # return the return code from this command $KDUMP_HELPER -c "$KDUMP_DUMPDEV" >> /dev/null } # invalidate the dump device so that it's not read on next boot invalidate_dumpdev () { dd if=/dev/zero of=$KDUMP_DUMPDEV bs=512 count=1 } # copy the dump from the dumpdevice to the harddisk copy_dump_from_dumpdev () { if [ $KDUMP_KEEP_OLD_DUMPS -gt 0 ]; then purge_old_dumps fi dumpsize=`$KDUMP_HELPER -l "$KDUMP_DUMPDEV" | sed -e 's/Length: //g'` dumpsize_mb=$(($dumpsize / 1024 / 1024)) if [ $KDUMP_FREE_DISK_SIZE -gt 0 ]; then restsize=`parse_rest_size "$KDUMP_SAVEDIR"` needsize=`expr $dumpsize_mb + $KDUMP_FREE_DISK_SIZE` if [ $restsize -lt $needsize ]; then echo -n " No enough space left on dump device ($restsize MB)" rc_status -s rc_failed 6 return fi fi coredir="${KDUMP_SAVEDIR}/`date +"%Y-%m-%d-%H:%M"`" mkdir -p $coredir echo -n "Saving crash dump to $coredir" dd if=$KDUMP_DUMPDEV of=$coredir/vmcore count=$dumpsize invalidate_dumpdev } case "$1" in start) if is_crash_kernel; then if [ -z "$KDUMP_DUMPDEV" ] ; then if [ -n "$KDUMP_TRANSFER" ]; then $KDUMP_TRANSFER else save_core fi fi if test "$KDUMP_IMMEDIATE_REBOOT" = "yes"; then /sbin/reboot # sleep to avoid the conflict with script "single" sleep 600 fi else if have_valid_dump_in_dumpdev ; then copy_dump_from_dumpdev fi load_kdump fi ;; stop) if [ ! -f /proc/vmcore ]; then if [ "$RUNLEVEL" != "" ]; then echo -n "Not unloading kdump during runlevel changes" rc_status -s else echo -n "Unloading kdump" $KEXEC -p -u rc_status -v fi fi ;; status) echo "not implemented" ;; restart|reload) $0 stop $0 start ;; condrestart) ;; *) echo $"Usage: $0 {start|stop|status|restart|reload}" exit 1 esac exit $?