From 24eaa7da8f220d3ef6bcbecf2ca44240ee48109d Mon Sep 17 00:00:00 2001 From: Dave Young Date: Sat, 28 Apr 2012 18:01:18 +0800 Subject: [PATCH] port raw dump from rhel6 [v7] Resolves: bz805783 kdumpctl: save_raw if found vmcore mkdumprd: checking available size of raw disk dracut module: do the dumping Note, add a dir /kdumpscripts for monitor_dd_progress and future kdump scripts [v1->v2]: monitor_dd_process become a script instead of a function add missed utils use pipe with dc [v2->v3]: Don: fix dd_progress_file typo Vivek: move [ -f $conf_file ] earlier don't split keyfile= and [ -f keyfile ] move default core_collector earlier move non-makedumpfile warnings to mkdumprd make check available size a common function Amerigo: use less pipe for grep then awk print use shell (( )) instead of dc use cut instead of awk no need install dc and awk make DD_BLKSIZE a variable don't add 0755 file in git, chmod in module-setup.sh [v3->v4]: vivek: kdumpctl multi raw target handling monitor_dd_progress- fix wrong size calculation: the tail -1 of dd pregress file is in bytes instead of blocks only print the whole dd src file size for non-filtered case check [ -b raw target device ] before dump [v4->v5]: vivek: move check [ -b $1 ] before monitor_dd_progress remove multi target function [v5->v6]: vivek: only warning for raw dump of non-makedumpfile core_collector [v6->v7]: kdumpctl should return 0 when there's no raw target Signed-off-by: Dave Young Acked-by: Vivek Goyal --- kdump_dracut_modules/99kdumpbase/kdump.sh | 22 ++- .../99kdumpbase/module-setup.sh | 4 + .../99kdumpbase/monitor_dd_progress | 26 ++++ kdumpctl | 48 ++++++- mkdumprd | 130 +++++++++++------- 5 files changed, 178 insertions(+), 52 deletions(-) create mode 100644 kdump_dracut_modules/99kdumpbase/monitor_dd_progress diff --git a/kdump_dracut_modules/99kdumpbase/kdump.sh b/kdump_dracut_modules/99kdumpbase/kdump.sh index d417b3c..1d666da 100755 --- a/kdump_dracut_modules/99kdumpbase/kdump.sh +++ b/kdump_dracut_modules/99kdumpbase/kdump.sh @@ -4,11 +4,15 @@ set -x KDUMP_PATH="/var/crash" -CORE_COLLECTOR="makedumpfile -d 31 -c" +CORE_COLLECTOR="makedumpfile -c --message-level 1 -d 31" DEFAULT_ACTION="dump_rootfs" DATEDIR=`date +%d.%m.%y-%T` DUMP_INSTRUCTION="" SSH_KEY_LOCATION="/root/.ssh/kdump_id_rsa" +KDUMP_SCRIPT_DIR="/kdumpscripts" +DD_BLKSIZE=512 + +export PATH=$PATH:$KDUMP_SCRIPT_DIR # we use manual setup nics in udev rules, # so we need to test network is really ok @@ -72,8 +76,20 @@ dump_localfs() dump_raw() { + [ -b "$1" ] || return 1 + + echo "Saving to raw disk $1" + if $(echo -n $CORE_COLLECTOR|grep -q makedumpfile); then + _src_size_mb="Unknown" + else + _src_size=`ls -l /proc/vmcore | cut -d' ' -f5` + _src_size_mb=$(($_src_size / 1048576)) + fi + + monitor_dd_progress $_src_size_mb & + CORE_COLLECTOR=`echo $CORE_COLLECTOR | sed -e's/\(^makedumpfile\)\(.*$\)/\1 -F \2/'` - $CORE_COLLECTOR /proc/vmcore | dd of=$1 bs=512 || return 1 + $CORE_COLLECTOR /proc/vmcore | dd of=$1 bs=$DD_BLKSIZE >> /tmp/dd_progress_file 2>&1 || return 1 return 0 } @@ -117,7 +133,7 @@ read_kdump_conf() KDUMP_PATH="$config_val" ;; core_collector) - CORE_COLLECTOR="$config_val" + [ -n "$config_val" ] && CORE_COLLECTOR="$config_val" ;; sshkey) if [ -f "$config_val" ]; then diff --git a/kdump_dracut_modules/99kdumpbase/module-setup.sh b/kdump_dracut_modules/99kdumpbase/module-setup.sh index f1d1336..f7b3a2c 100755 --- a/kdump_dracut_modules/99kdumpbase/module-setup.sh +++ b/kdump_dracut_modules/99kdumpbase/module-setup.sh @@ -86,6 +86,10 @@ install() { esac done < /etc/kdump.conf + inst "$moddir/monitor_dd_progress" "/kdumpscripts/monitor_dd_progress" + chmod +x ${initdir}/kdumpscripts/monitor_dd_progress + inst "/bin/dd" "/bin/dd" + inst "/bin/tail" "/bin/tail" inst "/bin/date" "/bin/date" inst "/bin/sync" "/bin/sync" inst "/bin/cut" "/bin/cut" diff --git a/kdump_dracut_modules/99kdumpbase/monitor_dd_progress b/kdump_dracut_modules/99kdumpbase/monitor_dd_progress new file mode 100644 index 0000000..01a1567 --- /dev/null +++ b/kdump_dracut_modules/99kdumpbase/monitor_dd_progress @@ -0,0 +1,26 @@ +#!/bin/sh + +SRC_FILE_MB=$1 + +while true +do + DD_PID=`pidof dd` + if [ -n "$DD_PID" ]; then + break + fi +done + +while true +do + sleep 5 + if [ ! -d /proc/$DD_PID ]; then + break + fi + + kill -s USR1 $DD_PID + CURRENT_SIZE=`tail -n 1 /tmp/dd_progress_file | sed "s/[^0-9].*//g"` + CURRENT_MB=$(($CURRENT_SIZE / 1048576)) + echo -n -e "Copied $CURRENT_MB MB / $SRC_FILE_MB MB\r" +done + +rm -f /tmp/dd_progress_file diff --git a/kdumpctl b/kdumpctl index 420265f..95f03bc 100755 --- a/kdumpctl +++ b/kdumpctl @@ -281,6 +281,41 @@ function status() fi } +function save_raw() +{ + local kdump_dir + local raw_target + + raw_target=$(awk '$1 ~ /^raw$/ { print $2; }' $KDUMP_CONFIG_FILE) + [ -z "$raw_target" ] && return 0 + [ -b "$raw_target" ] || { + echo "raw partition $raw_target not found" + return 1 + } + kdump_dir=`grep ^path $KDUMP_CONFIG_FILE | cut -d' ' -f2-` + if [ -z "${kdump_dir}" ]; then + coredir="/var/crash/`date +"%Y-%m-%d-%H:%M"`" + else + coredir="${kdump_dir}/`date +"%Y-%m-%d-%H:%M"`" + fi + + mkdir -p "$coredir" + [ -d "$coredir" ] || { + echo "failed to create $coredir" + return 1 + } + if makedumpfile -R $coredir/vmcore <$raw_target >/dev/null 2>&1; then + # dump found + echo "Dump saved to $coredir/vmcore" + # wipe makedumpfile header + dd if=/dev/zero of=$raw_target bs=1b count=1 2>/dev/null + else + rm -rf "$coredir" + fi + + return 0 +} + function start() { local nr @@ -290,7 +325,13 @@ function start() return 1 } - #TODO check raw partition for core dump image + save_raw + if [ $? -ne 0 ]; then + echo -n "Starting kdump:"; echo + $LOGGER "failed to start up" + return 1 + fi + status rc=$? if [ $rc == 2 ]; then @@ -338,6 +379,11 @@ function stop() fi } +if [ ! -f "$KDUMP_CONFIG_FILE" ]; then + echo -n "No kdump config file found!"; echo + exit 1 +fi + case "$1" in start) if [ -s /proc/vmcore ]; then diff --git a/mkdumprd b/mkdumprd index 384d0f9..15a45aa 100644 --- a/mkdumprd +++ b/mkdumprd @@ -33,6 +33,33 @@ add_dracut_sshkey() { add_dracut_arg "--sshkey" "$1" } +#Function: get_raw_size +#$1=dump target +get_raw_size() { + echo -n $(fdisk -s "$1") +} + +#Function: check_size +#$1: dump type string ('raw', 'local', 'ssh', 'nfs') +#$2: dump target +check_size() { + local avail memtotal + + memtotal=$(awk '/MemTotal/{print $2}' /proc/meminfo) + case "$1" in + raw) + avail=$(get_raw_size "$2") + ;; + *) + return + esac + + if [ $avail -lt $memtotal ]; then + echo "Warning: There is not enough space to save a vmcore." + echo " The size of $2 should be much greater than $memtotal kilo bytes." + fi +} + while [ $# -gt 0 ]; do case $1 in -d) @@ -98,60 +125,67 @@ add_mount() { } add_dracut_mount "$(to_mount "$(get_rootdev)")" -if [ -n "$conf_file" ]; then - # firstly get right SSH_KEY_LOCATION - keyfile=$(awk '/sshkey/ {print $2}' $conf_file) - if [ -f "$keyfile" ]; then - # canonicalize the path - SSH_KEY_LOCATION=$(/usr/bin/readlink -m $keyfile) - fi - while read config_opt config_val; - do - case "$config_opt" in - extra_modules) - extra_modules="$extra_modules $config_val" - ;; - ext[234]|xfs|btrfs|minix) +# firstly get right SSH_KEY_LOCATION +keyfile=$(awk '/sshkey/ {print $2}' $conf_file) +if [ -f "$keyfile" ]; then + # canonicalize the path + SSH_KEY_LOCATION=$(/usr/bin/readlink -m $keyfile) +fi + +while read config_opt config_val; +do + case "$config_opt" in + extra_modules) + extra_modules="$extra_modules $config_val" + ;; + ext[234]|xfs|btrfs|minix) + add_mount "$config_val" + if [ $? -ne 0 ]; then + echo "Dump target $config_val is probably not mounted." + exit 1 + fi + ;; + raw) + #checking raw disk writable + dd if=$config_val count=1 of=/dev/null > /dev/null 2>&1 || { + echo "Bad raw disk $config_val" + exit 1 + } + check_size raw $config_val + ;; + net) + check_remote "$config_val" + if strstr "$config_val" "@"; + then + add_dracut_module "ssh-client" + add_dracut_sshkey "$SSH_KEY_LOCATION" + else + add_dracut_module "nfs" add_mount "$config_val" if [ $? -ne 0 ]; then echo "Dump target $config_val is probably not mounted." exit 1 fi - ;; - raw) - #TODO - ;; - net) - check_remote "$config_val" - if strstr "$config_val" "@"; - then - add_dracut_module "ssh-client" - add_dracut_sshkey "$SSH_KEY_LOCATION" - else - add_dracut_module "nfs" - add_mount "$config_val" - if [ $? -ne 0 ]; then - echo "Dump target $config_val is probably not mounted." - exit 1 - fi - fi - ;; - core_collector) - add_dracut_arg "-I" "${config_val%% *}" - ;; - extra_bins) - add_dracut_arg "-I" "$config_val" - ;; - *) - if [ -n $(echo $config_opt | grep "^#.*$") ] - then - continue - fi - ;; - esac - done < $conf_file -fi + fi + ;; + core_collector) + if grep -q "^raw" $conf_file && [ "${config_val%% *}" != "makedumpfile" ]; then + echo "Warning: specifying a non-makedumpfile core collector, you will have to recover the vmcore manually." + fi + add_dracut_arg "-I" "${config_val%% *}" + ;; + extra_bins) + add_dracut_arg "-I" "$config_val" + ;; + *) + if [ -n $(echo $config_opt | grep "^#.*$") ] + then + continue + fi + ;; + esac +done < $conf_file if [ -n "$extra_modules" ] then