Commit 805bb6c1 authored by Jason Gunthorpe's avatar Jason Gunthorpe Committed by Alex Williamson

vfio: Split up vfio_group_get_device_fd()

The split follows the pairing with the destroy functions:

 - vfio_group_get_device_fd() destroyed by close()

 - vfio_device_open() destroyed by vfio_device_fops_release()

 - vfio_device_assign_container() destroyed by
   vfio_group_try_dissolve_container()

The next patch will put a lock around vfio_device_assign_container().
Reviewed-by: default avatarKevin Tian <kevin.tian@intel.com>
Signed-off-by: default avatarJason Gunthorpe <jgg@nvidia.com>
Tested-by: default avatarNicolin Chen <nicolinc@nvidia.com>
Tested-by: default avatarMatthew Rosato <mjrosato@linux.ibm.com>
Link: https://lore.kernel.org/r/3-v2-d035a1842d81+1bf-vfio_group_locking_jgg@nvidia.comSigned-off-by: default avatarAlex Williamson <alex.williamson@redhat.com>
parent c6f4860e
...@@ -1064,12 +1064,9 @@ static bool vfio_assert_device_open(struct vfio_device *device) ...@@ -1064,12 +1064,9 @@ static bool vfio_assert_device_open(struct vfio_device *device)
return !WARN_ON_ONCE(!READ_ONCE(device->open_count)); return !WARN_ON_ONCE(!READ_ONCE(device->open_count));
} }
static int vfio_group_get_device_fd(struct vfio_group *group, char *buf) static int vfio_device_assign_container(struct vfio_device *device)
{ {
struct vfio_device *device; struct vfio_group *group = device->group;
struct file *filep;
int fdno;
int ret = 0;
if (0 == atomic_read(&group->container_users) || if (0 == atomic_read(&group->container_users) ||
!group->container->iommu_driver) !group->container->iommu_driver)
...@@ -1078,13 +1075,22 @@ static int vfio_group_get_device_fd(struct vfio_group *group, char *buf) ...@@ -1078,13 +1075,22 @@ static int vfio_group_get_device_fd(struct vfio_group *group, char *buf)
if (group->type == VFIO_NO_IOMMU && !capable(CAP_SYS_RAWIO)) if (group->type == VFIO_NO_IOMMU && !capable(CAP_SYS_RAWIO))
return -EPERM; return -EPERM;
device = vfio_device_get_from_name(group, buf); atomic_inc(&group->container_users);
if (IS_ERR(device)) return 0;
return PTR_ERR(device); }
static struct file *vfio_device_open(struct vfio_device *device)
{
struct file *filep;
int ret;
ret = vfio_device_assign_container(device);
if (ret)
return ERR_PTR(ret);
if (!try_module_get(device->dev->driver->owner)) { if (!try_module_get(device->dev->driver->owner)) {
ret = -ENODEV; ret = -ENODEV;
goto err_device_put; goto err_unassign_container;
} }
mutex_lock(&device->dev_set->lock); mutex_lock(&device->dev_set->lock);
...@@ -1100,15 +1106,11 @@ static int vfio_group_get_device_fd(struct vfio_group *group, char *buf) ...@@ -1100,15 +1106,11 @@ static int vfio_group_get_device_fd(struct vfio_group *group, char *buf)
* We can't use anon_inode_getfd() because we need to modify * We can't use anon_inode_getfd() because we need to modify
* the f_mode flags directly to allow more than just ioctls * the f_mode flags directly to allow more than just ioctls
*/ */
fdno = ret = get_unused_fd_flags(O_CLOEXEC);
if (ret < 0)
goto err_close_device;
filep = anon_inode_getfile("[vfio-device]", &vfio_device_fops, filep = anon_inode_getfile("[vfio-device]", &vfio_device_fops,
device, O_RDWR); device, O_RDWR);
if (IS_ERR(filep)) { if (IS_ERR(filep)) {
ret = PTR_ERR(filep); ret = PTR_ERR(filep);
goto err_fd; goto err_close_device;
} }
/* /*
...@@ -1118,17 +1120,15 @@ static int vfio_group_get_device_fd(struct vfio_group *group, char *buf) ...@@ -1118,17 +1120,15 @@ static int vfio_group_get_device_fd(struct vfio_group *group, char *buf)
*/ */
filep->f_mode |= (FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); filep->f_mode |= (FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE);
atomic_inc(&group->container_users); if (device->group->type == VFIO_NO_IOMMU)
fd_install(fdno, filep);
if (group->type == VFIO_NO_IOMMU)
dev_warn(device->dev, "vfio-noiommu device opened by user " dev_warn(device->dev, "vfio-noiommu device opened by user "
"(%s:%d)\n", current->comm, task_pid_nr(current)); "(%s:%d)\n", current->comm, task_pid_nr(current));
return fdno; /*
* On success the ref of device is moved to the file and
* put in vfio_device_fops_release()
*/
return filep;
err_fd:
put_unused_fd(fdno);
err_close_device: err_close_device:
mutex_lock(&device->dev_set->lock); mutex_lock(&device->dev_set->lock);
if (device->open_count == 1 && device->ops->close_device) if (device->open_count == 1 && device->ops->close_device)
...@@ -1137,7 +1137,40 @@ static int vfio_group_get_device_fd(struct vfio_group *group, char *buf) ...@@ -1137,7 +1137,40 @@ static int vfio_group_get_device_fd(struct vfio_group *group, char *buf)
device->open_count--; device->open_count--;
mutex_unlock(&device->dev_set->lock); mutex_unlock(&device->dev_set->lock);
module_put(device->dev->driver->owner); module_put(device->dev->driver->owner);
err_device_put: err_unassign_container:
vfio_group_try_dissolve_container(device->group);
return ERR_PTR(ret);
}
static int vfio_group_get_device_fd(struct vfio_group *group, char *buf)
{
struct vfio_device *device;
struct file *filep;
int fdno;
int ret;
device = vfio_device_get_from_name(group, buf);
if (IS_ERR(device))
return PTR_ERR(device);
fdno = get_unused_fd_flags(O_CLOEXEC);
if (fdno < 0) {
ret = fdno;
goto err_put_device;
}
filep = vfio_device_open(device);
if (IS_ERR(filep)) {
ret = PTR_ERR(filep);
goto err_put_fdno;
}
fd_install(fdno, filep);
return fdno;
err_put_fdno:
put_unused_fd(fdno);
err_put_device:
vfio_device_put(device); vfio_device_put(device);
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment