iommufd: Move ioas related HWPT destruction into iommufd_hw_pagetable_destroy()
authorJason Gunthorpe <jgg@nvidia.com>
Wed, 1 Mar 2023 19:30:21 +0000 (15:30 -0400)
committerJason Gunthorpe <jgg@nvidia.com>
Mon, 6 Mar 2023 14:51:57 +0000 (10:51 -0400)
A HWPT is permanently associated with an IOAS when it is created, remove
the strange situation where a refcount != 0 HWPT can have been
disconnected from the IOAS by putting all the IOAS related destruction in
the object destroy function.

Initializing a HWPT is two stages, we have to allocate it, attach it to a
device and then populate the domain. Once the domain is populated it is
fully linked to the IOAS.

Arrange things so that all the error unwinds flow through the
iommufd_hw_pagetable_destroy() and allow it to handle all cases.

Link: https://lore.kernel.org/r/4-v3-ae9c2975a131+2e1e8-iommufd_hwpt_jgg@nvidia.com
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
drivers/iommu/iommufd/device.c
drivers/iommu/iommufd/hw_pagetable.c

index adb73539b39c0c880608d529918041b73c925622..6787a0d8d6e9f07e64af12e3db8c9b1470c9d3db 100644 (file)
@@ -386,28 +386,19 @@ void iommufd_device_detach(struct iommufd_device *idev)
 {
        struct iommufd_hw_pagetable *hwpt = idev->hwpt;
 
-       mutex_lock(&hwpt->ioas->mutex);
        mutex_lock(&hwpt->devices_lock);
        list_del(&idev->devices_item);
-       if (!iommufd_hw_pagetable_has_group(hwpt, idev->group)) {
-               if (list_empty(&hwpt->devices)) {
-                       iopt_table_remove_domain(&hwpt->ioas->iopt,
-                                                hwpt->domain);
-                       list_del(&hwpt->hwpt_item);
-               }
+       if (!iommufd_hw_pagetable_has_group(hwpt, idev->group))
                iommu_detach_group(hwpt->domain, idev->group);
-       }
        iopt_remove_reserved_iova(&hwpt->ioas->iopt, idev->dev);
+       idev->hwpt = NULL;
        mutex_unlock(&hwpt->devices_lock);
-       mutex_unlock(&hwpt->ioas->mutex);
 
        if (hwpt->auto_domain)
                iommufd_object_destroy_user(idev->ictx, &hwpt->obj);
        else
                refcount_dec(&hwpt->obj.users);
 
-       idev->hwpt = NULL;
-
        refcount_dec(&idev->obj.users);
 }
 EXPORT_SYMBOL_NS_GPL(iommufd_device_detach, IOMMUFD);
@@ -769,10 +760,6 @@ out_hwpt:
 void iommufd_device_selftest_detach(struct iommufd_ctx *ictx,
                                    struct iommufd_hw_pagetable *hwpt)
 {
-       mutex_lock(&hwpt->ioas->mutex);
-       iopt_table_remove_domain(&hwpt->ioas->iopt, hwpt->domain);
-       list_del(&hwpt->hwpt_item);
-       mutex_unlock(&hwpt->ioas->mutex);
        refcount_dec(&hwpt->obj.users);
 }
 #endif
index 43d473989a0667701b93697f1efa9955e1555c1f..10db1359c067c145fe6d06e77cd11e442444aea5 100644 (file)
@@ -13,7 +13,17 @@ void iommufd_hw_pagetable_destroy(struct iommufd_object *obj)
 
        WARN_ON(!list_empty(&hwpt->devices));
 
-       iommu_domain_free(hwpt->domain);
+       if (!list_empty(&hwpt->hwpt_item)) {
+               mutex_lock(&hwpt->ioas->mutex);
+               list_del(&hwpt->hwpt_item);
+               mutex_unlock(&hwpt->ioas->mutex);
+
+               iopt_table_remove_domain(&hwpt->ioas->iopt, hwpt->domain);
+       }
+
+       if (hwpt->domain)
+               iommu_domain_free(hwpt->domain);
+
        refcount_dec(&hwpt->ioas->obj.users);
        mutex_destroy(&hwpt->devices_lock);
 }
@@ -37,21 +47,22 @@ iommufd_hw_pagetable_alloc(struct iommufd_ctx *ictx, struct iommufd_ioas *ioas,
        if (IS_ERR(hwpt))
                return hwpt;
 
-       hwpt->domain = iommu_domain_alloc(dev->bus);
-       if (!hwpt->domain) {
-               rc = -ENOMEM;
-               goto out_abort;
-       }
-
        INIT_LIST_HEAD(&hwpt->devices);
        INIT_LIST_HEAD(&hwpt->hwpt_item);
        mutex_init(&hwpt->devices_lock);
        /* Pairs with iommufd_hw_pagetable_destroy() */
        refcount_inc(&ioas->obj.users);
        hwpt->ioas = ioas;
+
+       hwpt->domain = iommu_domain_alloc(dev->bus);
+       if (!hwpt->domain) {
+               rc = -ENOMEM;
+               goto out_abort;
+       }
+
        return hwpt;
 
 out_abort:
-       iommufd_object_abort(ictx, &hwpt->obj);
+       iommufd_object_abort_and_destroy(ictx, &hwpt->obj);
        return ERR_PTR(rc);
 }