If a test is killed, for example due to timeout, fput can be delayed, allowing the subsequent test to be started while the failing test still holds the device open count elevated. This results in a cascade of failures as each subsequent test fails on open, blocked by the single user requirement at the group or device cdev file. We can make the test framework more robust, and allow better identification of specific failing scenarios, by waiting-out transient -EBUSY failures on group open and cdev bind. The 20s retry window is heuristically determined in testing on a system where scheduling can be significantly delayed due to SMI handling of platform errors generated from the mix-and-match test. The SR-IOV uAPI and IOMMUFD setup tests retain their non-retry bind paths as these are not expected to encounter process kills due to underlying platform error handling variability. Assisted-by: Qwen3.8-27B Signed-off-by: Alex Williamson --- .../selftests/vfio/lib/vfio_pci_device.c | 29 +++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/vfio/lib/vfio_pci_device.c b/tools/testing/selftests/vfio/lib/vfio_pci_device.c index 4063a0e2b3df..8a3139b7c6dd 100644 --- a/tools/testing/selftests/vfio/lib/vfio_pci_device.c +++ b/tools/testing/selftests/vfio/lib/vfio_pci_device.c @@ -282,18 +282,34 @@ void vfio_pci_device_reset(struct vfio_pci_device *device) VFIO_ASSERT_EQ(r, 0, "ioctl(device->fd, VFIO_DEVICE_RESET) failed\n"); } +/* + * A prior test's delayed fput can briefly leave the open count elevated, so + * group open and cdev bind can see a transient -EBUSY. Retry to wait out the + * fput scheduling latency. + */ +#define VFIO_DEVICE_BUSY_RETRIES 200 +#define VFIO_DEVICE_BUSY_INTERVAL_US 100000 + void vfio_pci_group_setup(struct vfio_pci_device *device, const char *bdf) { struct vfio_group_status group_status = { .argsz = sizeof(group_status), }; char group_path[32]; + int retries = VFIO_DEVICE_BUSY_RETRIES; int group; group = sysfs_iommu_group_get(bdf); snprintf_assert(group_path, sizeof(group_path), "/dev/vfio/%d", group); - device->group_fd = open(group_path, O_RDWR); + for (;;) { + device->group_fd = open(group_path, O_RDWR); + if (device->group_fd >= 0 || errno != EBUSY || retries-- <= 0) + break; + + usleep(VFIO_DEVICE_BUSY_INTERVAL_US); + } + VFIO_ASSERT_GE(device->group_fd, 0, "open(%s) failed\n", group_path); ioctl_assert(device->group_fd, VFIO_GROUP_GET_STATUS, &group_status); @@ -432,7 +448,16 @@ int __vfio_device_bind_iommufd(int device_fd, int iommufd, const char *vf_token) static void vfio_device_bind_iommufd(int device_fd, int iommufd, const char *vf_token) { - int ret = __vfio_device_bind_iommufd(device_fd, iommufd, vf_token); + int retries = VFIO_DEVICE_BUSY_RETRIES; + int ret; + + for (;;) { + ret = __vfio_device_bind_iommufd(device_fd, iommufd, vf_token); + if (ret != -EBUSY || retries-- <= 0) + break; + + usleep(VFIO_DEVICE_BUSY_INTERVAL_US); + } VFIO_ASSERT_EQ(ret, 0, "Failed VFIO_DEVICE_BIND_IOMMUFD ioctl\n"); } -- 2.53.0