All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 0/5] Introduce vfio_dma_mapping_perf_test
@ 2026-11-14 13:21 Aaron Lewis
  2026-11-14 13:21 ` [PATCH v4 1/5] vfio: selftests: Assert the region was unmapped in iommu_unmap() Aaron Lewis
                   ` (4 more replies)
  0 siblings, 5 replies; 7+ messages in thread
From: Aaron Lewis @ 2026-11-14 13:21 UTC (permalink / raw)
  To: kvm; +Cc: alex, dmatlack, jgg, Aaron Lewis

Add a new VFIO selftest, vfio_dma_mapping_perf_test, to provide a
configurable tool for measuring DMA mapping and unmapping latencies
across backing memory types, IOMMU backends, and region sizes.

For example, running the test across various region sizes (backed by 1G
HugeTLB pages) makes it easy to collect and compare latencies:

Map latency:

IOCTL               |      1G  |      4G  |     32G  |     128G
--------------------+----------+----------+----------+-----------
VFIO_IOMMU_MAP_DMA  |  0.39 ms |  1.38 ms | 11.62 ms |  46.54 ms
IOMMU_IOAS_MAP      |  0.58 ms |  2.27 ms | 18.08 ms |  73.49 ms
IOMMU_IOAS_MAP_FILE |  0.01 ms |  0.02 ms |  0.10 ms |   0.32 ms

Unmap latency:

IOCTL               |      1G  |      4G  |     32G  |     128G
--------------------+----------+----------+----------+-----------
VFIO_IOMMU_MAP_DMA  |  1.51 ms |  5.69 ms | 45.78 ms | 187.66 ms
IOMMU_IOAS_MAP      |  1.84 ms |  6.83 ms | 52.53 ms | 211.75 ms
IOMMU_IOAS_MAP_FILE |  1.78 ms |  6.74 ms | 61.26 ms | 213.70 ms

The numbers in the tables were collected on EMR.

Changes in v4:
 - Split kselftest_harness.h custom CLI option support into its own patch
 - Printed usage help on invalid options and passed custom optstring to
   test_enabled()
 - Skipped variants when the '-b' size is not aligned to the page size
 - Renamed timer_start() to timer_get()

v3: https://lore.kernel.org/kvm/20260910153326.3085937-1-aaronlewis@google.com/

Aaron Lewis (5):
  vfio: selftests: Assert the region was unmapped in iommu_unmap()
  vfio: selftests: Introduce vfio_dma_mapping_perf_test
  vfio: selftests: Add memfd test to vfio_dma_mapping_perf_test
  selftests: harness: Support custom command-line options
  vfio: selftests: Allow a size for vfio_dma_mapping_perf_test

 tools/testing/selftests/kselftest_harness.h   | 127 +++++---
 tools/testing/selftests/vfio/Makefile         |   1 +
 .../selftests/vfio/lib/include/libvfio.h      |  31 ++
 .../vfio/lib/include/libvfio/iommu.h          |  14 +-
 tools/testing/selftests/vfio/lib/iommu.c      |  24 ++
 .../vfio/vfio_dma_mapping_perf_test.c         | 279 ++++++++++++++++++
 .../selftests/vfio/vfio_dma_mapping_test.c    |  11 +-
 7 files changed, 444 insertions(+), 43 deletions(-)
 create mode 100644 tools/testing/selftests/vfio/vfio_dma_mapping_perf_test.c

-- 
2.56.0.611.g1030f0b940-goog


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH v4 1/5] vfio: selftests: Assert the region was unmapped in iommu_unmap()
  2026-11-14 13:21 [PATCH v4 0/5] Introduce vfio_dma_mapping_perf_test Aaron Lewis
@ 2026-11-14 13:21 ` Aaron Lewis
  2026-11-14 13:21 ` [PATCH v4 2/5] vfio: selftests: Introduce vfio_dma_mapping_perf_test Aaron Lewis
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Aaron Lewis @ 2026-11-14 13:21 UTC (permalink / raw)
  To: kvm; +Cc: alex, dmatlack, jgg, Aaron Lewis

Add an assertion in iommu_unmap() to verify that the region was fully
unmapped. Centralizing this check simplifies the selftests by removing
the need for individual tests to handle the verification themselves.

Suggested-by: David Matlack <dmatlack@google.com>
Reviewed-by: David Matlack <dmatlack@google.com>
Signed-off-by: Aaron Lewis <aaronlewis@google.com>
---
 .../selftests/vfio/lib/include/libvfio/iommu.h        |  5 ++++-
 tools/testing/selftests/vfio/vfio_dma_mapping_test.c  | 11 ++---------
 2 files changed, 6 insertions(+), 10 deletions(-)

diff --git a/tools/testing/selftests/vfio/lib/include/libvfio/iommu.h b/tools/testing/selftests/vfio/lib/include/libvfio/iommu.h
index e9a3386a4719..5c77875240f4 100644
--- a/tools/testing/selftests/vfio/lib/include/libvfio/iommu.h
+++ b/tools/testing/selftests/vfio/lib/include/libvfio/iommu.h
@@ -46,7 +46,10 @@ int __iommu_unmap(struct iommu *iommu, struct dma_region *region, u64 *unmapped)
 
 static inline void iommu_unmap(struct iommu *iommu, struct dma_region *region)
 {
-	VFIO_ASSERT_EQ(__iommu_unmap(iommu, region, NULL), 0);
+	u64 unmapped;
+
+	VFIO_ASSERT_EQ(__iommu_unmap(iommu, region, &unmapped), 0);
+	VFIO_ASSERT_EQ(unmapped, region->size);
 }
 
 int __iommu_unmap_all(struct iommu *iommu, u64 *unmapped);
diff --git a/tools/testing/selftests/vfio/vfio_dma_mapping_test.c b/tools/testing/selftests/vfio/vfio_dma_mapping_test.c
index 7d0de8c79de1..1b90441644a2 100644
--- a/tools/testing/selftests/vfio/vfio_dma_mapping_test.c
+++ b/tools/testing/selftests/vfio/vfio_dma_mapping_test.c
@@ -138,7 +138,6 @@ TEST_F(vfio_dma_mapping_test, dma_map_unmap)
 	struct dma_region region;
 	struct iommu_mapping mapping;
 	u64 mapping_size = size;
-	u64 unmapped;
 	int rc;
 
 	region.vaddr = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0);
@@ -190,9 +189,7 @@ TEST_F(vfio_dma_mapping_test, dma_map_unmap)
 	}
 
 unmap:
