On Fri, 19 Jun 2026 at 01:32, Ackerley Tng via B4 Relay <[email protected]> wrote: > > From: Ackerley Tng <[email protected]> > > Add a selftest to verify that converting a shared guest_memfd page to a > private page fails if the page has an elevated reference count. > > When KVM converts a shared page to a private one, it expects the page to > have a reference count equal to the reference counts taken by the > filemap. If another kernel subsystem holds a reference to the page, the > conversion must be aborted. > > The test asserts that both bulk and single-page conversion attempts > correctly fail with EAGAIN for the pinned page. After the page is unpinned, > the test verifies that subsequent conversions succeed. > > Signed-off-by: Ackerley Tng <[email protected]> > Co-developed-by: Sean Christopherson <[email protected]> > Signed-off-by: Sean Christopherson <[email protected]>
Not sure Sashiko's concern is worth it. Reviewed-by: Fuad Tabba <[email protected]> Cheers, /fuad > --- > .../kvm/x86/guest_memfd_conversions_test.c | 56 > ++++++++++++++++++++++ > 1 file changed, 56 insertions(+) > > diff --git a/tools/testing/selftests/kvm/x86/guest_memfd_conversions_test.c > b/tools/testing/selftests/kvm/x86/guest_memfd_conversions_test.c > index 99b0023609670..4ebbd29029526 100644 > --- a/tools/testing/selftests/kvm/x86/guest_memfd_conversions_test.c > +++ b/tools/testing/selftests/kvm/x86/guest_memfd_conversions_test.c > @@ -441,6 +441,62 @@ GMEM_CONVERSION_TEST_INIT_SHARED(forked_accesses) > #undef TEST_STATE_AWAIT > } > > +static void test_convert_to_private_fails(test_data_t *t, u64 pgoff, > + size_t nr_pages, > + u64 expected_error_offset) > +{ > + /* +1 to make it anything but expected_error_offset. */ > + u64 error_offset = expected_error_offset + 1; > + u64 offset = pgoff * page_size; > + int ret; > + > + do { > + ret = __gmem_set_private(t->gmem_fd, offset, > + nr_pages * page_size, &error_offset); > + } while (ret == -1 && errno == EINTR); > + TEST_ASSERT(ret == -1 && errno == EAGAIN, > + "Wanted EAGAIN on page %lu, got %d (ret = %d)", pgoff, > + errno, ret); > + TEST_ASSERT_EQ(error_offset, expected_error_offset); > +} > + > +GMEM_CONVERSION_MULTIPAGE_TEST_INIT_SHARED(elevated_refcount, 4) > +{ > + int i; > + > + pin_pages(t->mem + test_page * page_size, page_size); > + > + for (i = 0; i < nr_pages; i++) > + test_shared(t, i, 0, 'A', 'B'); > + > + /* > + * Converting in bulk should fail as long any page in the range has > + * unexpected refcounts. > + */ > + test_convert_to_private_fails(t, 0, nr_pages, test_page * page_size); > + > + for (i = 0; i < nr_pages; i++) { > + /* > + * Converting page-wise should also fail as long any page in > the > + * range has unexpected refcounts. > + */ > + if (i == test_page) > + test_convert_to_private_fails(t, i, 1, test_page * > page_size); > + else > + test_convert_to_private(t, i, 'B', 'C'); > + } > + > + unpin_pages(); > + > + gmem_set_private(t->gmem_fd, 0, nr_pages * page_size); > + > + for (i = 0; i < nr_pages; i++) { > + char expected = i == test_page ? 'B' : 'C'; > + > + test_private(t, i, expected, 'D'); > + } > +} > + > int main(int argc, char *argv[]) > { > TEST_REQUIRE(kvm_check_cap(KVM_CAP_VM_TYPES) & > BIT(KVM_X86_SW_PROTECTED_VM)); > > -- > 2.55.0.rc0.738.g0c8ab3ebcc-goog > >
