iommufd/access: Add internal APIs for HW queue to use

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>
pull/1311/head
Nicolin Chen 2025-07-09 22:59:02 -07:00 committed by Jason Gunthorpe
parent 0e3e0b0c08
commit 1c26c3bbde
2 changed files with 73 additions and 9 deletions

View File

@ -1084,9 +1084,41 @@ 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);
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;
}
/**
* iommufd_access_create - Create an iommufd_access
* @ictx: iommufd file descriptor
@ -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;

View 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;