Messages in this thread Patch in this message | | | From | Nicolin Chen <> | Subject | [PATCH v2 1/3] iommufd: Add devices_users to track the hw_pagetable usage by device | Date | Sat, 28 Jan 2023 13:18:09 -0800 |
| |
From: Yi Liu <yi.l.liu@intel.com>
Currently, hw_pagetable tracks the attached devices using a device list. When attaching the first device to the kernel-managed hw_pagetable, it should be linked to IOAS. When detaching the last device from this hwpt, the link with IOAS should be removed too. And this first-or-last device check is done with list_empty(hwpt->devices).
However, with a nested configuration, when a device is attached to the user-managed stage-1 hw_pagetable, it will be added to this user-managed hwpt's device list instead of the kernel-managed stage-2 hwpt's one. And this breaks the logic for a kernel-managed hw_pagetable link/disconnect to/from IOAS/IOPT. e.g. the stage-2 hw_pagetable would be linked to IOAS multiple times if multiple device is attached, but it will become empty as soon as one device detached.
Add a devices_users in struct iommufd_hw_pagetable to track the users of hw_pagetable by the attached devices. Make this field as a pointer, only allocate for a stage-2 hw_pagetable. A stage-1 hw_pagetable should reuse the stage-2 hw_pagetable's devices_users, because when a device attaches to a stage-1 hw_pagetable, linking the stage-2 hwpt to the IOAS is still required. So, with a nested configuration, increase the devices_users on the stage-2 (parent) hwpt, no matter a device is attached to the stage-1 or the stage-2 hwpt.
Adding this devices_users also reduces the dependency on the device list, so it helps the following patch to remove the device list completely.
Signed-off-by: Yi Liu <yi.l.liu@intel.com> Co-developed-by: Nicolin Chen <nicolinc@nvidia.com> Signed-off-by: Nicolin Chen <nicolinc@nvidia.com> --- drivers/iommu/iommufd/device.c | 8 +++++--- drivers/iommu/iommufd/hw_pagetable.c | 11 +++++++++++ drivers/iommu/iommufd/iommufd_private.h | 1 + 3 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/drivers/iommu/iommufd/device.c b/drivers/iommu/iommufd/device.c index 9f3b9674d72e..208757c39c90 100644 --- a/drivers/iommu/iommufd/device.c +++ b/drivers/iommu/iommufd/device.c @@ -212,7 +212,7 @@ static int iommufd_device_do_attach(struct iommufd_device *idev, hwpt->domain->ops->enforce_cache_coherency( hwpt->domain); if (!hwpt->enforce_cache_coherency) { - WARN_ON(list_empty(&hwpt->devices)); + WARN_ON(refcount_read(hwpt->devices_users) == 1); rc = -EINVAL; goto out_unlock; } @@ -236,7 +236,7 @@ static int iommufd_device_do_attach(struct iommufd_device *idev, if (rc) goto out_iova; - if (list_empty(&hwpt->devices)) { + if (refcount_read(hwpt->devices_users) == 1) { rc = iopt_table_add_domain(&hwpt->ioas->iopt, hwpt->domain); if (rc) @@ -246,6 +246,7 @@ static int iommufd_device_do_attach(struct iommufd_device *idev, idev->hwpt = hwpt; refcount_inc(&hwpt->obj.users); + refcount_inc(hwpt->devices_users); list_add(&idev->devices_item, &hwpt->devices); mutex_unlock(&hwpt->devices_lock); return 0; @@ -387,9 +388,10 @@ void iommufd_device_detach(struct iommufd_device *idev) mutex_lock(&hwpt->ioas->mutex); mutex_lock(&hwpt->devices_lock); + refcount_dec(hwpt->devices_users); list_del(&idev->devices_item); if (!iommufd_hw_pagetable_has_group(hwpt, idev->group)) { - if (list_empty(&hwpt->devices)) { + if (refcount_read(hwpt->devices_users) == 1) { iopt_table_remove_domain(&hwpt->ioas->iopt, hwpt->domain); list_del(&hwpt->hwpt_item); diff --git a/drivers/iommu/iommufd/hw_pagetable.c b/drivers/iommu/iommufd/hw_pagetable.c index 43d473989a06..910e759ffeac 100644 --- a/drivers/iommu/iommufd/hw_pagetable.c +++ b/drivers/iommu/iommufd/hw_pagetable.c @@ -16,6 +16,8 @@ void iommufd_hw_pagetable_destroy(struct iommufd_object *obj) iommu_domain_free(hwpt->domain); refcount_dec(&hwpt->ioas->obj.users); mutex_destroy(&hwpt->devices_lock); + WARN_ON(!refcount_dec_if_one(hwpt->devices_users)); + kfree(hwpt->devices_users); } /** @@ -46,11 +48,20 @@ iommufd_hw_pagetable_alloc(struct iommufd_ctx *ictx, struct iommufd_ioas *ioas, INIT_LIST_HEAD(&hwpt->devices); INIT_LIST_HEAD(&hwpt->hwpt_item); mutex_init(&hwpt->devices_lock); + hwpt->devices_users = kzalloc(sizeof(*hwpt->devices_users), GFP_KERNEL); + if (!hwpt->devices_users) { + rc = -ENOMEM; + goto out_free_domain; + } + refcount_set(hwpt->devices_users, 1); + /* Pairs with iommufd_hw_pagetable_destroy() */ refcount_inc(&ioas->obj.users); hwpt->ioas = ioas; return hwpt; +out_free_domain: + iommu_domain_free(hwpt->domain); out_abort: iommufd_object_abort(ictx, &hwpt->obj); return ERR_PTR(rc); diff --git a/drivers/iommu/iommufd/iommufd_private.h b/drivers/iommu/iommufd/iommufd_private.h index 222e86591f8a..f128d77fb076 100644 --- a/drivers/iommu/iommufd/iommufd_private.h +++ b/drivers/iommu/iommufd/iommufd_private.h @@ -247,6 +247,7 @@ struct iommufd_hw_pagetable { /* Head at iommufd_ioas::hwpt_list */ struct list_head hwpt_item; struct mutex devices_lock; + refcount_t *devices_users; struct list_head devices; }; -- 2.39.1
| |