Add a wrapper script to simplify running the private_mem_conversions_test with a variety of configurations. Manually invoking the test for all supported memory backing source types is tedious.
The script automatically detects the availability of 2MB and 1GB hugepages and builds a list of source types to test. It then iterates through the list, running the test for each type with both a single memslot and multiple memslots. This makes it easier to get comprehensive test coverage across different memory configurations. Add and use a helper program in C to be able to read KVM_CAP_GUEST_MEMFD_MEMORY_ATTRIBUTES as defined in header files and then issue the ioctl to read the KVM CAP. Signed-off-by: Ackerley Tng <[email protected]> --- tools/testing/selftests/kvm/Makefile.kvm | 4 + .../selftests/kvm/kvm_has_gmem_attributes.c | 17 +++ .../kvm/x86/private_mem_conversions_test.sh | 128 +++++++++++++++++++++ 3 files changed, 149 insertions(+) diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm index 0e2a9adfca57e..c326aecfeebb0 100644 --- a/tools/testing/selftests/kvm/Makefile.kvm +++ b/tools/testing/selftests/kvm/Makefile.kvm @@ -54,6 +54,7 @@ LIBKVM_loongarch += lib/loongarch/exception.S # Non-compiled test targets TEST_PROGS_x86 += x86/nx_huge_pages_test.sh +TEST_PROGS_x86 += x86/private_mem_conversions_test.sh # Compiled test targets valid on all architectures with libkvm support TEST_GEN_PROGS_COMMON = demand_paging_test @@ -65,6 +66,8 @@ TEST_GEN_PROGS_COMMON += kvm_create_max_vcpus TEST_GEN_PROGS_COMMON += kvm_page_table_test TEST_GEN_PROGS_COMMON += set_memory_region_test +TEST_GEN_PROGS_EXTENDED_COMMON += kvm_has_gmem_attributes + # Compiled test targets TEST_GEN_PROGS_x86 = $(TEST_GEN_PROGS_COMMON) TEST_GEN_PROGS_x86 += x86/cpuid_test @@ -242,6 +245,7 @@ SPLIT_TESTS += get-reg-list TEST_PROGS += $(TEST_PROGS_$(ARCH)) TEST_GEN_PROGS += $(TEST_GEN_PROGS_$(ARCH)) +TEST_GEN_PROGS_EXTENDED += $(TEST_GEN_PROGS_EXTENDED_COMMON) TEST_GEN_PROGS_EXTENDED += $(TEST_GEN_PROGS_EXTENDED_$(ARCH)) LIBKVM += $(LIBKVM_$(ARCH)) diff --git a/tools/testing/selftests/kvm/kvm_has_gmem_attributes.c b/tools/testing/selftests/kvm/kvm_has_gmem_attributes.c new file mode 100644 index 0000000000000..4f361349412fb --- /dev/null +++ b/tools/testing/selftests/kvm/kvm_has_gmem_attributes.c @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Utility to check if KVM supports guest_memfd attributes. + * + * Copyright (C) 2025, Google LLC. + */ + +#include <stdio.h> + +#include "kvm_util.h" + +int main(void) +{ + printf("%u\n", kvm_check_cap(KVM_CAP_GUEST_MEMFD_MEMORY_ATTRIBUTES) > 0); + + return 0; +} diff --git a/tools/testing/selftests/kvm/x86/private_mem_conversions_test.sh b/tools/testing/selftests/kvm/x86/private_mem_conversions_test.sh new file mode 100755 index 0000000000000..7179a4fcdd498 --- /dev/null +++ b/tools/testing/selftests/kvm/x86/private_mem_conversions_test.sh @@ -0,0 +1,128 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0-only +# +# Wrapper script which runs different test setups of +# private_mem_conversions_test. +# +# Copyright (C) 2025, Google LLC. + +NUM_VCPUS_TO_TEST=4 +NUM_MEMSLOTS_TO_TEST=$NUM_VCPUS_TO_TEST + +# Required pages are based on the test setup in the C code. +REQUIRED_NUM_2M_HUGEPAGES=$((1024 * NUM_VCPUS_TO_TEST)) +REQUIRED_NUM_1G_HUGEPAGES=$((2 * NUM_VCPUS_TO_TEST)) + +get_hugepage_count() { + local page_size_kb=$1 + local path="/sys/kernel/mm/hugepages/hugepages-${page_size_kb}kB/nr_hugepages" + if [ -f "$path" ]; then + cat "$path" + else + echo 0 + fi +} + +get_default_hugepage_size_in_kb() { + local size=$(grep "Hugepagesize:" /proc/meminfo | awk '{print $2}') + echo "$size" +} + +run_tests() { + local executable_path=$1 + local src_type=$2 + local num_memslots=$3 + local num_vcpus=$4 + + echo "$executable_path -s $src_type -m $num_memslots -n $num_vcpus" + "$executable_path" -s "$src_type" -m "$num_memslots" -n "$num_vcpus" +} + +script_dir=$(dirname "$(realpath "$0")") +test_executable="${script_dir}/private_mem_conversions_test" +kvm_has_gmem_attributes_tool="${script_dir}/../kvm_has_gmem_attributes" + +if [ ! -f "$test_executable" ]; then + echo "Error: Test executable not found at '$test_executable'" >&2 + exit 1 +fi + +if [ ! -f "$kvm_has_gmem_attributes_tool" ]; then + echo "Error: kvm_has_gmem_attributes utility not found at '$kvm_has_gmem_attributes_tool'" >&2 + exit 1 +fi + +kvm_has_gmem_attributes=$("$kvm_has_gmem_attributes_tool" | tail -n1) + +if [ "$kvm_has_gmem_attributes" -eq 1 ]; then + backing_src_types=("shmem") +else + hugepage_2mb_count=$(get_hugepage_count 2048) + hugepage_2mb_enabled=$((hugepage_2mb_count >= REQUIRED_NUM_2M_HUGEPAGES)) + hugepage_1gb_count=$(get_hugepage_count 1048576) + hugepage_1gb_enabled=$((hugepage_1gb_count >= REQUIRED_NUM_1G_HUGEPAGES)) + + default_hugepage_size_kb=$(get_default_hugepage_size_in_kb) + hugepage_default_enabled=0 + if [ "$default_hugepage_size_kb" -eq 2048 ]; then + hugepage_default_enabled=$hugepage_2mb_enabled + elif [ "$default_hugepage_size_kb" -eq 1048576 ]; then + hugepage_default_enabled=$hugepage_1gb_enabled + fi + + backing_src_types=("anonymous" "anonymous_thp") + + if [ "$hugepage_default_enabled" -eq 1 ]; then + backing_src_types+=("anonymous_hugetlb") + else + echo "skipping anonymous_hugetlb backing source type" + fi + + if [ "$hugepage_2mb_enabled" -eq 1 ]; then + backing_src_types+=("anonymous_hugetlb_2mb") + else + echo "skipping anonymous_hugetlb_2mb backing source type" + fi + + if [ "$hugepage_1gb_enabled" -eq 1 ]; then + backing_src_types+=("anonymous_hugetlb_1gb") + else + echo "skipping anonymous_hugetlb_1gb backing source type" + fi + + backing_src_types+=("shmem") + + if [ "$hugepage_default_enabled" -eq 1 ]; then + backing_src_types+=("shared_hugetlb") + else + echo "skipping shared_hugetlb backing source type" + fi +fi + +return_code=0 +for i in "${!backing_src_types[@]}"; do + src_type=${backing_src_types[$i]} + if [ "$i" -gt 0 ]; then + echo + fi + + if ! run_tests "$test_executable" "$src_type" 1 1; then + return_code=$? + echo "Test failed for source type '$src_type'. Arguments: -s $src_type -m 1 -n 1" >&2 + break + fi + + if ! run_tests "$test_executable" "$src_type" 1 "$NUM_VCPUS_TO_TEST"; then + return_code=$? + echo "Test failed for source type '$src_type'. Arguments: -s $src_type -m 1 -n $NUM_VCPUS_TO_TEST" >&2 + break + fi + + if ! run_tests "$test_executable" "$src_type" "$NUM_MEMSLOTS_TO_TEST" "$NUM_VCPUS_TO_TEST"; then + return_code=$? + echo "Test failed for source type '$src_type'. Arguments: -s $src_type -m $NUM_MEMSLOTS_TO_TEST -n $NUM_VCPUS_TO_TEST" >&2 + break + fi +done + +exit "$return_code" -- 2.53.0.1018.g2bb0e51243-goog
