]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
iommufd/access: Add internal APIs for HW queue to use
authorNicolin Chen <nicolinc@nvidia.com>
Thu, 10 Jul 2025 05:59:02 +0000 (22:59 -0700)
committerJason Gunthorpe <jgg@nvidia.com>
Thu, 10 Jul 2025 15:38:51 +0000 (12:38 -0300)
The new HW queue object, as an internal iommufd object, wants to reuse the
struct iommufd_access to pin some iova range in the iopt.

However, an access generally takes the refcount of an ictx. So, in such an
internal case, a deadlock could happen when the release of the ictx has to
wait for the release of the access first when releasing a hw_queue object,
which could wait for the release of the ictx that is refcounted:
    ictx --releases--> hw_queue --releases--> access
      ^                                         |
      |_________________releases________________v

To address this, add a set of lightweight internal APIs to unlink the ictx
and the access, i.e. no ictx refcounting by the access:
    ictx --releases--> hw_queue --releases--> access

Then, there's no point in setting the access->ictx. So simply define !ictx
as an flag for an internal use and add an inline helper.

Link: https://patch.msgid.link/r/d8d84bf99cbebec56034b57b966a3d431385b90d.1752126748.git.nicolinc@nvidia.com
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
drivers/iommu/iommufd/device.c
drivers/iommu/iommufd/iommufd_private.h

index e9b6ca47095c8116e0f864daf8f91d51dd75ab14..07a4ff753c1207a1af0be798631bd8a32f3d5b95 100644 (file)
@@ -1084,7 +1084,39 @@ void iommufd_access_destroy_object(struct iommufd_object *obj)
        if (access->ioas)
                WARN_ON(iommufd_access_change_ioas(access, NULL));
        mutex_unlock(&access->ioas_lock);
-       iommufd_ctx_put(access->ictx);
+       if (!iommufd_access_is_internal(access))
+               iommufd_ctx_put(access->ictx);
+}
+
+static struct iommufd_access *__iommufd_access_create(struct iommufd_ctx *ictx)
+{
+       struct iommufd_access *access;
+
+       /*
+        * There is no uAPI for the access object, but to keep things symmetric
+        * use the object infrastructure anyhow.
+        */
+       access = iommufd_object_alloc(ictx, access, IOMMUFD_OBJ_ACCESS);
+       if (IS_ERR(access))
+               return access;
+
+       /* The calling driver is a user until iommufd_access_destroy() */
+       refcount_inc(&access->obj.users);
+       mutex_init(&access->ioas_lock);
+       return access;
+}
+
+struct iommufd_access *iommufd_access_create_internal(struct iommufd_ctx *ictx)
+{
+       struct iommufd_access *access;
+
+       access = __iommufd_access_create(ictx);
+       if (IS_ERR(access))
+               return access;
+       access->iova_alignment = PAGE_SIZE;
+
+       iommufd_object_finalize(ictx, &access->obj);
+       return access;
 }
 
 /**
@@ -1106,11 +1138,7 @@ iommufd_access_create(struct iommufd_ctx *ictx,
 {
        struct iommufd_access *access;
 
-       /*
-        * There is no uAPI for the access object, but to keep things symmetric
-        * use the object infrastructure anyhow.
-        */
-       access = iommufd_object_alloc(ictx, access, IOMMUFD_OBJ_ACCESS);
+       access = __iommufd_access_create(ictx);
        if (IS_ERR(access))
                return access;
 
@@ -1122,13 +1150,10 @@ iommufd_access_create(struct iommufd_ctx *ictx,
        else
                access->iova_alignment = 1;
 
-       /* The calling driver is a user until iommufd_access_destroy() */
-       refcount_inc(&access->obj.users);
        access->ictx = ictx;
        iommufd_ctx_get(ictx);
        iommufd_object_finalize(ictx, &access->obj);
        *id = access->obj.id;
-       mutex_init(&access->ioas_lock);
        return access;
 }
 EXPORT_SYMBOL_NS_GPL(iommufd_access_create, "IOMMUFD");
@@ -1173,6 +1198,22 @@ int iommufd_access_attach(struct iommufd_access *access, u32 ioas_id)
 }
 EXPORT_SYMBOL_NS_GPL(iommufd_access_attach, "IOMMUFD");
 
+int iommufd_access_attach_internal(struct iommufd_access *access,
+                                  struct iommufd_ioas *ioas)
+{
+       int rc;
+
+       mutex_lock(&access->ioas_lock);
+       if (WARN_ON(access->ioas)) {
+               mutex_unlock(&access->ioas_lock);
+               return -EINVAL;
+       }
+
+       rc = iommufd_access_change_ioas(access, ioas);
+       mutex_unlock(&access->ioas_lock);
+       return rc;
+}
+
 int iommufd_access_replace(struct iommufd_access *access, u32 ioas_id)
 {
        int rc;
index 320635a177b774d575e7f3e17708fbd3ae436981..9fdbf5f21f2e6596916b6d7850bd6d856f750d8a 100644 (file)
@@ -484,6 +484,29 @@ void iopt_remove_access(struct io_pagetable *iopt,
                        struct iommufd_access *access, u32 iopt_access_list_id);
 void iommufd_access_destroy_object(struct iommufd_object *obj);
 
+/* iommufd_access for internal use */
+static inline bool iommufd_access_is_internal(struct iommufd_access *access)
+{
+       return !access->ictx;
+}
+
+struct iommufd_access *iommufd_access_create_internal(struct iommufd_ctx *ictx);
+
+static inline void
+iommufd_access_destroy_internal(struct iommufd_ctx *ictx,
+                               struct iommufd_access *access)
+{
+       iommufd_object_destroy_user(ictx, &access->obj);
+}
+
+int iommufd_access_attach_internal(struct iommufd_access *access,
+                                  struct iommufd_ioas *ioas);
+
+static inline void iommufd_access_detach_internal(struct iommufd_access *access)
+{
+       iommufd_access_detach(access);
+}
+
 struct iommufd_eventq {
        struct iommufd_object obj;
        struct iommufd_ctx *ictx;