Skip to content

Commit

Permalink
iommufd: Add iommufd_access_change_ioas(_id) helpers
Browse files Browse the repository at this point in the history
The complication of the mutex and refcount will be amplified after we
introduce the replace support for accesses. So, add a preparatory change
of a constitutive helper iommufd_access_change_ioas() and its wrapper
iommufd_access_change_ioas_id(). They can simply take care of existing
iommufd_access_attach() and iommufd_access_detach(), properly sequencing
the refcount puts so that they are truely at the end of the sequence after
we know the IOAS pointer is not required any more.

Link: https://lore.kernel.org/r/da0c462532193b447329c4eb975a596f47e49b70.1690523699.git.nicolinc@nvidia.com
Suggested-by: Jason Gunthorpe <[email protected]>
Reviewed-by: Kevin Tian <[email protected]>
Signed-off-by: Nicolin Chen <[email protected]>
Signed-off-by: Jason Gunthorpe <[email protected]>
  • Loading branch information
nicolinc authored and jgunthorpe committed Jul 28, 2023
1 parent 5d5c85f commit 9227da7
Showing 1 changed file with 71 additions and 38 deletions.
109 changes: 71 additions & 38 deletions drivers/iommu/iommufd/device.c
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,70 @@ void iommufd_device_detach(struct iommufd_device *idev)
}
EXPORT_SYMBOL_NS_GPL(iommufd_device_detach, IOMMUFD);

/*
* On success, it will refcount_inc() at a valid new_ioas and refcount_dec() at
* a valid cur_ioas (access->ioas). A caller passing in a valid new_ioas should
* call iommufd_put_object() if it does an iommufd_get_object() for a new_ioas.
*/
static int iommufd_access_change_ioas(struct iommufd_access *access,
struct iommufd_ioas *new_ioas)
{
u32 iopt_access_list_id = access->iopt_access_list_id;
struct iommufd_ioas *cur_ioas = access->ioas;
int rc;

lockdep_assert_held(&access->ioas_lock);

/* We are racing with a concurrent detach, bail */
if (cur_ioas != access->ioas_unpin)
return -EBUSY;

if (cur_ioas == new_ioas)
return 0;

/*
* Set ioas to NULL to block any further iommufd_access_pin_pages().
* iommufd_access_unpin_pages() can continue using access->ioas_unpin.
*/
access->ioas = NULL;

if (new_ioas) {
rc = iopt_add_access(&new_ioas->iopt, access);
if (rc) {
access->ioas = cur_ioas;
return rc;
}
refcount_inc(&new_ioas->obj.users);
}

if (cur_ioas) {
if (access->ops->unmap) {
mutex_unlock(&access->ioas_lock);
access->ops->unmap(access->data, 0, ULONG_MAX);
mutex_lock(&access->ioas_lock);
}
iopt_remove_access(&cur_ioas->iopt, access, iopt_access_list_id);
refcount_dec(&cur_ioas->obj.users);
}

access->ioas = new_ioas;
access->ioas_unpin = new_ioas;

return 0;
}

static int iommufd_access_change_ioas_id(struct iommufd_access *access, u32 id)
{
struct iommufd_ioas *ioas = iommufd_get_ioas(access->ictx, id);
int rc;

if (IS_ERR(ioas))
return PTR_ERR(ioas);
rc = iommufd_access_change_ioas(access, ioas);
iommufd_put_object(&ioas->obj);
return rc;
}

void iommufd_access_destroy_object(struct iommufd_object *obj)
{
struct iommufd_access *access =
Expand Down Expand Up @@ -761,60 +825,29 @@ EXPORT_SYMBOL_NS_GPL(iommufd_access_destroy, IOMMUFD);

void iommufd_access_detach(struct iommufd_access *access)
{
struct iommufd_ioas *cur_ioas = access->ioas;

mutex_lock(&access->ioas_lock);
if (WARN_ON(!access->ioas))
goto out;
/*
* Set ioas to NULL to block any further iommufd_access_pin_pages().
* iommufd_access_unpin_pages() can continue using access->ioas_unpin.
*/
access->ioas = NULL;

if (access->ops->unmap) {
if (WARN_ON(!access->ioas)) {
mutex_unlock(&access->ioas_lock);
access->ops->unmap(access->data, 0, ULONG_MAX);
mutex_lock(&access->ioas_lock);
return;
}
iopt_remove_access(&cur_ioas->iopt, access,
access->iopt_access_list_id);
refcount_dec(&cur_ioas->obj.users);
out:
access->ioas_unpin = NULL;
WARN_ON(iommufd_access_change_ioas(access, NULL));
mutex_unlock(&access->ioas_lock);
}
EXPORT_SYMBOL_NS_GPL(iommufd_access_detach, IOMMUFD);

int iommufd_access_attach(struct iommufd_access *access, u32 ioas_id)
{
struct iommufd_ioas *new_ioas;
int rc = 0;
int rc;

mutex_lock(&access->ioas_lock);
if (WARN_ON(access->ioas || access->ioas_unpin)) {
if (WARN_ON(access->ioas)) {
mutex_unlock(&access->ioas_lock);
return -EINVAL;
}

new_ioas = iommufd_get_ioas(access->ictx, ioas_id);
if (IS_ERR(new_ioas)) {
mutex_unlock(&access->ioas_lock);
return PTR_ERR(new_ioas);
}

rc = iopt_add_access(&new_ioas->iopt, access);
if (rc) {
mutex_unlock(&access->ioas_lock);
iommufd_put_object(&new_ioas->obj);
return rc;
}
iommufd_ref_to_users(&new_ioas->obj);

access->ioas = new_ioas;
access->ioas_unpin = new_ioas;
rc = iommufd_access_change_ioas_id(access, ioas_id);
mutex_unlock(&access->ioas_lock);
return 0;
return rc;
}
EXPORT_SYMBOL_NS_GPL(iommufd_access_attach, IOMMUFD);

Expand Down

0 comments on commit 9227da7

Please sign in to comment.