ed(vma, start); + err = split_huge_pmd_if_needed(vma, start); + if (err) + return err; /* Check if we need to split end next. */ - split_huge_pmd_if_needed(vma, end); + err = split_huge_pmd_if_needed(vma, end); + if (err) + return err; /* If we're incrementing next->vm_start, we might need to split it. */ - if (next) - split_huge_pmd_if_needed(next, end); + if (next) { + err = split_huge_pmd_if_needed(next, end); + if (err) + return err; + } + + return 0; } static void unmap_folio(struct folio *folio) diff --git a/mm/vma.c b/mm/vma.c index be64f781a3aa7..f50b1f291ab7c 100644 --- a/mm/vma.c +++ b/mm/vma.c @@ -510,6 +510,15 @@ __split_vma(struct vma_iterator *vmi, struct vm_area_struct *vma, return err; } + /* + * Split any THP straddling the split boundary before splitting + * the VMA itself. Do this before vma_prepare() so we can + * cleanly fail without undoing VMA preparation. + */ + err = vma_adjust_trans_huge(vma, vma->vm_start, addr, NULL); + if (err) + return err; + new = vm_area_dup(vma); if (!new) return -ENOMEM; @@ -547,11 +556,6 @@ __split_vma(struct vma_iterator *vmi, struct vm_area_struct *vma, vp.insert = new; vma_prepare(&vp); - /* - * Get rid of huge pages and shared page tables straddling the split - * boundary. - */ - vma_adjust_trans_huge(vma, vma->vm_start, addr, NULL); if (is_vm_hugetlb_page(vma)) hugetlb_split(vma, addr); @@ -729,6 +733,7 @@ static int commit_merge(struct vma_merge_struct *vmg) { struct vm_area_struct *vma; struct vma_prepare vp; + int err; if (vmg->__adjust_next_start) { /* We manipulate middle and adjust next, which is the target. */ @@ -740,6 +745,16 @@ static int commit_merge(struct vma_merge_struct *vmg) vma_iter_config(vmg->vmi, vmg->start, vmg->end); } + /* + * THP pages may need to do additional splits if we increase + * middle->vm_start. Do this before vma_prepare() so we can + * cleanly fail without undoing VMA preparation. + */ + err = vma_adjust_trans_huge(vma, vmg->start, vmg->end, + vmg->__adjust_middle_start ? vmg->middle : NULL); + if (err) + return err; + init_multi_vma_prep(&vp, vma, vmg); /* @@ -752,12 +767,6 @@ static int commit_merge(struct vma_merge_struct *vmg) return -ENOMEM; vma_prepare(&vp); - /* - * THP pages may need to do additional splits if we increase - * middle->vm_start. - */ - vma_adjust_trans_huge(vma, vmg->start, vmg->end, - vmg->__adjust_middle_start ? vmg->middle : NULL); vma_set_range(vma, vmg->start, vmg->end, vmg->pgoff); vmg_adjust_set_range(vmg); vma_iter_store_overwrite(vmg->vmi, vmg->target); @@ -1229,9 +1238,14 @@ int vma_shrink(struct vma_iterator *vmi, struct vm_area_struct *vma, unsigned long start, unsigned long end, pgoff_t pgoff) { struct vma_prepare vp; + int err; WARN_ON((vma->vm_start != start) && (vma->vm_end != end)); + err = vma_adjust_trans_huge(vma, start, end, NULL); + if (err) + return err; + if (vma->vm_start < start) vma_iter_config(vmi, vma->vm_start, start); else @@ -1244,7 +1258,6 @@ int vma_shrink(struct vma_iterator *vmi, struct vm_area_struct *vma, init_vma_prep(&vp, vma); vma_prepare(&vp); - vma_adjust_trans_huge(vma, start, end, NULL); vma_iter_clear(vmi); vma_set_range(vma, start, end, pgoff); diff --git a/tools/testing/vma/include/stubs.h b/tools/testing/vma/include/stubs.h index 947a3a0c25665..171986f9c9fcd 100644 --- a/tools/testing/vma/include/stubs.h +++ b/tools/testing/vma/include/stubs.h @@ -418,11 +418,12 @@ static inline int vma_dup_policy(struct vm_area_struct *src, struct vm_area_stru return 0; } -static inline void vma_adjust_trans_huge(struct vm_area_struct *vma, - unsigned long start, - unsigned long end, - struct vm_area_struct *next) +static inline int vma_adjust_trans_huge(struct vm_area_struct *vma, + unsigned long start, + unsigned long end, + struct vm_area_struct *next) { + return 0; } static inline void hugetlb_split(struct vm_area_struct *, unsigned long) {} -- 2.47.3[RFC v2 02/21] mm: thp: propagate split failure from vma_adjust_trans_huge()Usama Arif undefinedAndrew Morton , david@kernel.org, lorenzo.stoakes@oracle.com, willy@infradead.org, linux-mm@kvack.org undefined undefined undefined undefined undefined undefined undefined undefined undefined undefined undefined undefined undefined undefined undefined undefined undefined undefined undefined undefined undefined undefined undefined undefined undefined undefined undefined undefined undefined›;†Ÿ9