Skip to content

Commit 96312e6

Browse files
aagittorvalds
authored andcommitted
mm/gup.c: teach get_user_pages_unlocked to handle FOLL_NOWAIT
KVM is hanging during postcopy live migration with userfaultfd because get_user_pages_unlocked is not capable to handle FOLL_NOWAIT. Earlier FOLL_NOWAIT was only ever passed to get_user_pages. Specifically faultin_page (the callee of get_user_pages_unlocked caller) doesn't know that if FAULT_FLAG_RETRY_NOWAIT was set in the page fault flags, when VM_FAULT_RETRY is returned, the mmap_sem wasn't actually released (even if nonblocking is not NULL). So it sets *nonblocking to zero and the caller won't release the mmap_sem thinking it was already released, but it wasn't because of FOLL_NOWAIT. Link: http://lkml.kernel.org/r/20180302174343.5421-2-aarcange@redhat.com Fixes: ce53053 ("kvm: switch get_user_page_nowait() to get_user_pages_unlocked()") Signed-off-by: Andrea Arcangeli <aarcange@redhat.com> Reported-by: Dr. David Alan Gilbert <dgilbert@redhat.com> Tested-by: Dr. David Alan Gilbert <dgilbert@redhat.com> Cc: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent 1b4cfe3 commit 96312e6

File tree

1 file changed

+5
-2
lines changed

1 file changed

+5
-2
lines changed

mm/gup.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,7 @@ static int faultin_page(struct task_struct *tsk, struct vm_area_struct *vma,
516516
}
517517

518518
if (ret & VM_FAULT_RETRY) {
519-
if (nonblocking)
519+
if (nonblocking && !(fault_flags & FAULT_FLAG_RETRY_NOWAIT))
520520
*nonblocking = 0;
521521
return -EBUSY;
522522
}
@@ -890,7 +890,10 @@ static __always_inline long __get_user_pages_locked(struct task_struct *tsk,
890890
break;
891891
}
892892
if (*locked) {
893-
/* VM_FAULT_RETRY didn't trigger */
893+
/*
894+
* VM_FAULT_RETRY didn't trigger or it was a
895+
* FOLL_NOWAIT.
896+
*/
894897
if (!pages_done)
895898
pages_done = ret;
896899
break;

0 commit comments

Comments
 (0)