[RHEL8,COMMIT] mm/gup: allow VM_FAULT_RETRY for multiple times

Submitted by Konstantin Khorenko on April 20, 2020, 7:34 a.m.

Details

Message ID 202004200734.03K7YN5H016114@finist_co8.work.ct
State New
Series "Series without cover letter"
Headers show

Commit Message

Konstantin Khorenko April 20, 2020, 7:34 a.m.
The commit is pushed to "branch-rh8-4.18.0-80.1.2.vz8.3.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh8-4.18.0-80.1.2.vz8.3.6
------>
commit 298030b5610006f6787318de79426c68693b814e
Author: Peter Xu <peterx@redhat.com>
Date:   Mon Apr 20 10:34:22 2020 +0300

    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 <peterx@redhat.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Tested-by: Brian Geffon <bgeffon@google.com>
    Cc: Andrea Arcangeli <aarcange@redhat.com>
    Cc: Bobby Powers <bobbypowers@gmail.com>
    Cc: David Hildenbrand <david@redhat.com>
    Cc: Denis Plotnikov <dplotnikov@virtuozzo.com>
    Cc: "Dr . David Alan Gilbert" <dgilbert@redhat.com>
    Cc: Hugh Dickins <hughd@google.com>
    Cc: Jerome Glisse <jglisse@redhat.com>
    Cc: Johannes Weiner <hannes@cmpxchg.org>
    Cc: "Kirill A . Shutemov" <kirill@shutemov.name>
    Cc: Martin Cracauer <cracauer@cons.org>
    Cc: Marty McFadden <mcfadden8@llnl.gov>
    Cc: Matthew Wilcox <willy@infradead.org>
    Cc: Maya Gokhale <gokhale2@llnl.gov>
    Cc: Mel Gorman <mgorman@suse.de>
    Cc: Mike Kravetz <mike.kravetz@oracle.com>
    Cc: Mike Rapoport <rppt@linux.vnet.ibm.com>
    Cc: Pavel Emelyanov <xemul@openvz.org>
    Link: http://lkml.kernel.org/r/20200220195357.16371-1-peterx@redhat.com
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
    
    https://jira.sw.ru/browse/PSBM-102938
    (cherry picked from commit 4426e945df588f2878affddf88a51259200f7e29)
    Signed-off-by: Andrey Ryabinin <aryabinin@virtuozzo.com>
---
 mm/gup.c     | 27 +++++++++++++++++++++------
 mm/hugetlb.c |  6 ++++--
 2 files changed, 25 insertions(+), 8 deletions(-)

Patch hide | download patch | download mbox

diff --git a/mm/gup.c b/mm/gup.c
index e06aa55b65b2..cdf438ea8621 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -511,7 +511,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;
 	}
 
@@ -853,7 +856,6 @@  int fixup_user_fault(struct task_struct *tsk, struct mm_struct *mm,
 		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;
 		}
@@ -928,17 +930,30 @@  static __always_inline long __get_user_pages_locked(struct task_struct *tsk,
 		/* VM_FAULT_RETRY triggered, so seek to the faulting offset */
 		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)
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 1c6584c8e78e..417b96f4aa14 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -4228,8 +4228,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);