[PATCH v3 19/24] vfio: selftests: Initialize vfio_pci_device using a VFIO cdev FD

David Matlack
2026-03-23T23:59:21Z

From: Vipin Sharma <vipinsh@google.com>

Use the given VFIO cdev FD to initialize vfio_pci_device in VFIO
selftests. Add the assertion to make sure that passed cdev FD is not
used with legacy VFIO APIs. If VFIO cdev FD is provided then do not open
the device instead use the FD for any interaction with the device.

This API will allow to write selftests where VFIO device FD is preserved
using liveupdate and retrieved later using liveupdate ioctl after kexec.

Signed-off-by: Vipin Sharma <vipinsh@google.com>
Co-developed-by: David Matlack <dmatlack@google.com>
Signed-off-by: David Matlack <dmatlack@google.com>
---
.../lib/include/libvfio/vfio_pci_device.h | 3 ++
.../selftests/vfio/lib/vfio_pci_device.c | 33 ++++++++++++++-----
2 files changed, 27 insertions(+), 9 deletions(-)

diff --git a/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h b/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h
index 2858885a89bb..896dfde88118 100644
--- a/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h
+++ b/tools/testing/selftests/vfio/lib/include/libvfio/vfio_pci_device.h
@@ -38,6 +38,9 @@ struct vfio_pci_device {
#define dev_info(_dev, _fmt, ...) printf("%s: " _fmt, (_dev)->bdf, ##__VA_ARGS__)
#define dev_err(_dev, _fmt, ...) fprintf(stderr, "%s: " _fmt, (_dev)->bdf, ##__VA_ARGS__)

+struct vfio_pci_device *__vfio_pci_device_init(const char *bdf,
+ struct iommu *iommu,
+ int device_fd);
struct vfio_pci_device *vfio_pci_device_init(const char *bdf, struct iommu *iommu);
void vfio_pci_device_cleanup(struct vfio_pci_device *device);

diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_device.c b/tools/testing/selftests/vfio/lib/vfio_pci_device.c
index 4e5871f1ebc3..e9215c712cda 100644
--- a/tools/testing/selftests/vfio/lib/vfio_pci_device.c
+++ b/tools/testing/selftests/vfio/lib/vfio_pci_device.c
@@ -340,19 +340,27 @@ static void vfio_device_attach_iommufd_pt(int device_fd, u32 pt_id)
ioctl_assert(device_fd, VFIO_DEVICE_ATTACH_IOMMUFD_PT, &args);
}

-static void vfio_pci_iommufd_setup(struct vfio_pci_device *device, const char *bdf)
+static void vfio_pci_iommufd_setup(struct vfio_pci_device *device,
+ const char *bdf, int device_fd)
{
- const char *cdev_path = vfio_pci_get_cdev_path(bdf);
+ const char *cdev_path;

- device->fd = open(cdev_path, O_RDWR);
- VFIO_ASSERT_GE(device->fd, 0);
- free((void *)cdev_path);
+ if (device_fd >= 0) {
+ device->fd = device_fd;
+ } else {
+ cdev_path = vfio_pci_get_cdev_path(bdf);
+ device->fd = open(cdev_path, O_RDWR);
+ VFIO_ASSERT_GE(device->fd, 0);
+ free((void *)cdev_path);
+ }

vfio_device_bind_iommufd(device->fd, device->iommu->iommufd);
vfio_device_attach_iommufd_pt(device->fd, device->iommu->ioas_id);
}

-struct vfio_pci_device *vfio_pci_device_init(const char *bdf, struct iommu *iommu)
+struct vfio_pci_device *__vfio_pci_device_init(const char *bdf,
+ struct iommu *iommu,
+ int device_fd)
{
struct vfio_pci_device *device;

@@ -363,10 +371,12 @@ struct vfio_pci_device *vfio_pci_device_init(const char *bdf, struct iommu *iomm
device->iommu = iommu;
device->bdf = bdf;

- if (iommu->mode->container_path)
+ if (iommu->mode->container_path) {
+ VFIO_ASSERT_EQ(device_fd, -1);
vfio_pci_container_setup(device, bdf);
- else
- vfio_pci_iommufd_setup(device, bdf);
+ } else {
+ vfio_pci_iommufd_setup(device, bdf, device_fd);
+ }

vfio_pci_device_setup(device);
vfio_pci_driver_probe(device);
@@ -374,6 +384,11 @@ struct vfio_pci_device *vfio_pci_device_init(const char *bdf, struct iommu *iomm
return device;
}

+struct vfio_pci_device *vfio_pci_device_init(const char *bdf, struct iommu *iommu)
+{
+ return __vfio_pci_device_init(bdf, iommu, /*device_fd=*/-1);
+}
+
void vfio_pci_device_cleanup(struct vfio_pci_device *device)
{
int i;
--
2.53.0.983.g0bb29b3bc5-goog