mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs.git
synced 2026-11-09 02:51:11 +01:00
mm/gup: allow VM_FAULT_RETRY for multiple times
This is the gup counterpart of the change that allows the VM_FAULT_RETRY to happen for more than once. One thing to mention is that we must check the fatal signal here before retry because the GUP can be interrupted by that, otherwise we can loop forever. Signed-off-by: Peter Xu <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Tested-by: Brian Geffon <[email protected]> Cc: Andrea Arcangeli <[email protected]> Cc: Bobby Powers <[email protected]> Cc: David Hildenbrand <[email protected]> Cc: Denis Plotnikov <[email protected]> Cc: "Dr . David Alan Gilbert" <[email protected]> Cc: Hugh Dickins <[email protected]> Cc: Jerome Glisse <[email protected]> Cc: Johannes Weiner <[email protected]> Cc: "Kirill A . Shutemov" <[email protected]> Cc: Martin Cracauer <[email protected]> Cc: Marty McFadden <[email protected]> Cc: Matthew Wilcox <[email protected]> Cc: Maya Gokhale <[email protected]> Cc: Mel Gorman <[email protected]> Cc: Mike Kravetz <[email protected]> Cc: Mike Rapoport <[email protected]> Cc: Pavel Emelyanov <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Linus Torvalds <[email protected]>
This commit is contained in:
1 parent
4064b98270
commit
4426e945df
2 files changed
+25
-8
No files matched your search
@@ -868,7 +868,10 @@ static int faultin_page(struct task_struct *tsk, struct vm_area_struct *vma,
|
||||
if (*flags & FOLL_NOWAIT)
|
||||
fault_flags |= FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_RETRY_NOWAIT;
|
||||
if (*flags & FOLL_TRIED) {
|
||||
VM_WARN_ON_ONCE(fault_flags & FAULT_FLAG_ALLOW_RETRY);
|
||||
/*
|
||||
* Note: FAULT_FLAG_ALLOW_RETRY and FAULT_FLAG_TRIED
|
||||
* can co-exist
|
||||
*/
|
||||
fault_flags |= FAULT_FLAG_TRIED;
|
||||
}
|
||||
|
||||
@@ -1228,7 +1231,6 @@ retry:
|
||||
down_read(&mm->mmap_sem);
|
||||
if (!(fault_flags & FAULT_FLAG_TRIED)) {
|
||||
*unlocked = true;
|
||||
fault_flags &= ~FAULT_FLAG_ALLOW_RETRY;
|
||||
fault_flags |= FAULT_FLAG_TRIED;
|
||||
goto retry;
|
||||
}
|
||||
@@ -1312,17 +1314,30 @@ static __always_inline long __get_user_pages_locked(struct task_struct *tsk,
|
||||
if (likely(pages))
|
||||
pages += ret;
|
||||
start += ret << PAGE_SHIFT;
|
||||
lock_dropped = true;
|
||||
|
||||
retry:
|
||||
/*
|
||||
* Repeat on the address that fired VM_FAULT_RETRY
|
||||
* without FAULT_FLAG_ALLOW_RETRY but with
|
||||
* FAULT_FLAG_TRIED.
|
||||
* with both FAULT_FLAG_ALLOW_RETRY and
|
||||
* FAULT_FLAG_TRIED. Note that GUP can be interrupted
|
||||
* by fatal signals, so we need to check it before we
|
||||
* start trying again otherwise it can loop forever.
|
||||
*/
|
||||
|
||||
if (fatal_signal_pending(current))
|
||||
break;
|
||||
|
||||
*locked = 1;
|
||||
lock_dropped = true;
|
||||
down_read(&mm->mmap_sem);
|
||||
|
||||
ret = __get_user_pages(tsk, mm, start, 1, flags | FOLL_TRIED,
|
||||
pages, NULL, NULL);
|
||||
pages, NULL, locked);
|
||||
if (!*locked) {
|
||||
/* Continue to retry until we succeeded */
|
||||
BUG_ON(ret != 0);
|
||||
goto retry;
|
||||
}
|
||||
if (ret != 1) {
|
||||
BUG_ON(ret > 1);
|
||||
if (!pages_done)
|
||||
|
||||
+4
-2
@@ -4349,8 +4349,10 @@ long follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,
|
||||
fault_flags |= FAULT_FLAG_ALLOW_RETRY |
|
||||
FAULT_FLAG_RETRY_NOWAIT;
|
||||
if (flags & FOLL_TRIED) {
|
||||
VM_WARN_ON_ONCE(fault_flags &
|
||||
FAULT_FLAG_ALLOW_RETRY);
|
||||
/*
|
||||
* Note: FAULT_FLAG_ALLOW_RETRY and
|
||||
* FAULT_FLAG_TRIED can co-exist
|
||||
*/
|
||||
fault_flags |= FAULT_FLAG_TRIED;
|
||||
}
|
||||
ret = hugetlb_fault(mm, vma, vaddr, fault_flags);
|
||||
|
||||
Reference in new issue
Block a user