|
@@ -338,11 +338,12 @@ static int vaddr_get_pfn(struct mm_struct *mm, unsigned long vaddr,
|
|
|
{
|
|
|
struct page *page[1];
|
|
|
struct vm_area_struct *vma;
|
|
|
+ struct vm_area_struct *vmas[1];
|
|
|
int ret;
|
|
|
|
|
|
if (mm == current->mm) {
|
|
|
- ret = get_user_pages_fast(vaddr, 1, !!(prot & IOMMU_WRITE),
|
|
|
- page);
|
|
|
+ ret = get_user_pages_longterm(vaddr, 1, !!(prot & IOMMU_WRITE),
|
|
|
+ page, vmas);
|
|
|
} else {
|
|
|
unsigned int flags = 0;
|
|
|
|
|
@@ -351,7 +352,18 @@ static int vaddr_get_pfn(struct mm_struct *mm, unsigned long vaddr,
|
|
|
|
|
|
down_read(&mm->mmap_sem);
|
|
|
ret = get_user_pages_remote(NULL, mm, vaddr, 1, flags, page,
|
|
|
- NULL, NULL);
|
|
|
+ vmas, NULL);
|
|
|
+ /*
|
|
|
+ * The lifetime of a vaddr_get_pfn() page pin is
|
|
|
+ * userspace-controlled. In the fs-dax case this could
|
|
|
+ * lead to indefinite stalls in filesystem operations.
|
|
|
+ * Disallow attempts to pin fs-dax pages via this
|
|
|
+ * interface.
|
|
|
+ */
|
|
|
+ if (ret > 0 && vma_is_fsdax(vmas[0])) {
|
|
|
+ ret = -EOPNOTSUPP;
|
|
|
+ put_page(page[0]);
|
|
|
+ }
|
|
|
up_read(&mm->mmap_sem);
|
|
|
}
|
|
|
|