-	rc = __iommu_unmap(self->iommu, &region, &unmapped);
-	ASSERT_EQ(rc, 0);
-	ASSERT_EQ(unmapped, region.size);
+	iommu_unmap(self->iommu, &region);
 	printf("Unmapped IOVA 0x%lx\n", region.iova);
 	ASSERT_NE(0, __to_iova(self->device, region.vaddr, NULL));
 	ASSERT_NE(0, iommu_mapping_get(device_bdf, region.iova, &mapping));
@@ -260,15 +257,11 @@ FIXTURE_TEARDOWN(vfio_dma_map_limit_test)
 TEST_F(vfio_dma_map_limit_test, unmap_range)
 {
 	struct dma_region *region = &self->region;
-	u64 unmapped;
-	int rc;
 
 	iommu_map(self->iommu, region);
 	ASSERT_EQ(region->iova, to_iova(self->device, region->vaddr));
 
-	rc = __iommu_unmap(self->iommu, region, &unmapped);
-	ASSERT_EQ(rc, 0);
-	ASSERT_EQ(unmapped, region->size);
+	iommu_unmap(self->iommu, region);
 }
 
 TEST_F(vfio_dma_map_limit_test, unmap_all)
-- 
2.56.0.611.g1030f0b940-goog


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v4 2/5] vfio: selftests: Introduce vfio_dma_mapping_perf_test
  2026-11-14 13:21 [PATCH v4 0/5] Introduce vfio_dma_mapping_perf_test Aaron Lewis
  2026-11-14 13:21 ` [PATCH v4 1/5] vfio: selftests: Assert the region was unmapped in iommu_unmap() Aaron Lewis
@ 2026-11-14 13:21 ` Aaron Lewis
  2026-11-14 13:21 ` [PATCH v4 3/5] vfio: selftests: Add memfd test to vfio_dma_mapping_perf_test Aaron Lewis
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 7+ messages in thread
From: Aaron Lewis @ 2026-11-14 13:21 UTC (permalink / raw)
  To: kvm; +Cc: alex, dmatlack, jgg, Aaron Lewis

Introduce vfio_dma_mapping_perf_test to aid in latency testing. Rather
than a traditional pass/fail test, which tends to be flaky when
enforcing latency bounds, this test directly reports the latency of
various stages in the mapping and unmapping process.

Start with a basic test that performs a simple DMA map/unmap and tracks
the duration of each operation. The test reports the following metrics:

1. Time taken by mmap().
2. Time taken to map a DMA region.
3. Time taken to unmap a DMA region.
4. Time taken by munmap().

Subsequent commits will introduce more features to allow for a wider
variety of testing.

To ensure consistent DMA mapping times, the test uses MAP_POPULATE when
calling mmap(). This forces page faults to be handled upfront, isolating
the DMA mapping times from them.

Reviewed-by: David Matlack <dmatlack@google.com>
Signed-off-by: Aaron Lewis <aaronlewis@google.com>
---
 tools/testing/selftests/vfio/Makefile         |  1 +
 .../selftests/vfio/lib/include/libvfio.h      | 31 +++++++
 .../vfio/vfio_dma_mapping_perf_test.c         | 90 +++++++++++++++++++
 3 files changed, 122 insertions(+)
 create mode 100644 tools/testing/selftests/vfio/vfio_dma_mapping_perf_test.c

diff --git a/tools/testing/selftests/vfio/Makefile b/tools/testing/selftests/vfio/Makefile
index 2c32c48db509..ed5856af5f9a 100644
--- a/tools/testing/selftests/vfio/Makefile
+++ b/tools/testing/selftests/vfio/Makefile
@@ -8,6 +8,7 @@ else
 CFLAGS = $(KHDR_INCLUDES)
 TEST_GEN_PROGS += vfio_dma_mapping_test
 TEST_GEN_PROGS += vfio_dma_mapping_mmio_test
+TEST_GEN_PROGS += vfio_dma_mapping_perf_test
 TEST_GEN_PROGS += vfio_iommufd_setup_test
 TEST_GEN_PROGS += vfio_pci_device_test
 TEST_GEN_PROGS += vfio_pci_device_init_perf_test
diff --git a/tools/testing/selftests/vfio/lib/include/libvfio.h b/tools/testing/selftests/vfio/lib/include/libvfio.h
index 07862b470777..05802a2c3aba 100644
--- a/tools/testing/selftests/vfio/lib/include/libvfio.h
+++ b/tools/testing/selftests/vfio/lib/include/libvfio.h
@@ -9,6 +9,37 @@
 #include <libvfio/vfio_pci_device.h>
 #include <libvfio/vfio_pci_driver.h>
 
+#include <stdint.h>
+#include <time.h>
+#include <linux/time64.h>
+
+static inline void timer_get(struct timespec *ts)
+{
+	clock_gettime(CLOCK_MONOTONIC, ts);
+}
+
+static inline uint64_t timer_elapsed_ns(struct timespec start)
+{
+	struct timespec end;
+
+	timer_get(&end);
+
+	return (uint64_t)(end.tv_sec - start.tv_sec) * NSEC_PER_SEC +
+	       (uint64_t)(end.tv_nsec - start.tv_nsec);
+}
+
+#define TIME(_name, _expression) do {				   \
+	struct timespec __start;				   \
+	int __errno;						   \
+								   \
+	timer_get(&__start);					   \
+	_expression;						   \
+	__errno = errno;					   \
+	ksft_print_msg(_name " = %.2lfms\n",			   \
+		       (double)timer_elapsed_ns(__start) / NSEC_PER_MSEC); \
+	errno = __errno;					   \
+} while (0)
+
 /*
  * Return the BDF string of the device that the test should use.
  *
diff --git a/tools/testing/selftests/vfio/vfio_dma_mapping_perf_test.c b/tools/testing/selftests/vfio/vfio_dma_mapping_perf_test.c
new file mode 100644
index 000000000000..4d41fecf2372
--- /dev/null
+++ b/tools/testing/selftests/vfio/vfio_dma_mapping_perf_test.c
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <limits.h>
+#include <stdio.h>
+#include <sys/mman.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/iommufd.h>
+#include <linux/limits.h>
+#include <linux/memfd.h>
+#include <linux/mman.h>
+#include <linux/sizes.h>
+#include <linux/time64.h>
+#include <linux/vfio.h>
+
+#include <libvfio.h>
+
+#include "kselftest_harness.h"
+
+static const char *device_bdf;
+
+FIXTURE(vfio_dma_mapping_perf_test) {
+	struct iommu *iommu;
+	struct vfio_pci_device *device;
+	struct iova_allocator *iova_allocator;
+};
+
+FIXTURE_VARIANT(vfio_dma_mapping_perf_test) {
+	const char *iommu_mode;
+	int mmap_flags;
+};
+
+#define FIXTURE_VARIANT_ADD_IOMMU_MODE(_iommu_mode, _name, _mmap_flags)		  \
+FIXTURE_VARIANT_ADD(vfio_dma_mapping_perf_test, _iommu_mode ## _ ## _name) {	  \
+	.iommu_mode = #_iommu_mode,						  \
+	.mmap_flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_POPULATE | (_mmap_flags), \
+}
+
+FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(anonymous, 0);
+FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(anonymous_hugetlb_2mb, MAP_HUGETLB | MAP_HUGE_2MB);
+FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(anonymous_hugetlb_1gb, MAP_HUGETLB | MAP_HUGE_1GB);
+
+#undef FIXTURE_VARIANT_ADD_IOMMU_MODE
+
+FIXTURE_SETUP(vfio_dma_mapping_perf_test)
+{
+	self->iommu = iommu_init(variant->iommu_mode);
+	self->device = vfio_pci_device_init(device_bdf, self->iommu);
+	self->iova_allocator = iova_allocator_init(self->iommu);
+}
+
+FIXTURE_TEARDOWN(vfio_dma_mapping_perf_test)
+{
+	iova_allocator_cleanup(self->iova_allocator);
+	vfio_pci_device_cleanup(self->device);
+	iommu_cleanup(self->iommu);
+}
+
+TEST_F(vfio_dma_mapping_perf_test, dma_map_unmap)
+{
+	const u64 size = SZ_1G;
+	const int flags = variant->mmap_flags;
+	struct dma_region region;
+
+	ksft_print_msg("mmap size = %lluG\n", (unsigned long long)(size / SZ_1G));
+
+	TIME("mmap",
+	     region.vaddr = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0));
+
+	/* Skip the test if there aren't enough HugeTLB pages available. */
+	if (flags & MAP_HUGETLB && region.vaddr == MAP_FAILED)
+		SKIP(return, "mmap() failed: %s (%d)\n", strerror(errno), errno);
+	else
+		ASSERT_NE(region.vaddr, MAP_FAILED);
+
+	region.iova = iova_allocator_alloc(self->iova_allocator, size);
+	region.size = size;
+
+	TIME("IOMMU map", iommu_map(self->iommu, &region));
+	ASSERT_EQ(region.iova, to_iova(self->device, region.vaddr));
+
+	TIME("IOMMU unmap", iommu_unmap(self->iommu, &region));
+	TIME("munmap", ASSERT_EQ(0, munmap(region.vaddr, size)));
+}
+
+int main(int argc, char *argv[])
+{
+	device_bdf = vfio_selftests_get_bdf(&argc, argv);
+	return test_harness_run(argc, argv);
+}
-- 
2.56.0.611.g1030f0b940-goog


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v4 3/5] vfio: selftests: Add memfd test to vfio_dma_mapping_perf_test
  2026-11-14 13:21 [PATCH v4 0/5] Introduce vfio_dma_mapping_perf_test Aaron Lewis
  2026-11-14 13:21 ` [PATCH v4 1/5] vfio: selftests: Assert the region was unmapped in iommu_unmap() Aaron Lewis
  2026-11-14 13:21 ` [PATCH v4 2/5] vfio: selftests: Introduce vfio_dma_mapping_perf_test Aaron Lewis
@ 2026-11-14 13:21 ` Aaron Lewis
  2026-11-14 13:21 ` [PATCH v4 4/5] selftests: harness: Support custom command-line options Aaron Lewis
  2026-11-14 13:22 ` [PATCH v4 5/5] vfio: selftests: Allow a size for vfio_dma_mapping_perf_test Aaron Lewis
  4 siblings, 0 replies; 7+ messages in thread
