Commit 3b86f317 authored by Lu Baolu's avatar Lu Baolu Committed by Joerg Roedel
Browse files

vfio: Remove iommu group notifier



The iommu core and driver core have been enhanced to avoid unsafe driver
binding to a live group after iommu_group_set_dma_owner(PRIVATE_USER)
has been called. There's no need to register iommu group notifier. This
removes the iommu group notifer which contains BUG_ON() and WARN().

Signed-off-by: default avatarLu Baolu <baolu.lu@linux.intel.com>
Reviewed-by: default avatarJason Gunthorpe <jgg@nvidia.com>
Acked-by: default avatarAlex Williamson <alex.williamson@redhat.com>
Link: https://lore.kernel.org/r/20220418005000.897664-11-baolu.lu@linux.intel.com


Signed-off-by: default avatarJoerg Roedel <jroedel@suse.de>
parent 93219ea9
Loading
Loading
Loading
Loading
+0 −147
Original line number Diff line number Diff line
@@ -71,7 +71,6 @@ struct vfio_group {
	struct vfio_container		*container;
	struct list_head		device_list;
	struct mutex			device_lock;
	struct notifier_block		nb;
	struct list_head		vfio_next;
	struct list_head		container_next;
	atomic_t			opened;
@@ -274,8 +273,6 @@ void vfio_unregister_iommu_driver(const struct vfio_iommu_driver_ops *ops)
}
EXPORT_SYMBOL_GPL(vfio_unregister_iommu_driver);

static int vfio_iommu_group_notifier(struct notifier_block *nb,
				     unsigned long action, void *data);
static void vfio_group_get(struct vfio_group *group);

/*
@@ -395,13 +392,6 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group,
		goto err_put;
	}

	group->nb.notifier_call = vfio_iommu_group_notifier;
	err = iommu_group_register_notifier(iommu_group, &group->nb);
	if (err) {
		ret = ERR_PTR(err);
		goto err_put;
	}

	mutex_lock(&vfio.group_lock);

	/* Did we race creating this group? */
@@ -422,7 +412,6 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group,

err_unlock:
	mutex_unlock(&vfio.group_lock);
	iommu_group_unregister_notifier(group->iommu_group, &group->nb);
err_put:
	put_device(&group->dev);
	return ret;
@@ -447,7 +436,6 @@ static void vfio_group_put(struct vfio_group *group)
	cdev_device_del(&group->cdev, &group->dev);
	mutex_unlock(&vfio.group_lock);

	iommu_group_unregister_notifier(group->iommu_group, &group->nb);
	put_device(&group->dev);
}

@@ -503,141 +491,6 @@ static struct vfio_device *vfio_group_get_device(struct vfio_group *group,
	return NULL;
}

/*
 * Some drivers, like pci-stub, are only used to prevent other drivers from
 * claiming a device and are therefore perfectly legitimate for a user owned
 * group.  The pci-stub driver has no dependencies on DMA or the IOVA mapping
 * of the device, but it does prevent the user from having direct access to
 * the device, which is useful in some circumstances.
 *
 * We also assume that we can include PCI interconnect devices, ie. bridges.
 * IOMMU grouping on PCI necessitates that if we lack isolation on a bridge
 * then all of the downstream devices will be part of the same IOMMU group as
 * the bridge.  Thus, if placing the bridge into the user owned IOVA space
 * breaks anything, it only does so for user owned devices downstream.  Note
 * that error notification via MSI can be affected for platforms that handle
 * MSI within the same IOVA space as DMA.
 */
static const char * const vfio_driver_allowed[] = { "pci-stub" };

static bool vfio_dev_driver_allowed(struct device *dev,
				    struct device_driver *drv)
{
	if (dev_is_pci(dev)) {
		struct pci_dev *pdev = to_pci_dev(dev);

		if (pdev->hdr_type != PCI_HEADER_TYPE_NORMAL)
			return true;
	}

	return match_string(vfio_driver_allowed,
			    ARRAY_SIZE(vfio_driver_allowed),
			    drv->name) >= 0;
}

/*
 * A vfio group is viable for use by userspace if all devices are in
 * one of the following states:
 *  - driver-less
 *  - bound to a vfio driver
 *  - bound to an otherwise allowed driver
 *  - a PCI interconnect device
 *
 * We use two methods to determine whether a device is bound to a vfio
 * driver.  The first is to test whether the device exists in the vfio
 * group.  The second is to test if the device exists on the group
 * unbound_list, indicating it's in the middle of transitioning from
 * a vfio driver to driver-less.
 */
static int vfio_dev_viable(struct device *dev, void *data)
{
	struct vfio_group *group = data;
	struct vfio_device *device;
	struct device_driver *drv = READ_ONCE(dev->driver);

	if (!drv || vfio_dev_driver_allowed(dev, drv))
		return 0;

	device = vfio_group_get_device(group, dev);
	if (device) {
		vfio_device_put(device);
		return 0;
	}

	return -EINVAL;
}

/*
 * Async device support
 */
static int vfio_group_nb_add_dev(struct vfio_group *group, struct device *dev)
{
	struct vfio_device *device;

	/* Do we already know about it?  We shouldn't */
	device = vfio_group_get_device(group, dev);
	if (WARN_ON_ONCE(device)) {
		vfio_device_put(device);
		return 0;
	}

	/* Nothing to do for idle groups */
	if (!atomic_read(&group->container_users))
		return 0;

	/* TODO Prevent device auto probing */
	dev_WARN(dev, "Device added to live group %d!\n",
		 iommu_group_id(group->iommu_group));

	return 0;
}

static int vfio_group_nb_verify(struct vfio_group *group, struct device *dev)
{
	/* We don't care what happens when the group isn't in use */
	if (!atomic_read(&group->container_users))
		return 0;

	return vfio_dev_viable(dev, group);
}

static int vfio_iommu_group_notifier(struct notifier_block *nb,
				     unsigned long action, void *data)
{
	struct vfio_group *group = container_of(nb, struct vfio_group, nb);
	struct device *dev = data;

	switch (action) {
	case IOMMU_GROUP_NOTIFY_ADD_DEVICE:
		vfio_group_nb_add_dev(group, dev);
		break;
	case IOMMU_GROUP_NOTIFY_DEL_DEVICE:
		/*
		 * Nothing to do here.  If the device is in use, then the
		 * vfio sub-driver should block the remove callback until
		 * it is unused.  If the device is unused or attached to a
		 * stub driver, then it should be released and we don't
		 * care that it will be going away.
		 */
		break;
	case IOMMU_GROUP_NOTIFY_BIND_DRIVER:
		dev_dbg(dev, "%s: group %d binding to driver\n", __func__,
			iommu_group_id(group->iommu_group));
		break;
	case IOMMU_GROUP_NOTIFY_BOUND_DRIVER:
		dev_dbg(dev, "%s: group %d bound to driver %s\n", __func__,
			iommu_group_id(group->iommu_group), dev->driver->name);
		BUG_ON(vfio_group_nb_verify(group, dev));
		break;
	case IOMMU_GROUP_NOTIFY_UNBIND_DRIVER:
		dev_dbg(dev, "%s: group %d unbinding from driver %s\n",
			__func__, iommu_group_id(group->iommu_group),
			dev->driver->name);
		break;
	}
	return NOTIFY_OK;
}

/*
 * VFIO driver API
 */