Skip to content

Commit

Permalink
vfio: Change struct vfio_group::opened from an atomic to bool
Browse files Browse the repository at this point in the history
This is not a performance path, just use the group_rwsem to protect the
value.

Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Tested-by: Nicolin Chen <nicolinc@nvidia.com>
Tested-by: Matthew Rosato <mjrosato@linux.ibm.com>
Link: https://lore.kernel.org/r/2-v2-d035a1842d81+1bf-vfio_group_locking_jgg@nvidia.com
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
  • Loading branch information
Jason Gunthorpe authored and Alex Williamson committed May 17, 2022
1 parent be8d3ad commit c6f4860
Showing 1 changed file with 27 additions and 19 deletions.
46 changes: 27 additions & 19 deletions drivers/vfio/vfio.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ struct vfio_group {
struct mutex device_lock;
struct list_head vfio_next;
struct list_head container_next;
atomic_t opened;
bool opened;
enum vfio_group_type type;
unsigned int dev_counter;
struct rw_semaphore group_rwsem;
Expand Down Expand Up @@ -1213,38 +1213,44 @@ static int vfio_group_fops_open(struct inode *inode, struct file *filep)
{
struct vfio_group *group =
container_of(inode->i_cdev, struct vfio_group, cdev);
int opened;
int ret;

/* users can be zero if this races with vfio_group_put() */
if (!refcount_inc_not_zero(&group->users))
return -ENODEV;
down_write(&group->group_rwsem);

if (group->type == VFIO_NO_IOMMU && !capable(CAP_SYS_RAWIO)) {
vfio_group_put(group);
return -EPERM;
/* users can be zero if this races with vfio_group_put() */
if (!refcount_inc_not_zero(&group->users)) {
ret = -ENODEV;
goto err_unlock;
}

/* Do we need multiple instances of the group open? Seems not. */
opened = atomic_cmpxchg(&group->opened, 0, 1);
if (opened) {
vfio_group_put(group);
return -EBUSY;
if (group->type == VFIO_NO_IOMMU && !capable(CAP_SYS_RAWIO)) {
ret = -EPERM;
goto err_put;
}

/* Is something still in use from a previous open? */
if (group->container) {
atomic_dec(&group->opened);
vfio_group_put(group);
return -EBUSY;
/*
* Do we need multiple instances of the group open? Seems not.
* Is something still in use from a previous open?
*/
if (group->opened || group->container) {
ret = -EBUSY;
goto err_put;
}
group->opened = true;

/* Warn if previous user didn't cleanup and re-init to drop them */
if (WARN_ON(group->notifier.head))
BLOCKING_INIT_NOTIFIER_HEAD(&group->notifier);

filep->private_data = group;

up_write(&group->group_rwsem);
return 0;
err_put:
vfio_group_put(group);
err_unlock:
up_write(&group->group_rwsem);
return ret;
}

static int vfio_group_fops_release(struct inode *inode, struct file *filep)
Expand All @@ -1255,7 +1261,9 @@ static int vfio_group_fops_release(struct inode *inode, struct file *filep)

vfio_group_try_dissolve_container(group);

atomic_dec(&group->opened);
down_write(&group->group_rwsem);
group->opened = false;
up_write(&group->group_rwsem);

vfio_group_put(group);

Expand Down

0 comments on commit c6f4860

Please sign in to comment.