mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Pranjal Shrivastava <praan@google.com>
To: Joerg Roedel <joro@8bytes.org>, Will Deacon <will@kernel.org>,
	 Robin Murphy <robin.murphy@arm.com>,
	Jason Gunthorpe <jgg@ziepe.ca>, Kevin Tian <kevin.tian@intel.com>,
	 Alex Williamson <alex@shazbot.org>,
	David Matlack <dmatlack@google.com>,
	Jonathan Corbet <corbet@lwn.net>,
	 Shuah Khan <skhan@linuxfoundation.org>,
	Randy Dunlap <rdunlap@infradead.org>
Cc: Mostafa Saleh <smostafa@google.com>,
	Daniel Mentz <danielmentz@google.com>,
	 Samiullah Khawaja <skhawaja@google.com>,
	iommu@lists.linux.dev, kvm@vger.kernel.org,
	 linux-kselftest@vger.kernel.org, linux-doc@vger.kernel.org,
	 Logan Odell <loganodell@google.com>,
	Pranjal Shrivastava <praan@google.com>,
	linux-fsdevel@vger.kernel.org,  linux-kernel@vger.kernel.org
Subject: [RFC PATCH 7/7] vfio/selftests: Add observability test for IO page table usage
Date: Thu,  1 Oct 2026 22:45:31 +0000	[thread overview]
Message-ID: <20261001224531.765278-8-praan@google.com> (raw)
In-Reply-To: <20261001224531.765278-1-praan@google.com>

Add a new selftest, vfio_nr_pages_test, to validate the iommu-nr-pages
fdinfo metric across all IOMMU backends (Type 1 and IOMMUFD native/compat).

The test performs a sparse mapping to force the underlying IOMMU driver
to allocate a deep page table hierarchy. It then asserts that the
nr_pages metric increases and proves the 'sticky' reclamation behavior
by verifying the page count does not drop immediately upon unmapping.

The test is skipped when the IOMMU driver does not account its page
table memory, in which case the metric is not reported.

Co-developed-by: Logan Odell <loganodell@google.com>
Signed-off-by: Logan Odell <loganodell@google.com>
Signed-off-by: Pranjal Shrivastava <praan@google.com>
---
 tools/testing/selftests/vfio/Makefile         |   1 +
 .../selftests/vfio/vfio_nr_pages_test.c       | 119 ++++++++++++++++++
 2 files changed, 120 insertions(+)
 create mode 100644 tools/testing/selftests/vfio/vfio_nr_pages_test.c

diff --git a/tools/testing/selftests/vfio/Makefile b/tools/testing/selftests/vfio/Makefile
index 2c32c48db509..140ef273e36b 100644
--- a/tools/testing/selftests/vfio/Makefile
+++ b/tools/testing/selftests/vfio/Makefile
@@ -13,6 +13,7 @@ TEST_GEN_PROGS += vfio_pci_device_test
 TEST_GEN_PROGS += vfio_pci_device_init_perf_test
 TEST_GEN_PROGS += vfio_pci_driver_test
 TEST_GEN_PROGS += vfio_pci_sriov_uapi_test
+TEST_GEN_PROGS += vfio_nr_pages_test
 
 TEST_FILES += scripts/cleanup.sh
 TEST_FILES += scripts/lib.sh
