Patch "mm/hugetlb.c: __get_user_pages ignores certain follow_hugetlb_page errors" has been added to the 4.12-stable tree
Subsystems (3)
This is a note to let you know that I've just added the patch titled
mm/hugetlb.c: __get_user_pages ignores certain follow_hugetlb_page errors
to the 4.12-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
mm-hugetlb.c-__get_user_pages-ignores-certain-follow_hugetlb_page-errors.patch
and it can be found in the queue-4.12 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
2be7cfed995e25de1ffaffe14cc065b7ffb528e0Mon Sep 17 00:00:00 2001
From: Daniel Jordan <[email protected]>
Date: Wed, 2 Aug 2017 13:31:47 -0700
Subject: mm/hugetlb.c: __get_user_pages ignores certain follow_hugetlb_page errors
From: Daniel Jordan <[email protected]>
commit 2be7cfed995e25de1ffaffe14cc065b7ffb528e0 upstream.
Commit 9a291a7c9428 ("mm/hugetlb: report -EHWPOISON not -EFAULT when FOLL_HWPOISON is specified") causes __get_user_pages to ignore certain errors from follow_hugetlb_page. After such error, __get_user_pages subsequently calls faultin_page on the same VMA and start address that follow_hugetlb_page failed on instead of returning the error immediately as it should.
In follow_hugetlb_page, when hugetlb_fault returns a value covered under VM_FAULT_ERROR, follow_hugetlb_page returns it without setting nr_pages to 0 as __get_user_pages expects in this case, which causes the following to happen in __get_user_pages: the "while (nr_pages)" check succeeds, we skip the "if (!vma..." check because we got a VMA the last time around, we find no page with follow_page_mask, and we call faultin_page, which calls hugetlb_fault for the second time.
This issue also slightly changes how __get_user_pages works. Before, it only returned error if it had made no progress (i = 0). But now, follow_hugetlb_page can clobber "i" with an error code since its new return path doesn't check for progress. So if "i" is nonzero before a failing call to follow_hugetlb_page, that indication of progress is lost and __get_user_pages can return error even if some pages were successfully pinned.
To fix this, change follow_hugetlb_page so that it updates nr_pages, allowing __get_user_pages to fail immediately and restoring the "error only if no progress" behavior to __get_user_pages.
Tested that __get_user_pages returns when expected on error from hugetlb_fault in follow_hugetlb_page.
--- mm/hugetlb.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-)
mm/hugetlb.c +3 -6
@@ -4095,6 +4095,7 @@ long follow_hugetlb_page(struct mm_strucunsigned long vaddr = *position;unsigned long remainder = *nr_pages;struct hstate *h =hstate_vma (vma); +int err = -EFAULT ;while (vaddr < vma->vm_end && remainder) {pte_t *pte;
@@ -4170,11 +4171,7 @@ long follow_hugetlb_page(struct mm_struc } ret =hugetlb_fault (mm, vma, vaddr, fault_flags);if (ret &VM_FAULT_ERROR ) { -int err =vm_fault_to_errno (ret, flags); - -if (err) -return err; - + err =vm_fault_to_errno (ret, flags); remainder =0 ;break ; }
@@ -4229,7 +4226,7 @@ same_page:*/ *position = vaddr; -return i ? i : -EFAULT ; +return i ? i : err; }#ifndef __HAVE_ARCH_FLUSH_HUGETLB_TLB_RANGE
Patches currently in stable-queue which might be from [email protected] are
queue-4.12/mm-hugetlb.c-__get_user_pages-ignores-certain-follow_hugetlb_page-errors.patch