vfio-mdev: Wire in a request handler for mdev parent
authorEric Farman <farman@linux.ibm.com>
Thu, 3 Dec 2020 21:35:11 +0000 (22:35 +0100)
committerAlex Williamson <alex.williamson@redhat.com>
Thu, 3 Dec 2020 23:21:07 +0000 (16:21 -0700)
While performing some destructive tests with vfio-ccw, where the
paths to a device are forcible removed and thus the device itself
is unreachable, it is rather easy to end up in an endless loop in
vfio_del_group_dev() due to the lack of a request callback for the
associated device.

In this example, one MDEV (77c) is used by a guest, while another
(77b) is not. The symptom is that the iommu is detached from the
mdev for 77b, but not 77c, until that guest is shutdown:

    [  238.794867] vfio_ccw 0.0.077b: MDEV: Unregistering
    [  238.794996] vfio_mdev 11f2d2bc-4083-431d-a023-eff72715c4f0: Removing from iommu group 2
    [  238.795001] vfio_mdev 11f2d2bc-4083-431d-a023-eff72715c4f0: MDEV: detaching iommu
    [  238.795036] vfio_ccw 0.0.077c: MDEV: Unregistering
    ...silence...

Let's wire in the request call back to the mdev device, so that a
device being physically removed from the host can be (gracefully?)
handled by the parent device at the time the device is removed.

Add a message when registering the device if a driver doesn't
provide this callback, so a clue is given that this same loop
may be encountered in a similar situation, and a message when
this occurs instead of the awkward silence noted above.

Signed-off-by: Eric Farman <farman@linux.ibm.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
drivers/vfio/mdev/mdev_core.c
drivers/vfio/mdev/vfio_mdev.c
include/linux/mdev.h

index b558d4cfd082ad44a6263b52faae9bdc4f84c774..6de97d25a3f87da67c297ea81b8a88f547c7e4e5 100644 (file)
@@ -154,6 +154,10 @@ int mdev_register_device(struct device *dev, const struct mdev_parent_ops *ops)
        if (!dev)
                return -EINVAL;
 
+       /* Not mandatory, but its absence could be a problem */
+       if (!ops->request)
+               dev_info(dev, "Driver cannot be asked to release device\n");
+
        mutex_lock(&parent_list_lock);
 
        /* Check for duplicate */
index 30964a4e0a28a86aafc380f5813b4e8f0dbabb18..b52eea128549ee14d36a7b6246886d86a5d32516 100644 (file)
@@ -98,6 +98,18 @@ static int vfio_mdev_mmap(void *device_data, struct vm_area_struct *vma)
        return parent->ops->mmap(mdev, vma);
 }
 
+static void vfio_mdev_request(void *device_data, unsigned int count)
+{
+       struct mdev_device *mdev = device_data;
+       struct mdev_parent *parent = mdev->parent;
+
+       if (parent->ops->request)
+               parent->ops->request(mdev, count);
+       else if (count == 0)
+               dev_notice(mdev_dev(mdev),
+                          "No mdev vendor driver request callback support, blocked until released by user\n");
+}
+
 static const struct vfio_device_ops vfio_mdev_dev_ops = {
        .name           = "vfio-mdev",
        .open           = vfio_mdev_open,
@@ -106,6 +118,7 @@ static const struct vfio_device_ops vfio_mdev_dev_ops = {
        .read           = vfio_mdev_read,
        .write          = vfio_mdev_write,
        .mmap           = vfio_mdev_mmap,
+       .request        = vfio_mdev_request,
 };
 
 static int vfio_mdev_probe(struct device *dev)
index 0ce30ca78db0466e02cf8d3373d84ff5ab13a5fd..9004375c462eba6cf982d397eb1f365cd61e9ac9 100644 (file)
@@ -72,6 +72,9 @@ struct device *mdev_get_iommu_device(struct device *dev);
  * @mmap:              mmap callback
  *                     @mdev: mediated device structure
  *                     @vma: vma structure
+ * @request:           request callback to release device
+ *                     @mdev: mediated device structure
+ *                     @count: request sequence number
  * Parent device that support mediated device should be registered with mdev
  * module with mdev_parent_ops structure.
  **/
@@ -92,6 +95,7 @@ struct mdev_parent_ops {
        long    (*ioctl)(struct mdev_device *mdev, unsigned int cmd,
                         unsigned long arg);
        int     (*mmap)(struct mdev_device *mdev, struct vm_area_struct *vma);
+       void    (*request)(struct mdev_device *mdev, unsigned int count);
 };
 
 /* interface for exporting mdev supported type attributes */