Linux-kselftest Archive mirror
 help / color / mirror / Atom feed
From: Sean Christopherson <seanjc@google.com>
To: Thomas Huth <thuth@redhat.com>
Cc: kvm@vger.kernel.org, Paolo Bonzini <pbonzini@redhat.com>,
	 linux-kselftest@vger.kernel.org, linux-kernel@vger.kernel.org,
	 Shuah Khan <shuah@kernel.org>,
	Muhammad Usama Anjum <usama.anjum@collabora.com>
Subject: Re: [PATCH v2] KVM: selftests: Use TAP interface in the set_memory_region test
Date: Fri, 3 May 2024 11:44:56 -0700	[thread overview]
Message-ID: <ZjUwqEXPA5QVItyX@google.com> (raw)
In-Reply-To: <25cc89b7-822f-4735-bec5-59458ec18a49@redhat.com>

On Fri, May 03, 2024, Thomas Huth wrote:
> On 02/05/2024 21.37, Sean Christopherson wrote:
> > On Fri, Apr 26, 2024, Thomas Huth wrote:
> > I like that we can actually report sub-tests as being skipped, but I don't like
> > having multiple ways to express requirements.  And IMO, this is much less readable
> > than TEST_REQUIRE(has_cap_guest_memfd());
> > 
> > AIUI, each test runs in a child process, so TEST_REQUIRE() can simply exit(), it
> > just needs to avoid ksft_exit_skip() so that a sub-test doesn't spit out the full
> > test summary.
> > 
> > And if using exit() isn't an option, setjmp()+longjmp() will do the trick (I got
> > that working for KVM_ONE_VCPU_TEST() before I realized tests run as a child).
> > 
> > The below is lightly tested, but I think it does what we want?
> 
> Not quite ... for example, if I force vmx_pmu_caps_test to skip the last
> test, I get:

...

> As you can see, the "ok 5" line is duplicated now, once marked with "# SKIP"
> and once as successfull. I don't think that this is valid TAP anymore?

Ah, IIUC, it's because the test reports a SKIP, and then also eventually exits
with KSFT_SKIP too.

> > I also think we would effectively forbid direct use of TEST().  Partly because
> > it's effectively necessary to use TEST_REQUIRE(), but also so that all tests will
> > have an existing single point of contact if we need/want to make similar changes
> > in the future.
> 
> Ok, but I wrote in the patch description, KVM_ONE_VCPU_TEST_SUITE() does not
> work for the set_memory_region test since it does not like to have a
> pre-defined vcpu ... so if we want to forbid TEST(), I assume we'd need
> another macro like KVM_BAREBONE_TEST_SUITE() ?

Yeah, though we probably don't need BAREBONE, e.g. KVM_TEST_SUITE() would suffice.
The "barebones" terminology exists for VMs because the vanilla "create VM" helpers
do waay more than the bare minimum, whereas I don't think we'll have the same
issues here.

> Not sure whether I really like it, though, since I'd prefer if we could keep
> the possibility to use the original selftest macros (for people who are
> already used to those macros from other selftests).

The more I fiddle with the kselftests harness, the more I'm opposed to using it
directly.  The harness code heavily assumes a "simple" environment, i.e. a test
environment without libraries.  E.g. including kselftest_harness.h without invoking
test_harness_run() fails due to unused functions, and including it in multiple
compilation units, e.g. to allow using its macros in utilities, fails due to
duplicate symbols.

It's obviously possible to split kselftest_harness.h to get around the immediate
issues, but that doesn't help with SKIP() (and other macros) only being usable at
the top-level TEST().  And using the undersored globals and functions params,
i.e. the "private" stuff, directly seems like a bad idea, e.g. the odds of KVM
selftests being broken by changes to the common code would be too high for my
taste.

While I agree it would be nice to not diverge from the common kselftest framework,
as far as things like SKIP and ASSERT macros go, that ship sailed a long time ago,
as TEST_REQUIRE() and TEST_ASSERT() usage is ubiquitous throughout KVM selftests.
And given the limitations of the common framework versus what we have in KVM's
framework, I don't see us converging on the common framework.

It's not perfect, but the best idea I can come up with is to trampoline the skip
out through KVM's harness and on to the common harness.

---
 .../selftests/kvm/include/kvm_test_harness.h  | 11 ++++++-
 .../testing/selftests/kvm/include/test_util.h | 31 ++++++++++++++++++-
 tools/testing/selftests/kvm/lib/kvm_util.c    |  2 ++
 .../selftests/kvm/x86_64/vmx_pmu_caps_test.c  |  3 +-
 4 files changed, 43 insertions(+), 4 deletions(-)

diff --git a/tools/testing/selftests/kvm/include/kvm_test_harness.h b/tools/testing/selftests/kvm/include/kvm_test_harness.h
index 8f7c6858e8e2..fa4b5f707135 100644
--- a/tools/testing/selftests/kvm/include/kvm_test_harness.h
+++ b/tools/testing/selftests/kvm/include/kvm_test_harness.h
@@ -9,6 +9,7 @@
 #define SELFTEST_KVM_TEST_HARNESS_H
 
 #include "kselftest_harness.h"
