Re: [PATCH v5 09/10] vfio/pci: Extend VFIO_DEVICE_GET_PCI_HOT_RESET_INFO for vfio device cdev

Cédric Le Goater
2023-05-15T07:30:57Z

On 5/13/23 15:21, Yi Liu wrote:
> This makes VFIO_DEVICE_GET_PCI_HOT_RESET_INFO ioctl to use the iommufd_ctx
> of the cdev device to check the ownership of the other affected devices.
>
> This returns devid for each of the affected devices. If it is bound to the
> iommufd_ctx of the cdev device, _INFO reports a valid devid > 0; If it is
> not opened by the calling user, but it belongs to the same iommu_group of
> a device that is bound to the iommufd_ctx of the cdev device, reports devid
> value of 0; If the device is un-owned device, configured within a different
> iommufd, or opened outside of the vfio device cdev API, the _INFO ioctl shall
> report devid value of -1.
>
> devid >=0 doesn't block hot-reset as the affected devices are considered to
> be owned, while devid == -1 will block the use of VFIO_DEVICE_PCI_HOT_RESET
> outside of proof-of-ownership calling conventions (ie. via legacy group
> accessed devices).
>
> This adds flag VFIO_PCI_HOT_RESET_FLAG_DEV_ID to tell the user devid is
> returned in case of calling user get device fd from other software stack
> and adds flag VFIO_PCI_HOT_RESET_FLAG_DEV_ID_OWNED to tell user if all
> the affected devices are owned, so user can know it without looping all
> the returned devids.
>
> Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
> Suggested-by: Alex Williamson <alex.williamson@redhat.com>
> Signed-off-by: Yi Liu <yi.l.liu@intel.com>
> ---
> drivers/vfio/pci/vfio_pci_core.c | 52 ++++++++++++++++++++++++++++++--
> include/uapi/linux/vfio.h | 46 +++++++++++++++++++++++++++-
> 2 files changed, 95 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c
> index 4df2def35bdd..57586be770af 100644
> --- a/drivers/vfio/pci/vfio_pci_core.c
> +++ b/drivers/vfio/pci/vfio_pci_core.c
> @@ -27,6 +27,7 @@
> #include <linux/vgaarb.h>
> #include <linux/nospec.h>
> #include <linux/sched/mm.h>
> +#include <linux/iommufd.h>
> #if IS_ENABLED(CONFIG_EEH)
> #include <asm/eeh.h>
> #endif
> @@ -36,6 +37,10 @@
> #define DRIVER_AUTHOR "Alex Williamson <alex.williamson@redhat.com>"
> #define DRIVER_DESC "core driver for VFIO based PCI devices"
>
> +#ifdef CONFIG_IOMMUFD

To import the IOMMUFD namespace, I had to use :

#if IS_ENABLED(CONFIG_IOMMUFD)

Thanks,

C.

