diff options
Diffstat (limited to 'mm/userfaultfd.c')
-rw-r--r-- | mm/userfaultfd.c | 22 |
1 files changed, 17 insertions, 5 deletions
diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c index 39791b81ede7..5029f241908f 100644 --- a/mm/userfaultfd.c +++ b/mm/userfaultfd.c | |||
@@ -404,7 +404,8 @@ static __always_inline ssize_t __mcopy_atomic(struct mm_struct *dst_mm, | |||
404 | unsigned long dst_start, | 404 | unsigned long dst_start, |
405 | unsigned long src_start, | 405 | unsigned long src_start, |
406 | unsigned long len, | 406 | unsigned long len, |
407 | bool zeropage) | 407 | bool zeropage, |
408 | bool *mmap_changing) | ||
408 | { | 409 | { |
409 | struct vm_area_struct *dst_vma; | 410 | struct vm_area_struct *dst_vma; |
410 | ssize_t err; | 411 | ssize_t err; |
@@ -431,6 +432,15 @@ retry: | |||
431 | down_read(&dst_mm->mmap_sem); | 432 | down_read(&dst_mm->mmap_sem); |
432 | 433 | ||
433 | /* | 434 | /* |
435 | * If memory mappings are changing because of non-cooperative | ||
436 | * operation (e.g. mremap) running in parallel, bail out and | ||
437 | * request the user to retry later | ||
438 | */ | ||
439 | err = -EAGAIN; | ||
440 | if (mmap_changing && READ_ONCE(*mmap_changing)) | ||
441 | goto out_unlock; | ||
442 | |||
443 | /* | ||
434 | * Make sure the vma is not shared, that the dst range is | 444 | * Make sure the vma is not shared, that the dst range is |
435 | * both valid and fully within a single existing vma. | 445 | * both valid and fully within a single existing vma. |
436 | */ | 446 | */ |
@@ -563,13 +573,15 @@ out: | |||
563 | } | 573 | } |
564 | 574 | ||
565 | ssize_t mcopy_atomic(struct mm_struct *dst_mm, unsigned long dst_start, | 575 | ssize_t mcopy_atomic(struct mm_struct *dst_mm, unsigned long dst_start, |
566 | unsigned long src_start, unsigned long len) | 576 | unsigned long src_start, unsigned long len, |
577 | bool *mmap_changing) | ||
567 | { | 578 | { |
568 | return __mcopy_atomic(dst_mm, dst_start, src_start, len, false); | 579 | return __mcopy_atomic(dst_mm, dst_start, src_start, len, false, |
580 | mmap_changing); | ||
569 | } | 581 | } |
570 | 582 | ||
571 | ssize_t mfill_zeropage(struct mm_struct *dst_mm, unsigned long start, | 583 | ssize_t mfill_zeropage(struct mm_struct *dst_mm, unsigned long start, |
572 | unsigned long len) | 584 | unsigned long len, bool *mmap_changing) |
573 | { | 585 | { |
574 | return __mcopy_atomic(dst_mm, start, 0, len, true); | 586 | return __mcopy_atomic(dst_mm, start, 0, len, true, mmap_changing); |
575 | } | 587 | } |