Re: [PATCH v8 6/6] Add common functions for SET_IRQS and GET_REGION_INFO ioctls

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

 



On Tue, 11 Oct 2016 01:58:37 +0530
Kirti Wankhede <kwankhede@xxxxxxxxxx> wrote:

> Add common functions for SET_IRQS and to add capability buffer for
> GET_REGION_INFO ioctls

Clearly should be two (or more) separate patches since SET_IRQS and
REGION_INFO are unrelated changes.  Each of the two capabilities handled
could possibly be separate patches as well.

 
> Signed-off-by: Kirti Wankhede <kwankhede@xxxxxxxxxx>
> Signed-off-by: Neo Jia <cjia@xxxxxxxxxx>
> Change-Id: Id9e976a2c08b9b2b37da77dac4365ae8f6024b4a
> ---
>  drivers/vfio/pci/vfio_pci.c | 103 +++++++++++++++------------------------
>  drivers/vfio/vfio.c         | 116 ++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/vfio.h        |   7 +++
>  3 files changed, 162 insertions(+), 64 deletions(-)
> 
> diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
> index 188b1ff03f5f..f312cbb0eebc 100644
> --- a/drivers/vfio/pci/vfio_pci.c
> +++ b/drivers/vfio/pci/vfio_pci.c
> @@ -478,12 +478,12 @@ static int vfio_pci_for_each_slot_or_bus(struct pci_dev *pdev,
>  }
>  
>  static int msix_sparse_mmap_cap(struct vfio_pci_device *vdev,
> +				struct vfio_region_info *info,
>  				struct vfio_info_cap *caps)
>  {
> -	struct vfio_info_cap_header *header;
>  	struct vfio_region_info_cap_sparse_mmap *sparse;
>  	size_t end, size;
> -	int nr_areas = 2, i = 0;
> +	int nr_areas = 2, i = 0, ret;
>  
>  	end = pci_resource_len(vdev->pdev, vdev->msix_bar);
>  
> @@ -494,13 +494,10 @@ static int msix_sparse_mmap_cap(struct vfio_pci_device *vdev,
>  
>  	size = sizeof(*sparse) + (nr_areas * sizeof(*sparse->areas));
>  
> -	header = vfio_info_cap_add(caps, size,
> -				   VFIO_REGION_INFO_CAP_SPARSE_MMAP, 1);
> -	if (IS_ERR(header))
> -		return PTR_ERR(header);
> +	sparse = kzalloc(size, GFP_KERNEL);
> +	if (!sparse)
> +		return -ENOMEM;
>  
> -	sparse = container_of(header,
> -			      struct vfio_region_info_cap_sparse_mmap, header);
>  	sparse->nr_areas = nr_areas;
>  
>  	if (vdev->msix_offset & PAGE_MASK) {
> @@ -516,24 +513,14 @@ static int msix_sparse_mmap_cap(struct vfio_pci_device *vdev,
>  		i++;
>  	}
>  
> -	return 0;
> -}
> -
> -static int region_type_cap(struct vfio_pci_device *vdev,
> -			   struct vfio_info_cap *caps,
> -			   unsigned int type, unsigned int subtype)
> -{
> -	struct vfio_info_cap_header *header;
> -	struct vfio_region_info_cap_type *cap;
> +	info->flags |= VFIO_REGION_INFO_FLAG_CAPS;
>  
> -	header = vfio_info_cap_add(caps, sizeof(*cap),
> -				   VFIO_REGION_INFO_CAP_TYPE, 1);
> -	if (IS_ERR(header))
> -		return PTR_ERR(header);
> +	ret = vfio_info_add_capability(info, caps,
> +				      VFIO_REGION_INFO_CAP_SPARSE_MMAP, sparse);
> +	kfree(sparse);
>  
> -	cap = container_of(header, struct vfio_region_info_cap_type, header);
> -	cap->type = type;
> -	cap->subtype = subtype;
> +	if (ret)
> +		return ret;
>  
>  	return 0;

Just: return ret;

>  }
> @@ -628,7 +615,8 @@ static long vfio_pci_ioctl(void *device_data,
>  			    IORESOURCE_MEM && info.size >= PAGE_SIZE) {
>  				info.flags |= VFIO_REGION_INFO_FLAG_MMAP;
>  				if (info.index == vdev->msix_bar) {
> -					ret = msix_sparse_mmap_cap(vdev, &caps);
> +					ret = msix_sparse_mmap_cap(vdev, &info,
> +								   &caps);
>  					if (ret)
>  						return ret;
>  				}
> @@ -676,6 +664,9 @@ static long vfio_pci_ioctl(void *device_data,
>  
>  			break;
>  		default:
> +		{
> +			struct vfio_region_info_cap_type cap_type;
> +
>  			if (info.index >=
>  			    VFIO_PCI_NUM_REGIONS + vdev->num_regions)
>  				return -EINVAL;
> @@ -684,29 +675,26 @@ static long vfio_pci_ioctl(void *device_data,
>  
>  			info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index);
>  			info.size = vdev->region[i].size;
> -			info.flags = vdev->region[i].flags;
> +			info.flags = vdev->region[i].flags |
> +				     VFIO_REGION_INFO_FLAG_CAPS;
>  
> -			ret = region_type_cap(vdev, &caps,
> -					      vdev->region[i].type,
> -					      vdev->region[i].subtype);
> +			cap_type.type = vdev->region[i].type;
> +			cap_type.subtype = vdev->region[i].subtype;
> +
> +			ret = vfio_info_add_capability(&info, &caps,
> +						      VFIO_REGION_INFO_CAP_TYPE,
> +						      &cap_type);
>  			if (ret)
>  				return ret;
> +
> +		}
>  		}
>  
> -		if (caps.size) {
> -			info.flags |= VFIO_REGION_INFO_FLAG_CAPS;
> -			if (info.argsz < sizeof(info) + caps.size) {
> -				info.argsz = sizeof(info) + caps.size;
> -				info.cap_offset = 0;
> -			} else {
> -				vfio_info_cap_shift(&caps, sizeof(info));
> -				if (copy_to_user((void __user *)arg +
> -						  sizeof(info), caps.buf,
> -						  caps.size)) {
> -					kfree(caps.buf);
> -					return -EFAULT;
> -				}
> -				info.cap_offset = sizeof(info);
> +		if (info.cap_offset) {
> +			if (copy_to_user((void __user *)arg + info.cap_offset,
> +					 caps.buf, caps.size)) {
> +				kfree(caps.buf);
> +				return -EFAULT;
>  			}
>  
>  			kfree(caps.buf);
> @@ -754,35 +742,22 @@ static long vfio_pci_ioctl(void *device_data,
>  	} else if (cmd == VFIO_DEVICE_SET_IRQS) {
>  		struct vfio_irq_set hdr;
>  		u8 *data = NULL;
> -		int ret = 0;
> +		int max, ret = 0, data_size = 0;
>  
>  		minsz = offsetofend(struct vfio_irq_set, count);
>  
>  		if (copy_from_user(&hdr, (void __user *)arg, minsz))
>  			return -EFAULT;
>  
> -		if (hdr.argsz < minsz || hdr.index >= VFIO_PCI_NUM_IRQS ||
> -		    hdr.flags & ~(VFIO_IRQ_SET_DATA_TYPE_MASK |
> -				  VFIO_IRQ_SET_ACTION_TYPE_MASK))
> -			return -EINVAL;
> -
> -		if (!(hdr.flags & VFIO_IRQ_SET_DATA_NONE)) {
> -			size_t size;
> -			int max = vfio_pci_get_irq_count(vdev, hdr.index);
> +		max = vfio_pci_get_irq_count(vdev, hdr.index);
>  
> -			if (hdr.flags & VFIO_IRQ_SET_DATA_BOOL)
> -				size = sizeof(uint8_t);
> -			else if (hdr.flags & VFIO_IRQ_SET_DATA_EVENTFD)
> -				size = sizeof(int32_t);
> -			else
> -				return -EINVAL;
> -
> -			if (hdr.argsz - minsz < hdr.count * size ||
> -			    hdr.start >= max || hdr.start + hdr.count > max)
> -				return -EINVAL;


vfio_platform has very similar code that would also need to be updated.

> +		ret = vfio_set_irqs_validate_and_prepare(&hdr, max, &data_size);
> +		if (ret)
> +			return ret;
>  
> +		if (data_size) {
>  			data = memdup_user((void __user *)(arg + minsz),
> -					   hdr.count * size);
> +					    data_size);
>  			if (IS_ERR(data))
>  				return PTR_ERR(data);
>  		}
> @@ -790,7 +765,7 @@ static long vfio_pci_ioctl(void *device_data,
>  		mutex_lock(&vdev->igate);
>  
>  		ret = vfio_pci_set_irqs_ioctl(vdev, hdr.flags, hdr.index,
> -					      hdr.start, hdr.count, data);
> +				hdr.start, hdr.count, data);

White space bogosity.

>  
>  		mutex_unlock(&vdev->igate);
>  		kfree(data);
> diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c
> index e3e342861e04..0185d5fb2c85 100644
> --- a/drivers/vfio/vfio.c
> +++ b/drivers/vfio/vfio.c
> @@ -1782,6 +1782,122 @@ void vfio_info_cap_shift(struct vfio_info_cap *caps, size_t offset)
>  }
>  EXPORT_SYMBOL_GPL(vfio_info_cap_shift);
>  
> +static int sparse_mmap_cap(struct vfio_info_cap *caps, void *cap_type)
> +{
> +	struct vfio_info_cap_header *header;
> +	struct vfio_region_info_cap_sparse_mmap *sparse_cap, *sparse = cap_type;
> +	size_t size;
> +
> +	size = sizeof(*sparse) + sparse->nr_areas *  sizeof(*sparse->areas);
> +	header = vfio_info_cap_add(caps, size,
> +				   VFIO_REGION_INFO_CAP_SPARSE_MMAP, 1);
> +	if (IS_ERR(header))
> +		return PTR_ERR(header);
> +
> +	sparse_cap = container_of(header,
> +			struct vfio_region_info_cap_sparse_mmap, header);
> +	sparse_cap->nr_areas = sparse->nr_areas;
> +	memcpy(sparse_cap->areas, sparse->areas,
> +	       sparse->nr_areas * sizeof(*sparse->areas));
> +	return 0;
> +}
> +
> +static int region_type_cap(struct vfio_info_cap *caps, void *cap_type)
> +{
> +	struct vfio_info_cap_header *header;
> +	struct vfio_region_info_cap_type *type_cap, *cap = cap_type;
> +
> +	header = vfio_info_cap_add(caps, sizeof(*cap),
> +				   VFIO_REGION_INFO_CAP_TYPE, 1);
> +	if (IS_ERR(header))
> +		return PTR_ERR(header);
> +
> +	type_cap = container_of(header, struct vfio_region_info_cap_type,
> +				header);
> +	type_cap->type = cap->type;
> +	type_cap->subtype = cap->subtype;
> +	return 0;
> +}

Why can't we just do a memcpy of all the data past the header?  Do we
need separate functions for these?

vfio_info_cap_add() should now be static and unexported, right?

> +
> +int vfio_info_add_capability(struct vfio_region_info *info,
> +			     struct vfio_info_cap *caps,
> +			     int cap_type_id,
> +			     void *cap_type)
> +{
> +	int ret;
> +
> +	if (!(info->flags & VFIO_REGION_INFO_FLAG_CAPS) || !cap_type)

Why make the caller set flags, seems rather arbitrary since this
function controls the cap_offset and whether we actually end up copying
the data.

> +		return 0;
> +
> +	switch (cap_type_id) {
> +	case VFIO_REGION_INFO_CAP_SPARSE_MMAP:
> +		ret = sparse_mmap_cap(caps, cap_type);
> +		if (ret)
> +			return ret;
> +		break;
> +
> +	case VFIO_REGION_INFO_CAP_TYPE:
> +		ret = region_type_cap(caps, cap_type);
> +		if (ret)
> +			return ret;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	if (caps->size) {
> +		if (info->argsz < sizeof(*info) + caps->size) {
> +			info->argsz = sizeof(*info) + caps->size;
> +			info->cap_offset = 0;
> +		} else {
> +			vfio_info_cap_shift(caps, sizeof(*info));
> +			info->cap_offset = sizeof(*info);
> +		}
> +	}
> +	return 0;
> +}
> +EXPORT_SYMBOL(vfio_info_add_capability);
> +
> +int vfio_set_irqs_validate_and_prepare(struct vfio_irq_set *hdr, int num_irqs,
> +				       int *data_size)
> +{
> +	unsigned long minsz;
> +
> +	minsz = offsetofend(struct vfio_irq_set, count);
> +
> +	if ((hdr->argsz < minsz) || (hdr->index >= VFIO_PCI_NUM_IRQS) ||
> +	    (hdr->flags & ~(VFIO_IRQ_SET_DATA_TYPE_MASK |
> +				VFIO_IRQ_SET_ACTION_TYPE_MASK)))
> +		return -EINVAL;
> +
> +	if (data_size)
> +		*data_size = 0;
> +
> +	if (!(hdr->flags & VFIO_IRQ_SET_DATA_NONE)) {
> +		size_t size;
> +
> +		if (hdr->flags & VFIO_IRQ_SET_DATA_BOOL)
> +			size = sizeof(uint8_t);
> +		else if (hdr->flags & VFIO_IRQ_SET_DATA_EVENTFD)
> +			size = sizeof(int32_t);
> +		else
> +			return -EINVAL;
> +
> +		if ((hdr->argsz - minsz < hdr->count * size) ||
> +		    (hdr->start >= num_irqs) ||
> +		    (hdr->start + hdr->count > num_irqs))
> +			return -EINVAL;
> +
> +		if (!data_size)
> +			return -EINVAL;
> +
> +		*data_size = hdr->count * size;
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL(vfio_set_irqs_validate_and_prepare);
> +
>  static struct vfio_group *vfio_group_from_dev(struct device *dev)
>  {
>  	struct vfio_device *device;
> diff --git a/include/linux/vfio.h b/include/linux/vfio.h
> index 0bd25ba6223d..5641dab72ded 100644
> --- a/include/linux/vfio.h
> +++ b/include/linux/vfio.h
> @@ -108,6 +108,13 @@ extern struct vfio_info_cap_header *vfio_info_cap_add(
>  		struct vfio_info_cap *caps, size_t size, u16 id, u16 version);
>  extern void vfio_info_cap_shift(struct vfio_info_cap *caps, size_t offset);
>  
> +extern int vfio_info_add_capability(struct vfio_region_info *info,
> +				    struct vfio_info_cap *caps,
> +				    int cap_type_id, void *cap_type);
> +
> +extern int vfio_set_irqs_validate_and_prepare(struct vfio_irq_set *hdr,
> +					      int num_irqs, int *data_size);
> +
>  struct pci_dev;
>  #ifdef CONFIG_EEH
>  extern void vfio_spapr_pci_eeh_open(struct pci_dev *pdev);

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[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