|
@@ -76,6 +76,7 @@ struct vfio_group {
|
|
|
struct notifier_block nb;
|
|
|
struct list_head vfio_next;
|
|
|
struct list_head container_next;
|
|
|
+ atomic_t opened;
|
|
|
};
|
|
|
|
|
|
struct vfio_device {
|
|
@@ -206,6 +207,7 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group)
|
|
|
INIT_LIST_HEAD(&group->device_list);
|
|
|
mutex_init(&group->device_lock);
|
|
|
atomic_set(&group->container_users, 0);
|
|
|
+ atomic_set(&group->opened, 0);
|
|
|
group->iommu_group = iommu_group;
|
|
|
|
|
|
group->nb.notifier_call = vfio_iommu_group_notifier;
|
|
@@ -1236,12 +1238,22 @@ static long vfio_group_fops_compat_ioctl(struct file *filep,
|
|
|
static int vfio_group_fops_open(struct inode *inode, struct file *filep)
|
|
|
{
|
|
|
struct vfio_group *group;
|
|
|
+ int opened;
|
|
|
|
|
|
group = vfio_group_get_from_minor(iminor(inode));
|
|
|
if (!group)
|
|
|
return -ENODEV;
|
|
|
|
|
|
+ /* 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;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Is something still in use from a previous open? */
|
|
|
if (group->container) {
|
|
|
+ atomic_dec(&group->opened);
|
|
|
vfio_group_put(group);
|
|
|
return -EBUSY;
|
|
|
}
|
|
@@ -1259,6 +1271,8 @@ static int vfio_group_fops_release(struct inode *inode, struct file *filep)
|
|
|
|
|
|
vfio_group_try_dissolve_container(group);
|
|
|
|
|
|
+ atomic_dec(&group->opened);
|
|
|
+
|
|
|
vfio_group_put(group);
|
|
|
|
|
|
return 0;
|