Using for_each_vma_range to find vmas, and not only inside locking, but also outside locking to ensure that vma_start_write are performed. Reported-and-tested-by: syzbot+b591856e0f0139f83023@xxxxxxxxxxxxxxxxxxxxxxxxx Signed-off-by: Edward AD <eadavis@xxxxxxxx> --- mm/pagewalk.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mm/pagewalk.c b/mm/pagewalk.c index b7d7e4fcfad7..b31d59a27f57 100644 --- a/mm/pagewalk.c +++ b/mm/pagewalk.c @@ -479,6 +479,7 @@ int walk_page_range(struct mm_struct *mm, unsigned long start, .mm = mm, .private = private, }; + struct vma_iterator vmi; if (start >= end) return -EINVAL; @@ -488,8 +489,9 @@ int walk_page_range(struct mm_struct *mm, unsigned long start, process_mm_walk_lock(walk.mm, ops->walk_lock); - vma = find_vma(walk.mm, start); - do { + vma_iter_init(&vmi, walk.mm, start); + for_each_vma_range(vmi, vma, end) { + process_vma_walk_lock(vma, ops->walk_lock); if (!vma) { /* after the last vma */ walk.vma = NULL; next = end; @@ -501,10 +503,8 @@ int walk_page_range(struct mm_struct *mm, unsigned long start, if (ops->pte_hole) err = ops->pte_hole(start, next, -1, &walk); } else { /* inside vma */ - process_vma_walk_lock(vma, ops->walk_lock); walk.vma = vma; next = min(end, vma->vm_end); - vma = find_vma(mm, vma->vm_end); err = walk_page_test(start, next, &walk); if (err > 0) { @@ -522,7 +522,7 @@ int walk_page_range(struct mm_struct *mm, unsigned long start, } if (err) break; - } while (start = next, start < end); + }; return err; } -- 2.25.1