On Fri, Aug 21, 2020 at 05:28:12AM -0400, Jason Wang wrote:
> This patch introduces a new ioctl for vhost-vdpa device that can
> report the iova range by the device.
> 
> For device that implements get_iova_range() method, we fetch it from
> the vDPA device. If device doesn't implement get_iova_range() but
> depends on platform IOMMU, we will query via DOMAIN_ATTR_GEOMETRY,
> otherwise [0, ULLONG_MAX] is assumed.
> 
> For safety, this patch also rules out the map request which is not in
> the valid range.
> 
> Signed-off-by: Jason Wang <[email protected]>
> ---
>  drivers/vhost/vdpa.c             | 41 ++++++++++++++++++++++++++++++++
>  include/uapi/linux/vhost.h       |  4 ++++
>  include/uapi/linux/vhost_types.h |  9 +++++++
>  3 files changed, 54 insertions(+)
> 
> diff --git a/drivers/vhost/vdpa.c b/drivers/vhost/vdpa.c
> index 3fab94f88894..1adb4adb0345 100644
> --- a/drivers/vhost/vdpa.c
> +++ b/drivers/vhost/vdpa.c
> @@ -48,6 +48,7 @@ struct vhost_vdpa {
>       int minor;
>       struct eventfd_ctx *config_ctx;
>       int in_batch;
> +     struct vdpa_iova_range range;
>  };
>  
>  static DEFINE_IDA(vhost_vdpa_ida);
> @@ -344,6 +345,16 @@ static long vhost_vdpa_set_config_call(struct vhost_vdpa 
> *v, u32 __user *argp)
>       return 0;
>  }
>  
> +static long vhost_vdpa_get_iova_range(struct vhost_vdpa *v, u32 __user *argp)
> +{
> +     struct vhost_vdpa_iova_range range = {
> +             .first = v->range.first,
> +             .last = v->range.last,
> +     };
> +
> +     return copy_to_user(argp, &range, sizeof(range));
> +}
> +
>  static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd,
>                                  void __user *argp)
>  {
> @@ -476,6 +487,9 @@ static long vhost_vdpa_unlocked_ioctl(struct file *filep,
>       case VHOST_VDPA_SET_CONFIG_CALL:
>               r = vhost_vdpa_set_config_call(v, argp);
>               break;
> +     case VHOST_VDPA_GET_IOVA_RANGE:
> +             r = vhost_vdpa_get_iova_range(v, argp);
> +             break;
>       default:
>               r = vhost_dev_ioctl(&v->vdev, cmd, argp);
>               if (r == -ENOIOCTLCMD)
> @@ -597,6 +611,10 @@ static int vhost_vdpa_process_iotlb_update(struct 
> vhost_vdpa *v,
>       u64 iova = msg->iova;
>       int ret = 0;
>  
> +     if (msg->iova < v->range.first ||
> +         msg->iova + msg->size - 1 > v->range.last)
> +             return -EINVAL;
> +
>       if (vhost_iotlb_itree_first(iotlb, msg->iova,
>                                   msg->iova + msg->size - 1))
>               return -EEXIST;
> @@ -762,6 +780,27 @@ static void vhost_vdpa_free_domain(struct vhost_vdpa *v)
>       v->domain = NULL;
>  }
>  
> +static void vhost_vdpa_set_iova_range(struct vhost_vdpa *v)
> +{
> +     struct vdpa_iova_range *range = &v->range;
> +     struct iommu_domain_geometry geo;
> +     struct vdpa_device *vdpa = v->vdpa;
> +     const struct vdpa_config_ops *ops = vdpa->config;
> +
> +     if (ops->get_iova_range) {
> +             *range = ops->get_iova_range(vdpa);
> +     } else if (v->domain &&
> +                !iommu_domain_get_attr(v->domain,
> +                DOMAIN_ATTR_GEOMETRY, &geo) &&
> +                geo.force_aperture) {
> +             range->first = geo.aperture_start;
> +             range->last = geo.aperture_end;
> +     } else {
> +             range->first = 0;
> +             range->last = ULLONG_MAX;
> +     }

Shouldn't we require drivers that publish VIRTIO_F_ACCESS_PLATFORM to
implement get_iova_range?

> +}
> +
>  static int vhost_vdpa_open(struct inode *inode, struct file *filep)
>  {
>       struct vhost_vdpa *v;
> @@ -802,6 +841,8 @@ static int vhost_vdpa_open(struct inode *inode, struct 
> file *filep)
>       if (r)
>               goto err_init_iotlb;
>  
> +     vhost_vdpa_set_iova_range(v);
> +
>       filep->private_data = v;
>  
>       return 0;
> diff --git a/include/uapi/linux/vhost.h b/include/uapi/linux/vhost.h
> index 75232185324a..c998860d7bbc 100644
> --- a/include/uapi/linux/vhost.h
> +++ b/include/uapi/linux/vhost.h
> @@ -146,4 +146,8 @@
>  
>  /* Set event fd for config interrupt*/
>  #define VHOST_VDPA_SET_CONFIG_CALL   _IOW(VHOST_VIRTIO, 0x77, int)
> +
> +/* Get the valid iova range */
> +#define VHOST_VDPA_GET_IOVA_RANGE    _IOR(VHOST_VIRTIO, 0x78, \
> +                                          struct vhost_vdpa_iova_range)
>  #endif
> diff --git a/include/uapi/linux/vhost_types.h 
> b/include/uapi/linux/vhost_types.h
> index 9a269a88a6ff..f7f6a3a28977 100644
> --- a/include/uapi/linux/vhost_types.h
> +++ b/include/uapi/linux/vhost_types.h
> @@ -138,6 +138,15 @@ struct vhost_vdpa_config {
>       __u8 buf[0];
>  };
>  
> +/* vhost vdpa IOVA range
> + * @first: First address that can be mapped by vhost-vDPA
> + * @last: Last address that can be mapped by vhost-vDPA
> + */
> +struct vhost_vdpa_iova_range {
> +     __u64 first;
> +     __u64 last;
> +};
> +
>  /* Feature bits */
>  /* Log all write descriptors. Can be changed while device is active. */
>  #define VHOST_F_LOG_ALL 26
> -- 
> 2.18.1
> 

Reply via email to