vfio: Use get_user_pages_longterm correctly

The patch noted in the fixes below converted get_user_pages_fast() to
get_user_pages_longterm(), however the two calls differ in a few ways.

First _fast() is documented to not require the mmap_sem, while _longterm()
is documented to need it. Hold the mmap sem as required.

Second, _fast accepts an 'int write' while _longterm uses 'unsigned int
gup_flags', so the expression '!!(prot & IOMMU_WRITE)' is only working by
luck as FOLL_WRITE is currently == 0x1. Use the expected FOLL_WRITE
constant instead.

Fixes: 94db151dc8 ("vfio: disable filesystem-dax page pinning")
Cc: <stable@vger.kernel.org>
Signed-off-by: Jason Gunthorpe <jgg@mellanox.com>
Acked-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
This commit is contained in:
Jason Gunthorpe 2018-06-29 11:31:50 -06:00 committed by Alex Williamson
parent 7733e05b34
commit bb94b55af3
1 changed files with 7 additions and 9 deletions

View File

@ -343,18 +343,16 @@ static int vaddr_get_pfn(struct mm_struct *mm, unsigned long vaddr,
struct page *page[1]; struct page *page[1];
struct vm_area_struct *vma; struct vm_area_struct *vma;
struct vm_area_struct *vmas[1]; struct vm_area_struct *vmas[1];
unsigned int flags = 0;
int ret; int ret;
if (prot & IOMMU_WRITE)
flags |= FOLL_WRITE;
down_read(&mm->mmap_sem);
if (mm == current->mm) { if (mm == current->mm) {
ret = get_user_pages_longterm(vaddr, 1, !!(prot & IOMMU_WRITE), ret = get_user_pages_longterm(vaddr, 1, flags, page, vmas);
page, vmas);
} else { } else {
unsigned int flags = 0;
if (prot & IOMMU_WRITE)
flags |= FOLL_WRITE;
down_read(&mm->mmap_sem);
ret = get_user_pages_remote(NULL, mm, vaddr, 1, flags, page, ret = get_user_pages_remote(NULL, mm, vaddr, 1, flags, page,
vmas, NULL); vmas, NULL);
/* /*
@ -368,8 +366,8 @@ static int vaddr_get_pfn(struct mm_struct *mm, unsigned long vaddr,
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
put_page(page[0]); put_page(page[0]);
} }
up_read(&mm->mmap_sem);
} }
up_read(&mm->mmap_sem);
if (ret == 1) { if (ret == 1) {
*pfn = page_to_pfn(page[0]); *pfn = page_to_pfn(page[0]);