qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 1/1] mm: gup: teach get_user_pages_unlocked to handl


From: Andrea Arcangeli
Subject: [Qemu-devel] [PATCH 1/1] mm: gup: teach get_user_pages_unlocked to handle FOLL_NOWAIT
Date: Fri, 2 Mar 2018 18:43:43 +0100

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 <address@hidden>
Tested-by: Dr. David Alan Gilbert <address@hidden>
Signed-off-by: Andrea Arcangeli <address@hidden>
---
 mm/gup.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

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;



reply via email to

[Prev in Thread] Current Thread [Next in Thread]