From: Samiullah Khawaja <skhawaja@google.com>
To: David Matlack <dmatlack@google.com>
Cc: Joerg Roedel <joro@8bytes.org>, Will Deacon <will@kernel.org>,
Jason Gunthorpe <jgg@ziepe.ca>,
Robin Murphy <robin.murphy@arm.com>,
Kevin Tian <kevin.tian@intel.com>,
Alex Williamson <alex@shazbot.org>,
iommu@lists.linux.dev, linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org,
Pasha Tatashin <pasha.tatashin@soleen.com>,
Lu Baolu <baolu.lu@linux.intel.com>,
Pranjal Shrivastava <praan@google.com>
Subject: Re: [RFC PATCH 2/3] vfio: selftests: Add iommufd hwpt replace test
Date: Fri, 23 Oct 2026 23:10:36 +0000 [thread overview]
Message-ID: <atvop22fFX7tkt9G@google.com> (raw)
In-Reply-To: <atk_Jq9gEpU5kB8p@google.com>
On Wed, Oct 21, 2026 at 10:39:34PM +0000, David Matlack wrote:
>On 2026-09-25 01:13 AM, Samiullah Khawaja wrote:
>> Add a test that does iommufd hwpt replace while a DMA is ongoing. This
>> verifies the hitless replace of IOMMU domain without disrupting the DMA.
>>
>> Note that the new domain is attached after mapping the required DMA
>> memory at the same IOVA in the new domain.
>>
>> Signed-off-by: Samiullah Khawaja <skhawaja@google.com>
>
>Aside from the MODE_IOMMUFD nit,
>
>Reviewed-by: David Matlack <dmatlack@google.com>
>
>> ---
>> tools/testing/selftests/vfio/Makefile | 1 +
>> .../vfio/vfio_iommufd_hwpt_replace_test.c | 171 ++++++++++++++++++
>> 2 files changed, 172 insertions(+)
>> create mode 100644 tools/testing/selftests/vfio/vfio_iommufd_hwpt_replace_test.c
>>
>> diff --git a/tools/testing/selftests/vfio/Makefile b/tools/testing/selftests/vfio/Makefile
>> index 2c32c48db509..01d0e808871b 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_iommufd_hwpt_replace_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/vfio_iommufd_hwpt_replace_test.c b/tools/testing/selftests/vfio/vfio_iommufd_hwpt_replace_test.c
>> new file mode 100644
>> index 000000000000..3ec243aae626
>> --- /dev/null
>> +++ b/tools/testing/selftests/vfio/vfio_iommufd_hwpt_replace_test.c
>> @@ -0,0 +1,171 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +#include <string.h>
>> +#include <sys/ioctl.h>
>> +#include <sys/mman.h>
>> +
>> +#include <linux/sizes.h>
>> +#include <linux/vfio.h>
>> +
>> +#include <libvfio.h>
>> +
>> +#include "kselftest_harness.h"
>> +
>> +static const char *device_bdf;
>> +
>> +static void region_setup(struct iommu *iommu,
>> + struct iova_allocator *iova_allocator,
>> + struct dma_region *region, u64 size)
>> +{
>> + const int flags = MAP_SHARED | MAP_ANONYMOUS;
>> + const int prot = PROT_READ | PROT_WRITE;
>> + void *vaddr;
>> +
>> + vaddr = mmap(NULL, size, prot, flags, -1, 0);
>> + VFIO_ASSERT_NE(vaddr, MAP_FAILED);
>> +
>> + region->vaddr = vaddr;
>> + region->iova = iova_allocator_alloc(iova_allocator, size);
>> + region->size = size;
>> +
>> + iommu_map(iommu, region);
>> +}
>> +
>> +static void region_teardown(struct iommu *iommu, struct dma_region *region)
>> +{
>> + iommu_unmap(iommu, region);
>> + VFIO_ASSERT_EQ(munmap(region->vaddr, region->size), 0);
>> +}
>> +
>> +FIXTURE(vfio_iommufd_replace_hwpt_test) {
>> + struct iommu *iommu;
>> + struct vfio_pci_device *device;
>> + struct iova_allocator *iova_allocator;
>> + struct dma_region memcpy_region;
>> +
>> + u64 size;
>> + void *src;
>> + void *dst;
>> + iova_t src_iova;
>> + iova_t dst_iova;
>> +};
>> +
>> +FIXTURE_SETUP(vfio_iommufd_replace_hwpt_test)
>> +{
>> + struct vfio_pci_driver *driver;
>> +
>> + self->iommu = iommu_init("iommufd");
>
>nit: iommu_init(MODE_IOMMUFD)
>
>This needs to be fixed in iommufd_iommu_init() in the previous patch as
>well.
>
>> + self->device = vfio_pci_device_init(device_bdf, self->iommu);
>> + self->iova_allocator = iova_allocator_init(self->iommu);
>> +
>> + driver = &self->device->driver;
>> +
>> + region_setup(self->iommu, self->iova_allocator, &self->memcpy_region, SZ_2M);
>> + region_setup(self->iommu, self->iova_allocator, &driver->region, SZ_2M);
>
>The driver->region.size is now populated automatically based on what the
>driver needs. So you can just pass in driver->region.size here instead
>of hard-coding SZ_2M.
>
>> +
>> + if (driver->ops)
>> + vfio_pci_driver_init(self->device);
>> +
>> + self->size = self->memcpy_region.size / 2;
>> + self->src = self->memcpy_region.vaddr;
>> + self->dst = self->src + self->size;
>> +
>> + self->src_iova = to_iova(self->device, self->src);
>> + self->dst_iova = to_iova(self->device, self->dst);
>> +}
>> +
>> +FIXTURE_TEARDOWN(vfio_iommufd_replace_hwpt_test)
>> +{
>> + struct vfio_pci_driver *driver = &self->device->driver;
>> +
>> + if (driver->ops)
>> + vfio_pci_driver_remove(self->device);
>> +
>> + region_teardown(self->iommu, &self->memcpy_region);
>> + region_teardown(self->iommu, &driver->region);
>> +
>> + iova_allocator_cleanup(self->iova_allocator);
>> + vfio_pci_device_cleanup(self->device);
>> + iommu_cleanup(self->iommu);
>> +}
>> +
>> +FIXTURE_VARIANT(vfio_iommufd_replace_hwpt_test) {
>> + u32 attaches;
>> +};
>> +
>> +FIXTURE_VARIANT_ADD(vfio_iommufd_replace_hwpt_test, domain_replace) {
>> + .attaches = 1000,
>
>Maybe we should replace memcpy_wait() with memcpy_poll() and move the
>wait loop out into the generic driver layer (vfio_pci_driver.c)
>repeatedly calling memcpy_poll(). The would let you do replaces until
>the memcpy is done instead of hard-coding a random number, and also lift
>more code out of the the drivers and into the generic core.
The purpose of this being here was to a N number of attaches/replaces as
it might have chance to produce faults, as this is basically race. While
I agree poll() is a useful op to have, but in the context of this test
maybe it is an overkill.
Thanks,
Sami
>
>It should be easy enough to swap the drivers from wait() to poll() model
>if you are feeling up for it. Not a blocker for this series though.
>
>> +};
>> +
>> +FIXTURE_VARIANT_ADD(vfio_iommufd_replace_hwpt_test, noreplace) {
>> + .attaches = 0,
>> +};
>> +
>> +TEST_F_TIMEOUT(vfio_iommufd_replace_hwpt_test, memcpy, 120)
>> +{
>> + struct dma_region memcpy_region = {}, driver_region = {};
>> + struct vfio_pci_driver *driver = &self->device->driver;
>> + struct iommu *iommu2 = NULL;
>> + u64 size = 0;
>> + int ret;
>> + u32 i;
>> +
>> + if (variant->attaches) {
>> + iommu2 = iommufd_iommu_init(self->iommu->iommufd,
>> + self->device->dev_id);
>> +
>> + memcpy_region = self->memcpy_region;
>> + driver_region = self->device->driver.region;
>> +
>> + iommu_map(iommu2, &memcpy_region);
>> + iommu_map(iommu2, &driver_region);
>> + }
>> +
>> + if (driver->ops) {
>> + memset(self->src, 'x', self->size);
>> + memset(self->dst, 'y', self->size);
>> +
>> + size = min_t(u64, driver->max_memcpy_size, self->size);
>> +
>> + /*
>> + * Fill the device's queue. memcpy_start() returns with
>> + * max_memcpy_count transfers still outstanding.
>> + */
>> + vfio_pci_driver_memcpy_start(self->device,
>> + self->src_iova,
>> + self->dst_iova,
>> + size, driver->max_memcpy_count);
>> + }
>> +
>> + /*
>> + * Replace the domain repeatedly while that transfer is in flight. Since
>> + * domain replacement is a race with the translation requests, it needs
>> + * to be done multiple times to capture the small window where iommu
>> + * faults can occur.
>> + *
>> + * The loop ends on the original domain, so the teardown below is safe.
>> + */
>> + for (i = 0; i < variant->attaches; i++) {
>> + vfio_pci_device_attach_iommu(self->device, iommu2);
>> + vfio_pci_device_attach_iommu(self->device, self->iommu);
>> + }
>> +
>> + if (driver->ops) {
>> + ret = vfio_pci_driver_memcpy_wait(self->device);
>> +
>> + ASSERT_EQ(0, ret);
>> + ASSERT_EQ(0, memcmp(self->src, self->dst, size));
>> + }
>> +
>> + if (iommu2) {
>> + iommu_unmap(iommu2, &memcpy_region);
>> + iommu_unmap(iommu2, &driver_region);
>> + iommu_cleanup(iommu2);
>> + }
>> +}
>> +
>> +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
>>
next prev parent reply other threads:[~2026-10-23 23:10 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-25 1:13 [RFC PATCH 0/3] iommu/arm-smmu-v3: Add support for hitless replace of CD entries Samiullah Khawaja
2026-09-25 1:13 ` [RFC PATCH 1/3] vfio: selftests: Add support of creating iommus from iommufd Samiullah Khawaja
2026-10-21 22:19 ` David Matlack
2026-10-23 23:04 ` Samiullah Khawaja
2026-09-25 1:13 ` [RFC PATCH 2/3] vfio: selftests: Add iommufd hwpt replace test Samiullah Khawaja
2026-10-21 22:39 ` David Matlack
2026-10-23 23:10 ` Samiullah Khawaja [this message]
2026-09-25 1:13 ` [RFC PATCH 3/3] iommu/arm-smmu-v3: Add support for hitless replace of S1 domains Samiullah Khawaja
2026-10-23 13:43 ` Robin Murphy
2026-10-23 13:49 ` Jason Gunthorpe
2026-10-23 14:04 ` Robin Murphy
2026-10-23 14:29 ` Jason Gunthorpe
2026-10-23 23:31 ` Samiullah Khawaja
2026-09-25 21:44 ` [RFC PATCH 0/3] iommu/arm-smmu-v3: Add support for hitless replace of CD entries David Matlack
2026-09-25 22:27 ` Samiullah Khawaja
2026-10-23 12:10 ` Robin Murphy
2026-10-23 13:46 ` Jason Gunthorpe
2026-10-23 14:12 ` Robin Murphy
2026-10-23 22:59 ` Samiullah Khawaja
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=atvop22fFX7tkt9G@google.com \
--to=skhawaja@google.com \
--cc=alex@shazbot.org \
--cc=baolu.lu@linux.intel.com \
--cc=dmatlack@google.com \
--cc=iommu@lists.linux.dev \
--cc=jgg@ziepe.ca \
--cc=joro@8bytes.org \
--cc=kevin.tian@intel.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=pasha.tatashin@soleen.com \
--cc=praan@google.com \
--cc=robin.murphy@arm.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®