> +MODULE_IMPORT_NS(IOMMUFD);
> +#endif
> +
> static bool nointxmask;
> static bool disable_vga;
> static bool disable_idle_d3;
> @@ -776,6 +781,9 @@ struct vfio_pci_fill_info {
> int max;
> int cur;
> struct vfio_pci_dependent_device *devices;
> + struct vfio_device *vdev;
> + bool devid:1;
> + bool dev_owned:1;
> };
>
> static int vfio_pci_fill_devs(struct pci_dev *pdev, void *data)
> @@ -790,7 +798,37 @@ static int vfio_pci_fill_devs(struct pci_dev *pdev, void *data)
> if (!iommu_group)
> return -EPERM; /* Cannot reset non-isolated devices */
>
> - fill->devices[fill->cur].group_id = iommu_group_id(iommu_group);
> + if (fill->devid) {
> + struct iommufd_ctx *iommufd = vfio_iommufd_physical_ictx(fill->vdev);
> + struct vfio_device_set *dev_set = fill->vdev->dev_set;
> + struct vfio_device *vdev;
> +
> + /*
> + * Report devid for the affected devices:
> + * - valid devid > 0 for the devices that are bound with
> + * the iommufd of the calling device.
> + * - devid == 0 for the devices that have not been opened
> + * but have same group with one of the devices bound to
> + * the iommufd of the calling device.
> + * - devid == -1 for others, and clear dev_owned flag.
> + */
> + vdev = vfio_find_device_in_devset(dev_set, &pdev->dev);
> + if (vdev && iommufd == vfio_iommufd_physical_ictx(vdev)) {
> + int ret;
> +
> + ret = vfio_iommufd_physical_devid(vdev);
> + if (WARN_ON(ret < 0))
> + return ret;
> + fill->devices[fill->cur].devid = ret;
> + } else if (vdev && iommufd_ctx_has_group(iommufd, iommu_group)) {
> + fill->devices[fill->cur].devid = VFIO_PCI_DEVID_OWNED;
> + } else {
> + fill->devices[fill->cur].devid = VFIO_PCI_DEVID_NOT_OWNED;
> + fill->dev_owned = false;
> + }
> + } else {
> + fill->devices[fill->cur].group_id = iommu_group_id(iommu_group);
> + }
> fill->devices[fill->cur].segment = pci_domain_nr(pdev->bus);
> fill->devices[fill->cur].bus = pdev->bus->number;
> fill->devices[fill->cur].devfn = pdev->devfn;
> @@ -1229,17 +1267,27 @@ static int vfio_pci_ioctl_get_pci_hot_reset_info(
> return -ENOMEM;
>
> fill.devices = devices;
> + fill.vdev = &vdev->vdev;
>
> + mutex_lock(&vdev->vdev.dev_set->lock);
> + fill.devid = fill.dev_owned = vfio_device_cdev_opened(&vdev->vdev);
> ret = vfio_pci_for_each_slot_or_bus(vdev->pdev, vfio_pci_fill_devs,
> &fill, slot);
> + mutex_unlock(&vdev->vdev.dev_set->lock);
>
> /*
> * If a device was removed between counting and filling, we may come up
> * short of fill.max. If a device was added, we'll have a return of
> * -EAGAIN above.
> */
> - if (!ret)
> + if (!ret) {
> hdr.count = fill.cur;
> + if (fill.devid) {
> + hdr.flags |= VFIO_PCI_HOT_RESET_FLAG_DEV_ID;
> + if (fill.dev_owned)
> + hdr.flags |= VFIO_PCI_HOT_RESET_FLAG_DEV_ID_OWNED;
> + }
> + }
>
> reset_info_exit:
> if (copy_to_user(arg, &hdr, minsz))
> diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
> index 0552e8dcf0cb..01203215251a 100644
> --- a/include/uapi/linux/vfio.h
> +++ b/include/uapi/linux/vfio.h
> @@ -650,11 +650,53 @@ enum {
> * VFIO_DEVICE_GET_PCI_HOT_RESET_INFO - _IOWR(VFIO_TYPE, VFIO_BASE + 12,
> * struct vfio_pci_hot_reset_info)
> *
> + * This command is used to query the affected devices in the hot reset for
> + * a given device.
> + *
> + * This command always reports the segment, bus, and devfn information for
> + * each affected device, and selectively reports the group_id or devid per
> + * the way how the calling device is opened.
> + *
> + * - If the calling device is opened via the traditional group/container
> + * API, group_id is reported. User should check if it has owned all
> + * the affected devices and provides a set of group fds to prove the
> + * ownership in VFIO_DEVICE_PCI_HOT_RESET ioctl.
> + *
> + * - If the calling device is opened as a cdev, devid is reported.
> + * Flag VFIO_PCI_HOT_RESET_FLAG_DEV_ID is set to indicate this
> + * data type. For a given affected device, it is considered owned by
> + * this interface if it meets the following conditions:
> + * 1) Has a valid devid within the iommufd_ctx of the calling device.
> + * Ownership cannot be determined across separate iommufd_ctx and the
> + * cdev calling conventions do not support a proof-of-ownership model
> + * as provided in the legacy group interface. In this case a valid
> + * devid with value greater than zero is provided in the return
> + * structure.
> + * 2) Does not have a valid devid within the iommufd_ctx of the calling
> + * device, but belongs to the same IOMMU group as the calling device
> + * or another opened device that has a valid devid within the
> + * iommufd_ctx of the calling device. This provides implicit ownership
> + * for devices within the same DMA isolation context. In this case
> + * the invalid devid value of zero is provided in the return structure.
> + *
> + * A devid value of -1 is provided in the return structure for devices
> + * where ownership is not available. Such devices prevent the use of
> + * VFIO_DEVICE_PCI_HOT_RESET outside of proof-of-ownership calling
> + * conventions (ie. via legacy group accessed devices).
> + * Flag VFIO_PCI_HOT_RESET_FLAG_DEV_ID_OWNED would be set when all the
> + * affected devices are owned by the user. This flag is available only
> + * when VFIO_PCI_HOT_RESET_FLAG_DEV_ID is set, otherwise reserved.
> + *
> * Return: 0 on success, -errno on failure:
> * -enospc = insufficient buffer, -enodev = unsupported for device.
> */
> struct vfio_pci_dependent_device {
> - __u32 group_id;
> + union {
> + __u32 group_id;
> + __u32 devid;
> +#define VFIO_PCI_DEVID_OWNED 0
> +#define VFIO_PCI_DEVID_NOT_OWNED -1
> + };
> __u16 segment;
> __u8 bus;
> __u8 devfn; /* Use PCI_SLOT/PCI_FUNC */
> @@ -663,6 +705,8 @@ struct vfio_pci_dependent_device {
> struct vfio_pci_hot_reset_info {
> __u32 argsz;
> __u32 flags;
> +#define VFIO_PCI_HOT_RESET_FLAG_DEV_ID (1 << 0)
> +#define VFIO_PCI_HOT_RESET_FLAG_DEV_ID_OWNED (1 << 1)
> __u32 count;
> struct vfio_pci_dependent_device devices[];
> };