From 58a5b446e1313f6a4825c7fa1b423b55ddec8553 Mon Sep 17 00:00:00 2001 From: Minwoo Im Date: Tue, 2 Jul 2024 11:16:00 +0900 Subject: [PATCH] iommu: Add put_device_fd callback for vfio Application might open and close the vfio device file descriptors in an alive session. This patch added support for putting (closing) the open file descriptors for vfio resources to unbind the vfio device successfully. Signed-off-by: Minwoo Im --- include/vfn/vfio/pci.h | 11 +++++++++++ src/iommu/context.h | 1 + src/iommu/iommufd.c | 17 +++++++++++++++++ src/iommu/vfio.c | 43 +++++++++++++++++++++++++++++++++++++++--- src/nvme/core.c | 2 +- src/vfio/pci.c | 9 +++++++++ 6 files changed, 79 insertions(+), 4 deletions(-) diff --git a/include/vfn/vfio/pci.h b/include/vfn/vfio/pci.h index 17b3335e..fede5e3c 100644 --- a/include/vfn/vfio/pci.h +++ b/include/vfn/vfio/pci.h @@ -47,6 +47,17 @@ struct vfio_pci_device { */ int vfio_pci_open(struct vfio_pci_device *pci, const char *bdf); +/** + * vfio_pci_close - close vfio device file descriptor + * @pci: &struct vfio_pci_device whose fd is to close + * + * Close vfio group file descriptor + * + * Return: On success, returns ``0``. On error, returns ``-1`` and sets + * ``errno``. + */ +int vfio_pci_close(struct vfio_pci_device *pci); + /** * vfio_pci_map_bar - map a vfio device region into virtual memory * @pci: &struct vfio_pci_device diff --git a/src/iommu/context.h b/src/iommu/context.h index d260b561..ef2cfeef 100644 --- a/src/iommu/context.h +++ b/src/iommu/context.h @@ -26,6 +26,7 @@ struct iommu_ctx_ops { /* device ops */ int (*get_device_fd)(struct iommu_ctx *ctx, const char *bdf); + int (*put_device_fd)(struct iommu_ctx *ctx, const char *bdf); }; struct iova_mapping { diff --git a/src/iommu/iommufd.c b/src/iommu/iommufd.c index 8213bddd..d4be5081 100644 --- a/src/iommu/iommufd.c +++ b/src/iommu/iommufd.c @@ -37,6 +37,7 @@ #include "vfn/iommu.h" #include "ccan/list/list.h" +#include "ccan/compiler/compiler.h" #include "context.h" #include "trace.h" @@ -48,6 +49,7 @@ struct iommu_ioas { char *name; uint32_t id; + int devfd; }; static struct iommu_ioas iommufd_default_ioas = { @@ -147,6 +149,7 @@ static int iommufd_get_device_fd(struct iommu_ctx *ctx, const char *bdf) goto close_dev; } + ioas->devfd = devfd; return devfd; close_dev: @@ -156,6 +159,19 @@ static int iommufd_get_device_fd(struct iommu_ctx *ctx, const char *bdf) return -1; } +static int iommufd_put_device_fd(struct iommu_ctx *ctx, const char *bdf UNUSED) +{ + struct iommu_ioas *ioas = container_of_var(ctx, ioas, ctx); + + if (ioas->devfd) { + close(ioas->devfd); + return 0; + } + + errno = ENODEV; + return -1; +} + static int iommu_ioas_do_dma_map(struct iommu_ctx *ctx, void *vaddr, size_t len, uint64_t *iova, unsigned long flags) { @@ -234,6 +250,7 @@ static int iommu_ioas_do_dma_unmap_all(struct iommu_ctx *ctx) static const struct iommu_ctx_ops iommufd_ops = { .get_device_fd = iommufd_get_device_fd, + .put_device_fd = iommufd_put_device_fd, .dma_map = iommu_ioas_do_dma_map, .dma_unmap = iommu_ioas_do_dma_unmap, diff --git a/src/iommu/vfio.c b/src/iommu/vfio.c index cd25ab97..e5de4e16 100644 --- a/src/iommu/vfio.c +++ b/src/iommu/vfio.c @@ -50,6 +50,7 @@ struct vfio_group { struct vfio_container *container; char *path; + int nr_devs; }; struct vfio_container { @@ -363,8 +364,8 @@ static int vfio_get_group_fd(struct vfio_container *vfio, * Returns an existing vfio_group instance, or an empty one with group->path * filled out, otherwise return NULL in case no more group available. */ -static struct vfio_group *vfio_get_group(struct vfio_container *vfio, - const char *bdf) +static struct vfio_group *__vfio_get_group(struct vfio_container *vfio, + const char *bdf, bool alloc) { __autofree char *path = NULL; struct vfio_group *group; @@ -383,6 +384,9 @@ static struct vfio_group *vfio_get_group(struct vfio_container *vfio, return group; } + if (!alloc) + return NULL; + /* * If existing group is not found, provide an empty one for the * correspnoding 'bdf' device. @@ -391,6 +395,7 @@ static struct vfio_group *vfio_get_group(struct vfio_container *vfio, group = &vfio->groups[i]; if (!group->path) { group->path = strdup(path); + group->nr_devs = 0; return group; } } @@ -398,13 +403,25 @@ static struct vfio_group *vfio_get_group(struct vfio_container *vfio, return NULL; } +static struct vfio_group *vfio_get_or_create_group(struct vfio_container *vfio, + const char *bdf) +{ + return __vfio_get_group(vfio, bdf, true); +} + +static struct vfio_group *vfio_get_group(struct vfio_container *vfio, + const char *bdf) +{ + return __vfio_get_group(vfio, bdf, false); +} + static int vfio_get_device_fd(struct iommu_ctx *ctx, const char *bdf) { struct vfio_container *vfio = container_of_var(ctx, vfio, ctx); struct vfio_group *group; int gfd, ret_fd; - group = vfio_get_group(vfio, bdf); + group = vfio_get_or_create_group(vfio, bdf); if (!group) { log_debug("could not determine iommu group for device %s\n", bdf); errno = EMFILE; @@ -422,9 +439,28 @@ static int vfio_get_device_fd(struct iommu_ctx *ctx, const char *bdf) return -1; } + atomic_inc(&group->nr_devs); return ret_fd; } +static int vfio_put_device_fd(struct iommu_ctx *ctx, const char *bdf) +{ + struct vfio_container *vfio = container_of_var(ctx, vfio, ctx); + struct vfio_group *group; + + group = vfio_get_group(vfio, bdf); + if (!group) { + log_debug("could not find iommu group for device %s\n", bdf); + errno = ENODEV; + return -1; + } + + if (atomic_dec_fetch(&group->nr_devs) == 0) + close(group->fd); + + return 0; +} + static int vfio_iommu_type1_do_dma_map(struct iommu_ctx *ctx, void *vaddr, size_t len, uint64_t *iova, unsigned long flags) { @@ -525,6 +561,7 @@ static int vfio_iommu_type1_do_dma_unmap_all(struct iommu_ctx *ctx) static const struct iommu_ctx_ops vfio_ops = { .get_device_fd = vfio_get_device_fd, + .put_device_fd = vfio_put_device_fd, .iova_reserve = vfio_iommu_type1_iova_reserve, .iova_put_ephemeral = vfio_iommu_type1_iova_put_ephemeral, diff --git a/src/nvme/core.c b/src/nvme/core.c index 0c105c01..b06bf862 100644 --- a/src/nvme/core.c +++ b/src/nvme/core.c @@ -681,5 +681,5 @@ void nvme_close(struct nvme_ctrl *ctrl) vfio_pci_unmap_bar(&ctrl->pci, 0, ctrl->regs, 0x1000, 0); vfio_pci_unmap_bar(&ctrl->pci, 0, ctrl->doorbells, 0x1000, 0x1000); - //vfio_close(ctrl->pci.vfio); + vfio_pci_close(&ctrl->pci); } diff --git a/src/vfio/pci.c b/src/vfio/pci.c index 76d9c1f3..46c181bc 100644 --- a/src/vfio/pci.c +++ b/src/vfio/pci.c @@ -188,3 +188,12 @@ int vfio_pci_open(struct vfio_pci_device *pci, const char *bdf) return 0; } + +int vfio_pci_close(struct vfio_pci_device *pci) +{ + struct iommu_ctx *ctx = pci->dev.ctx; + + close(pci->dev.fd); + + return ctx->ops.put_device_fd(ctx, pci->bdf); +}