From a2f442f1b0a99b3634f299fc48d505486fb5ab79 Mon Sep 17 00:00:00 2001 From: Wardenjohn Date: Sat, 12 Oct 2024 11:15:16 +0800 Subject: [PATCH] kpatch: Add subcommand '--enabling' to adjust new sysfs attribute 'stack_order' of livepatch Add an sub command of kpatch list with '--enabling' option to adjust kernel new attribute 'stack_order' of livepatch of kernel v6.13 or later. Now, using 'kpatch list --enabling' can output the enabling function in the system and the relationship from the enabling function to its object and its related module. Signed-off-by: Wardenjohn --- kpatch/kpatch | 115 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 89 insertions(+), 26 deletions(-) diff --git a/kpatch/kpatch b/kpatch/kpatch index 0e94a5d73..a8dc06aeb 100755 --- a/kpatch/kpatch +++ b/kpatch/kpatch @@ -56,6 +56,7 @@ usage () { usage_cmd "info " "show information about a patch module" echo >&2 usage_cmd "list" "list installed patch modules" + usage_cmd "list --enabling" "list the enabling functions and its relationship from patch module to the function enabling in the system" echo >&2 usage_cmd "signal" "signal/poke any process stalling the current patch transition. This is only useful on systems that have the sysfs livepatch signal interface. On other systems, the signaling should be done automatically by the OS and this subcommand is a no-op." echo >&2 @@ -446,6 +447,78 @@ get_module_version() { MODVER="${MODVER/ */}" } +declare -A function_map +show_enabled_function() { + + for module_dir in /sys/kernel/livepatch/*; do + if [ -d "$module_dir" ]; then + if [[ ! -e "$module_dir/stack_order" ]]; then + echo "stack_order attribute not exist, maybe this kernel do not support it." + return; + fi + stack_order=$(cat "$module_dir/stack_order") + + module_name=$(basename "$module_dir") + for obj_dir in "$module_dir"/*/; do + for func_dir in "$obj_dir"/*; do + obj_name=$(basename "$obj_dir") + if [ -d "$func_dir" ]; then + func_name=$(basename "$func_dir") + func_name=${func_name%%,*} + if [[ -z "${function_map[$func_name]}" ]]; then + function_map[$func_name]="$stack_order:$module_name:$obj_name" + else + IFS=':' read -r recorded_order this_module this_obj <<< "${function_map[$func_name]}" + if [[ $recorded_order -lt $stack_order ]]; then + function_map[$func_name]="$stack_order:$module_name:$obj_name" + fi + fi + fi + done + done + fi + done + + echo "" + echo "The function enabling in the system:" + output_data=( + "Module Object Function" + ) + for func_name in "${!function_map[@]}"; do + IFS=':' read -r stack_order module_name obj_name <<< "${function_map[$func_name]}" + output_data+=("$module_name $obj_name $func_name") + done + printf "%s\n" "${output_data[@]}" | column -t +} + +print_patch_info() { + echo "Loaded patch modules:" + for module in "$SYSFS"/*; do + if [[ -e "$module" ]]; then + modname=$(basename "$module") + if [[ "$(cat "$module/enabled" 2>/dev/null)" -eq 1 ]]; then + in_transition "$modname" && state="enabling..." \ + || state="enabled" + else + in_transition "$modname" && state="disabling..." \ + || state="disabled" + fi + echo "$modname [$state]" + fi + done + show_stalled_processes + echo "" + echo "Installed patch modules:" + for kdir in "$INSTALLDIR"/*; do + [[ -e "$kdir" ]] || continue + for module in "$kdir"/*.ko; do + [[ -e "$module" ]] || continue + mod_name "$module" + echo "$MODNAME ($(basename "$kdir"))" + done + done +} + unset MODULE # Initialize the $SYSFS var. This only works if the core module has been @@ -592,32 +665,22 @@ case "$1" in ;; "list") - [[ "$#" -ne 1 ]] && usage - echo "Loaded patch modules:" - for module in "$SYSFS"/*; do - if [[ -e "$module" ]]; then - modname=$(basename "$module") - if [[ "$(cat "$module/enabled" 2>/dev/null)" -eq 1 ]]; then - in_transition "$modname" && state="enabling..." \ - || state="enabled" - else - in_transition "$modname" && state="disabling..." \ - || state="disabled" - fi - echo "$modname [$state]" - fi - done - show_stalled_processes - echo "" - echo "Installed patch modules:" - for kdir in "$INSTALLDIR"/*; do - [[ -e "$kdir" ]] || continue - for module in "$kdir"/*.ko; do - [[ -e "$module" ]] || continue - mod_name "$module" - echo "$MODNAME ($(basename "$kdir"))" - done - done + [[ "$#" -gt 2 ]] && usage + if [[ -n "$2" ]]; then + case "$2" in + --enabling) + print_patch_info + show_enabled_function + shift + ;; + *) + usage + shift + ;; + esac + else + print_patch_info + fi ;; "info")