Re: [PATCH V2 2/3] vhost: vdpa: report iova range

From: Eli Cohen
Date: Sun Aug 23 2020 - 02:44:04 EST


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 <jasowang@xxxxxxxxxx>
> ---
> 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
>