a9fda5
kdumpctl: Add kdumpctl estimate
@@ -977,3 +977,74 @@ get_all_kdump_crypt_dev()
|
|
977
977
|
[[ -n "$_crypt" ]] && echo $_crypt
|
978
978
|
done
|
979
979
|
}
|
980
|
+
|
981
|
+
check_vmlinux()
|
982
|
+
{
|
983
|
+
# Use readelf to check if it's a valid ELF
|
984
|
+
readelf -h $1 &>/dev/null || return 1
|
985
|
+
}
|
986
|
+
|
987
|
+
get_vmlinux_size()
|
988
|
+
{
|
989
|
+
local size=0
|
990
|
+
|
991
|
+
while read _type _offset _virtaddr _physaddr _fsize _msize _flg _aln; do
|
992
|
+
size=$(( $size + $_msize ))
|
993
|
+
done <<< $(readelf -l -W $1 | grep "^ LOAD" 2>/dev/stderr)
|
994
|
+
|
995
|
+
echo $size
|
996
|
+
}
|
997
|
+
|
998
|
+
try_decompress()
|
999
|
+
{
|
1000
|
+
# The obscure use of the "tr" filter is to work around older versions of
|
1001
|
+
# "grep" that report the byte offset of the line instead of the pattern.
|
1002
|
+
|
1003
|
+
# Try to find the header ($1) and decompress from here
|
1004
|
+
for pos in `tr "$1\n$2" "\n$2=" < "$4" | grep -abo "^$2"`
|
1005
|
+
do
|
1006
|
+
if ! type -P $3 > /dev/null; then
|
1007
|
+
ddebug "Signiature detected but '$3' is missing, skip this decompressor"
|
1008
|
+
break
|
1009
|
+
fi
|
1010
|
+
|
1011
|
+
pos=${pos%%:*}
|
1012
|
+
tail -c+$pos "$img" | $3 > $5 2> /dev/null
|
1013
|
+
if check_vmlinux $5; then
|
1014
|
+
ddebug "Kernel is extracted with '$3'"
|
1015
|
+
return 0
|
1016
|
+
fi
|
1017
|
+
done
|
1018
|
+
|
1019
|
+
return 1
|
1020
|
+
}
|
1021
|
+
|
1022
|
+
# Borrowed from linux/scripts/extract-vmlinux
|
1023
|
+
get_kernel_size()
|
1024
|
+
{
|
1025
|
+
# Prepare temp files:
|
1026
|
+
local img=$1 tmp=$(mktemp /tmp/vmlinux-XXX)
|
1027
|
+
trap "rm -f $tmp" 0
|
1028
|
+
|
1029
|
+
# Try to check if it's a vmlinux already
|
1030
|
+
check_vmlinux $img && get_vmlinux_size $img && return 0
|
1031
|
+
|
1032
|
+
# That didn't work, so retry after decompression.
|
1033
|
+
try_decompress '\037\213\010' xy gunzip $img $tmp || \
|
1034
|
+
try_decompress '\3757zXZ\000' abcde unxz $img $tmp || \
|
1035
|
+
try_decompress 'BZh' xy bunzip2 $img $tmp || \
|
1036
|
+
try_decompress '\135\0\0\0' xxx unlzma $img $tmp || \
|
1037
|
+
try_decompress '\211\114\132' xy 'lzop -d' $img $tmp || \
|
1038
|
+
try_decompress '\002!L\030' xxx 'lz4 -d' $img $tmp || \
|
1039
|
+
try_decompress '(\265/\375' xxx unzstd $img $tmp
|
1040
|
+
|
1041
|
+
# Finally check for uncompressed images or objects:
|
1042
|
+
[[ $? -eq 0 ]] && get_vmlinux_size $tmp && return 0
|
1043
|
+
|
1044
|
+
# Fallback to use iomem
|
1045
|
+
local _size=0
|
1046
|
+
for _seg in $(cat /proc/iomem | grep -E "Kernel (code|rodata|data|bss)" | cut -d ":" -f 1); do
|
1047
|
+
_size=$(( $_size + 0x${_seg#*-} - 0x${_seg%-*} ))
|
1048
|
+
done
|
1049
|
+
echo $_size
|
1050
|
+
}
|
@@ -1214,6 +1214,97 @@ rebuild() {
|
|
1214
1214
|
return $?
|
1215
1215
|
}
|
1216
1216
|
|
1217
|
+
do_estimate() {
|
1218
|
+
local kdump_mods
|
1219
|
+
local -A large_mods
|
1220
|
+
local baseline
|
1221
|
+
local kernel_size mod_size initrd_size baseline_size runtime_size reserved_size estimated_size recommanded_size
|
1222
|
+
local size_mb=$(( 1024 * 1024 ))
|
1223
|
+
|
1224
|
+
setup_initrd
|
1225
|
+
if [ ! -f "$TARGET_INITRD" ]; then
|
1226
|
+
derror "kdumpctl estimate: kdump initramfs is not built yet."
|
1227
|
+
exit 1
|
1228
|
+
fi
|
1229
|
+
|
1230
|
+
kdump_mods="$(lsinitrd "$TARGET_INITRD" -f /usr/lib/dracut/hostonly-kernel-modules.txt | tr '\n' ' ')"
|
1231
|
+
baseline=$(kdump_get_arch_recommend_size)
|
1232
|
+
if [[ "${baseline: -1}" == "M" ]]; then
|
1233
|
+
baseline=${baseline%M}
|
1234
|
+
elif [[ "${baseline: -1}" == "G" ]]; then
|
1235
|
+
baseline=$(( ${baseline%G} * 1024 ))
|
1236
|
+
elif [[ "${baseline: -1}" == "T" ]]; then
|
1237
|
+
baseline=$(( ${baseline%Y} * 1048576 ))
|
1238
|
+
fi
|
1239
|
+
|
1240
|
+
# The default value when using crashkernel=auto
|
1241
|
+
baseline_size=$((baseline * size_mb))
|
1242
|
+
# Current reserved crashkernel size
|
1243
|
+
reserved_size=$(cat /sys/kernel/kexec_crash_size)
|
1244
|
+
# A pre-estimated value for userspace usage and kernel
|
1245
|
+
# runtime allocation, 64M should good for most cases
|
1246
|
+
runtime_size=$((64 * size_mb))
|
1247
|
+
# Kernel image size
|
1248
|
+
kernel_size=$(get_kernel_size "$KDUMP_KERNEL")
|
1249
|
+
# Kdump initramfs size
|
1250
|
+
initrd_size=$(du -b "$TARGET_INITRD" | awk '{print $1}')
|
1251
|
+
# Kernel modules static size after loaded
|
1252
|
+
mod_size=0
|
1253
|
+
while read -r _name _size _; do
|
1254
|
+
if [[ ! " $kdump_mods " == *" $_name "* ]]; then
|
1255
|
+
continue
|
1256
|
+
fi
|
1257
|
+
mod_size=$((mod_size + _size))
|
1258
|
+
|
1259
|
+
# Mark module with static size larger than 2M as large module
|
1260
|
+
if [[ $((_size / size_mb)) -ge 1 ]]; then
|
1261
|
+
large_mods[$_name]=$_size
|
1262
|
+
fi
|
1263
|
+
done <<< "$(< /proc/modules)"
|
1264
|
+
|
1265
|
+
# Extra memory usage required for LUKS2 decryption
|
1266
|
+
crypt_size=0
|
1267
|
+
for _dev in $(get_all_kdump_crypt_dev); do
|
1268
|
+
_crypt_info=$(cryptsetup luksDump "/dev/block/$_dev")
|
1269
|
+
[[ $(echo "$_crypt_info" | sed -n "s/^Version:\s*\(.*\)/\1/p" ) == "2" ]] || continue
|
1270
|
+
for _mem in $(echo "$_crypt_info" | sed -n "s/\sMemory:\s*\(.*\)/\1/p" | sort -n ); do
|
1271
|
+
crypt_size=$((crypt_size + _mem * 1024))
|
1272
|
+
break
|
1273
|
+
done
|
1274
|
+
done
|
1275
|
+
[[ $crypt_size -ne 0 ]] && echo -e "Encrypted kdump target requires extra memory, assuming using the keyslot with minimun memory requirement\n"
|
1276
|
+
|
1277
|
+
estimated_size=$((kernel_size + mod_size + initrd_size + runtime_size + crypt_size))
|
1278
|
+
if [[ $baseline_size -gt $estimated_size ]]; then
|
1279
|
+
recommanded_size=$baseline_size
|
1280
|
+
else
|
1281
|
+
recommanded_size=$estimated_size
|
1282
|
+
fi
|
1283
|
+
|
1284
|
+
echo "Reserved crashkernel: $((reserved_size / size_mb))M"
|
1285
|
+
echo "Recommanded crashkernel: $((recommanded_size / size_mb))M"
|
1286
|
+
echo
|
1287
|
+
echo "Kernel image size: $((kernel_size / size_mb))M"
|
1288
|
+
echo "Kernel modules size: $((mod_size / size_mb))M"
|
1289
|
+
echo "Initramfs size: $((initrd_size / size_mb))M"
|
1290
|
+
echo "Runtime reservation: $((runtime_size / size_mb))M"
|
1291
|
+
[[ $crypt_size -ne 0 ]] && \
|
1292
|
+
echo "LUKS required size: $((crypt_size / size_mb))M"
|
1293
|
+
echo -n "Large modules:"
|
1294
|
+
if [[ "${#large_mods[@]}" -eq 0 ]]; then
|
1295
|
+
echo " <none>"
|
1296
|
+
else
|
1297
|
+
echo ""
|
1298
|
+
for _mod in "${!large_mods[@]}"; do
|
1299
|
+
echo " $_mod: ${large_mods[$_mod]}"
|
1300
|
+
done
|
1301
|
+
fi
|
1302
|
+
|
1303
|
+
if [[ $reserved_size -lt $recommanded_size ]]; then
|
1304
|
+
echo "WARNING: Current crashkernel size is lower than recommanded size $((recommanded_size / size_mb))M."
|
1305
|
+
fi
|
1306
|
+
}
|
1307
|
+
|
1217
1308
|
if [ ! -f "$KDUMP_CONFIG_FILE" ]; then
|
1218
1309
|
derror "Error: No kdump config file found!"
|
1219
1310
|
exit 1
|
@@ -1269,8 +1360,11 @@ main ()
|
|
1269
1360
|
showmem)
|
1270
1361
|
show_reserved_mem
|
1271
1362
|
;;
|
1363
|
+
estimate)
|
1364
|
+
do_estimate
|
1365
|
+
;;
|
1272
1366
|
*)
|
1273
|
-
dinfo $"Usage: $0 {start|stop|status|restart|reload|rebuild|propagate|showmem}"
|
1367
|
+
dinfo $"Usage: $0 {estimate|start|stop|status|restart|reload|rebuild|propagate|showmem}"
|
1274
1368
|
exit 1
|
1275
1369
|
esac
|
1276
1370
|
}
|
@@ -44,6 +44,11 @@ impossible to use password authentication during kdump.
|
|
44
44
|
.TP
|
45
45
|
.I showmem
|
46
46
|
Prints the size of reserved memory for crash kernel in megabytes.
|
47
|
+
.TP
|
48
|
+
.I estimate
|
49
|
+
Estimate a suitable crashkernel value for current machine. This is a
|
50
|
+
best-effort estimate. It will print a recommanded crashkernel value
|
51
|
+
based on current kdump setup, and list some details of memory usage.
|
47
52
|
|
48
53
|
.SH "SEE ALSO"
|
49
54
|
.BR kdump.conf (5),
|