Add a hook to vfio_device_ops to allow sub-modules provide virtual addresses for an mmap() request. Note that the fallback will be mm_get_unmapped_area(), which should maintain the old behavior of generic VA allocation (__get_unmapped_area). It's a bit unfortunate that is needed, as the current get_unmapped_area() file ops cannot support a retval which fallbacks to the default. So that is needed both here and whenever sub-module will opt-in with its own. Signed-off-by: Peter Xu <peterx@xxxxxxxxxx> --- drivers/vfio/vfio_main.c | 18 ++++++++++++++++++ include/linux/vfio.h | 7 +++++++ 2 files changed, 25 insertions(+) diff --git a/drivers/vfio/vfio_main.c b/drivers/vfio/vfio_main.c index 1fd261efc582..19db8e58d223 100644 --- a/drivers/vfio/vfio_main.c +++ b/drivers/vfio/vfio_main.c @@ -1354,6 +1354,23 @@ static int vfio_device_fops_mmap(struct file *filep, struct vm_area_struct *vma) return device->ops->mmap(device, vma); } +static unsigned long vfio_device_get_unmapped_area(struct file *file, + unsigned long addr, + unsigned long len, + unsigned long pgoff, + unsigned long flags) +{ + struct vfio_device_file *df = file->private_data; + struct vfio_device *device = df->device; + + if (!device->ops->get_unmapped_area) + return mm_get_unmapped_area(current->mm, file, addr, + len, pgoff, flags); + + return device->ops->get_unmapped_area(device, file, addr, len, + pgoff, flags); +} + const struct file_operations vfio_device_fops = { .owner = THIS_MODULE, .open = vfio_device_fops_cdev_open, @@ -1363,6 +1380,7 @@ const struct file_operations vfio_device_fops = { .unlocked_ioctl = vfio_device_fops_unl_ioctl, .compat_ioctl = compat_ptr_ioctl, .mmap = vfio_device_fops_mmap, + .get_unmapped_area = vfio_device_get_unmapped_area, }; static struct vfio_device *vfio_device_from_file(struct file *file) diff --git a/include/linux/vfio.h b/include/linux/vfio.h index 707b00772ce1..48fe71c61ed2 100644 --- a/include/linux/vfio.h +++ b/include/linux/vfio.h @@ -108,6 +108,7 @@ struct vfio_device { * @dma_unmap: Called when userspace unmaps IOVA from the container * this device is attached to. * @device_feature: Optional, fill in the VFIO_DEVICE_FEATURE ioctl + * @get_unmapped_area: Optional, provide virtual address hint for mmap() */ struct vfio_device_ops { char *name; @@ -135,6 +136,12 @@ struct vfio_device_ops { void (*dma_unmap)(struct vfio_device *vdev, u64 iova, u64 length); int (*device_feature)(struct vfio_device *device, u32 flags, void __user *arg, size_t argsz); + unsigned long (*get_unmapped_area)(struct vfio_device *device, + struct file *file, + unsigned long addr, + unsigned long len, + unsigned long pgoff, + unsigned long flags); }; #if IS_ENABLED(CONFIG_IOMMUFD) -- 2.49.0