From 119e9db233ad0f4cbd4cfb9f9385a7bca378b37d Mon Sep 17 00:00:00 2001 From: Zeng Chi Date: Mon, 21 Sep 2026 18:24:42 +0800 Subject: KVM: Don't pre-reserve xarray entries when storing empty/NULL attributes Skip the xarray reservation loop when clearing all memory attributes, as storing NULL only erases the entry and never needs to allocate, so no reservation (and no cleanup of a failed one) is required in that case. Suggested-by: Sean Christopherson Cc: David Ballesteros Signed-off-by: Zeng Chi Link: https://patch.msgid.link/20260921102442.1232375-1-zeng_chi911@163.com [sean: split to separate patch] Signed-off-by: Sean Christopherson --- tools/testing/selftests/verification/.gitignore | 2 + tools/testing/selftests/verification/Makefile | 8 +++ tools/testing/selftests/verification/config | 1 + tools/testing/selftests/verification/settings | 1 + .../selftests/verification/test.d/functions | 39 +++++++++++ .../selftests/verification/test.d/rv_deadline.tc | 23 +++++++ .../test.d/rv_monitor_enable_disable.tc | 75 ++++++++++++++++++++++ .../verification/test.d/rv_monitor_reactor.tc | 68 ++++++++++++++++++++ .../verification/test.d/rv_monitors_available.tc | 18 ++++++ .../selftests/verification/test.d/rv_stall.tc | 33 ++++++++++ .../verification/test.d/rv_wwnr_printk.tc | 52 +++++++++++++++ .../selftests/verification/verificationtest-ktap | 8 +++ 12 files changed, 328 insertions(+) create mode 100644 tools/testing/selftests/verification/.gitignore create mode 100644 tools/testing/selftests/verification/Makefile create mode 100644 tools/testing/selftests/verification/config create mode 100644 tools/testing/selftests/verification/settings create mode 100644 tools/testing/selftests/verification/test.d/functions create mode 100644 tools/testing/selftests/verification/test.d/rv_deadline.tc create mode 100644 tools/testing/selftests/verification/test.d/rv_monitor_enable_disable.tc create mode 100644 tools/testing/selftests/verification/test.d/rv_monitor_reactor.tc create mode 100644 tools/testing/selftests/verification/test.d/rv_monitors_available.tc create mode 100644 tools/testing/selftests/verification/test.d/rv_stall.tc create mode 100644 tools/testing/selftests/verification/test.d/rv_wwnr_printk.tc create mode 100755 tools/testing/selftests/verification/verificationtest-ktap (limited to 'tools/testing/selftests/verification') diff --git a/tools/testing/selftests/verification/.gitignore b/tools/testing/selftests/verification/.gitignore new file mode 100644 index 000000000..2659417cb --- /dev/null +++ b/tools/testing/selftests/verification/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +logs diff --git a/tools/testing/selftests/verification/Makefile b/tools/testing/selftests/verification/Makefile new file mode 100644 index 000000000..aa8790c22 --- /dev/null +++ b/tools/testing/selftests/verification/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 +all: + +TEST_PROGS := verificationtest-ktap +TEST_FILES := test.d settings +EXTRA_CLEAN := $(OUTPUT)/logs/* + +include ../lib.mk diff --git a/tools/testing/selftests/verification/config b/tools/testing/selftests/verification/config new file mode 100644 index 000000000..43072c1c3 --- /dev/null +++ b/tools/testing/selftests/verification/config @@ -0,0 +1 @@ +CONFIG_RV=y diff --git a/tools/testing/selftests/verification/settings b/tools/testing/selftests/verification/settings new file mode 100644 index 000000000..e7b941753 --- /dev/null +++ b/tools/testing/selftests/verification/settings @@ -0,0 +1 @@ +timeout=0 diff --git a/tools/testing/selftests/verification/test.d/functions b/tools/testing/selftests/verification/test.d/functions new file mode 100644 index 000000000..ec36a092f --- /dev/null +++ b/tools/testing/selftests/verification/test.d/functions @@ -0,0 +1,39 @@ +check_requires() { # Check required files, monitors and reactors + for i in "$@" ; do + p=${i%:program} + m=${i%:monitor} + r=${i%:reactor} + if [ $p != $i ]; then + if ! which $p ; then + echo "Required program $p is not found." + exit_unresolved + fi + elif [ $m != $i ]; then + if ! grep -wq $m available_monitors ; then + echo "Required monitor $m is not configured." + exit_unsupported + fi + elif [ $r != $i ]; then + if ! grep -wq $r available_reactors ; then + echo "Required reactor $r is not configured." + exit_unsupported + fi + elif [ ! -e $i ]; then + echo "Required feature interface $i doesn't exist." + exit_unsupported + fi + done +} + +initialize_system() { # Reset RV to initial-state + echo > enabled_monitors + for m in monitors/*; do + echo nop > $m/reactors || true + done + echo 1 > monitoring_on + echo 1 > reacting_on || true +} + +finish_system() { + initialize_system +} diff --git a/tools/testing/selftests/verification/test.d/rv_deadline.tc b/tools/testing/selftests/verification/test.d/rv_deadline.tc new file mode 100644 index 000000000..fc95267db --- /dev/null +++ b/tools/testing/selftests/verification/test.d/rv_deadline.tc @@ -0,0 +1,23 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# description: Test deadline monitors trigger no reaction +# requires: available_reactors deadline:monitor printk:reactor stress-ng:program + +load() { # returns true if there was a reaction + local lines_before + lines_before=$(dmesg | wc -l) + stress-ng --cpu 2 --sched deadline --sched-period 100000000 \ + --sched-deadline 100000000 --sched-runtime 20000000 -t 5 & + stress-ng --cpu 2 --sched rr --sched-prio 50 --cyclic 1 \ + --cyclic-policy rr --cyclic-prio 50 -t 5 & + wait + dmesg | tail -n +$((lines_before + 1)) | grep -q "rv: monitor [a-z]\+ does not allow event" +} + +echo 1 > monitors/deadline/enable +echo printk > monitors/deadline/reactors + +! load || false + +echo nop > monitors/deadline/reactors +echo 0 > monitors/deadline/enable diff --git a/tools/testing/selftests/verification/test.d/rv_monitor_enable_disable.tc b/tools/testing/selftests/verification/test.d/rv_monitor_enable_disable.tc new file mode 100644 index 000000000..61e2c8b54 --- /dev/null +++ b/tools/testing/selftests/verification/test.d/rv_monitor_enable_disable.tc @@ -0,0 +1,75 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# description: Test monitor enable/disable + +test_simple_monitor() { + local monitor="$1" + local prefix="$2" # nested monitors + + echo 1 > "monitors/$prefix$monitor/enable" + grep -q "$monitor$" enabled_monitors + + echo 0 > "monitors/$prefix$monitor/enable" + ! grep -q "$monitor$" enabled_monitors || false + + echo "$monitor" >> enabled_monitors + grep -q 1 "monitors/$prefix$monitor/enable" + + echo "!$monitor" >> enabled_monitors + grep -q 0 "monitors/$prefix$monitor/enable" +} + +test_container_monitor() { + local monitor="$1" + local nested + + echo 1 > "monitors/$monitor/enable" + grep -q "^$monitor$" enabled_monitors + + for nested_dir in "monitors/$monitor"/*; do + [ -d "$nested_dir" ] || continue + nested=$(basename "$nested_dir") + grep -q "^$monitor:$nested$" enabled_monitors + done + test -n "$nested" + + echo 0 > "monitors/$monitor/enable" + ! grep -q "^$monitor$" enabled_monitors || false + + for nested_dir in "monitors/$monitor"/*; do + [ -d "$nested_dir" ] || continue + nested=$(basename "$nested_dir") + ! grep -q "^$monitor:$nested$" enabled_monitors || false + done + + echo "$monitor" >> enabled_monitors + grep -q 1 "monitors/$monitor/enable" + + for nested_dir in "monitors/$monitor"/*; do + [ -d "$nested_dir" ] || continue + nested=$(basename "$nested_dir") + grep -q "^$monitor:$nested$" enabled_monitors + done + + echo "!$monitor" >> enabled_monitors + grep -q 0 "monitors/$monitor/enable" + + for nested_dir in "monitors/$monitor"/*; do + [ -d "$nested_dir" ] || continue + nested=$(basename "$nested_dir") + test_simple_monitor "$nested" "$monitor/" + done +} + +for monitor_dir in monitors/*; do + monitor=$(basename "$monitor_dir") + + if find "$monitor_dir" -mindepth 1 -type d | grep -q .; then + test_container_monitor "$monitor" + else + test_simple_monitor "$monitor" + fi +done + +! echo non_existent_monitor > enabled_monitors || false +! grep -q "^non_existent_monitor$" enabled_monitors || false diff --git a/tools/testing/selftests/verification/test.d/rv_monitor_reactor.tc b/tools/testing/selftests/verification/test.d/rv_monitor_reactor.tc new file mode 100644 index 000000000..516a20971 --- /dev/null +++ b/tools/testing/selftests/verification/test.d/rv_monitor_reactor.tc @@ -0,0 +1,68 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# description: Test monitor reactor setting +# requires: available_reactors + +test_monitor_reactor() { + local monitor="$1" + local prefix="$2" # nested monitors + + while read -r reactor; do + [ "$reactor" = nop ] && continue + + echo "$reactor" > "monitors/$prefix$monitor/reactors" + grep -q "\\[$reactor\\]" "monitors/$prefix$monitor/reactors" + done < available_reactors + + echo nop > "monitors/$prefix$monitor/reactors" + grep -q "\\[nop\\]" "monitors/$prefix$monitor/reactors" +} + +test_container_monitor() { + local monitor="$1" + local nested + + while read -r reactor; do + [ "$reactor" = nop ] && continue + + echo "$reactor" > "monitors/$monitor/reactors" + grep -q "\\[$reactor\\]" "monitors/$monitor/reactors" + + for nested_dir in "monitors/$monitor"/*; do + [ -d "$nested_dir" ] || continue + nested=$(basename "$nested_dir") + grep -q "\\[$reactor\\]" "monitors/$monitor/$nested/reactors" + done + done < available_reactors + test -n "$nested" + + echo nop > "monitors/$monitor/reactors" + grep -q "\\[nop\\]" "monitors/$monitor/reactors" + + for nested_dir in "monitors/$monitor"/*; do + [ -d "$nested_dir" ] || continue + nested=$(basename "$nested_dir") + grep -q "\\[nop\\]" "monitors/$monitor/$nested/reactors" + done + + for nested_dir in "monitors/$monitor"/*; do + [ -d "$nested_dir" ] || continue + nested=$(basename "$nested_dir") + test_monitor_reactor "$nested" "$monitor/" + done +} + +for monitor_dir in monitors/*; do + monitor=$(basename "$monitor_dir") + + if find "$monitor_dir" -mindepth 1 -type d | grep -q .; then + test_container_monitor "$monitor" + else + test_monitor_reactor "$monitor" + fi +done + +monitor=$(ls /sys/kernel/tracing/rv/monitors -1 | head -n 1) +test -f "monitors/$monitor/reactors" +! echo non_existent_reactor > "monitors/$monitor/reactors" || false +! grep -q "\\[non_existent_reactor\\]" "monitors/$monitor/reactors" || false diff --git a/tools/testing/selftests/verification/test.d/rv_monitors_available.tc b/tools/testing/selftests/verification/test.d/rv_monitors_available.tc new file mode 100644 index 000000000..e6a4a1410 --- /dev/null +++ b/tools/testing/selftests/verification/test.d/rv_monitors_available.tc @@ -0,0 +1,18 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# description: Check available monitors + +for monitor_dir in monitors/*; do + monitor=$(basename "$monitor_dir") + + grep -q "^$monitor$" available_monitors + grep -q . "$monitor_dir"/desc + + for nested_dir in "$monitor_dir"/*; do + [ -d "$nested_dir" ] || continue + nested=$(basename "$nested_dir") + + grep -q "^$monitor:$nested$" available_monitors + grep -q . "$nested_dir"/desc + done +done diff --git a/tools/testing/selftests/verification/test.d/rv_stall.tc b/tools/testing/selftests/verification/test.d/rv_stall.tc new file mode 100644 index 000000000..515a10263 --- /dev/null +++ b/tools/testing/selftests/verification/test.d/rv_stall.tc @@ -0,0 +1,33 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# description: Test stall monitor +# requires: available_reactors stall:monitor printk:reactor stress-ng:program + +THRESHOLD=/sys/module/stall/parameters/threshold_jiffies +ORIG_THRESHOLD=$(cat $THRESHOLD) +trap 'echo $ORIG_THRESHOLD > $THRESHOLD' EXIT + +load() { # returns true if there was a reaction + local lines_before cpu + cpu=$(($(nproc) - 1)) + lines_before=$(dmesg | wc -l) + stress-ng --cpu 1 --taskset "$cpu" --sched rr --sched-prio 1 -t 3 & + stress-ng --cpu 5 --taskset "$cpu" -t 3 & + wait + dmesg | tail -n +$((lines_before + 1)) | grep -q "rv: monitor stall does not allow event" +} + +echo 5000 > $THRESHOLD +echo 1 > monitors/stall/enable +echo printk > monitors/stall/reactors + +! load || false + +echo 0 > monitors/stall/enable +echo 70 > $THRESHOLD +echo 1 > monitors/stall/enable + +load + +echo nop > monitors/stall/reactors +echo 0 > monitors/stall/enable diff --git a/tools/testing/selftests/verification/test.d/rv_wwnr_printk.tc b/tools/testing/selftests/verification/test.d/rv_wwnr_printk.tc new file mode 100644 index 000000000..17e1edfb3 --- /dev/null +++ b/tools/testing/selftests/verification/test.d/rv_wwnr_printk.tc @@ -0,0 +1,52 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# description: Test wwnr monitor with printk reactor +# requires: available_reactors wwnr:monitor printk:reactor stress-ng:program + +load() { # returns true if there was a reaction + local lines_before num load_pid ret + num=$((($(nproc) + 1) / 2)) + lines_before=$(dmesg | wc -l) + stress-ng --cpu-sched "$num" --timer "$num" -t 5 -q & + load_pid=$! + timeout 5 dmesg -w | tail -n +$((lines_before + 1)) | \ + grep -m 1 -q "rv: monitor wwnr does not allow event" + ret=$? + kill "$load_pid" || true + wait "$load_pid" || true + return $ret +} + +# loads may flood the ringbuffer, wait for all pending printks (timeout at 2 minutes) +wait_dmesg_flush() { + local last_before last_after + for _ in $(seq 400); do + last_before=$last_after + last_after=$(dmesg | grep "rv:" | tail -n 1 || true) + [ "$last_before" = "$last_after" ] && return 0 + sleep .3 + done + return 1 +} + +echo 1 > monitors/wwnr/enable +echo printk > monitors/wwnr/reactors + +load + +echo 0 > monitoring_on +wait_dmesg_flush + +! load || false +echo 1 > monitoring_on + +load + +echo 0 > reacting_on +wait_dmesg_flush + +! load || false +echo 1 > reacting_on + +echo nop > monitors/wwnr/reactors +echo 0 > monitors/wwnr/enable diff --git a/tools/testing/selftests/verification/verificationtest-ktap b/tools/testing/selftests/verification/verificationtest-ktap new file mode 100755 index 000000000..18f7fe324 --- /dev/null +++ b/tools/testing/selftests/verification/verificationtest-ktap @@ -0,0 +1,8 @@ +#!/bin/sh -e +# SPDX-License-Identifier: GPL-2.0-only +# +# ftracetest-ktap: Wrapper to integrate ftracetest with the kselftest runner +# +# Copyright (C) Arm Ltd., 2023 + +../ftrace/ftracetest -K -v --rv ../verification -- cgit v1.3.1