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 | 25 +++++++++++++++++++++++++ include/linux/vfio.h | 8 ++++++++ 2 files changed, 33 insertions(+) diff --git a/drivers/vfio/vfio_main.c b/drivers/vfio/vfio_main.c index 1fd261efc582..480cc2398810 100644 --- a/drivers/vfio/vfio_main.c +++ b/drivers/vfio/vfio_main.c @@ -1354,6 +1354,28 @@ static int vfio_device_fops_mmap(struct file *filep, struct vm_area_struct *vma) return device->ops->mmap(device, vma); } +#ifdef CONFIG_ARCH_SUPPORTS_HUGE_PFNMAP +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; + unsigned long ret; + + if (device->ops->get_unmapped_area) { + ret = device->ops->get_unmapped_area(device, file, addr, + len, pgoff, flags); + if (ret) + return ret; + } + + return mm_get_unmapped_area(current->mm, file, addr, len, pgoff, flags); +} +#endif + const struct file_operations vfio_device_fops = { .owner = THIS_MODULE, .open = vfio_device_fops_cdev_open, @@ -1363,6 +1385,9 @@ const struct file_operations vfio_device_fops = { .unlocked_ioctl = vfio_device_fops_unl_ioctl, .compat_ioctl = compat_ptr_ioctl, .mmap = vfio_device_fops_mmap, +#ifdef CONFIG_ARCH_SUPPORTS_HUGE_PFNMAP + .get_unmapped_area = vfio_device_get_unmapped_area, +#endif }; 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..d900541e2716 100644 --- a/include/linux/vfio.h +++ b/include/linux/vfio.h @@ -108,6 +108,8 @@ 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(). + * If zero is returned, fallback to the default allocator. */ struct vfio_device_ops { char *name; @@ -135,6 +137,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