diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/vfio/vfio_iommu_type1.c | 18 |
1 files changed, 15 insertions, 3 deletions
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c index e30e29ae4819..45657e2b1ff7 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c | |||
@@ -338,11 +338,12 @@ static int vaddr_get_pfn(struct mm_struct *mm, unsigned long vaddr, | |||
338 | { | 338 | { |
339 | struct page *page[1]; | 339 | struct page *page[1]; |
340 | struct vm_area_struct *vma; | 340 | struct vm_area_struct *vma; |
341 | struct vm_area_struct *vmas[1]; | ||
341 | int ret; | 342 | int ret; |
342 | 343 | ||
343 | if (mm == current->mm) { | 344 | if (mm == current->mm) { |
344 | ret = get_user_pages_fast(vaddr, 1, !!(prot & IOMMU_WRITE), | 345 | ret = get_user_pages_longterm(vaddr, 1, !!(prot & IOMMU_WRITE), |
345 | page); | 346 | page, vmas); |
346 | } else { | 347 | } else { |
347 | unsigned int flags = 0; | 348 | unsigned int flags = 0; |
348 | 349 | ||
@@ -351,7 +352,18 @@ static int vaddr_get_pfn(struct mm_struct *mm, unsigned long vaddr, | |||
351 | 352 | ||
352 | down_read(&mm->mmap_sem); | 353 | down_read(&mm->mmap_sem); |
353 | ret = get_user_pages_remote(NULL, mm, vaddr, 1, flags, page, | 354 | ret = get_user_pages_remote(NULL, mm, vaddr, 1, flags, page, |
354 | NULL, NULL); | 355 | vmas, NULL); |
356 | /* | ||
357 | * The lifetime of a vaddr_get_pfn() page pin is | ||
358 | * userspace-controlled. In the fs-dax case this could | ||
359 | * lead to indefinite stalls in filesystem operations. | ||
360 | * Disallow attempts to pin fs-dax pages via this | ||
361 | * interface. | ||
362 | */ | ||
363 | if (ret > 0 && vma_is_fsdax(vmas[0])) { | ||
364 | ret = -EOPNOTSUPP; | ||
365 | put_page(page[0]); | ||
366 | } | ||
355 | up_read(&mm->mmap_sem); | 367 | up_read(&mm->mmap_sem); |
356 | } | 368 | } |
357 | 369 | ||