diff mbox series

[3/7] mm/gup: fix fixup_user_fault() on multiple retries

Message ID 20200514005041.Biir9x7Bl%akpm@linux-foundation.org (mailing list archive)
State New, archived
Headers show
Series [1/7] mm, memcg: fix inconsistent oom event behavior | expand

Commit Message

Andrew Morton May 14, 2020, 12:50 a.m. UTC
From: Peter Xu <peterx@redhat.com>
Subject: mm/gup: fix fixup_user_fault() on multiple retries

This part is overlooked when reworking the gup code on multiple retries. 
When we get the 2nd+ retry, we'll be with TRIED flag set.  Current code
will bail out on the 2nd retry because the !TRIED check will fail so the
retry logic will be skipped.  What's worse is that, it will also return
zero which errornously hints the caller that the page is faulted in while
it's not.

The !TRIED flag check seems to not be needed even before the mutliple
retries change because if we get a VM_FAULT_RETRY, it must be the 1st
retry, and we should not have TRIED set for that.

Fix it by removing the !TRIED check, at the meantime check against fatal
signals properly before the page fault so we can still properly respond to
the user killing the process during retries.

Link: http://lkml.kernel.org/r/20200502003523.8204-1-peterx@redhat.com
Fixes: 4426e945df58 ("mm/gup: allow VM_FAULT_RETRY for multiple times")
Signed-off-by: Peter Xu <peterx@redhat.com>
Cc: Alex Williamson <alex.williamson@redhat.com>
Cc: Brian Geffon <bgeffon@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---

 mm/gup.c |   12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)
diff mbox series

Patch

--- a/mm/gup.c~mm-gup-fix-fixup_user_fault-on-multiple-retries
+++ a/mm/gup.c
@@ -1218,6 +1218,10 @@  retry:
 	if (!vma_permits_fault(vma, fault_flags))
 		return -EFAULT;
 
+	if ((fault_flags & FAULT_FLAG_KILLABLE) &&
+	    fatal_signal_pending(current))
+		return -EINTR;
+
 	ret = handle_mm_fault(vma, address, fault_flags);
 	major |= ret & VM_FAULT_MAJOR;
 	if (ret & VM_FAULT_ERROR) {
@@ -1230,11 +1234,9 @@  retry:
 
 	if (ret & VM_FAULT_RETRY) {
 		down_read(&mm->mmap_sem);
-		if (!(fault_flags & FAULT_FLAG_TRIED)) {
-			*unlocked = true;
-			fault_flags |= FAULT_FLAG_TRIED;
-			goto retry;
-		}
+		*unlocked = true;
+		fault_flags |= FAULT_FLAG_TRIED;
+		goto retry;
 	}
 
 	if (tsk) {