diff options
Diffstat (limited to 'drivers/vfio/vfio.c')
-rw-r--r-- | drivers/vfio/vfio.c | 14 |
1 files changed, 14 insertions, 0 deletions
diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c index 259ad282ae5d..c488da5db7c7 100644 --- a/drivers/vfio/vfio.c +++ b/drivers/vfio/vfio.c | |||
@@ -76,6 +76,7 @@ struct vfio_group { | |||
76 | struct notifier_block nb; | 76 | struct notifier_block nb; |
77 | struct list_head vfio_next; | 77 | struct list_head vfio_next; |
78 | struct list_head container_next; | 78 | struct list_head container_next; |
79 | atomic_t opened; | ||
79 | }; | 80 | }; |
80 | 81 | ||
81 | struct vfio_device { | 82 | struct vfio_device { |
@@ -206,6 +207,7 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group) | |||
206 | INIT_LIST_HEAD(&group->device_list); | 207 | INIT_LIST_HEAD(&group->device_list); |
207 | mutex_init(&group->device_lock); | 208 | mutex_init(&group->device_lock); |
208 | atomic_set(&group->container_users, 0); | 209 | atomic_set(&group->container_users, 0); |
210 | atomic_set(&group->opened, 0); | ||
209 | group->iommu_group = iommu_group; | 211 | group->iommu_group = iommu_group; |
210 | 212 | ||
211 | group->nb.notifier_call = vfio_iommu_group_notifier; | 213 | group->nb.notifier_call = vfio_iommu_group_notifier; |
@@ -1236,12 +1238,22 @@ static long vfio_group_fops_compat_ioctl(struct file *filep, | |||
1236 | static int vfio_group_fops_open(struct inode *inode, struct file *filep) | 1238 | static int vfio_group_fops_open(struct inode *inode, struct file *filep) |
1237 | { | 1239 | { |
1238 | struct vfio_group *group; | 1240 | struct vfio_group *group; |
1241 | int opened; | ||
1239 | 1242 | ||
1240 | group = vfio_group_get_from_minor(iminor(inode)); | 1243 | group = vfio_group_get_from_minor(iminor(inode)); |
1241 | if (!group) | 1244 | if (!group) |
1242 | return -ENODEV; | 1245 | return -ENODEV; |
1243 | 1246 | ||
1247 | /* Do we need multiple instances of the group open? Seems not. */ | ||
1248 | opened = atomic_cmpxchg(&group->opened, 0, 1); | ||
1249 | if (opened) { | ||
1250 | vfio_group_put(group); | ||
1251 | return -EBUSY; | ||
1252 | } | ||
1253 | |||
1254 | /* Is something still in use from a previous open? */ | ||
1244 | if (group->container) { | 1255 | if (group->container) { |
1256 | atomic_dec(&group->opened); | ||
1245 | vfio_group_put(group); | 1257 | vfio_group_put(group); |
1246 | return -EBUSY; | 1258 | return -EBUSY; |
1247 | } | 1259 | } |
@@ -1259,6 +1271,8 @@ static int vfio_group_fops_release(struct inode *inode, struct file *filep) | |||
1259 | 1271 | ||
1260 | vfio_group_try_dissolve_container(group); | 1272 | vfio_group_try_dissolve_container(group); |
1261 | 1273 | ||
1274 | atomic_dec(&group->opened); | ||
1275 | |||
1262 | vfio_group_put(group); | 1276 | vfio_group_put(group); |
1263 | 1277 | ||
1264 | return 0; | 1278 | return 0; |