Commit 2cd8b14a authored by Yishai Hadas's avatar Yishai Hadas Committed by Alex Williamson
Browse files

vfio/pci: Move to the device set infrastructure



PCI wants to have the usual open/close_device() logic with the slight
twist that the open/close_device() must be done under a singelton lock
shared by all of the vfio_devices that are in the PCI "reset group".

The reset group, and thus the device set, is determined by what devices
pci_reset_bus() touches, which is either the entire bus or only the slot.

Rely on the core code to do everything reflck was doing and delete reflck
entirely.

Signed-off-by: default avatarYishai Hadas <yishaih@nvidia.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarJason Gunthorpe <jgg@nvidia.com>
Reviewed-by: default avatarCornelia Huck <cohuck@redhat.com>
Link: https://lore.kernel.org/r/8-v4-9ea22c5e6afb+1adf-vfio_reflck_jgg@nvidia.com


Signed-off-by: default avatarAlex Williamson <alex.williamson@redhat.com>
parent ab7e5e34
Loading
Loading
Loading
Loading
+37 −125
Original line number Diff line number Diff line
@@ -530,14 +530,11 @@ static void vfio_pci_vf_token_user_add(struct vfio_pci_device *vdev, int val)
	vfio_device_put(&pf_vdev->vdev);
}

static void vfio_pci_release(struct vfio_device *core_vdev)
static void vfio_pci_close_device(struct vfio_device *core_vdev)
{
	struct vfio_pci_device *vdev =
		container_of(core_vdev, struct vfio_pci_device, vdev);

	mutex_lock(&vdev->reflck->lock);

	if (!(--vdev->refcnt)) {
	vfio_pci_vf_token_user_add(vdev, -1);
	vfio_spapr_pci_eeh_release(vdev->pdev);
	vfio_pci_disable(vdev);
@@ -554,29 +551,19 @@ static void vfio_pci_release(struct vfio_device *core_vdev)
	mutex_unlock(&vdev->igate);
}

	mutex_unlock(&vdev->reflck->lock);
}

static int vfio_pci_open(struct vfio_device *core_vdev)
static int vfio_pci_open_device(struct vfio_device *core_vdev)
{
	struct vfio_pci_device *vdev =
		container_of(core_vdev, struct vfio_pci_device, vdev);
	int ret = 0;

	mutex_lock(&vdev->reflck->lock);

	if (!vdev->refcnt) {
	ret = vfio_pci_enable(vdev);
	if (ret)
			goto error;
		return ret;

	vfio_spapr_pci_eeh_open(vdev->pdev);
	vfio_pci_vf_token_user_add(vdev, 1);
	}
	vdev->refcnt++;
error:
	mutex_unlock(&vdev->reflck->lock);
	return ret;
	return 0;
}

static int vfio_pci_get_irq_count(struct vfio_pci_device *vdev, int irq_type)
@@ -1870,8 +1857,8 @@ static int vfio_pci_match(struct vfio_device *core_vdev, char *buf)

