316 lines
7.2 KiB
Bash
316 lines
7.2 KiB
Bash
#! /bin/sh
|
|
#
|
|
# Copyright 2005 Red Hat, Inc.
|
|
# Author: Jeff Moyer <jmoyer@redhat.com>
|
|
# Modifications for SUSE from Chris Mason <mason@suse.com>
|
|
# Takashi Iwai <tiwai@suse.de>
|
|
#
|
|
# 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 $?
|