Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gen-kdump-sysconfig.sh
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ fi
#
# Generate the config file
#
cat <<EOF
cat << EOF
# Kernel Version string for the -kdump kernel, such as 2.6.13-1544.FC5kdump
# If no version is specified, then the init script will try to find a
# kdump kernel with the same version number as the running kernel.
Expand Down
55 changes: 47 additions & 8 deletions kdump-lib.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ FADUMP_REGISTER_SYS_NODE="/sys/kernel/fadump/registered"
FADUMP_APPEND_ARGS_SYS_NODE="/sys/kernel/fadump/bootargs_append"
# shellcheck disable=SC2034
FENCE_KDUMP_CONFIG_FILE="/etc/sysconfig/fence_kdump"
maximize_crashkernel=false

is_fadump_capable()
{
Expand All @@ -35,7 +36,26 @@ is_aws_aarch64()

is_sme_or_sev_active()
{
journalctl -q --dmesg --grep "^Memory Encryption Features active: AMD (SME|SEV)$" > /dev/null 2>&1
$maximize_crashkernel || journalctl -q --dmesg --grep "^Memory Encryption Features active: AMD (SME|SEV)$" > /dev/null 2>&1
}

# read the value of an environ variable from given environ file path
#
# The environment variable entries in /proc/[pid]/environ are separated
# by null bytes instead of by spaces.
#
# $1: environment variable
# $2: environ file path
read_proc_environ_var()
{
local _var=$1 _environ_path=$2
sed -n -E "s/.*(^|\x00)${_var}=([^\x00]*).*/\2/p" < "$_environ_path"
}

_OSBUILD_ENVIRON_PATH='/proc/1/environ'
_is_osbuild()
{
[[ $(read_proc_environ_var container "$_OSBUILD_ENVIRON_PATH") == bwrap-osbuild ]]
}

has_command()
Expand Down Expand Up @@ -831,12 +851,19 @@ get_recommend_size()

has_mlx5()
{
[[ -d /sys/bus/pci/drivers/mlx5_core ]]
$maximize_crashkernel || [[ -d /sys/bus/pci/drivers/mlx5_core ]]
}

has_aarch64_smmu()
{
ls /sys/devices/platform/arm-smmu-* 1> /dev/null 2>&1
$maximize_crashkernel || ls /sys/devices/platform/arm-smmu-* 1> /dev/null 2>&1
}

is_aarch64_64k_kernel()
{
local _kernel="$1"
# the naming convention of 64k variant suffixes with +64k, e.g. "vmlinuz-5.14.0-312.el9.aarch64+64k"
$maximize_crashkernel || echo "$_kernel" | grep -q 64k
}

is_memsize()
Expand Down Expand Up @@ -946,13 +973,16 @@ _crashkernel_parse()

# $1 crashkernel command line parameter
# $2 size to be added
# $3 optionally skip the first n items in command line
_crashkernel_add()
{
local ck delta ret
local ck delta skip ret
local range size offset
local count=0

ck="$1"
delta="$2"
skip="${3:-0}" # Default to 0 if third parameter not provided
ret=""

while IFS=';' read -r size range offset; do
Expand All @@ -967,8 +997,12 @@ _crashkernel_add()
ret+="$range:"
fi

size=$(memsize_add "$size" "$delta") || return 1
if ((count >= skip)); then
size=$(memsize_add "$size" "$delta") || return 1
fi

ret+="$size,"
((count++))
done < <(_crashkernel_parse "$ck")

echo "${ret%,}"
Expand All @@ -982,7 +1016,11 @@ kdump_get_arch_recommend_crashkernel()
{
local _arch _ck_cmdline _dump_mode
local _delta=0
local _skip=0

# osbuild deploys rpm on isolated environment. kdump-utils has no opportunity
# to deduce the exact memory cost on the real target.
_is_osbuild && maximize_crashkernel=true
if [[ -z $1 ]]; then
if is_fadump_capable; then
_dump_mode=fadump
Expand All @@ -1008,9 +1046,10 @@ kdump_get_arch_recommend_crashkernel()
else
_running_kernel=$2
fi
# skip adding additional memory for small-memory machine
_skip=1

# the naming convention of 64k variant suffixes with +64k, e.g. "vmlinuz-5.14.0-312.el9.aarch64+64k"
if echo "$_running_kernel" | grep -q 64k; then
if is_aarch64_64k_kernel "$_running_kernel"; then
# Without smmu, the diff of MemFree between 4K and 64K measured on a high end aarch64 machine is 82M.
# Picking up 100M to cover this diff. And finally, we have "2G-4G:356M;4G-64G:420M;64G-:676M"
((_delta += 100))
Expand All @@ -1031,7 +1070,7 @@ kdump_get_arch_recommend_crashkernel()
fi
fi

echo -n "$(_crashkernel_add "$_ck_cmdline" "${_delta}M")"
echo -n "$(_crashkernel_add "$_ck_cmdline" "${_delta}M" "$_skip")"
}

# return recommended size based on current system RAM size
Expand Down
67 changes: 48 additions & 19 deletions kdumpctl
Original file line number Diff line number Diff line change
Expand Up @@ -1210,6 +1210,53 @@ prepare_luks()
done
}

get_crashkernel_bounce_buffer_size()
{
local lines first_line start_hex end_hex start_dec end_dec size_bytes

mapfile -t lines < <(grep "Crash kernel" /proc/iomem)

if [ ${#lines[@]} -le 1 ]; then
echo 0
return
fi

first_line=${lines[0]}
# Extract start and end addresses
start_hex=$(echo "$first_line" | awk '{split($1, a, "-"); print a[1]}')
end_hex=$(echo "$first_line" | awk '{split($1, a, "-"); print a[2]}')
Comment on lines +1226 to +1227
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

These two lines invoke awk twice on the same input ($first_line) to extract the start and end addresses. This is inefficient. You can achieve the same result with a single awk command and read, which is cleaner and more performant.

Suggested change
start_hex=$(echo "$first_line" | awk '{split($1, a, "-"); print a[1]}')
end_hex=$(echo "$first_line" | awk '{split($1, a, "-"); print a[2]}')
read -r start_hex end_hex < <(echo "$first_line" | awk '{split($1, a, "-"); print a[1], a[2]}')

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @pfliu this suggestion from Gemini seems to make sense, what do you think?

# Convert hex to decimal
start_dec=$((0x$start_hex))
end_dec=$((0x$end_hex))
# Calculate size in bytes
size_bytes=$((end_dec - start_dec + 1))
echo "$size_bytes"
}

suggest_crashkernel_reset()
{
local _crashkernel _recommend_value _actual_value _bounce_buff_size

_crashkernel=$(sed -n 's/.*crashkernel=\([^ ]*\).*/\1/p' /proc/cmdline)
[[ $(kdump_get_conf_val auto_reset_crashkernel) == no ]] && return
# At present, the crashkernel value for fadump is not dynamic
is_fadump_capable && return

_recommend_value=$(kdump_get_arch_recommend_size)
# The crashkernel formula does not account for DMA-bounce buffers,
# unlike kexec_crash_size which does. Systems using DMA-bounce buffers
# should factor this into the calculation.
_bounce_buff_size=$(get_crashkernel_bounce_buffer_size)
_recommend_value=$(memsize_add "$_recommend_value" "$_bounce_buff_size")
_recommend_value=$(to_bytes "$_recommend_value")
_actual_value=$(cat /sys/kernel/kexec_crash_size)

if [ "$_recommend_value" -lt "$_actual_value" ]; then
dwarn "The reserved crashkernel is abundant. Using 'kdumpctl reset-crashkernel' to reset kernel cmdline. It will take effect in the next boot"
dwarn "To release the abundant memory immediately, you can run: 'kdumpctl stop; echo $_recommend_value >/sys/kernel/kexec_crash_size; kdumpctl start'"
fi
}

start()
{
check_dump_feasibility || return
Expand Down Expand Up @@ -1243,6 +1290,7 @@ start()
start_dump || return

dinfo "Starting kdump: [OK]"
suggest_crashkernel_reset
return 0
}

Expand Down Expand Up @@ -1970,25 +2018,6 @@ reset_crashkernel_after_update()
done
}

# read the value of an environ variable from given environ file path
#
# The environment variable entries in /proc/[pid]/environ are separated
# by null bytes instead of by spaces.
#
# $1: environment variable
# $2: environ file path
read_proc_environ_var()
{
local _var=$1 _environ_path=$2
sed -n -E "s/.*(^|\x00)${_var}=([^\x00]*).*/\2/p" < "$_environ_path"
}

_OSBUILD_ENVIRON_PATH='/proc/1/environ'
_is_osbuild()
{
[[ $(read_proc_environ_var container "$_OSBUILD_ENVIRON_PATH") == bwrap-osbuild ]]
}

reset_crashkernel_for_installed_kernel()
{
local _installed_kernel _grub_entry_index _kernel _old_ck _old_fadump
Expand Down
21 changes: 20 additions & 1 deletion spec/kdump-lib_spec.sh
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Describe 'kdump-lib'
End

Describe "_crashkernel_add()"
Context "For valid input values"
Context "For valid input values with two arguments (skip defaults to 0)"
Parameters
"2G-4G:256M,4G-64G:320M,64G-:576M" "100M" "2G-4G:356M,4G-64G:420M,64G-:676M"
"2G-4G:256M" "100" "2G-4G:268435556" # avoids any rounding when size % 1024 != 0
Expand All @@ -74,6 +74,25 @@ Describe 'kdump-lib'
The output should equal "$3"
End
End

Context "For valid input values with three arguments (explicit skip)"
Parameters
"2G-4G:256M,4G-64G:320M,64G-:576M" "100M" "1" "2G-4G:256M,4G-64G:420M,64G-:676M"
"2G-4G:256M,4G-64G:320M,64G-:576M" "100M" "2" "2G-4G:256M,4G-64G:320M,64G-:676M"
"2G-4G:256M,4G-64G:320M,64G-:576M" "100M" "3" "2G-4G:256M,4G-64G:320M,64G-:576M"
"2G-4G:256M,4G-64G:320M,64G-:576M@4G" "100M" "1" "2G-4G:256M,4G-64G:420M,64G-:676M@4G"
"2G-4G:1G,4G-64G:2G,64G-:3G@4G" "100M" "1" "2G-4G:1G,4G-64G:2148M,64G-:3172M@4G"
"2G-4G:10000K,4G-64G:20000K" "100M" "1" "2G-4G:10000K,4G-64G:122400K"
"1M@1G" "1K" "1" "1M@1G"
"128G-1T:4G,10T-100T:1T" "1G" "1" "128G-1T:4G,10T-100T:1025G"
"1K,low" "1" "1" "1K,low"
End
It "should add delta to values after ':' starting after skip count"
When call _crashkernel_add "$1" "$2" "$3"
The output should equal "$4"
End
End

Context "For invalid input values"
Parameters
"2G-4G:256M.4G-64G:320M" "100M"
Expand Down
Loading