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
parent
0e3e0b0c08
commit
1c26c3bbde
|
|
@ -1084,9 +1084,41 @@ void iommufd_access_destroy_object(struct iommufd_object *obj)
|
||||||
if (access->ioas)
|
if (access->ioas)
|
||||||
WARN_ON(iommufd_access_change_ioas(access, NULL));
|
WARN_ON(iommufd_access_change_ioas(access, NULL));
|
||||||
mutex_unlock(&access->ioas_lock);
|
mutex_unlock(&access->ioas_lock);
|
||||||
|
if (!iommufd_access_is_internal(access))
|
||||||
iommufd_ctx_put(access->ictx);
|
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
|
* iommufd_access_create - Create an iommufd_access
|
||||||
* @ictx: iommufd file descriptor
|
* @ictx: iommufd file descriptor
|
||||||
|
|
@ -1106,11 +1138,7 @@ iommufd_access_create(struct iommufd_ctx *ictx,
|
||||||
{
|
{
|
||||||
struct iommufd_access *access;
|
struct iommufd_access *access;
|
||||||
|
|
||||||
/*
|
access = __iommufd_access_create(ictx);
|
||||||
* 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))
|
if (IS_ERR(access))
|
||||||
return access;
|
return access;
|
||||||
|
|
||||||
|
|
@ -1122,13 +1150,10 @@ iommufd_access_create(struct iommufd_ctx *ictx,
|
||||||
else
|
else
|
||||||
access->iova_alignment = 1;
|
access->iova_alignment = 1;
|
||||||
|
|
||||||
/* The calling driver is a user until iommufd_access_destroy() */
|
|
||||||
refcount_inc(&access->obj.users);
|
|
||||||
access->ictx = ictx;
|
access->ictx = ictx;
|
||||||
iommufd_ctx_get(ictx);
|
iommufd_ctx_get(ictx);
|
||||||
iommufd_object_finalize(ictx, &access->obj);
|
iommufd_object_finalize(ictx, &access->obj);
|
||||||
*id = access->obj.id;
|
*id = access->obj.id;
|
||||||
mutex_init(&access->ioas_lock);
|
|
||||||
return access;
|
return access;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_NS_GPL(iommufd_access_create, "IOMMUFD");
|
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");
|
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 iommufd_access_replace(struct iommufd_access *access, u32 ioas_id)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
|
||||||
|
|
@ -484,6 +484,29 @@ void iopt_remove_access(struct io_pagetable *iopt,
|
||||||
struct iommufd_access *access, u32 iopt_access_list_id);
|
struct iommufd_access *access, u32 iopt_access_list_id);
|
||||||
void iommufd_access_destroy_object(struct iommufd_object *obj);
|
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_eventq {
|
||||||
struct iommufd_object obj;
|
struct iommufd_object obj;
|
||||||
struct iommufd_ctx *ictx;
|
struct iommufd_ctx *ictx;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue