[PATCH v1 1/1] vfio: fix device lookup with no-IOMMU mode enabled
Anatoly Burakov
anatoly.burakov at intel.com
Thu Oct 15 17:43:53 CEST 2026
Currently, when the `enable_unsafe_noiommu_mode` VFIO module parameter is
set, VFIO selects PA IOVA mode and then only looks for no-IOMMU device
nodes: `/dev/vfio/noiommu-N` in group mode, and `noiommu-vfioN` in cdev
mode.
However, the parameter does not make every VFIO device a no-IOMMU
device. The kernel only creates a no-IOMMU group for a device that has no
IOMMU group of its own; devices behind a real IOMMU still get a regular
`/dev/vfio/N` group and `vfioN` cdev. On such systems, devices bound
to `vfio-pci` are therefore reported as not managed by VFIO and fail
to probe.
Fix it by trying the regular node name first and falling back to the
no-IOMMU one, in both group and cdev modes.
Fixes: 6cb38a7f56e0 ("vfio: introduce VFIO mode")
Fixes: d129414711aa ("vfio: introduce cdev mode")
Signed-off-by: Anatoly Burakov <anatoly.burakov at intel.com>
---
lib/eal/linux/eal_vfio_cdev.c | 65 +++++++++++++++++-----------------
lib/eal/linux/eal_vfio_group.c | 19 +++++-----
2 files changed, 44 insertions(+), 40 deletions(-)
diff --git a/lib/eal/linux/eal_vfio_cdev.c b/lib/eal/linux/eal_vfio_cdev.c
index ab4d3f9f44..4a955248ae 100644
--- a/lib/eal/linux/eal_vfio_cdev.c
+++ b/lib/eal/linux/eal_vfio_cdev.c
@@ -23,8 +23,29 @@
#include "eal_internal_cfg.h"
#define DEV_VFIO_IOMMUFD_PATH "/dev/iommu"
-#define DEV_VFIO_CDEV_FMT "/dev/vfio/devices/vfio%d"
-#define DEV_VFIO_NOIOMMU_CDEV_FMT "/dev/vfio/devices/noiommu-vfio%d"
+#define DEV_VFIO_CDEV_FMT "/dev/vfio/devices/%s%d"
+
+/*
+ * Global no-IOMMU mode does not mean every device is no-IOMMU: the kernel only
+ * creates no-IOMMU devices for devices without an IOMMU group, so cdev names
+ * are tried in this order regardless of IOVA mode.
+ */
+static const char * const cdev_prefixes[] = {"vfio", "noiommu-vfio"};
+
+/* return length of the matching cdev prefix, or 0 if the name has none */
+static size_t
+cdev_match_prefix(const char *name)
+{
+ unsigned int i;
+
+ for (i = 0; i < RTE_DIM(cdev_prefixes); i++) {
+ size_t len = strlen(cdev_prefixes[i]);
+
+ if (strncmp(name, cdev_prefixes[i], len) == 0)
+ return len;
+ }
+ return 0;
+}
static int vfio_cdev_dma_map(struct vfio_container *cfg);
static int vfio_cdev_dma_mem_map(struct vfio_container *cfg, uint64_t vaddr,
@@ -208,28 +229,12 @@ int
vfio_cdev_get_device_num(const char *sysfs_base, const char *dev_addr, int *cdev_dev_num)
{
char linkname[PATH_MAX] = {0};
- const char *prefix;
size_t prefix_len;
char *dev_tok, *end;
int dev_num;
DIR *dir;
struct dirent *entry;
- /* different prefixes for different IOMMU modes */
- switch (vfio_global_cfg.iova_mode) {
- case DEV_VFIO_IOVA_MODE_VA:
- prefix = "vfio";
- prefix_len = strlen(prefix);
- break;
- case DEV_VFIO_IOVA_MODE_PA:
- prefix = "noiommu-vfio";
- prefix_len = strlen(prefix);
- break;
- default:
- EAL_LOG(ERR, "VFIO IOMMU mode is not initialized");
- return -1;
- }
-
/* check if vfio-dev directory exists for this device */
snprintf(linkname, sizeof(linkname), "%s/%s/vfio-dev", sysfs_base, dev_addr);
@@ -241,7 +246,8 @@ vfio_cdev_get_device_num(const char *sysfs_base, const char *dev_addr, int *cdev
/* find the matching VFIO cdev entry */
while ((entry = readdir(dir)) != NULL) {
- if (strncmp(entry->d_name, prefix, prefix_len) != 0)
+ prefix_len = cdev_match_prefix(entry->d_name);
+ if (prefix_len == 0)
continue;
/* parse device number after the cdev entry prefix */
@@ -281,21 +287,16 @@ static int
cdev_open_device_fd(int cdev_dev_num)
{
char devname[PATH_MAX] = {0};
- int dev_fd;
+ int dev_fd = -1;
+ unsigned int i;
- switch (vfio_global_cfg.iova_mode) {
- case DEV_VFIO_IOVA_MODE_VA:
- snprintf(devname, sizeof(devname), DEV_VFIO_CDEV_FMT, cdev_dev_num);
- break;
- case DEV_VFIO_IOVA_MODE_PA:
- snprintf(devname, sizeof(devname), DEV_VFIO_NOIOMMU_CDEV_FMT, cdev_dev_num);
- break;
- default:
- EAL_LOG(ERR, "VFIO IOMMU mode is not initialized");
- return -1;
+ for (i = 0; i < RTE_DIM(cdev_prefixes); i++) {
+ snprintf(devname, sizeof(devname), DEV_VFIO_CDEV_FMT,
+ cdev_prefixes[i], cdev_dev_num);
+ dev_fd = open(devname, O_RDWR);
+ if (dev_fd >= 0 || errno != ENOENT)
+ break;
}
-
- dev_fd = open(devname, O_RDWR);
if (dev_fd < 0) {
EAL_LOG(ERR, "Cannot open %s: %s", devname, strerror(errno));
return -1;
diff --git a/lib/eal/linux/eal_vfio_group.c b/lib/eal/linux/eal_vfio_group.c
index aef3e9f27a..7c879830ac 100644
--- a/lib/eal/linux/eal_vfio_group.c
+++ b/lib/eal/linux/eal_vfio_group.c
@@ -554,17 +554,20 @@ vfio_open_group_sysfs(int iommu_group_num)
char filename[PATH_MAX];
int fd;
- if (vfio_global_cfg.iova_mode == DEV_VFIO_IOVA_MODE_VA)
- snprintf(filename, sizeof(filename), DEV_VFIO_GROUP_FMT, iommu_group_num);
- else if (vfio_global_cfg.iova_mode == DEV_VFIO_IOVA_MODE_PA)
- snprintf(filename, sizeof(filename), DEV_VFIO_NOIOMMU_GROUP_FMT, iommu_group_num);
-
- /* reset errno before open to differentiate errors */
- errno = 0;
+ /*
+ * Global no-IOMMU mode does not mean every group is no-IOMMU: the
+ * kernel only creates no-IOMMU groups for devices without an IOMMU
+ * group, so try the regular group first, then the no-IOMMU one.
+ */
+ snprintf(filename, sizeof(filename), DEV_VFIO_GROUP_FMT, iommu_group_num);
fd = open(filename, O_RDWR);
+ if (fd < 0 && errno == ENOENT) {
+ snprintf(filename, sizeof(filename), DEV_VFIO_NOIOMMU_GROUP_FMT, iommu_group_num);
+ fd = open(filename, O_RDWR);
+ }
/* we have to differentiate between failed open and non-existence */
- if (errno == ENOENT)
+ if (fd < 0 && errno == ENOENT)
return -ENOENT;
return fd;
}
--
2.52.0
More information about the dev
mailing list