+#include "test_util.h"
 
 #define KVM_ONE_VCPU_TEST_SUITE(name)					\
 	FIXTURE(name) {							\
@@ -28,8 +29,16 @@ static void __suite##_##test(struct kvm_vcpu *vcpu);			\
 									\
 TEST_F(suite, test)							\
 {									\
+	struct kvm_selftests_subtest subtest;				\
+									\
 	vcpu_arch_set_entry_point(self->vcpu, guestcode);		\
-	__suite##_##test(self->vcpu);					\
+									\
+	kvm_subtest = &subtest;						\
+	if (!setjmp(subtest.buf))					\
+		__suite##_##test(self->vcpu);				\
+	else								\
+		SKIP(, "%s", subtest.reason);				\
+	kvm_subtest = NULL;						\
 }									\
 static void __suite##_##test(struct kvm_vcpu *vcpu)
 
diff --git a/tools/testing/selftests/kvm/include/test_util.h b/tools/testing/selftests/kvm/include/test_util.h
index 3e473058849f..2fce7b2ed07c 100644
--- a/tools/testing/selftests/kvm/include/test_util.h
+++ b/tools/testing/selftests/kvm/include/test_util.h
@@ -8,6 +8,7 @@
 #ifndef SELFTEST_KVM_TEST_UTIL_H
 #define SELFTEST_KVM_TEST_UTIL_H
 
+#include <setjmp.h>
 #include <stdlib.h>
 #include <stdarg.h>
 #include <stdbool.h>
@@ -18,8 +19,22 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/mman.h>
+
 #include "kselftest.h"
 
+/*
+ * kvm_selftests_subtest is used to trampoline from __TEST_REQUIRE(), which can
+ * be called from any context, e.g. KVM selftests library code, out to the test
+ * being run, as the kselftests harness only allows calling SKIP() (and other
+ * macros/helpers) from the top-level TEST_*() context.
+ */
+struct kvm_selftests_subtest {
+	char reason[1024];
+	jmp_buf buf;
+};
+
+extern struct kvm_selftests_subtest *kvm_subtest;
+
 #define msecs_to_usecs(msec)    ((msec) * 1000ULL)
 
 static inline int _no_printf(const char *format, ...) { return 0; }
@@ -36,10 +51,24 @@ static inline int _no_printf(const char *format, ...) { return 0; }
 #endif
 
 void __printf(1, 2) print_skip(const char *fmt, ...);
+
+/*
+ * Skip the test if a required capability/feature/whatever is not available,
+ * e.g. due to lack of support in the underlying hardware, running against an
+ * older kernel/KVM, etc.  If a subtest is running, skip only the subtest,
+ * otherwise treat the requirement as applying to the entire test.
+ */
 #define __TEST_REQUIRE(f, fmt, ...)				\
 do {								\
-	if (!(f))						\
+	if (!(f)) {						\
+		if (kvm_subtest) {				\
+			snprintf(kvm_subtest->reason,		\
+				 sizeof(kvm_subtest->reason),	\
+				 fmt, ##__VA_ARGS__);		\
+			longjmp(kvm_subtest->buf, 1);		\
+		}						\
 		ksft_exit_skip("- " fmt "\n", ##__VA_ARGS__);	\
+	}							\
 } while (0)
 
 #define TEST_REQUIRE(f) __TEST_REQUIRE(f, "Requirement not met: %s", #f)
diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c
index 6b2158655baa..9601eed3ed57 100644
--- a/tools/testing/selftests/kvm/lib/kvm_util.c
+++ b/tools/testing/selftests/kvm/lib/kvm_util.c
@@ -19,6 +19,8 @@
 
 #define KVM_UTIL_MIN_PFN	2
 
+struct kvm_selftests_subtest *kvm_subtest;
+
 uint32_t guest_random_seed;
 struct guest_random_state guest_rng;
 
diff --git a/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c b/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c
index 7c92536551cc..a58e0b1c2ee5 100644
--- a/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c
+++ b/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c
@@ -195,8 +195,7 @@ KVM_ONE_VCPU_TEST(vmx_pmu_caps, lbr_perf_capabilities, guest_code)
 {
 	int r;
 
-	if (!host_cap.lbr_format)
-		return;
+	TEST_REQUIRE(host_cap.lbr_format);
 
 	vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, host_cap.capabilities);
 	vcpu_set_msr(vcpu, MSR_LBR_TOS, 7);

base-commit: df8e458e70ce925b533ff33f1e8979650cf44e3e
-- 


      reply	other threads:[~2024-05-03 18:44 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-04-26 11:45 [PATCH v2] KVM: selftests: Use TAP interface in the set_memory_region test Thomas Huth
2024-04-26 14:03 ` Muhammad Usama Anjum
2024-05-02 19:37 ` Sean Christopherson
2024-05-03  7:30   ` Thomas Huth
2024-05-03 18:44     ` Sean Christopherson [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=ZjUwqEXPA5QVItyX@google.com \
    --to=seanjc@google.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=pbonzini@redhat.com \
    --cc=shuah@kernel.org \
    --cc=thuth@redhat.com \
    --cc=usama.anjum@collabora.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).