Skip to content

Commit

Permalink
Automatic merge of 'master' into merge (2023-12-10 10:26)
Browse files Browse the repository at this point in the history
  • Loading branch information
mpe committed Dec 9, 2023
2 parents b740804 + bee0e77 commit 1d9ceee
Show file tree
Hide file tree
Showing 11 changed files with 188 additions and 125 deletions.
14 changes: 7 additions & 7 deletions drivers/iommu/iommufd/device.c
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,7 @@ iommufd_device_auto_get_domain(struct iommufd_device *idev,
continue;
destroy_hwpt = (*do_attach)(idev, hwpt);
if (IS_ERR(destroy_hwpt)) {
iommufd_put_object(&hwpt->obj);
iommufd_put_object(idev->ictx, &hwpt->obj);
/*
* -EINVAL means the domain is incompatible with the
* device. Other error codes should propagate to
Expand All @@ -583,7 +583,7 @@ iommufd_device_auto_get_domain(struct iommufd_device *idev,
goto out_unlock;
}
*pt_id = hwpt->obj.id;
iommufd_put_object(&hwpt->obj);
iommufd_put_object(idev->ictx, &hwpt->obj);
goto out_unlock;
}

Expand Down Expand Up @@ -652,15 +652,15 @@ static int iommufd_device_change_pt(struct iommufd_device *idev, u32 *pt_id,
destroy_hwpt = ERR_PTR(-EINVAL);
goto out_put_pt_obj;
}
iommufd_put_object(pt_obj);
iommufd_put_object(idev->ictx, pt_obj);

/* This destruction has to be after we unlock everything */
if (destroy_hwpt)
iommufd_hw_pagetable_put(idev->ictx, destroy_hwpt);
return 0;

out_put_pt_obj:
iommufd_put_object(pt_obj);
iommufd_put_object(idev->ictx, pt_obj);
return PTR_ERR(destroy_hwpt);
}

Expand Down Expand Up @@ -792,7 +792,7 @@ static int iommufd_access_change_ioas_id(struct iommufd_access *access, u32 id)
if (IS_ERR(ioas))
return PTR_ERR(ioas);
rc = iommufd_access_change_ioas(access, ioas);
iommufd_put_object(&ioas->obj);
iommufd_put_object(access->ictx, &ioas->obj);
return rc;
}

Expand Down Expand Up @@ -941,7 +941,7 @@ void iommufd_access_notify_unmap(struct io_pagetable *iopt, unsigned long iova,

access->ops->unmap(access->data, iova, length);

iommufd_put_object(&access->obj);
iommufd_put_object(access->ictx, &access->obj);
xa_lock(&ioas->iopt.access_list);
}
xa_unlock(&ioas->iopt.access_list);
Expand Down Expand Up @@ -1243,6 +1243,6 @@ int iommufd_get_hw_info(struct iommufd_ucmd *ucmd)
out_free:
kfree(data);
out_put:
iommufd_put_object(&idev->obj);
iommufd_put_object(ucmd->ictx, &idev->obj);
return rc;
}
8 changes: 4 additions & 4 deletions drivers/iommu/iommufd/hw_pagetable.c
Original file line number Diff line number Diff line change
Expand Up @@ -318,9 +318,9 @@ int iommufd_hwpt_alloc(struct iommufd_ucmd *ucmd)
if (ioas)
mutex_unlock(&ioas->mutex);
out_put_pt:
iommufd_put_object(pt_obj);
iommufd_put_object(ucmd->ictx, pt_obj);
out_put_idev:
iommufd_put_object(&idev->obj);
iommufd_put_object(ucmd->ictx, &idev->obj);
return rc;
}

Expand All @@ -345,7 +345,7 @@ int iommufd_hwpt_set_dirty_tracking(struct iommufd_ucmd *ucmd)
rc = iopt_set_dirty_tracking(&ioas->iopt, hwpt_paging->common.domain,
enable);

iommufd_put_object(&hwpt_paging->common.obj);
iommufd_put_object(ucmd->ictx, &hwpt_paging->common.obj);
return rc;
}

