mirror of
https://github.com/torvalds/linux.git
synced 2026-09-25 21:21:09 -04:00
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/[email protected]
Fixes: ce53053ce3 ("kvm: switch get_user_page_nowait() to get_user_pages_unlocked()")
Signed-off-by: Andrea Arcangeli <[email protected]>
Reported-by: Dr. David Alan Gilbert <[email protected]>
Tested-by: Dr. David Alan Gilbert <[email protected]>
Cc: Al Viro <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
This commit is contained in:
committed by
Linus Torvalds
parent
1b4cfe3c0a
commit
96312e6128
@@ -516,7 +516,7 @@ static int faultin_page(struct task_struct *tsk, struct vm_area_struct *vma,
|
||||
}
|
||||
|
||||
if (ret & VM_FAULT_RETRY) {
|
||||
if (nonblocking)
|
||||
if (nonblocking && !(fault_flags & FAULT_FLAG_RETRY_NOWAIT))
|
||||
*nonblocking = 0;
|
||||
return -EBUSY;
|
||||
}
|
||||
@@ -890,7 +890,10 @@ static __always_inline long __get_user_pages_locked(struct task_struct *tsk,
|
||||
break;
|
||||
}
|
||||
if (*locked) {
|
||||
/* VM_FAULT_RETRY didn't trigger */
|
||||
/*
|
||||
* VM_FAULT_RETRY didn't trigger or it was a
|
||||
* FOLL_NOWAIT.
|
||||
*/
|
||||
if (!pages_done)
|
||||
pages_done = ret;
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user