From 246c1acfd1b9e600b84497cd3c5480df9e0c353d Mon Sep 17 00:00:00 2001 From: Minwoo Im Date: Mon, 13 Oct 2025 18:04:46 +0900 Subject: [PATCH 1/2] iommu: choose iommu backend in runtime We can manage iommu hardware through either (1) vfio or (2) iommufd which has been newly added to kernel recently. libvfn has provided enabling iommufd in the compile time, but sometimes application might want to use vfio type rather than iommufd if app wants to map PCI BAR area to iommu mapping table which can't be done with iommufd. To provide flexibility to applications, choose iommu backends in the runtime if iommufd is built properly on the system where iommufd kernel header file is available. The default backend will be iommufd if available, but user can override it with VFN_IOMMU_FORCE_VFIO environment varaible for vfio mode. Signed-off-by: Minwoo Im --- src/iommu/context.c | 25 +++++++++++-------------- src/iommu/context.h | 2 -- src/iommu/iommufd.c | 30 ++++++++++++++++++++++++++++-- src/iommu/meson.build | 5 +---- 4 files changed, 40 insertions(+), 22 deletions(-) diff --git a/src/iommu/context.c b/src/iommu/context.c index da852f8a..0a6875a8 100644 --- a/src/iommu/context.c +++ b/src/iommu/context.c @@ -26,24 +26,21 @@ #define IOVA_MIN 0x10000 #define IOVA_MAX_39BITS (1ULL << 39) -#ifdef HAVE_VFIO_DEVICE_BIND_IOMMUFD -static inline bool __iommufd_is_broken(void) +static inline bool __iommufd_is_available(void) { struct stat sb; - if (stat("/dev/vfio/devices", &sb) || !S_ISDIR(sb.st_mode)) { - log_info("iommufd broken; probably missing CONFIG_VFIO_DEVICE_CDEV=y\n"); + if (stat("/dev/vfio/devices", &sb) || !S_ISDIR(sb.st_mode)) + return false; + if (stat("/dev/iommu", &sb)) + return false; - return true; - } - return false; + return true; } -#endif struct iommu_ctx *iommu_get_default_context(void) { -#ifdef HAVE_VFIO_DEVICE_BIND_IOMMUFD - if (__iommufd_is_broken()) + if (!__iommufd_is_available()) goto fallback; if (getenv("VFN_IOMMU_FORCE_VFIO")) @@ -52,20 +49,20 @@ struct iommu_ctx *iommu_get_default_context(void) return iommufd_get_default_iommu_context(); fallback: -#endif return vfio_get_default_iommu_context(); } struct iommu_ctx *iommu_get_context(const char *name) { -#ifdef HAVE_VFIO_DEVICE_BIND_IOMMUFD - if (__iommufd_is_broken()) + if (!__iommufd_is_available()) + goto fallback; + + if (getenv("VFN_IOMMU_FORCE_VFIO")) goto fallback; return iommufd_get_iommu_context(name); fallback: -#endif return vfio_get_iommu_context(name); } diff --git a/src/iommu/context.h b/src/iommu/context.h index a3b56c71..5b802026 100644 --- a/src/iommu/context.h +++ b/src/iommu/context.h @@ -57,10 +57,8 @@ struct iommu_ctx *iommu_get_default_context(void); struct iommu_ctx *vfio_get_default_iommu_context(void); struct iommu_ctx *vfio_get_iommu_context(const char *name); -#ifdef HAVE_VFIO_DEVICE_BIND_IOMMUFD struct iommu_ctx *iommufd_get_default_iommu_context(void); struct iommu_ctx *iommufd_get_iommu_context(const char *name); -#endif void iommu_ctx_init(struct iommu_ctx *ctx); int iommu_iova_range_to_string(struct iommu_iova_range *range, char **str); diff --git a/src/iommu/iommufd.c b/src/iommu/iommufd.c index 37fda2ee..5aba730c 100644 --- a/src/iommu/iommufd.c +++ b/src/iommu/iommufd.c @@ -28,19 +28,26 @@ #include #include -#include #include +#ifdef HAVE_VFIO_DEVICE_BIND_IOMMUFD +#include +#endif + #include "vfn/trace.h" #include "vfn/support.h" #include "vfn/pci.h" #include "vfn/iommu.h" + +#include "context.h" + +#ifdef HAVE_VFIO_DEVICE_BIND_IOMMUFD + #include "vfn/iommu/iommufd.h" #include "ccan/list/list.h" #include "ccan/compiler/compiler.h" -#include "context.h" #include "trace.h" static int __iommufd = -1; @@ -419,3 +426,22 @@ struct iommu_ctx *iommufd_get_default_iommu_context(void) return &iommufd_default_ioas.ctx; } + +#else /* !HAVE_VFIO_DEVICE_BIND_IOMMUFD */ + +struct iommu_ctx *iommufd_get_iommu_context(const char *name) +{ + (void)name; + log_debug("iommufd support not compiled in (missing kernel headers)\n"); + errno = ENOTSUP; + return NULL; +} + +struct iommu_ctx *iommufd_get_default_iommu_context(void) +{ + log_debug("iommufd support not compiled in (missing kernel headers)\n"); + errno = ENOTSUP; + return NULL; +} + +#endif /* HAVE_VFIO_DEVICE_BIND_IOMMUFD */ diff --git a/src/iommu/meson.build b/src/iommu/meson.build index b79965e6..0c4e62f4 100644 --- a/src/iommu/meson.build +++ b/src/iommu/meson.build @@ -3,10 +3,7 @@ iommu_sources = files( 'dma.c', 'dmabuf.c', 'vfio.c', + 'iommufd.c', ) -if config_host.get('HAVE_VFIO_DEVICE_BIND_IOMMUFD', false) - iommu_sources += files('iommufd.c',) -endif - vfn_sources += iommu_sources From 169e4b985bdcae42bba925afddc9148249a687fd Mon Sep 17 00:00:00 2001 From: Minwoo Im Date: Mon, 13 Oct 2025 21:32:13 +0900 Subject: [PATCH 2/2] iommu: add ``iommu_ctx_is_iommufd()`` To figure out which backend iommu context is binded to the given device from application side. The previous commit has started supporting choosing iommu context type in the runtime so that application might want to figure out which type of context is binded. Signed-off-by: Minwoo Im --- include/vfn/iommu/context.h | 8 ++++++++ src/iommu/context.c | 5 +++++ src/iommu/context.h | 2 ++ src/iommu/iommufd.c | 1 + src/iommu/vfio.c | 1 + 5 files changed, 17 insertions(+) diff --git a/include/vfn/iommu/context.h b/include/vfn/iommu/context.h index 8656252c..5a396b2b 100644 --- a/include/vfn/iommu/context.h +++ b/include/vfn/iommu/context.h @@ -23,4 +23,12 @@ */ struct iommu_ctx *iommu_get_context(const char *name); +/** + * iommu_ctx_is_iommufd - Check whether the given @ctx is binded to iommufd + * @ctx: &struct iommu_ctx + * + * Return: ``true`` if @ctx is binded to iommufd, otherwise ``false``. + */ +bool iommu_ctx_is_iommufd(struct iommu_ctx *ctx); + #endif /* LIBVFN_IOMMU_CONTEXT_H */ diff --git a/src/iommu/context.c b/src/iommu/context.c index 0a6875a8..5eb68a55 100644 --- a/src/iommu/context.c +++ b/src/iommu/context.c @@ -81,3 +81,8 @@ void iommu_ctx_init(struct iommu_ctx *ctx) skiplist_init(&ctx->map.list); pthread_rwlock_init(&ctx->map.lock, NULL); } + +bool iommu_ctx_is_iommufd(struct iommu_ctx *ctx) +{ + return ctx->iommufd; +} diff --git a/src/iommu/context.h b/src/iommu/context.h index 5b802026..0b2f9d90 100644 --- a/src/iommu/context.h +++ b/src/iommu/context.h @@ -50,6 +50,8 @@ struct iommu_ctx { int nranges; struct iommu_iova_range *iova_ranges; + + bool iommufd; }; struct iommu_ctx *iommu_get_default_context(void); diff --git a/src/iommu/iommufd.c b/src/iommu/iommufd.c index 5aba730c..836aa2ac 100644 --- a/src/iommu/iommufd.c +++ b/src/iommu/iommufd.c @@ -72,6 +72,7 @@ struct iommu_ioas { }; static struct iommu_ioas iommufd_default_ioas = { + .ctx.iommufd = true, .name = "default", }; diff --git a/src/iommu/vfio.c b/src/iommu/vfio.c index 212fcd3f..9c99ce44 100644 --- a/src/iommu/vfio.c +++ b/src/iommu/vfio.c @@ -78,6 +78,7 @@ struct vfio_container { }; static struct vfio_container vfio_default_container = { + .ctx.iommufd = false, .fd = -1, .name = "default", .nr_groups = 0,