From: Aaron Lewis <aaronlewis@google.com>
To: kvm@vger.kernel.org
Cc: alex@shazbot.org, dmatlack@google.com, jgg@nvidia.com,
Aaron Lewis <aaronlewis@google.com>
Subject: [PATCH v4 3/5] vfio: selftests: Add memfd test to vfio_dma_mapping_perf_test
Date: Sat, 14 Nov 2026 13:21:58 +0000 [thread overview]
Message-ID: <20261114132200.113697-4-aaronlewis@google.com> (raw)
In-Reply-To: <20261114132200.113697-1-aaronlewis@google.com>
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(®ion->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, ®ion));
+ ASSERT_EQ(region.iova, to_iova(self->device, region.vaddr));
+
+ TIME("IOMMU unmap", iommu_unmap(self->iommu, ®ion));
+
+ 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
next prev parent reply other threads:[~2026-11-14 13:22 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
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 [this message]
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
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=20261114132200.113697-4-aaronlewis@google.com \
--to=aaronlewis@google.com \
--cc=alex@shazbot.org \
--cc=dmatlack@google.com \
--cc=jgg@nvidia.com \
--cc=kvm@vger.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