a9fda5 kdumpctl: Add kdumpctl estimate

Authored and Committed by Kairui Song 3 years ago
    kdumpctl: Add kdumpctl estimate
    
    Resolves: bz1951415
    Upstream: fedora
    Conflict: none
    
    commit e9e6a2c745d41f5447c0062525c0e4f3f489b903
    Author: Kairui Song <kasong@redhat.com>
    Date:   Thu Apr 22 03:27:10 2021 +0800
    
        kdumpctl: Add kdumpctl estimate
    
        Add a rough esitimation support, currently, following memory usage are
        checked by this sub command:
    
        - System RAM
        - Kdump Initramfs size
        - Kdump Kernel image size
        - Kdump Kernel module size
        - Kdump userspace user and other runtime allocated memory (currently
          simply using a fixed value: 64M)
        - LUKS encryption memory usage
    
        The output of kdumpctl estimate looks like this:
          # kdumpctl estimate
          Reserved crashkernel:    256M
          Recommanded crashkernel: 160M
    
          Kernel image size:   47M
          Kernel modules size: 12M
          Initramfs size:      19M
          Runtime reservation: 64M
          Large modules:
              xfs: 1892352
              nouveau: 2318336
    
        And if the kdump target is encrypted:
          # kdumpctl estimate
          Encrypted kdump target requires extra memory, assuming using the keyslot with minimun memory requirement
    
          Reserved crashkernel:    256M
          Recommanded crashkernel: 655M
    
          Kernel image size:   47M
          Kernel modules size: 12M
          Initramfs size:      19M
          Runtime reservation: 64M
          LUKS required size:  512M
          Large modules:
              xfs: 1892352
              nouveau: 2318336
          WARNING: Current crashkernel size is lower than recommanded size 655M.
    
        The "Recommanded" value is calculated based on memory usages mentioned
        above, and will be adjusted accodingly to be no less than the value provided
        by kdump_get_arch_recommend_size.
    
        Signed-off-by: Kairui Song <kasong@redhat.com>
        Acked-by: Pingfan Liu <piliu@redhat.com>
    
    Signed-off-by: Kairui Song <kasong@redhat.com>
    
        
file modified
+71 -0
kdump-lib.sh CHANGED
@@ -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
+ }
file modified
+95 -1
kdumpctl CHANGED
@@ -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
}
file modified
+5 -0
kdumpctl.8 CHANGED
@@ -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),