From: Aaron Lewis @ 2026-11-14 13:21 UTC (permalink / raw)
  To: kvm; +Cc: alex, dmatlack, jgg, Aaron Lewis

Add a second test to "vfio_dma_mapping_perf_test" to evaluate memfd
latencies. A key motivator for adding this test is to demonstrate that
the IOMMU_IOAS_MAP_FILE ioctl is significantly faster than other methods
of mapping DMA regions. This performance difference is more apparent
with larger memory regions, which will be added in a subsequent commit.

To support this, add IOMMU_IOAS_MAP_FILE ioctl support to the VFIO
selftest library via iommufd_map_file().

Reviewed-by: David Matlack <dmatlack@google.com>
Signed-off-by: Aaron Lewis <aaronlewis@google.com>
---
 .../vfio/lib/include/libvfio/iommu.h          |  9 ++
 tools/testing/selftests/vfio/lib/iommu.c      | 24 +++++
 .../vfio/vfio_dma_mapping_perf_test.c         | 99 +++++++++++++++++++
 3 files changed, 132 insertions(+)

diff --git a/tools/testing/selftests/vfio/lib/include/libvfio/iommu.h b/tools/testing/selftests/vfio/lib/include/libvfio/iommu.h
index 5c77875240f4..2336dcebce5c 100644
--- a/tools/testing/selftests/vfio/lib/include/libvfio/iommu.h
+++ b/tools/testing/selftests/vfio/lib/include/libvfio/iommu.h
@@ -22,6 +22,8 @@ struct dma_region {
 	void *vaddr;
 	iova_t iova;
 	u64 size;
+	int fd;
+	u64 fd_offset;
 };
 
 struct iommu {
@@ -35,6 +37,13 @@ struct iommu {
 struct iommu *iommu_init(const char *iommu_mode);
 void iommu_cleanup(struct iommu *iommu);
 
+int __iommufd_map_file(struct iommu *iommu, struct dma_region *region);
+
+static inline void iommufd_map_file(struct iommu *iommu, struct dma_region *region)
+{
+	VFIO_ASSERT_EQ(__iommufd_map_file(iommu, region), 0);
+}
+
 int __iommu_map(struct iommu *iommu, struct dma_region *region);
 
 static inline void iommu_map(struct iommu *iommu, struct dma_region *region)
diff --git a/tools/testing/selftests/vfio/lib/iommu.c b/tools/testing/selftests/vfio/lib/iommu.c
index b6f3c5c84e01..a0a3dc4b968c 100644
--- a/tools/testing/selftests/vfio/lib/iommu.c
+++ b/tools/testing/selftests/vfio/lib/iommu.c
@@ -97,6 +97,30 @@ iova_t iommu_hva2iova(struct iommu *iommu, void *vaddr)
 	return iova;
 }
 
+int __iommufd_map_file(struct iommu *iommu, struct dma_region *region)
+{
+	VFIO_ASSERT_TRUE(iommu->iommufd, "IOMMU_IOAS_MAP_FILE is an IOMMUFD IOCTL.");
+
+	struct iommu_ioas_map_file args = {
+		.size = sizeof(args),
+		.flags = IOMMU_IOAS_MAP_READABLE |
+			IOMMU_IOAS_MAP_WRITEABLE |
+			IOMMU_IOAS_MAP_FIXED_IOVA,
+		.ioas_id = iommu->ioas_id,
+		.fd = region->fd,
+		.start = region->fd_offset,
+		.iova = region->iova,
+		.length = region->size,
+	};
+
+	if (ioctl(iommu->iommufd, IOMMU_IOAS_MAP_FILE, &args))
+		return -errno;
+
+	list_add(&region->link, &iommu->dma_regions);
+
+	return 0;
+}
+
 static int vfio_iommu_map(struct iommu *iommu, struct dma_region *region)
 {
 	struct vfio_iommu_type1_dma_map args = {
diff --git a/tools/testing/selftests/vfio/vfio_dma_mapping_perf_test.c b/tools/testing/selftests/vfio/vfio_dma_mapping_perf_test.c
index 4d41fecf2372..086a63a50df8 100644
--- a/tools/testing/selftests/vfio/vfio_dma_mapping_perf_test.c
+++ b/tools/testing/selftests/vfio/vfio_dma_mapping_perf_test.c
@@ -83,6 +83,105 @@ TEST_F(vfio_dma_mapping_perf_test, dma_map_unmap)
 	TIME("munmap", ASSERT_EQ(0, munmap(region.vaddr, size)));
 }
 
+FIXTURE(vfio_dma_mapping_perf_memfd_test) {
+	struct iommu *iommu;
+	struct vfio_pci_device *device;
+	struct iova_allocator *iova_allocator;
+};
+
+FIXTURE_VARIANT(vfio_dma_mapping_perf_memfd_test) {
+	int mmap_flags;
+	int memfd_flags;
+};
+
+#define FIXTURE_VARIANT_ADD_MEMFD_MODE(_name, _mmap_flags, _memfd_flags)      \
+FIXTURE_VARIANT_ADD(vfio_dma_mapping_perf_memfd_test, iommufd ## _ ## _name) {\
+	.mmap_flags = MAP_SHARED | MAP_POPULATE | (_mmap_flags),	      \
+	.memfd_flags = (_memfd_flags),					      \
+}
+
+FIXTURE_VARIANT_ADD_MEMFD_MODE(memfd, 0, 0);
+FIXTURE_VARIANT_ADD_MEMFD_MODE(memfd_hugetlb_2mb,
+				    MAP_HUGETLB | MAP_HUGE_2MB,
+				    MFD_HUGETLB | MFD_HUGE_2MB);
+FIXTURE_VARIANT_ADD_MEMFD_MODE(memfd_hugetlb_1gb,
+				    MAP_HUGETLB | MAP_HUGE_1GB,
+				    MFD_HUGETLB | MFD_HUGE_1GB);
+
+#undef FIXTURE_VARIANT_ADD_MEMFD_MODE
+
+FIXTURE_SETUP(vfio_dma_mapping_perf_memfd_test)
+{
+	self->iommu = iommu_init(MODE_IOMMUFD);
+	self->device = vfio_pci_device_init(device_bdf, self->iommu);
+	self->iova_allocator = iova_allocator_init(self->iommu);
+}
+
+FIXTURE_TEARDOWN(vfio_dma_mapping_perf_memfd_test)
+{
+	iova_allocator_cleanup(self->iova_allocator);
+	vfio_pci_device_cleanup(self->device);
+	iommu_cleanup(self->iommu);
+}
+
+static void *setup_memfd(int *fd, u64 size, int mmap_flags, int mfd_flags)
+{
+	void *buf = MAP_FAILED;
+
+	TIME("memfd_create",
+	     *fd = memfd_create("vfio_dma_mapping_perf_memfd_test", mfd_flags));
+	if (*fd < 0)
+		return MAP_FAILED;
+
+	if (ftruncate(*fd, size))
+		goto out;
+
+	TIME("mmap",
+	     buf = mmap(NULL, size, PROT_READ | PROT_WRITE, mmap_flags, *fd, 0));
+
+out:
+	if (buf == MAP_FAILED)
+		close(*fd);
+
+	return buf;
+}
+
+static void teardown_memfd(int fd, u64 size, void *vaddr)
+{
+	TIME("munmap", VFIO_ASSERT_EQ(0, munmap(vaddr, size)));
+	TIME("close", VFIO_ASSERT_EQ(0, close(fd)));
+}
+
+TEST_F(vfio_dma_mapping_perf_memfd_test, dma_map_unmap_from_file)
+{
+	const u64 size = SZ_1G;
+	const int mmap_flags = variant->mmap_flags;
+	struct dma_region region;
+	int fd;
+
+	ksft_print_msg("mmap size = %lluG\n", (unsigned long long)(size / SZ_1G));
+
+	region.vaddr = setup_memfd(&fd, size, mmap_flags, variant->memfd_flags);
+
+	/* Skip the test if there aren't enough HugeTLB pages available. */
+	if (mmap_flags & MAP_HUGETLB && region.vaddr == MAP_FAILED)
+		SKIP(return, "setup_memfd() failed: %s (%d)\n", strerror(errno), errno);
+	else
+		ASSERT_NE(region.vaddr, MAP_FAILED);
+
+	region.iova = iova_allocator_alloc(self->iova_allocator, size);
+	region.size = size;
+	region.fd = fd;
+	region.fd_offset = 0;
+
+	TIME("IOMMU map file", iommufd_map_file(self->iommu, &region));
+	ASSERT_EQ(region.iova, to_iova(self->device, region.vaddr));
+
+	TIME("IOMMU unmap", iommu_unmap(self->iommu, &region));
+
+	teardown_memfd(fd, size, region.vaddr);
+}
+
 int main(int argc, char *argv[])
 {
 	device_bdf = vfio_selftests_get_bdf(&argc, argv);
-- 
2.56.0.611.g1030f0b940-goog


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v4 4/5] selftests: harness: Support custom command-line options
  2026-11-14 13:21 [PATCH v4 0/5] Introduce vfio_dma_mapping_perf_test Aaron Lewis
                   ` (2 preceding siblings ...)
  2026-11-14 13:21 ` [PATCH v4 3/5] vfio: selftests: Add memfd test to vfio_dma_mapping_perf_test Aaron Lewis
@ 2026-11-14 13:21 ` Aaron Lewis
  2026-11-14 13:22 ` [PATCH v4 5/5] vfio: selftests: Allow a size for vfio_dma_mapping_perf_test Aaron Lewis
  4 siblings, 0 replies; 7+ messages in thread
From: Aaron Lewis @ 2026-11-14 13:21 UTC (permalink / raw)
  To: kvm
  Cc: alex, dmatlack, jgg, Aaron Lewis, Kees Cook, Andy Lutomirski,
	Will Drewry, Shuah Khan, linux-kselftest

Because the selftest harness parses command-line parameters directly,
adding custom options to individual tests requires the test harness to
recognize them.

Add support to kselftest_harness.h for custom command-line options via
struct test_harness_cli_opts and test_harness_run_opts(), allowing tests
to register a custom getopt optstring, option handler, and optional help
callback while keeping test_harness_run() unchanged for existing callers.

Assert if the custom options string is problematic (e.g. conflicting
with built-in options or exceeding the buffer limit). This should only
happen when developing a test, and asserting makes the issue immediately
obvious to the developer.

Also update test_enabled() to match exact option characters rather than
tolower(opt) so custom options that differ only by case (such as 'R') do
not mistakenly match built-in single-case options like '-r'.

Signed-off-by: Aaron Lewis <aaronlewis@google.com>
---
 tools/testing/selftests/kselftest_harness.h | 127 +++++++++++++++-----
 1 file changed, 94 insertions(+), 33 deletions(-)

diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h
index 29a19bc87084..562d4c0edac5 100644
--- a/tools/testing/selftests/kselftest_harness.h
+++ b/tools/testing/selftests/kselftest_harness.h
@@ -54,6 +54,7 @@
 #define _GNU_SOURCE
 #endif
 #include <asm/types.h>
+#include <assert.h>
 #include <ctype.h>
 #include <errno.h>
 #include <linux/unistd.h>
@@ -76,6 +77,18 @@ static inline void __kselftest_memset_safe(void *s, int c, size_t n)
 		memset(s, c, n);
 }
 
+/**
+ * struct test_harness_cli_opts - Custom command-line options for test harness
+ * @optstring: getopt option string; must not conflict with harness options.
+ * @handler: Callback to handle custom options; returns KSFT_PASS or KSFT_FAIL.
+ * @help: Optional callback to print custom option help text.
+ */
+struct test_harness_cli_opts {
+	const char *optstring;
+	int (*handler)(int opt, char *optarg);
+	void (*help)(void);
+};
+
 #define KSELFTEST_PRIO_TEST    20000
 #define KSELFTEST_PRIO_XFAIL   20001
 
@@ -1097,11 +1110,60 @@ static void test_harness_list_tests(void)
 	}
 }
 
-static int test_harness_argv_check(int argc, char **argv)
+#define OPTSTRING_LEN 128
+
+static void optstring_append_custom(char *optstring, size_t size,
+				    const struct test_harness_cli_opts *opts)
+{
+	const char *c;
+
+	if (!opts || !opts->optstring)
+		return;
+
+	assert(strlen(optstring) + strlen(opts->optstring) < size);
+
+	for (c = opts->optstring; *c; c++) {
+		if (isalnum(*c))
+			assert(!strchr(optstring, *c));
+	}
+
+	strncat(optstring, opts->optstring, size - strlen(optstring) - 1);
+}
+
+static void test_harness_usage(const char *prog,
+			       const struct test_harness_cli_opts *opts)
+{
+	fprintf(stderr,
+		"Usage: %s [-h|-l|-d] [-t|-T|-v|-V|-f|-F|-r name]\n"
+		"\t-h       print help\n"
+		"\t-l       list all tests\n"
+		"\t-d       enable debug prints\n"
+		"\n"
+		"\t-t name  include test\n"
+		"\t-T name  exclude test\n"
+		"\t-v name  include variant\n"
+		"\t-V name  exclude variant\n"
+		"\t-f name  include fixture\n"
+		"\t-F name  exclude fixture\n"
+		"\t-r name  run specified test\n"
+		"\n"
+		"Test filter options can be specified multiple times. The filtering stops\n"
+		"at the first match. For example to include all tests from variant 'bla'\n"
+		"but not test 'foo' specify '-T foo -v bla'.\n", prog);
+
+	if (opts && opts->help) {
+		fprintf(stderr, "\nCustom options:\n");
+		opts->help();
+	}
+}
+
+static int test_harness_argv_check(int argc, char **argv, const char *optstring,
+				   const struct test_harness_cli_opts *opts)
 {
 	int opt;
 
-	while ((opt = getopt(argc, argv, "dhlF:f:V:v:t:T:r:")) != -1) {
+	optind = 1;
+	while ((opt = getopt(argc, argv, optstring)) != -1) {
 		switch (opt) {
 		case 'f':
 		case 'F':
@@ -1118,35 +1180,21 @@ static int test_harness_argv_check(int argc, char **argv)
 			ksft_debug_enabled = true;
 			break;
 		case 'h':
+			test_harness_usage(argv[0], opts);
+			return KSFT_SKIP;
 		default:
-			fprintf(stderr,
-				"Usage: %s [-h|-l|-d] [-t|-T|-v|-V|-f|-F|-r name]\n"
-				"\t-h       print help\n"
-				"\t-l       list all tests\n"
-				"\t-d       enable debug prints\n"
-				"\n"
-				"\t-t name  include test\n"
-				"\t-T name  exclude test\n"
-				"\t-v name  include variant\n"
-				"\t-V name  exclude variant\n"
-				"\t-f name  include fixture\n"
-				"\t-F name  exclude fixture\n"
-				"\t-r name  run specified test\n"
-				"\n"
-				"Test filter options can be specified "
-				"multiple times. The filtering stops\n"
-				"at the first match. For example to "
-				"include all tests from variant 'bla'\n"
-				"but not test 'foo' specify '-T foo -v bla'.\n"
-				"", argv[0]);
-			return opt == 'h' ? KSFT_SKIP : KSFT_FAIL;
+			if (opts && opts->handler &&
+			    opts->handler(opt, optarg) == KSFT_PASS)
+				break;
+			test_harness_usage(argv[0], opts);
+			return KSFT_FAIL;
 		}
 	}
 
 	return KSFT_PASS;
 }
 
-static bool test_enabled(int argc, char **argv,
+static bool test_enabled(int argc, char **argv, const char *optstring,
 			 struct __fixture_metadata *f,
 			 struct __fixture_variant_metadata *v,
 			 struct __test_metadata *t)
@@ -1156,24 +1204,28 @@ static bool test_enabled(int argc, char **argv,
 	int opt;
 
 	optind = 1;
-	while ((opt = getopt(argc, argv, "dF:f:V:v:t:T:r:")) != -1) {
-		if (opt != 'd')
-			has_positive |= islower(opt);
-
-		switch (tolower(opt)) {
+	while ((opt = getopt(argc, argv, optstring)) != -1) {
+		switch (opt) {
 		case 't':
+		case 'T':
+			has_positive |= islower(opt);
 			if (!strcmp(t->name, optarg))
 				return islower(opt);
 			break;
 		case 'f':
+		case 'F':
+			has_positive |= islower(opt);
 			if (!strcmp(f->name, optarg))
 				return islower(opt);
 			break;
 		case 'v':
+		case 'V':
+			has_positive |= islower(opt);
 			if (!strcmp(v->name, optarg))
 				return islower(opt);
 			break;
 		case 'r':
+			has_positive = true;
 			if (!tlen) {
 				flen = strlen(f->name);
 				vlen = strlen(v->name);
@@ -1262,8 +1314,10 @@ static void __run_test(struct __fixture_metadata *f,
 			      diagnostic ? "%s" : NULL, diagnostic);
 }
 
-static int test_harness_run(int argc, char **argv)
+static int test_harness_run_opts(int argc, char **argv,
+				 const struct test_harness_cli_opts *opts)
 {
+	char optstring[OPTSTRING_LEN] = "dhlF:f:V:v:t:T:r:";
 	struct __fixture_variant_metadata no_variant = { .name = "", };
 	struct __fixture_variant_metadata *v;
 	struct __fixture_metadata *f;
@@ -1274,7 +1328,9 @@ static int test_harness_run(int argc, char **argv)
 	unsigned int count = 0;
 	unsigned int pass_count = 0;
 
-	ret = test_harness_argv_check(argc, argv);
+	optstring_append_custom(optstring, sizeof(optstring), opts);
+
+	ret = test_harness_argv_check(argc, argv, optstring, opts);
 	if (ret != KSFT_PASS)
 		return ret;
 
@@ -1283,7 +1339,7 @@ static int test_harness_run(int argc, char **argv)
 			unsigned int old_tests = test_count;
 
 			for (t = f->tests; t; t = t->next)
-				if (test_enabled(argc, argv, f, v, t))
+				if (test_enabled(argc, argv, optstring, f, v, t))
 					test_count++;
 
 			if (old_tests != test_count)
@@ -1301,7 +1357,7 @@ static int test_harness_run(int argc, char **argv)
 	for (f = __fixture_list; f; f = f->next) {
 		for (v = f->variant ?: &no_variant; v; v = v->next) {
 			for (t = f->tests; t; t = t->next) {
-				if (!test_enabled(argc, argv, f, v, t))
+				if (!test_enabled(argc, argv, optstring, f, v, t))
 					continue;
 				count++;
 				t->results = results;
@@ -1324,6 +1380,11 @@ static int test_harness_run(int argc, char **argv)
 	return KSFT_FAIL;
 }
 
+static inline int test_harness_run(int argc, char **argv)
+{
+	return test_harness_run_opts(argc, argv, NULL);
+}
+
 static void __attribute__((constructor(KSELFTEST_PRIO_TEST))) __constructor_order_first(void)
 {
 	__constructor_order_forward = true;
-- 
2.56.0.611.g1030f0b940-goog


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v4 5/5] vfio: selftests: Allow a size for vfio_dma_mapping_perf_test
  2026-11-14 13:21 [PATCH v4 0/5] Introduce vfio_dma_mapping_perf_test Aaron Lewis
                   ` (3 preceding siblings ...)
  2026-11-14 13:21 ` [PATCH v4 4/5] selftests: harness: Support custom command-line options Aaron Lewis
@ 2026-11-14 13:22 ` Aaron Lewis
  2026-11-14 13:29   ` sashiko-bot
  4 siblings, 1 reply; 7+ messages in thread
From: Aaron Lewis @ 2026-11-14 13:22 UTC (permalink / raw)
  To: kvm
  Cc: alex, dmatlack, jgg, Aaron Lewis, Kees Cook, Andy Lutomirski,
	Will Drewry, Shuah Khan, linux-kselftest

Allow the user to specify a DMA region size via the command line for
vfio_dma_mapping_perf_test.

Use test_harness_run_opts() to introduce a '-b' option to specify the
DMA region size so that both the test size and test harness options can
be passed together naturally:

  ./vfio_dma_mapping_perf_test -b 16G -v vfio_type1_iommu_anonymous_hugetlb_1gb

Signed-off-by: Aaron Lewis <aaronlewis@google.com>
---
 .../vfio/vfio_dma_mapping_perf_test.c         | 144 ++++++++++++++----
 1 file changed, 117 insertions(+), 27 deletions(-)

diff --git a/tools/testing/selftests/vfio/vfio_dma_mapping_perf_test.c b/tools/testing/selftests/vfio/vfio_dma_mapping_perf_test.c
index 086a63a50df8..6e38cc134a49 100644
--- a/tools/testing/selftests/vfio/vfio_dma_mapping_perf_test.c
+++ b/tools/testing/selftests/vfio/vfio_dma_mapping_perf_test.c
@@ -1,10 +1,12 @@
 // SPDX-License-Identifier: GPL-2.0-only
+#include <ctype.h>
 #include <limits.h>
 #include <stdio.h>
 #include <sys/mman.h>
 #include <time.h>
 #include <unistd.h>
 
+#include <linux/align.h>
 #include <linux/iommufd.h>
 #include <linux/limits.h>
 #include <linux/memfd.h>
@@ -17,7 +19,81 @@
 
 #include "kselftest_harness.h"
 
-static const char *device_bdf;
+static struct {
+	u64 size;
+	const char *size_str;
+	const char *device_bdf;
+} test_params = {
+	.size = SZ_1G,
+	.size_str = "1G",
+};
+
+/*
+ * Parses "[0-9]+[kmgt]?".
+ */
+static u64 parse_size(const char *size)
+{
+	int shift = 0;
+	char *scale;
+	u64 base;
+
+	VFIO_ASSERT_TRUE(size && isdigit(size[0]),
+			 "Need at least one digit in '%s'.", size);
+
+	base = strtoull(size, &scale, 0);
+
+	VFIO_ASSERT_GT(base, 0, "Size must be greater than 0!");
+	VFIO_ASSERT_TRUE(base != ULLONG_MAX, "Overflow parsing size!");
+
+	switch (tolower(*scale)) {
+	case 't':
+		shift = 40;
+		break;
+	case 'g':
+		shift = 30;
+		break;
+	case 'm':
+		shift = 20;
+		break;
+	case 'k':
+		shift = 10;
+		break;
+	case 'b':
+	case '\0':
+		shift = 0;
+		break;
+	default:
+		VFIO_FAIL("Unknown size letter '%c'.", *scale);
+	}
+
+	VFIO_ASSERT_TRUE((base << shift) >> shift == base,
+			 "Overflow scaling size!");
+
+	return base << shift;
+}
+
+static void opts_help(void)
+{
+	fprintf(stderr,
+		"\t-b bytes Specify the size of the DMA region to be mapped\n"
+		"\t         and unmapped. e.g. 16M or 8G, (default: 1G)\n");
+}
+
+static int opts_handler(int opt, char *optarg)
+{
+	if (opt == 'b') {
+		test_params.size = parse_size(optarg);
+		test_params.size_str = optarg;
+		return KSFT_PASS;
+	}
+	return KSFT_FAIL;
+}
+
+static const struct test_harness_cli_opts opts = {
+	.optstring = "b:",
+	.handler = opts_handler,
+	.help = opts_help,
+};
 
 FIXTURE(vfio_dma_mapping_perf_test) {
 	struct iommu *iommu;
@@ -27,25 +103,27 @@ FIXTURE(vfio_dma_mapping_perf_test) {
 
 FIXTURE_VARIANT(vfio_dma_mapping_perf_test) {
 	const char *iommu_mode;
+	u64 page_size;
 	int mmap_flags;
 };
 
-#define FIXTURE_VARIANT_ADD_IOMMU_MODE(_iommu_mode, _name, _mmap_flags)		  \
-FIXTURE_VARIANT_ADD(vfio_dma_mapping_perf_test, _iommu_mode ## _ ## _name) {	  \
-	.iommu_mode = #_iommu_mode,						  \
-	.mmap_flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_POPULATE | (_mmap_flags), \
+#define FIXTURE_VARIANT_ADD_IOMMU_MODE(_iommu_mode, _name, _page_size, _mmap_flags) \
+FIXTURE_VARIANT_ADD(vfio_dma_mapping_perf_test, _iommu_mode ## _ ## _name) {	    \
+	.iommu_mode = #_iommu_mode,						    \
+	.page_size = (_page_size),						    \
+	.mmap_flags = MAP_ANONYMOUS | MAP_PRIVATE | MAP_POPULATE | (_mmap_flags),   \
 }
 
-FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(anonymous, 0);
-FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(anonymous_hugetlb_2mb, MAP_HUGETLB | MAP_HUGE_2MB);
-FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(anonymous_hugetlb_1gb, MAP_HUGETLB | MAP_HUGE_1GB);
+FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(anonymous, 0, 0);
+FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(anonymous_hugetlb_2mb, SZ_2M, MAP_HUGETLB | MAP_HUGE_2MB);
+FIXTURE_VARIANT_ADD_ALL_IOMMU_MODES(anonymous_hugetlb_1gb, SZ_1G, MAP_HUGETLB | MAP_HUGE_1GB);
 
 #undef FIXTURE_VARIANT_ADD_IOMMU_MODE
 
 FIXTURE_SETUP(vfio_dma_mapping_perf_test)
 {
 	self->iommu = iommu_init(variant->iommu_mode);
-	self->device = vfio_pci_device_init(device_bdf, self->iommu);
+	self->device = vfio_pci_device_init(test_params.device_bdf, self->iommu);
 	self->iova_allocator = iova_allocator_init(self->iommu);
 }
 
@@ -58,11 +136,16 @@ FIXTURE_TEARDOWN(vfio_dma_mapping_perf_test)
 
 TEST_F(vfio_dma_mapping_perf_test, dma_map_unmap)
 {
-	const u64 size = SZ_1G;
+	const u64 page_size = variant->page_size ?: getpagesize();
+	const u64 size = test_params.size;
 	const int flags = variant->mmap_flags;
 	struct dma_region region;
 
-	ksft_print_msg("mmap size = %lluG\n", (unsigned long long)(size / SZ_1G));
+	if (!IS_ALIGNED(size, page_size))
+		SKIP(return, "Size 0x%llx is not aligned to page size 0x%llx",
+		     (unsigned long long)size, (unsigned long long)page_size);
+
+	ksft_print_msg("mmap size = %s\n", test_params.size_str);
 
 	TIME("mmap",
 	     region.vaddr = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0));
@@ -90,30 +173,32 @@ FIXTURE(vfio_dma_mapping_perf_memfd_test) {
 };
 
 FIXTURE_VARIANT(vfio_dma_mapping_perf_memfd_test) {
+	u64 page_size;
 	int mmap_flags;
 	int memfd_flags;
 };
 
-#define FIXTURE_VARIANT_ADD_MEMFD_MODE(_name, _mmap_flags, _memfd_flags)      \
-FIXTURE_VARIANT_ADD(vfio_dma_mapping_perf_memfd_test, iommufd ## _ ## _name) {\
-	.mmap_flags = MAP_SHARED | MAP_POPULATE | (_mmap_flags),	      \
-	.memfd_flags = (_memfd_flags),					      \
+#define FIXTURE_VARIANT_ADD_MEMFD_MODE(_name, _page_size, _mmap_flags, _memfd_flags) \
+FIXTURE_VARIANT_ADD(vfio_dma_mapping_perf_memfd_test, iommufd ## _ ## _name) {	     \
+	.page_size = (_page_size),						     \
+	.mmap_flags = MAP_SHARED | MAP_POPULATE | (_mmap_flags),		     \
+	.memfd_flags = (_memfd_flags),						     \
 }
 
-FIXTURE_VARIANT_ADD_MEMFD_MODE(memfd, 0, 0);
-FIXTURE_VARIANT_ADD_MEMFD_MODE(memfd_hugetlb_2mb,
-				    MAP_HUGETLB | MAP_HUGE_2MB,
-				    MFD_HUGETLB | MFD_HUGE_2MB);
-FIXTURE_VARIANT_ADD_MEMFD_MODE(memfd_hugetlb_1gb,
-				    MAP_HUGETLB | MAP_HUGE_1GB,
-				    MFD_HUGETLB | MFD_HUGE_1GB);
+FIXTURE_VARIANT_ADD_MEMFD_MODE(memfd, 0, 0, 0);
+FIXTURE_VARIANT_ADD_MEMFD_MODE(memfd_hugetlb_2mb, SZ_2M,
+			       MAP_HUGETLB | MAP_HUGE_2MB,
+			       MFD_HUGETLB | MFD_HUGE_2MB);
+FIXTURE_VARIANT_ADD_MEMFD_MODE(memfd_hugetlb_1gb, SZ_1G,
+			       MAP_HUGETLB | MAP_HUGE_1GB,
+			       MFD_HUGETLB | MFD_HUGE_1GB);
 
 #undef FIXTURE_VARIANT_ADD_MEMFD_MODE
 
 FIXTURE_SETUP(vfio_dma_mapping_perf_memfd_test)
 {
 	self->iommu = iommu_init(MODE_IOMMUFD);
-	self->device = vfio_pci_device_init(device_bdf, self->iommu);
+	self->device = vfio_pci_device_init(test_params.device_bdf, self->iommu);
 	self->iova_allocator = iova_allocator_init(self->iommu);
 }
 
@@ -154,12 +239,17 @@ static void teardown_memfd(int fd, u64 size, void *vaddr)
 
 TEST_F(vfio_dma_mapping_perf_memfd_test, dma_map_unmap_from_file)
 {
-	const u64 size = SZ_1G;
+	const u64 page_size = variant->page_size ?: getpagesize();
+	const u64 size = test_params.size;
 	const int mmap_flags = variant->mmap_flags;
 	struct dma_region region;
 	int fd;
 
-	ksft_print_msg("mmap size = %lluG\n", (unsigned long long)(size / SZ_1G));
+	if (!IS_ALIGNED(size, page_size))
+		SKIP(return, "Size 0x%llx is not aligned to page size 0x%llx",
+		     (unsigned long long)size, (unsigned long long)page_size);
+
+	ksft_print_msg("mmap size = %s\n", test_params.size_str);
 
 	region.vaddr = setup_memfd(&fd, size, mmap_flags, variant->memfd_flags);
 
@@ -184,6 +274,6 @@ TEST_F(vfio_dma_mapping_perf_memfd_test, dma_map_unmap_from_file)
 
 int main(int argc, char *argv[])
 {
-	device_bdf = vfio_selftests_get_bdf(&argc, argv);
-	return test_harness_run(argc, argv);
+	test_params.device_bdf = vfio_selftests_get_bdf(&argc, argv);
+	return test_harness_run_opts(argc, argv, &opts);
 }
-- 
2.56.0.611.g1030f0b940-goog


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH v4 5/5] vfio: selftests: Allow a size for vfio_dma_mapping_perf_test
  2026-11-14 13:22 ` [PATCH v4 5/5] vfio: selftests: Allow a size for vfio_dma_mapping_perf_test Aaron Lewis
@ 2026-11-14 13:29   ` sashiko-bot
  0 siblings, 0 replies; 7+ messages in thread
From: sashiko-bot @ 2026-11-14 13:29 UTC (permalink / raw)
  To: Aaron Lewis, kvm

Thank you for your contribution! Sashiko AI review found 1 potential
issue to consider:
- [Low] vfio: selftests: non-power-of-2 -b size aborts in
  iova_allocator_alloc()
--

commit 7eb32375cc90a8bc43da0741f8174df52036eeb6
Author: Aaron Lewis <aaronlewis@google.com>

vfio: selftests: Allow a size for vfio_dma_mapping_perf_test

This commit adds a '-b' command-line option to vfio_dma_mapping_perf_test to
allow specifying the DMA region size to map and unmap.

> diff --git a/tools/testing/selftests/vfio/vfio_dma_mapping_perf_test.c b/tools/testing/selftests/vfio/vfio_dma_mapping_perf_test.c
> index 086a63a50df80..6e38cc134a49c 100644
> --- a/tools/testing/selftests/vfio/vfio_dma_mapping_perf_test.c
> +++ b/tools/testing/selftests/vfio/vfio_dma_mapping_perf_test.c

[ ... ]

> @@ -58,11 +136,16 @@ FIXTURE_TEARDOWN(vfio_dma_mapping_perf_test)
>  
>  TEST_F(vfio_dma_mapping_perf_test, dma_map_unmap)
>  {
> -	const u64 size = SZ_1G;
> +	const u64 page_size = variant->page_size ?: getpagesize();
> +	const u64 size = test_params.size;
>  	const int flags = variant->mmap_flags;
>  	struct dma_region region;
>  
> -	ksft_print_msg("mmap size = %lluG\n", (unsigned long long)(size / SZ_1G));
> +	if (!IS_ALIGNED(size, page_size))
> +		SKIP(return, "Size 0x%llx is not aligned to page size 0x%llx",
> +		     (unsigned long long)size, (unsigned long long)page_size);
> +
> +	ksft_print_msg("mmap size = %s\n", test_params.size_str);
>  
>  	TIME("mmap",
>  	     region.vaddr = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0));

[Severity: Low]
Will passing a non-power-of-2 size such as "-b 3G" abort the test inside
iova_allocator_alloc()?

parse_size() accepts any positive multiplier and both dma_map_unmap and
dma_map_unmap_from_file only check IS_ALIGNED(size, page_size), but after
populating the mapping they pass size directly to iova_allocator_alloc(),
which requires a power of two:

tools/testing/selftests/vfio/lib/iova_allocator.c:iova_allocator_alloc() {
	VFIO_ASSERT_GT(size, 0, "Invalid size arg, zero\n");
	VFIO_ASSERT_EQ(size & (size - 1), 0, "Invalid size arg, non-power-of-2\n");
    ...
}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261114132200.113697-1-aaronlewis@google.com?part=5

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2026-11-14 13:29 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-14 13:21 [PATCH v4 0/5] Introduce vfio_dma_mapping_perf_test Aaron Lewis
2026-11-14 13:21 ` [PATCH v4 1/5] vfio: selftests: Assert the region was unmapped in iommu_unmap() Aaron Lewis
2026-11-14 13:21 ` [PATCH v4 2/5] vfio: selftests: Introduce vfio_dma_mapping_perf_test Aaron Lewis
2026-11-14 13:21 ` [PATCH v4 3/5] vfio: selftests: Add memfd test to vfio_dma_mapping_perf_test Aaron Lewis
2026-11-14 13:21 ` [PATCH v4 4/5] selftests: harness: Support custom command-line options Aaron Lewis
2026-11-14 13:22 ` [PATCH v4 5/5] vfio: selftests: Allow a size for vfio_dma_mapping_perf_test Aaron Lewis
2026-11-14 13:29   ` sashiko-bot

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.