Commit 1c26c3bb authored by Nicolin Chen's avatar Nicolin Chen Committed by Jason Gunthorpe
Browse files

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: default avatarKevin Tian <kevin.tian@intel.com>
Reviewed-by: default avatarJason Gunthorpe <jgg@nvidia.com>
Signed-off-by: default avatarNicolin Chen <nicolinc@nvidia.com>
Signed-off-by: default avatarJason Gunthorpe <jgg@nvidia.com>
parent 0e3e0b0c
Loading
Loading
Loading
Loading
+50 −9
Original line number Diff line number Diff line
@@ -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;
+23 −0
Original line number Diff line number Diff line
@@ -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;