The patch titled Subject: mm/gup: continue VM_FAULT_RETRY processing event for pre-faults has been added to the -mm tree. Its filename is mm-gup-continue-vm_fault_retry-processing-event-for-pre-faults.patch This patch should soon appear at http://ozlabs.org/~akpm/mmots/broken-out/mm-gup-continue-vm_fault_retry-processing-event-for-pre-faults.patch and later at http://ozlabs.org/~akpm/mmotm/broken-out/mm-gup-continue-vm_fault_retry-processing-event-for-pre-faults.patch Before you just go and hit "reply", please: a) Consider who else should be cc'ed b) Prefer to cc a suitable mailing list as well c) Ideally: find the original patch on the mailing list and do a reply-to-all to that, adding suitable additional cc's *** Remember to use Documentation/process/submit-checklist.rst when testing your code *** The -mm tree is included into linux-next and is updated there every 3-4 working days ------------------------------------------------------ From: Mike Rapoport <rppt@xxxxxxxxxxxxx> Subject: mm/gup: continue VM_FAULT_RETRY processing event for pre-faults When get_user_pages*() is called with pages = NULL, the processing of VM_FAULT_RETRY terminates early without actually retrying to fault-in all the pages. If the pages in the requested range belong to a VMA that has userfaultfd registered, handle_userfault() returns VM_FAULT_RETRY *after* user space has populated the page, but for the gup pre-fault case there's no actual retry and the caller will get no pages although they are present. This issue was uncovered when running post-copy memory restore in CRIU after d9c9ce34ed5c ("x86/fpu: Fault-in user stack if copy_fpstate_to_sigframe() fails"). After this change, the copying of FPU state to the sigframe switched from copy_to_user() variants which caused a real page fault to get_user_pages() with pages parameter set to NULL. In post-copy mode of CRIU, the destination memory is managed with userfaultfd and lack of the retry for pre-fault case in get_user_pages() causes a crash of the restored process. Making the pre-fault behavior of get_user_pages() the same as the "normal" one fixes the issue. Link: http://lkml.kernel.org/r/1557844195-18882-1-git-send-email-rppt@xxxxxxxxxxxxx Fixes: d9c9ce34ed5c ("x86/fpu: Fault-in user stack if copy_fpstate_to_sigframe() fails") Signed-off-by: Mike Rapoport <rppt@xxxxxxxxxxxxx> Cc: Andrea Arcangeli <aarcange@xxxxxxxxxx> Tested-by: Andrei Vagin <avagin@xxxxxxxxx> [https://travis-ci.org/avagin/linux/builds/533184940] Cc: Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx> Cc: Borislav Petkov <bp@xxxxxxx> Signed-off-by: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> --- mm/gup.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) --- a/mm/gup.c~mm-gup-continue-vm_fault_retry-processing-event-for-pre-faults +++ a/mm/gup.c @@ -1041,10 +1041,6 @@ static __always_inline long __get_user_p BUG_ON(ret >= nr_pages); } - if (!pages) - /* If it's a prefault don't insist harder */ - return ret; - if (ret > 0) { nr_pages -= ret; pages_done += ret; @@ -1060,8 +1056,12 @@ static __always_inline long __get_user_p pages_done = ret; break; } - /* VM_FAULT_RETRY triggered, so seek to the faulting offset */ - pages += ret; + /* + * VM_FAULT_RETRY triggered, so seek to the faulting offset. + * For the prefault case (!pages) we only update counts. + */ + if (likely(pages)) + pages += ret; start += ret << PAGE_SHIFT; /* @@ -1084,7 +1084,8 @@ static __always_inline long __get_user_p pages_done++; if (!nr_pages) break; - pages++; + if (likely(pages)) + pages++; start += PAGE_SIZE; } if (lock_dropped && *locked) { _ Patches currently in -mm which might be from rppt@xxxxxxxxxxxxx are mm-gup-continue-vm_fault_retry-processing-event-for-pre-faults.patch arm-remove-arch_select_memory_model.patch s390-remove-arch_select_memory_model.patch sparc-remove-arch_select_memory_model.patch