This patch is based on previous patch series:
[PATCH 0/8] Better support for LUKS targets
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
This will provide user three values as reference,
The output of kdumpctl estimate looks like this:
# kdumpctl estimate
This encrypted kdump target requires extra memory, assuming using the keyslow with
minimun memory requirement
Reserved crashkernel: 256M
Estimated crashkernel: 655M
Recommanded crashkernel: 655M
Kernel image size: 48M
Kernel modules size: 13M
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 654M.
"Reserved crashkernel" is currently reserved crashkernel value.
"Baseline crashkernel" is the crashkernel size when `crashkernel=auto`
is used, based on crashkernel auto rules from RHEL.
"Estimated crashkernel" is the estimate value based on the memory usage
items listed above.
"LUKS required size" is printed only if LUKS2 encryption is used for
dump target and key decryption requires extra memory.
"Recommanded crashkernel" will use the largest value of estimated
crashkernel and the baseline crashkernel.
All values are rounded up and converted to MB.
All modules with static size larger than 1M will be listed as large
module.
Signed-off-by: Kairui Song <kasong(a)redhat.com>
---
Update from v2:
- Update get_kernel_size, if binutils or kernel decompression tools
are not installed, will get kernel size from iomem.
- Add support for detecting LUKS memory requirement.
Update from v1:
- Fix typos
- Remove "Baseline crashkernel:" from output
kdump-lib.sh | 70 +++++++++++++++++++++++++++++++++++
kdumpctl | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 169 insertions(+), 2 deletions(-)
diff --git a/kdump-lib.sh b/kdump-lib.sh
index 0b547a4..ad9fd90 100755
--- a/kdump-lib.sh
+++ b/kdump-lib.sh
@@ -1024,5 +1024,75 @@ get_luks_dev_master_key()
fi
dwarn "Can't get key of LUKS device $(readlink -f /dev/block/$_dev)"
+}
+
+check_vmlinux()
+{
+ # Use readelf to check if it's a valid ELF
+ readelf -h $1 &>/dev/null || return 1
+}
+
+get_vmlinux_size()
+{
+ local size=0
+
+ while read _type _offset _virtaddr _physaddr _fsize _msize _flg _aln; do
+ size=$(( $size + $_msize ))
+ done <<< $(readelf -l -W $1 | grep "^ LOAD" 2>/dev/stderr)
+
+ echo $size
+}
+
+try_decompress()
+{
+ # The obscure use of the "tr" filter is to work around older versions of
+ # "grep" that report the byte offset of the line instead of the pattern.
+
+ # Try to find the header ($1) and decompress from here
+ for pos in `tr "$1\n$2" "\n$2=" < "$4" | grep -abo
"^$2"`
+ do
+ if ! type -P $3 > /dev/null; then
+ ddebug "Signiature detected but '$3' is missing, skip this
decompressor"
+ break
+ fi
+
+ pos=${pos%%:*}
+ tail -c+$pos "$img" | $3 > $5 2> /dev/null
+ if check_vmlinux $5; then
+ ddebug "Kernel is extracted with '$3'"
+ return 0
+ fi
+ done
+
return 1
}
+
+# Borrowed from linux/scripts/extract-vmlinux
+get_kernel_size()
+{
+ # Prepare temp files:
+ local img=$1 tmp=$(mktemp /tmp/vmlinux-XXX)
+ trap "rm -f $tmp" 0
+
+ # Try to check if it's a vmlinux already
+ check_vmlinux $img && get_vmlinux_size $img && return 0
+
+ # That didn't work, so retry after decompression.
+ try_decompress '\037\213\010' xy gunzip $img $tmp || \
+ try_decompress '\3757zXZ\000' abcde unxz $img $tmp || \
+ try_decompress 'BZh' xy bunzip2 $img $tmp || \
+ try_decompress '\135\0\0\0' xxx unlzma $img $tmp || \
+ try_decompress '\211\114\132' xy 'lzop -d' $img $tmp || \
+ try_decompress '\002!L\030' xxx 'lz4 -d' $img $tmp || \
+ try_decompress '(\265/\375' xxx unzstd $img $tmp
+
+ # Finally check for uncompressed images or objects:
+ [[ $? -eq 0 ]] && get_vmlinux_size $tmp && return 0
+
+ # Fallback to use iomem
+ local _size=0
+ for _seg in $(cat /proc/iomem | grep -E "Kernel (code|rodata|data|bss)" |
cut -d ":" -f 1); do
+ _size=$(( $_size + 0x${_seg#*-} - 0x${_seg%-*} ))
+ done
+ echo $_size
+}
diff --git a/kdumpctl b/kdumpctl
index 18c3971..fdedfc6 100755
--- a/kdumpctl
+++ b/kdumpctl
@@ -1314,6 +1314,100 @@ rebuild() {
return $?
}
+do_estimate() {
+ local kdump_mods
+ local -A large_mods
+ local baseline
+ local kernel_size mod_size initrd_size baseline_size runtime_size reserved_size
estimated_size recommanded_size
+ local size_mb=$(( 1024 * 1024 ))
+
+ setup_initrd
+
+ if [ ! -f $TARGET_INITRD ]; then
+ derror "kdumpctl estimate: kdump initramfs is not built yet."
+ exit 1
+ fi
+
+ kdump_mods="$(lsinitrd $TARGET_INITRD -f
/usr/lib/dracut/hostonly-kernel-modules.txt | tr '\n' ' ')"
+
+ baseline=$(kdump_get_arch_recommend_size)
+ if [[ "${baseline: -1}" == "M" ]]; then
+ baseline=${baseline%M}
+ elif [[ "${baseline: -1}" == "G" ]]; then
+ baseline=$(( ${baseline%G} * 1024 ))
+ elif [[ "${baseline: -1}" == "T" ]]; then
+ baseline=$(( ${baseline%Y} * 1048576 ))
+ fi
+
+ # The default value when using crashkernel=auto
+ baseline_size=$(( $baseline * $size_mb ))
+ # Current reserved crashkernel size
+ reserved_size=$(cat /sys/kernel/kexec_crash_size)
+ # A pre-estimated value for userspace usage and kernel
+ # runtime allocation, 64M should good for most cases
+ runtime_size=$(( 64 * $size_mb ))
+ # Kernel image size
+ kernel_size=$(get_kernel_size $KDUMP_KERNEL)
+ # Kdump initramfs size
+ initrd_size=$(du -b $TARGET_INITRD | awk '{print $1}')
+ # Kernel modules size after loaded
+ mod_size=0
+ while read -r _name _size _; do
+ if [[ ! " $kdump_mods " == *" $_name "* ]]; then
+ continue
+ fi
+ mod_size=$(( $mod_size + $_size ))
+
+ # Mark module with static size larger than 2M as large module
+ if [[ $(( $_size / $size_mb )) -ge 1 ]]; then
+ large_mods[$_name]=$_size
+ fi
+ done <<< "$(< /proc/modules)"
+
+ crypt_size=0
+ for _dev in $(get_all_kdump_crypt_dev); do
+ _crypt_info=$(cryptsetup luksDump /dev/block/$_dev)
+ [[ $(echo "$_crypt_info" | sed -n "s/^Version:\s*\(.*\)/\1/p" ) ==
"2" ]] || continue
+ for _mem in $(echo "$_crypt_info" | sed -n
"s/\sMemory:\s*\(.*\)/\1/p" | sort -n ); do
+ crypt_size=$(( $crypt_size + $_mem * 1024 ))
+ break
+ done
+ done
+ [[ $crypt_size -ne 0 ]] && echo -e "Encrypted kdump target requires extra
memory, assuming using the keyslot with minimun memory requirement\n"
+
+ estimated_size=$(( $kernel_size + $mod_size + $initrd_size + $runtime_size + $crypt_size
))
+
+ if [[ $baseline_size -gt $estimated_size ]]; then
+ recommanded_size=$baseline_size
+ else
+ recommanded_size=$estimated_size
+ fi
+
+ echo "Reserved crashkernel: $(( ( $reserved_size + $size_mb - 1 ) / $size_mb
))M"
+ echo "Estimated crashkernel: $(( ( $estimated_size + $size_mb - 1 ) / $size_mb
))M"
+ echo "Recommanded crashkernel: $(( ( $recommanded_size + $size_mb - 1 ) / $size_mb
))M"
+ echo
+ echo "Kernel image size: $(( ( $kernel_size + $size_mb - 1 ) / $size_mb
))M"
+ echo "Kernel modules size: $(( ( $mod_size + $size_mb - 1 ) / $size_mb ))M"
+ echo "Initramfs size: $(( ( $initrd_size + $size_mb - 1 ) / $size_mb
))M"
+ echo "Runtime reservation: $(( ( $runtime_size + $size_mb - 1 ) / $size_mb
))M"
+ [[ $crypt_size -ne 0 ]] && \
+ echo "LUKS required size: $(( ( $crypt_size + $size_mb - 1 ) / $size_mb ))M"
+ echo -n "Large modules:"
+ if [[ "${#large_mods[@]}" -eq 0 ]]; then
+ echo " <none>"
+ else
+ echo ""
+ for _mod in "${!large_mods[@]}"; do
+ echo " $_mod: ${large_mods[$_mod]}"
+ done
+ fi
+
+ if [[ $reserved_size -le $recommanded_size ]]; then
+ echo "WARNING: Current crashkernel size is lower than recommanded size $(( (
$recommanded_size + 1023 ) / $size_mb ))M."
+ fi
+}
+
if [ ! -f "$KDUMP_CONFIG_FILE" ]; then
derror "Error: No kdump config file found!"
exit 1
@@ -1321,7 +1415,7 @@ fi
usage()
{
- dinfo $"Usage: $0 {start|stop|status|restart|reload|rebuild|propagate|showmem}
[--askpass]"
+ dinfo $"Usage: $0
{start|stop|status|restart|reload|rebuild|propagate|showmem|estimate} [--askpass]"
exit 1
}
@@ -1333,7 +1427,7 @@ main()
local cmd
case "$1" in
- condrestart|start|stop|status|restart|reload|rebuild|propagate|showmem)
+ condrestart|start|stop|status|restart|reload|rebuild|propagate|showmem|estimate)
cmd=$1
;;
*)
@@ -1403,6 +1497,9 @@ main()
showmem)
show_reserved_mem
;;
+ estimate)
+ do_estimate
+ ;;
*)
usage
exit 1
--
2.30.2
Show replies by date