Message ID | 20180302174343.5421-2-aarcange@redhat.com |
---|---|
State | New |
Headers | show |
Series | FOLL_NOWAIT and get_user_pages_unlocked | expand |
On Fri, 2 Mar 2018 18:43:43 +0100 Andrea Arcangeli <aarcange@redhat.com> wrote: > 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. > > Reported-by: Dr. David Alan Gilbert <dgilbert@redhat.com> > Tested-by: Dr. David Alan Gilbert <dgilbert@redhat.com> > Signed-off-by: Andrea Arcangeli <aarcange@redhat.com> I added Fixes: ce53053ce378c ("kvm: switch get_user_page_nowait() to get_user_pages_unlocked()") Cc: <stable@vger.kernel.org>
diff --git a/mm/gup.c b/mm/gup.c index 1b46e6e74881..6afae32571ca 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -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;