Commit 294aaccb authored by Jason Gunthorpe's avatar Jason Gunthorpe
Browse files

vfio: Move vfio_device driver open/close code to a function

This error unwind is getting complicated. Move all the code into two
pair'd function. The functions should be called when the open_count == 1
after incrementing/before decrementing.

Link: https://lore.kernel.org/r/1-v4-42cd2eb0e3eb+335a-vfio_iommufd_jgg@nvidia.com


Reviewed-by: default avatarKevin Tian <kevin.tian@intel.com>
Reviewed-by: default avatarYi Liu <yi.l.liu@intel.com>
Reviewed-by: default avatarAlex Williamson <alex.williamson@redhat.com>
Tested-by: default avatarAlex Williamson <alex.williamson@redhat.com>
Tested-by: default avatarYi Liu <yi.l.liu@intel.com>
Tested-by: default avatarNicolin Chen <nicolinc@nvidia.com>
Tested-by: default avatarLixiao Yang <lixiao.yang@intel.com>
Tested-by: default avatarMatthew Rosato <mjrosato@linux.ibm.com>
Tested-by: default avatarYu He <yu.he@intel.com>
Signed-off-by: default avatarJason Gunthorpe <jgg@nvidia.com>
parent 2a54e347
Loading
Loading
Loading
Loading
+53 −42
Original line number Diff line number Diff line
@@ -734,40 +734,68 @@ bool vfio_assert_device_open(struct vfio_device *device)
	return !WARN_ON_ONCE(!READ_ONCE(device->open_count));
}

static struct file *vfio_device_open(struct vfio_device *device)
static int vfio_device_first_open(struct vfio_device *device)
{
	struct file *filep;
	int ret;

	mutex_lock(&device->group->group_lock);
	ret = vfio_device_assign_container(device);
	mutex_unlock(&device->group->group_lock);
	if (ret)
		return ERR_PTR(ret);
	lockdep_assert_held(&device->dev_set->lock);

	if (!try_module_get(device->dev->driver->owner)) {
		ret = -ENODEV;
		goto err_unassign_container;
	}
	if (!try_module_get(device->dev->driver->owner))
		return -ENODEV;

	mutex_lock(&device->dev_set->lock);
	device->open_count++;
	if (device->open_count == 1) {
	/*
		 * Here we pass the KVM pointer with the group under the read
		 * lock.  If the device driver will use it, it must obtain a
		 * reference and release it during close_device.
	 * Here we pass the KVM pointer with the group under the lock.  If the
	 * device driver will use it, it must obtain a reference and release it
	 * during close_device.
	 */
	mutex_lock(&device->group->group_lock);
	device->kvm = device->group->kvm;

	if (device->ops->open_device) {
		ret = device->ops->open_device(device);
		if (ret)
				goto err_undo_count;
			goto err_module_put;
	}
	vfio_device_container_register(device);
	mutex_unlock(&device->group->group_lock);
	return 0;

err_module_put:
	device->kvm = NULL;
	mutex_unlock(&device->group->group_lock);
	module_put(device->dev->driver->owner);
	return ret;
}

static void vfio_device_last_close(struct vfio_device *device)
{
	lockdep_assert_held(&device->dev_set->lock);

	mutex_lock(&device->group->group_lock);
	vfio_device_container_unregister(device);
	if (device->ops->close_device)
		device->ops->close_device(device);
	device->kvm = NULL;
	mutex_unlock(&device->group->group_lock);
	module_put(device->dev->driver->owner);
}

static struct file *vfio_device_open(struct vfio_device *device)
{
	struct file *filep;
	int ret;

	mutex_lock(&device->group->group_lock);
	ret = vfio_device_assign_container(device);
	mutex_unlock(&device->group->group_lock);
	if (ret)
		return ERR_PTR(ret);

	mutex_lock(&device->dev_set->lock);
	device->open_count++;
	if (device->open_count == 1) {
		ret = vfio_device_first_open(device);
		if (ret)
			goto err_unassign_container;
	}
	mutex_unlock(&device->dev_set->lock);

@@ -800,20 +828,11 @@ static struct file *vfio_device_open(struct vfio_device *device)

err_close_device:
	mutex_lock(&device->dev_set->lock);
	mutex_lock(&device->group->group_lock);
	if (device->open_count == 1 && device->ops->close_device) {
		device->ops->close_device(device);

		vfio_device_container_unregister(device);
	}
err_undo_count:
	mutex_unlock(&device->group->group_lock);
	if (device->open_count == 1)
		vfio_device_last_close(device);
err_unassign_container:
	device->open_count--;
	if (device->open_count == 0 && device->kvm)
		device->kvm = NULL;
	mutex_unlock(&device->dev_set->lock);
	module_put(device->dev->driver->owner);
err_unassign_container:
	vfio_device_unassign_container(device);
	return ERR_PTR(ret);
}
@@ -1016,19 +1035,11 @@ static int vfio_device_fops_release(struct inode *inode, struct file *filep)

	mutex_lock(&device->dev_set->lock);
	vfio_assert_device_open(device);
	mutex_lock(&device->group->group_lock);
	if (device->open_count == 1 && device->ops->close_device)
		device->ops->close_device(device);

	vfio_device_container_unregister(device);
	mutex_unlock(&device->group->group_lock);
	if (device->open_count == 1)
		vfio_device_last_close(device);
	device->open_count--;
	if (device->open_count == 0)
		device->kvm = NULL;
	mutex_unlock(&device->dev_set->lock);

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

	vfio_device_unassign_container(device);

	vfio_device_put_registration(device);