diff --git a/tools/testing/selftests/vfio/vfio_nr_pages_test.c b/tools/testing/selftests/vfio/vfio_nr_pages_test.c
new file mode 100644
index 000000000000..aef6b1dd8e19
--- /dev/null
+++ b/tools/testing/selftests/vfio/vfio_nr_pages_test.c
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <stdio.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <linux/sizes.h>
+
+#include <libvfio.h>
+
+#include "../kselftest_harness.h"
+
+static const char *device_bdf;
+
+static long read_nr_pages(struct iommu *iommu)
+{
+	char path[256];
+	char line[128];
+	FILE *f;
+	long val = -1;
+	int fd = iommu->container_fd != -1 ? iommu->container_fd : iommu->iommufd;
+
+	snprintf(path, sizeof(path), "/proc/self/fdinfo/%d", fd);
+	f = fopen(path, "r");
+	if (!f)
+		return -1;
+
+	while (fgets(line, sizeof(line), f)) {
+		if (sscanf(line, "iommu-nr-pages: %ld", &val) == 1)
+			break;
+	}
+
+	fclose(f);
+	return val;
+}
+
+FIXTURE(vfio_nr_pages_test) {
+	struct iommu *iommu;
+	struct vfio_pci_device *device;
+};
+
+FIXTURE_VARIANT(vfio_nr_pages_test) {
+	const char *iommu_mode;
+};
+
+#define FIXTURE_VARIANT_ADD_IOMMU_MODE(_name) \
+FIXTURE_VARIANT_ADD(vfio_nr_pages_test, _name) { \
+	.iommu_mode = #_name, \
+}
+
+FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES();
+
+FIXTURE_SETUP(vfio_nr_pages_test)
+{
+	self->iommu = iommu_init(variant->iommu_mode);
+	if (!self->iommu)
+		SKIP(return, "IOMMU mode %s not supported", variant->iommu_mode);
+
+	self->device = vfio_pci_device_init(device_bdf, self->iommu);
+	if (!self->device) {
+		iommu_cleanup(self->iommu);
+		SKIP(return, "Failed to initialize VFIO device");
+	}
+}
+
+FIXTURE_TEARDOWN(vfio_nr_pages_test)
+{
+	if (self->device)
+		vfio_pci_device_cleanup(self->device);
+	if (self->iommu)
+		iommu_cleanup(self->iommu);
+}
+
+TEST_F(vfio_nr_pages_test, sparse_mapping_sticky_reclamation)
+{
+	long nr_pages_initial, nr_pages_mapped, nr_pages_final;
+	struct dma_region region1 = {0};
+	struct dma_region region2 = {0};
+
+	if (!self->iommu || !self->device)
+		SKIP(return, "Fixture setup failed");
+
+	nr_pages_initial = read_nr_pages(self->iommu);
+	if (nr_pages_initial < 0)
+		SKIP(return, "iommu-nr-pages not reported by this IOMMU");
+
+	/* Map a page at start */
+	region1.size = SZ_4K;
+	region1.vaddr = mmap_reserve(region1.size, region1.size, 0);
+	ASSERT_NE(MAP_FAILED, region1.vaddr);
+	region1.iova = 0x100000;
+	iommu_map(self->iommu, &region1);
+
+	/* Map another page far away (1GB stride) to force deep page tables */
+	region2.size = SZ_4K;
+	region2.vaddr = mmap_reserve(region2.size, region2.size, 0);
+	ASSERT_NE(MAP_FAILED, region2.vaddr);
+	region2.iova = 0x100000 + SZ_1G;
+	iommu_map(self->iommu, &region2);
+
+	nr_pages_mapped = read_nr_pages(self->iommu);
+	ASSERT_GT(nr_pages_mapped, nr_pages_initial);
+
+	/* Unmap both regions */
+	iommu_unmap(self->iommu, &region1);
+	iommu_unmap(self->iommu, &region2);
+
+	nr_pages_final = read_nr_pages(self->iommu);
+
+	/* Page tables should remain allocated */
+	ASSERT_EQ(nr_pages_final, nr_pages_mapped);
+
+	munmap(region1.vaddr, region1.size);
+	munmap(region2.vaddr, region2.size);
+}
+
+int main(int argc, char *argv[])
+{
+	device_bdf = vfio_selftests_get_bdf(&argc, argv);
+	return test_harness_run(argc, argv);
+}
-- 
2.56.0.rc1.315.gc6ed9934b7-goog


      parent reply	other threads:[~2026-10-01 22:46 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <20261001224531.765278-1-praan@google.com>
2026-10-01 22:45 ` [RFC PATCH 1/7] iommu: Add infrastructure for per-domain IOPT accounting Pranjal Shrivastava
2026-10-01 22:45 ` [RFC PATCH 2/7] iommu: Implement domain-attributed page allocation Pranjal Shrivastava
2026-10-01 22:45 ` [RFC PATCH 3/7] iommupt: Enable per-domain IOPT attribution Pranjal Shrivastava
2026-10-01 22:45 ` [RFC PATCH 4/7] vfio/type1: Expose IO page table usage via fdinfo Pranjal Shrivastava
2026-10-01 22:45 ` [RFC PATCH 5/7] iommufd: " Pranjal Shrivastava
2026-10-01 22:45 ` [RFC PATCH 6/7] iommufd/selftest: Add observability test for iommu-nr-pages Pranjal Shrivastava
2026-10-01 22:45 ` Pranjal Shrivastava [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=20261001224531.765278-8-praan@google.com \
    --to=praan@google.com \
    --cc=alex@shazbot.org \
    --cc=corbet@lwn.net \
    --cc=danielmentz@google.com \
    --cc=dmatlack@google.com \
    --cc=iommu@lists.linux.dev \
    --cc=jgg@ziepe.ca \
    --cc=joro@8bytes.org \
    --cc=kevin.tian@intel.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=loganodell@google.com \
    --cc=rdunlap@infradead.org \
    --cc=robin.murphy@arm.com \
    --cc=skhan@linuxfoundation.org \
    --cc=skhawaja@google.com \
    --cc=smostafa@google.com \
    --cc=will@kernel.org \
    /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

all inboxes | Powered by JetHome®