Expand All @@ -368,6 +368,6 @@ int iommufd_hwpt_get_dirty_bitmap(struct iommufd_ucmd *ucmd)
rc = iopt_read_and_clear_dirty_data(
&ioas->iopt, hwpt_paging->common.domain, cmd->flags, cmd);

iommufd_put_object(&hwpt_paging->common.obj);
iommufd_put_object(ucmd->ictx, &hwpt_paging->common.obj);
return rc;
}
14 changes: 7 additions & 7 deletions drivers/iommu/iommufd/ioas.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ int iommufd_ioas_iova_ranges(struct iommufd_ucmd *ucmd)
rc = -EMSGSIZE;
out_put:
up_read(&ioas->iopt.iova_rwsem);
iommufd_put_object(&ioas->obj);
iommufd_put_object(ucmd->ictx, &ioas->obj);
return rc;
}

Expand Down Expand Up @@ -175,7 +175,7 @@ int iommufd_ioas_allow_iovas(struct iommufd_ucmd *ucmd)
interval_tree_remove(node, &allowed_iova);
kfree(container_of(node, struct iopt_allowed, node));
}
iommufd_put_object(&ioas->obj);
iommufd_put_object(ucmd->ictx, &ioas->obj);
return rc;
}

Expand Down Expand Up @@ -228,7 +228,7 @@ int iommufd_ioas_map(struct iommufd_ucmd *ucmd)
cmd->iova = iova;
rc = iommufd_ucmd_respond(ucmd, sizeof(*cmd));
out_put:
iommufd_put_object(&ioas->obj);
iommufd_put_object(ucmd->ictx, &ioas->obj);
return rc;
}

Expand Down Expand Up @@ -258,7 +258,7 @@ int iommufd_ioas_copy(struct iommufd_ucmd *ucmd)
return PTR_ERR(src_ioas);
rc = iopt_get_pages(&src_ioas->iopt, cmd->src_iova, cmd->length,
&pages_list);
iommufd_put_object(&src_ioas->obj);
iommufd_put_object(ucmd->ictx, &src_ioas->obj);
if (rc)
return rc;

Expand All @@ -279,7 +279,7 @@ int iommufd_ioas_copy(struct iommufd_ucmd *ucmd)
cmd->dst_iova = iova;
rc = iommufd_ucmd_respond(ucmd, sizeof(*cmd));
out_put_dst:
iommufd_put_object(&dst_ioas->obj);
iommufd_put_object(ucmd->ictx, &dst_ioas->obj);
out_pages:
iopt_free_pages_list(&pages_list);
return rc;
Expand Down Expand Up @@ -315,7 +315,7 @@ int iommufd_ioas_unmap(struct iommufd_ucmd *ucmd)
rc = iommufd_ucmd_respond(ucmd, sizeof(*cmd));

out_put:
iommufd_put_object(&ioas->obj);
iommufd_put_object(ucmd->ictx, &ioas->obj);
return rc;
}

Expand Down Expand Up @@ -393,6 +393,6 @@ int iommufd_ioas_option(struct iommufd_ucmd *ucmd)
rc = -EOPNOTSUPP;
}