static const struct vfio_device_ops vfio_pci_ops = {
	.name		= "vfio-pci",
	.open		= vfio_pci_open,
	.release	= vfio_pci_release,
	.open_device	= vfio_pci_open_device,
	.close_device	= vfio_pci_close_device,
	.ioctl		= vfio_pci_ioctl,
	.read		= vfio_pci_read,
	.write		= vfio_pci_write,
@@ -1880,9 +1867,6 @@ static const struct vfio_device_ops vfio_pci_ops = {
	.match		= vfio_pci_match,
};

static int vfio_pci_reflck_attach(struct vfio_pci_device *vdev);
static void vfio_pci_reflck_put(struct vfio_pci_reflck *reflck);

static int vfio_pci_bus_notifier(struct notifier_block *nb,
				 unsigned long action, void *data)
{
@@ -2020,12 +2004,23 @@ static int vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
	INIT_LIST_HEAD(&vdev->vma_list);
	init_rwsem(&vdev->memory_lock);

	ret = vfio_pci_reflck_attach(vdev);
	if (pci_is_root_bus(pdev->bus)) {
		ret = vfio_assign_device_set(&vdev->vdev, vdev);
	} else if (!pci_probe_reset_slot(pdev->slot)) {
		ret = vfio_assign_device_set(&vdev->vdev, pdev->slot);
	} else {
		/*
		 * If there is no slot reset support for this device, the whole
		 * bus needs to be grouped together to support bus-wide resets.
		 */
		ret = vfio_assign_device_set(&vdev->vdev, pdev->bus);
	}

	if (ret)
		goto out_uninit;
	ret = vfio_pci_vf_init(vdev);
	if (ret)
		goto out_reflck;
		goto out_uninit;
	ret = vfio_pci_vga_init(vdev);
	if (ret)
		goto out_vf;
@@ -2057,8 +2052,6 @@ static int vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
		vfio_pci_set_power_state(vdev, PCI_D0);
out_vf:
	vfio_pci_vf_uninit(vdev);
out_reflck:
	vfio_pci_reflck_put(vdev->reflck);
out_uninit:
	vfio_uninit_group_dev(&vdev->vdev);
	kfree(vdev->pm_save);
@@ -2077,7 +2070,6 @@ static void vfio_pci_remove(struct pci_dev *pdev)
	vfio_unregister_group_dev(&vdev->vdev);

	vfio_pci_vf_uninit(vdev);
	vfio_pci_reflck_put(vdev->reflck);
	vfio_uninit_group_dev(&vdev->vdev);
	vfio_pci_vga_uninit(vdev);

@@ -2153,86 +2145,6 @@ static struct pci_driver vfio_pci_driver = {
	.err_handler		= &vfio_err_handlers,
};

static DEFINE_MUTEX(reflck_lock);

static struct vfio_pci_reflck *vfio_pci_reflck_alloc(void)
{
	struct vfio_pci_reflck *reflck;

	reflck = kzalloc(sizeof(*reflck), GFP_KERNEL);
	if (!reflck)
		return ERR_PTR(-ENOMEM);

	kref_init(&reflck->kref);
	mutex_init(&reflck->lock);

	return reflck;
}

static void vfio_pci_reflck_get(struct vfio_pci_reflck *reflck)
{
	kref_get(&reflck->kref);
}

static int vfio_pci_reflck_find(struct pci_dev *pdev, void *data)
{
	struct vfio_pci_reflck **preflck = data;
	struct vfio_device *device;
	struct vfio_pci_device *vdev;

	device = vfio_device_get_from_dev(&pdev->dev);
	if (!device)
		return 0;

	if (pci_dev_driver(pdev) != &vfio_pci_driver) {
		vfio_device_put(device);
		return 0;
	}

	vdev = container_of(device, struct vfio_pci_device, vdev);

	if (vdev->reflck) {
		vfio_pci_reflck_get(vdev->reflck);
		*preflck = vdev->reflck;
		vfio_device_put(device);
		return 1;
	}

	vfio_device_put(device);
	return 0;
}

static int vfio_pci_reflck_attach(struct vfio_pci_device *vdev)
{
	bool slot = !pci_probe_reset_slot(vdev->pdev->slot);

	mutex_lock(&reflck_lock);

	if (pci_is_root_bus(vdev->pdev->bus) ||
	    vfio_pci_for_each_slot_or_bus(vdev->pdev, vfio_pci_reflck_find,
					  &vdev->reflck, slot) <= 0)
		vdev->reflck = vfio_pci_reflck_alloc();

	mutex_unlock(&reflck_lock);

	return PTR_ERR_OR_ZERO(vdev->reflck);
}

static void vfio_pci_reflck_release(struct kref *kref)
{
	struct vfio_pci_reflck *reflck = container_of(kref,
						      struct vfio_pci_reflck,
						      kref);

	kfree(reflck);
	mutex_unlock(&reflck_lock);
}

static void vfio_pci_reflck_put(struct vfio_pci_reflck *reflck)
{
	kref_put_mutex(&reflck->kref, vfio_pci_reflck_release, &reflck_lock);
}

static int vfio_pci_get_unused_devs(struct pci_dev *pdev, void *data)
{
	struct vfio_devices *devs = data;
@@ -2254,7 +2166,7 @@ static int vfio_pci_get_unused_devs(struct pci_dev *pdev, void *data)
	vdev = container_of(device, struct vfio_pci_device, vdev);

	/* Fault if the device is not unused */
	if (vdev->refcnt) {
	if (device->open_count) {
		vfio_device_put(device);
		return -EBUSY;
	}
@@ -2303,7 +2215,7 @@ static int vfio_pci_try_zap_and_vma_lock_cb(struct pci_dev *pdev, void *data)
 *  - At least one of the affected devices is marked dirty via
 *    needs_reset (such as by lack of FLR support)
 * Then attempt to perform that bus or slot reset.  Callers are required
 * to hold vdev->reflck->lock, protecting the bus/slot reset group from
 * to hold vdev->dev_set->lock, protecting the bus/slot reset group from
 * concurrent opens.  A vfio_device reference is acquired for each device
 * to prevent unbinds during the reset operation.
 *
+0 −7
Original line number Diff line number Diff line
@@ -83,11 +83,6 @@ struct vfio_pci_dummy_resource {
	struct list_head	res_next;
};

struct vfio_pci_reflck {
	struct kref		kref;
	struct mutex		lock;
};

struct vfio_pci_vf_token {
	struct mutex		lock;
	uuid_t			uuid;
@@ -130,8 +125,6 @@ struct vfio_pci_device {
	bool			needs_pm_restore;
	struct pci_saved_state	*pci_saved_state;
	struct pci_saved_state	*pm_save;
	struct vfio_pci_reflck	*reflck;
	int			refcnt;
	int			ioeventfds_nr;
	struct eventfd_ctx	*err_trigger;
	struct eventfd_ctx	*req_trigger;