From 93de2a6a4b91b72607136dd656edf03fb399d27f Mon Sep 17 00:00:00 2001 From: Sean Christopherson Date: Wed, 23 Sep 2026 09:37:21 -0700 Subject: KVM: SEV: Do cache maintenance on the source VM during intra-host migration Manually perform cache maintenance on the source VM during intra-host migration to ensure no stale data is left in CPU caches after the VM is destroyed. Because the source VM is "converted" to a non-SEV VM, KVM's memory reclaim flows won't trigger cache maintenance, e.g. when all guest memory is reclaimed in response to detaching from the mmu_notifier. Note, relying on the destination VM to do cache maintenance isn't an option as KVM doesn't require identical guest memory configurations, i.e. the source VM may have access to memory that the destination VM does not. Enforcing equivalent memory configurations is infeasible, as it would require a *deep* comparison of memslots, e.g. to verify that not only are the memslot identical, but what the memslots point at is also identical. Fixes: b56639318bb2 ("KVM: SEV: Add support for SEV intra host migration") Cc: stable@vger.kernel.org Reported-by: Stefan Teodorescu Signed-off-by: Sean Christopherson Message-ID: <20260923163721.1584779-3-seanjc@google.com> Signed-off-by: Paolo Bonzini --- 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