iommufd_put_object(&ioas->obj);
iommufd_put_object(ucmd->ictx, &ioas->obj);
return rc;
}
70 changes: 57 additions & 13 deletions drivers/iommu/iommufd/iommufd_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ struct iommufd_ctx {
struct file *file;
struct xarray objects;
struct xarray groups;
wait_queue_head_t destroy_wait;

u8 account_mode;
/* Compatibility with VFIO no iommu */
Expand Down Expand Up @@ -135,47 +136,90 @@ enum iommufd_object_type {

/* Base struct for all objects with a userspace ID handle. */
struct iommufd_object {
struct rw_semaphore destroy_rwsem;
refcount_t shortterm_users;
refcount_t users;
enum iommufd_object_type type;
unsigned int id;
};

static inline bool iommufd_lock_obj(struct iommufd_object *obj)
{
if (!down_read_trylock(&obj->destroy_rwsem))
if (!refcount_inc_not_zero(&obj->users))
return false;
if (!refcount_inc_not_zero(&obj->users)) {
up_read(&obj->destroy_rwsem);
if (!refcount_inc_not_zero(&obj->shortterm_users)) {
/*
* If the caller doesn't already have a ref on obj this must be
* called under the xa_lock. Otherwise the caller is holding a
* ref on users. Thus it cannot be one before this decrement.
*/
refcount_dec(&obj->users);
return false;
}
return true;
}

struct iommufd_object *iommufd_get_object(struct iommufd_ctx *ictx, u32 id,
enum iommufd_object_type type);
static inline void iommufd_put_object(struct iommufd_object *obj)
static inline void iommufd_put_object(struct iommufd_ctx *ictx,
struct iommufd_object *obj)
{
/*
* Users first, then shortterm so that REMOVE_WAIT_SHORTTERM never sees
* a spurious !0 users with a 0 shortterm_users.
*/
refcount_dec(&obj->users);
up_read(&obj->destroy_rwsem);
if (refcount_dec_and_test(&obj->shortterm_users))
wake_up_interruptible_all(&ictx->destroy_wait);
}

void iommufd_object_abort(struct iommufd_ctx *ictx, struct iommufd_object *obj);
void iommufd_object_abort_and_destroy(struct iommufd_ctx *ictx,
struct iommufd_object *obj);
void iommufd_object_finalize(struct iommufd_ctx *ictx,
struct iommufd_object *obj);
void __iommufd_object_destroy_user(struct iommufd_ctx *ictx,
struct iommufd_object *obj, bool allow_fail);

enum {
REMOVE_WAIT_SHORTTERM = 1,
};
int iommufd_object_remove(struct iommufd_ctx *ictx,
struct iommufd_object *to_destroy, u32 id,
unsigned int flags);

/*
* The caller holds a users refcount and wants to destroy the object. At this
* point the caller has no shortterm_users reference and at least the xarray
* will be holding one.
*/
static inline void iommufd_object_destroy_user(struct iommufd_ctx *ictx,
struct iommufd_object *obj)
{
__iommufd_object_destroy_user(ictx, obj, false);
int ret;

ret = iommufd_object_remove(ictx, obj, obj->id, REMOVE_WAIT_SHORTTERM);

/*
* If there is a bug and we couldn't destroy the object then we did put
* back the caller's users refcount and will eventually try to free it
* again during close.
*/
WARN_ON(ret);
}
static inline void iommufd_object_deref_user(struct iommufd_ctx *ictx,
struct iommufd_object *obj)

/*
* The HWPT allocated by autodomains is used in possibly many devices and
* is automatically destroyed when its refcount reaches zero.
*
* If userspace uses the HWPT manually, even for a short term, then it will
* disrupt this refcounting and the auto-free in the kernel will not work.
* Userspace that tries to use the automatically allocated HWPT must be careful
* to ensure that it is consistently destroyed, eg by not racing accesses
* and by not attaching an automatic HWPT to a device manually.
*/
static inline void
iommufd_object_put_and_try_destroy(struct iommufd_ctx *ictx,
struct iommufd_object *obj)
{
__iommufd_object_destroy_user(ictx, obj, true);
iommufd_object_remove(ictx, obj, obj->id, 0);
}

struct iommufd_object *_iommufd_object_alloc(struct iommufd_ctx *ictx,
Expand Down Expand Up @@ -311,7 +355,7 @@ static inline void iommufd_hw_pagetable_put(struct iommufd_ctx *ictx,
lockdep_assert_not_held(&hwpt_paging->ioas->mutex);

if (hwpt_paging->auto_domain) {
iommufd_object_deref_user(ictx, &hwpt->obj);
iommufd_object_put_and_try_destroy(ictx, &hwpt->obj);
return;
}
}
Expand Down
Loading

0 comments on commit 1d9ceee

Please sign in to comment.