Skip to content

Commit b76c0ee

Browse files
jgunthorpeawilliam
authored andcommitted
vfio: Simplify the life cycle of the group FD
Once userspace opens a group FD it is prevented from opening another instance of that same group FD until all the prior group FDs and users of the container are done. The first is done trivially by checking the group->opened during group FD open. However, things get a little weird if userspace creates a device FD and then closes the group FD. The group FD still cannot be re-opened, but this time it is because the group->container is still set and container_users is elevated by the device FD. Due to this mismatched lifecycle we have the vfio_group_try_dissolve_container() which tries to auto-free a container after the group FD is closed but the device FD remains open. Instead have the device FD hold onto a reference to the single group FD. This directly prevents vfio_group_fops_release() from being called when any device FD exists and makes the lifecycle model more understandable. vfio_group_try_dissolve_container() is removed as the only place a container is auto-deleted is during vfio_group_fops_release(). At this point the container_users is either 1 or 0 since all device FDs must be closed. Change group->opened to group->opened_file which points to the single struct file * that is open for the group. If the group->open_file is NULL then group->container == NULL. If all device FDs have closed then the group's notifier list must be empty. 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/5-v2-d035a1842d81+1bf-vfio_group_locking_jgg@nvidia.com Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
1 parent e0e29bd commit b76c0ee

File tree

1 file changed

+24
-28
lines changed

1 file changed

+24
-28
lines changed

drivers/vfio/vfio.c

Lines changed: 24 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,11 @@ struct vfio_group {
7373
struct mutex device_lock;
7474
struct list_head vfio_next;
7575
struct list_head container_next;
76-
bool opened;
7776
enum vfio_group_type type;
7877
unsigned int dev_counter;
7978
struct rw_semaphore group_rwsem;
8079
struct kvm *kvm;
80+
struct file *opened_file;
8181
struct blocking_notifier_head notifier;
8282
};
8383

@@ -967,20 +967,6 @@ static int vfio_group_unset_container(struct vfio_group *group)
967967
return 0;
968968
}
969969

970-
/*
971-
* When removing container users, anything that removes the last user
972-
* implicitly removes the group from the container. That is, if the
973-
* group file descriptor is closed, as well as any device file descriptors,
974-
* the group is free.
975-
*/
976-
static void vfio_group_try_dissolve_container(struct vfio_group *group)
977-
{
978-
down_write(&group->group_rwsem);
979-
if (0 == atomic_dec_if_positive(&group->container_users))
980-
__vfio_group_unset_container(group);
981-
up_write(&group->group_rwsem);
982-
}
983-
984970
static int vfio_group_set_container(struct vfio_group *group, int container_fd)
985971
{
986972
struct fd f;
@@ -1068,10 +1054,19 @@ static int vfio_device_assign_container(struct vfio_device *device)
10681054
if (group->type == VFIO_NO_IOMMU && !capable(CAP_SYS_RAWIO))
10691055
return -EPERM;
10701056

1057+
get_file(group->opened_file);
10711058
atomic_inc(&group->container_users);
10721059
return 0;
10731060
}
10741061

1062+
static void vfio_device_unassign_container(struct vfio_device *device)
1063+
{
1064+
down_write(&device->group->group_rwsem);
1065+
atomic_dec(&device->group->container_users);
1066+
fput(device->group->opened_file);
1067+
up_write(&device->group->group_rwsem);
1068+
}
1069+
10751070
static struct file *vfio_device_open(struct vfio_device *device)
10761071
{
10771072
struct file *filep;
@@ -1133,7 +1128,7 @@ static struct file *vfio_device_open(struct vfio_device *device)
11331128
mutex_unlock(&device->dev_set->lock);
11341129
module_put(device->dev->driver->owner);
11351130
err_unassign_container:
1136-
vfio_group_try_dissolve_container(device->group);
1131+
vfio_device_unassign_container(device);
11371132
return ERR_PTR(ret);
11381133
}
11391134

@@ -1264,18 +1259,12 @@ static int vfio_group_fops_open(struct inode *inode, struct file *filep)
12641259

12651260
/*
12661261
* Do we need multiple instances of the group open? Seems not.
1267-
* Is something still in use from a previous open?
12681262
*/
1269-
if (group->opened || group->container) {
1263+
if (group->opened_file) {
12701264
ret = -EBUSY;
12711265
goto err_put;
12721266
}
1273-
group->opened = true;
1274-
1275-
/* Warn if previous user didn't cleanup and re-init to drop them */
1276-
if (WARN_ON(group->notifier.head))
1277-
BLOCKING_INIT_NOTIFIER_HEAD(&group->notifier);
1278-
1267+
group->opened_file = filep;
12791268
filep->private_data = group;
12801269

12811270
up_write(&group->group_rwsem);
@@ -1293,10 +1282,17 @@ static int vfio_group_fops_release(struct inode *inode, struct file *filep)
12931282

12941283
filep->private_data = NULL;
12951284

1296-
vfio_group_try_dissolve_container(group);
1297-
12981285
down_write(&group->group_rwsem);
1299-
group->opened = false;
1286+
/*
1287+
* Device FDs hold a group file reference, therefore the group release
1288+
* is only called when there are no open devices.
1289+
*/
1290+
WARN_ON(group->notifier.head);
1291+
if (group->container) {
1292+
WARN_ON(atomic_read(&group->container_users) != 1);
1293+
__vfio_group_unset_container(group);
1294+
}
1295+
group->opened_file = NULL;
13001296
up_write(&group->group_rwsem);
13011297

13021298
vfio_group_put(group);
@@ -1328,7 +1324,7 @@ static int vfio_device_fops_release(struct inode *inode, struct file *filep)
13281324

13291325
module_put(device->dev->driver->owner);
13301326

1331-
vfio_group_try_dissolve_container(device->group);
1327+
vfio_device_unassign_container(device);
13321328

13331329
vfio_device_put(device);
13341330

0 commit comments

Comments
 (0)