Re: [PATCH V3 vfio 2/2] vfio: Split migration ops from main device ops

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, 28 Jun 2022 18:59:10 +0300
Yishai Hadas <yishaih@xxxxxxxxxx> wrote:

> vfio core checks whether the driver sets some migration op (e.g.
> set_state/get_state) and accordingly calls its op.
> 
> However, currently mlx5 driver sets the above ops without regards to its
> migration caps.
> 
> This might lead to unexpected usage/Oops if user space may call to the
> above ops even if the driver doesn't support migration. As for example,
> the migration state_mutex is not initialized in that case.
> 
> The cleanest way to manage that seems to split the migration ops from
> the main device ops, this will let the driver setting them separately
> from the main ops when it's applicable.
> 
> As part of that, validate ops construction on registration and include a
> check for VFIO_MIGRATION_STOP_COPY since the uAPI claims it must be set
> in migration_flags.
> 
> HISI driver was changed as well to match this scheme.
> 
> This scheme may enable down the road to come with some extra group of
> ops (e.g. DMA log) that can be set without regards to the other options
> based on driver caps.
> 
> Fixes: 6fadb021266d ("vfio/mlx5: Implement vfio_pci driver for mlx5 devices")
> Reviewed-by: Kevin Tian <kevin.tian@xxxxxxxxx>
> Signed-off-by: Yishai Hadas <yishaih@xxxxxxxxxx>
> ---
>  .../vfio/pci/hisilicon/hisi_acc_vfio_pci.c    | 11 +++++--
>  drivers/vfio/pci/mlx5/cmd.c                   |  4 ++-
>  drivers/vfio/pci/mlx5/cmd.h                   |  3 +-
>  drivers/vfio/pci/mlx5/main.c                  |  9 ++++--
>  drivers/vfio/pci/vfio_pci_core.c              |  7 +++++
>  drivers/vfio/vfio.c                           | 11 ++++---
>  include/linux/vfio.h                          | 30 ++++++++++++-------
>  7 files changed, 51 insertions(+), 24 deletions(-)
> 
> diff --git a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
> index 4def43f5f7b6..ea762e28c1cc 100644
> --- a/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
> +++ b/drivers/vfio/pci/hisilicon/hisi_acc_vfio_pci.c
> @@ -1185,7 +1185,7 @@ static int hisi_acc_vfio_pci_open_device(struct vfio_device *core_vdev)
>  	if (ret)
>  		return ret;
>  
> -	if (core_vdev->ops->migration_set_state) {
> +	if (core_vdev->mig_ops) {
>  		ret = hisi_acc_vf_qm_init(hisi_acc_vdev);
>  		if (ret) {
>  			vfio_pci_core_disable(vdev);
> @@ -1208,6 +1208,11 @@ static void hisi_acc_vfio_pci_close_device(struct vfio_device *core_vdev)
>  	vfio_pci_core_close_device(core_vdev);
>  }
>  
> +static const struct vfio_migration_ops hisi_acc_vfio_pci_migrn_state_ops = {
> +	.migration_set_state = hisi_acc_vfio_pci_set_device_state,
> +	.migration_get_state = hisi_acc_vfio_pci_get_device_state,
> +};
> +
>  static const struct vfio_device_ops hisi_acc_vfio_pci_migrn_ops = {
>  	.name = "hisi-acc-vfio-pci-migration",
>  	.open_device = hisi_acc_vfio_pci_open_device,
> @@ -1219,8 +1224,6 @@ static const struct vfio_device_ops hisi_acc_vfio_pci_migrn_ops = {
>  	.mmap = hisi_acc_vfio_pci_mmap,
>  	.request = vfio_pci_core_request,
>  	.match = vfio_pci_core_match,
> -	.migration_set_state = hisi_acc_vfio_pci_set_device_state,
> -	.migration_get_state = hisi_acc_vfio_pci_get_device_state,
>  };
>  
>  static const struct vfio_device_ops hisi_acc_vfio_pci_ops = {
> @@ -1272,6 +1275,8 @@ static int hisi_acc_vfio_pci_probe(struct pci_dev *pdev, const struct pci_device
>  		if (!ret) {
>  			vfio_pci_core_init_device(&hisi_acc_vdev->core_device, pdev,
>  						  &hisi_acc_vfio_pci_migrn_ops);
> +			hisi_acc_vdev->core_device.vdev.mig_ops =
> +					&hisi_acc_vfio_pci_migrn_state_ops;
>  		} else {
>  			pci_warn(pdev, "migration support failed, continue with generic interface\n");
>  			vfio_pci_core_init_device(&hisi_acc_vdev->core_device, pdev,
> diff --git a/drivers/vfio/pci/mlx5/cmd.c b/drivers/vfio/pci/mlx5/cmd.c
> index cdd0c667dc77..dd5d7bfe0a49 100644
> --- a/drivers/vfio/pci/mlx5/cmd.c
> +++ b/drivers/vfio/pci/mlx5/cmd.c
> @@ -108,7 +108,8 @@ void mlx5vf_cmd_remove_migratable(struct mlx5vf_pci_core_device *mvdev)
>  	destroy_workqueue(mvdev->cb_wq);
>  }
>  
> -void mlx5vf_cmd_set_migratable(struct mlx5vf_pci_core_device *mvdev)
> +void mlx5vf_cmd_set_migratable(struct mlx5vf_pci_core_device *mvdev,
> +			       const struct vfio_migration_ops *mig_ops)
>  {
>  	struct pci_dev *pdev = mvdev->core_device.pdev;
>  	int ret;
> @@ -149,6 +150,7 @@ void mlx5vf_cmd_set_migratable(struct mlx5vf_pci_core_device *mvdev)
>  	mvdev->core_device.vdev.migration_flags =
>  		VFIO_MIGRATION_STOP_COPY |
>  		VFIO_MIGRATION_P2P;
> +	mvdev->core_device.vdev.mig_ops = mig_ops;
>  
>  end:
>  	mlx5_vf_put_core_dev(mvdev->mdev);
> diff --git a/drivers/vfio/pci/mlx5/cmd.h b/drivers/vfio/pci/mlx5/cmd.h
> index aa692d9ce656..8208f4701a90 100644
> --- a/drivers/vfio/pci/mlx5/cmd.h
> +++ b/drivers/vfio/pci/mlx5/cmd.h
> @@ -62,7 +62,8 @@ int mlx5vf_cmd_suspend_vhca(struct mlx5vf_pci_core_device *mvdev, u16 op_mod);
>  int mlx5vf_cmd_resume_vhca(struct mlx5vf_pci_core_device *mvdev, u16 op_mod);
>  int mlx5vf_cmd_query_vhca_migration_state(struct mlx5vf_pci_core_device *mvdev,
>  					  size_t *state_size);
> -void mlx5vf_cmd_set_migratable(struct mlx5vf_pci_core_device *mvdev);
> +void mlx5vf_cmd_set_migratable(struct mlx5vf_pci_core_device *mvdev,
> +			       const struct vfio_migration_ops *mig_ops);
>  void mlx5vf_cmd_remove_migratable(struct mlx5vf_pci_core_device *mvdev);
>  void mlx5vf_cmd_close_migratable(struct mlx5vf_pci_core_device *mvdev);
>  int mlx5vf_cmd_save_vhca_state(struct mlx5vf_pci_core_device *mvdev,
> diff --git a/drivers/vfio/pci/mlx5/main.c b/drivers/vfio/pci/mlx5/main.c
> index d754990f0662..a9b63d15c5d3 100644
> --- a/drivers/vfio/pci/mlx5/main.c
> +++ b/drivers/vfio/pci/mlx5/main.c
> @@ -574,6 +574,11 @@ static void mlx5vf_pci_close_device(struct vfio_device *core_vdev)
>  	vfio_pci_core_close_device(core_vdev);
>  }
>  
> +static const struct vfio_migration_ops mlx5vf_pci_mig_ops = {
> +	.migration_set_state = mlx5vf_pci_set_device_state,
> +	.migration_get_state = mlx5vf_pci_get_device_state,
> +};
> +
>  static const struct vfio_device_ops mlx5vf_pci_ops = {
>  	.name = "mlx5-vfio-pci",
>  	.open_device = mlx5vf_pci_open_device,
> @@ -585,8 +590,6 @@ static const struct vfio_device_ops mlx5vf_pci_ops = {
>  	.mmap = vfio_pci_core_mmap,
>  	.request = vfio_pci_core_request,
>  	.match = vfio_pci_core_match,
> -	.migration_set_state = mlx5vf_pci_set_device_state,
> -	.migration_get_state = mlx5vf_pci_get_device_state,
>  };
>  
>  static int mlx5vf_pci_probe(struct pci_dev *pdev,
> @@ -599,7 +602,7 @@ static int mlx5vf_pci_probe(struct pci_dev *pdev,
>  	if (!mvdev)
>  		return -ENOMEM;
>  	vfio_pci_core_init_device(&mvdev->core_device, pdev, &mlx5vf_pci_ops);
> -	mlx5vf_cmd_set_migratable(mvdev);
> +	mlx5vf_cmd_set_migratable(mvdev, &mlx5vf_pci_mig_ops);
>  	dev_set_drvdata(&pdev->dev, &mvdev->core_device);
>  	ret = vfio_pci_core_register_device(&mvdev->core_device);
>  	if (ret)
> diff --git a/drivers/vfio/pci/vfio_pci_core.c b/drivers/vfio/pci/vfio_pci_core.c
> index a0d69ddaf90d..cf875309dac0 100644
> --- a/drivers/vfio/pci/vfio_pci_core.c
> +++ b/drivers/vfio/pci/vfio_pci_core.c
> @@ -1855,6 +1855,13 @@ int vfio_pci_core_register_device(struct vfio_pci_core_device *vdev)
>  	if (pdev->hdr_type != PCI_HEADER_TYPE_NORMAL)
>  		return -EINVAL;
>  
> +	if (vdev->vdev.mig_ops) {
> +		if ((!(vdev->vdev.mig_ops->migration_get_state &&
> +		       vdev->vdev.mig_ops->migration_set_state)) ||
> +		    (!(vdev->vdev.migration_flags & VFIO_MIGRATION_STOP_COPY)))
> +			return -EINVAL;

A bit excessive on the parenthesis, a logical NOT is just below parens
and well above a logical OR on order of operations, so it should be
fine as:

	if (!(vdev->vdev.mig_ops->migration_get_state &&
	      vdev->vdev.mig_ops->migration_set_state) ||
	    !(vdev->vdev.migration_flags & VFIO_MIGRATION_STOP_COPY))
		return -EINVAL;

Looks ok to me otherwise, so if there are no other changes maybe I can
roll that in on commit.  Thanks,

Alex

> +	}
> +
>  	/*
>  	 * Prevent binding to PFs with VFs enabled, the VFs might be in use
>  	 * by the host or other users.  We cannot capture the VFs if they
> diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c
> index e22be13e6771..ccbd106b95d8 100644
> --- a/drivers/vfio/vfio.c
> +++ b/drivers/vfio/vfio.c
> @@ -1534,8 +1534,7 @@ vfio_ioctl_device_feature_mig_device_state(struct vfio_device *device,
>  	struct file *filp = NULL;
>  	int ret;
>  
> -	if (!device->ops->migration_set_state ||
> -	    !device->ops->migration_get_state)
> +	if (!device->mig_ops)
>  		return -ENOTTY;
>  
>  	ret = vfio_check_feature(flags, argsz,
> @@ -1551,7 +1550,8 @@ vfio_ioctl_device_feature_mig_device_state(struct vfio_device *device,
>  	if (flags & VFIO_DEVICE_FEATURE_GET) {
>  		enum vfio_device_mig_state curr_state;
>  
> -		ret = device->ops->migration_get_state(device, &curr_state);
> +		ret = device->mig_ops->migration_get_state(device,
> +							   &curr_state);
>  		if (ret)
>  			return ret;
>  		mig.device_state = curr_state;
> @@ -1559,7 +1559,7 @@ vfio_ioctl_device_feature_mig_device_state(struct vfio_device *device,
>  	}
>  
>  	/* Handle the VFIO_DEVICE_FEATURE_SET */
> -	filp = device->ops->migration_set_state(device, mig.device_state);
> +	filp = device->mig_ops->migration_set_state(device, mig.device_state);
>  	if (IS_ERR(filp) || !filp)
>  		goto out_copy;
>  
> @@ -1582,8 +1582,7 @@ static int vfio_ioctl_device_feature_migration(struct vfio_device *device,
>  	};
>  	int ret;
>  
> -	if (!device->ops->migration_set_state ||
> -	    !device->ops->migration_get_state)
> +	if (!device->mig_ops)
>  		return -ENOTTY;
>  
>  	ret = vfio_check_feature(flags, argsz, VFIO_DEVICE_FEATURE_GET,
> diff --git a/include/linux/vfio.h b/include/linux/vfio.h
> index aa888cc51757..d6c592565be7 100644
> --- a/include/linux/vfio.h
> +++ b/include/linux/vfio.h
> @@ -32,6 +32,11 @@ struct vfio_device_set {
>  struct vfio_device {
>  	struct device *dev;
>  	const struct vfio_device_ops *ops;
> +	/*
> +	 * mig_ops is a static property of the vfio_device which must be set
> +	 * prior to registering the vfio_device.
> +	 */
> +	const struct vfio_migration_ops *mig_ops;
>  	struct vfio_group *group;
>  	struct vfio_device_set *dev_set;
>  	struct list_head dev_set_list;
> @@ -61,16 +66,6 @@ struct vfio_device {
>   *         match, -errno for abort (ex. match with insufficient or incorrect
>   *         additional args)
>   * @device_feature: Optional, fill in the VFIO_DEVICE_FEATURE ioctl
> - * @migration_set_state: Optional callback to change the migration state for
> - *         devices that support migration. It's mandatory for
> - *         VFIO_DEVICE_FEATURE_MIGRATION migration support.
> - *         The returned FD is used for data transfer according to the FSM
> - *         definition. The driver is responsible to ensure that FD reaches end
> - *         of stream or error whenever the migration FSM leaves a data transfer
> - *         state or before close_device() returns.
> - * @migration_get_state: Optional callback to get the migration state for
> - *         devices that support migration. It's mandatory for
> - *         VFIO_DEVICE_FEATURE_MIGRATION migration support.
>   */
>  struct vfio_device_ops {
>  	char	*name;
> @@ -87,6 +82,21 @@ struct vfio_device_ops {
>  	int	(*match)(struct vfio_device *vdev, char *buf);
>  	int	(*device_feature)(struct vfio_device *device, u32 flags,
>  				  void __user *arg, size_t argsz);
> +};
> +
> +/**
> + * @migration_set_state: Optional callback to change the migration state for
> + *         devices that support migration. It's mandatory for
> + *         VFIO_DEVICE_FEATURE_MIGRATION migration support.
> + *         The returned FD is used for data transfer according to the FSM
> + *         definition. The driver is responsible to ensure that FD reaches end
> + *         of stream or error whenever the migration FSM leaves a data transfer
> + *         state or before close_device() returns.
> + * @migration_get_state: Optional callback to get the migration state for
> + *         devices that support migration. It's mandatory for
> + *         VFIO_DEVICE_FEATURE_MIGRATION migration support.
> + */
> +struct vfio_migration_ops {
>  	struct file *(*migration_set_state)(
>  		struct vfio_device *device,
>  		enum vfio_device_mig_state new_state);




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux