On Sat, Oct 3, 2026 at 6:38 PM Lorenzo Stoakes (ARM) <[email protected]> wrote: > > This determines whether a VMA cannot be expanded or merged because what > they mapped was determined to be a set size at mmap time. > > This typically refers to mappings not managed by core mm, however > VMA_DONTEXPAND_BIT > is not reliably set alongside VMA_PFNMAP_BIT or VMA_MIXEDMAP_BIT, so we > must explicitly test for this for now. > > We also explicitly test for VMA_PFNMAP_BIT as VMA_DONTEXPAND_BIT may not be > set for VMA_PFNMAP_BIT's despite the one implying the other. > > Use this predicate in vma_flags_can_merge() and in check_prep_vma() in the > mremap logic testing to see if mremap() can expand the VMA. The criteria > for khugepaged and MADV_COLLAPSE eligibility in > __thp_vma_allowable_orders() are precisely those for mergeability, so use > vma_can_merge() there (with an expanded comment). > > This obviates the need for the VM_NO_KHUGEPAGED mask, so remove it. > > Hugetlb VMAs remain excluded from khugepaged as hugetlbfs always sets > VMA_DONTEXPAND_BIT. > > Also update the userland VMA tests to reflect the change. > > No functional change intended. > > Reviewed-by: Zi Yan <[email protected]> > Signed-off-by: Lorenzo Stoakes (ARM) <[email protected]>
Reviewed-by: Suren Baghdasaryan <[email protected]> > --- > include/linux/mm.h | 39 +++++++++++++++++++++++++++++++++++---- > mm/huge_memory.c | 11 +++++++---- > mm/mremap.c | 5 ++--- > tools/testing/vma/include/dup.h | 16 +++++++++++++++- > 4 files changed, 59 insertions(+), 12 deletions(-) > > diff --git a/include/linux/mm.h b/include/linux/mm.h > index 83953757735a..6b5f06cd174a 100644 > --- a/include/linux/mm.h > +++ b/include/linux/mm.h > @@ -600,9 +600,6 @@ enum { > #define VMA_REMAP_FLAGS mk_vma_flags(VMA_IO_BIT, VMA_PFNMAP_BIT, \ > VMA_DONTEXPAND_BIT, VMA_DONTDUMP_BIT) > > -/* This mask prevents VMA from being scanned with khugepaged */ > -#define VM_NO_KHUGEPAGED (VM_SPECIAL | VM_HUGETLB) > - > /* This mask defines which mm->def_flags a process can inherit its parent */ > #define VM_INIT_DEF_MASK VM_NOHUGEPAGE > > @@ -1647,6 +1644,40 @@ static inline bool vma_is_mm_managed(const struct > vm_area_struct *vma) > return vma_flags_is_mm_managed(&vma->flags); > } > > +/** > + * vma_flags_is_fixed_mapping() - Do the specified VMA flags indicate that > this > + * is a fixed mapping that cannot be expanded or merged? > + * @flags: The VMA flags to test. > + * > + * Fixed mappings are those whose size is set at the point of mmap (for > + * instance, a mapping of a fixed range of memory established by a driver), > + * and thus cannot be expanded or merged. > + * > + * Returns: true if the flags indicate a fixed mapping. > + */ > +static inline bool vma_flags_is_fixed_mapping(const vma_flags_t *flags) > +{ > + /* > + * VMA_PFNMAP_BIT should imply VMA_DONTEXPAND_BIT, but some callers > set > + * only the former. > + */ > + return vma_flags_test_any(flags, VMA_PFNMAP_BIT, VMA_DONTEXPAND_BIT); > +} > + > +/** > + * vma_is_fixed_mapping() - Is this VMA a fixed mapping that cannot be > + * expanded or merged? > + * @vma: The VMA to test. > + * > + * See vma_flags_is_fixed_mapping() for a description of this property. > + * > + * Returns: true if the VMA maps a fixed mapping. > + */ > +static inline bool vma_is_fixed_mapping(const struct vm_area_struct *vma) > +{ > + return vma_flags_is_fixed_mapping(&vma->flags); > +} > + > /** > * vma_flags_can_merge() - Do the specified VMA flags permit the VMA to be > * merged with another? > @@ -1668,7 +1699,7 @@ static inline bool vma_flags_can_merge(const > vma_flags_t *flags) > if (!vma_flags_is_mm_managed(flags)) > return false; > /* VMA explicitly marked as being unmergeable. */ > - if (vma_flags_test(flags, VMA_DONTEXPAND_BIT)) > + if (vma_flags_is_fixed_mapping(flags)) > return false; > > return true; > diff --git a/mm/huge_memory.c b/mm/huge_memory.c > index 4cd917f77f3f..87e8bf8029ab 100644 > --- a/mm/huge_memory.c > +++ b/mm/huge_memory.c > @@ -212,11 +212,14 @@ unsigned long __thp_vma_allowable_orders(struct > vm_area_struct *vma, > return in_pf ? orders : 0; > > /* > - * khugepaged special VMA and hugetlb VMA. > - * Must be checked after dax since some dax mappings may have > - * VM_MIXEDMAP set. > + * khugepaged moves data from VMAs once collapsed, after they have > been > + * faulted in, relying on refaulting for file-backed memory. > + * > + * Mappings not managed by core mm cannot be reliably reconstructed > from > + * page faults, and fixed mappings (including hugetlb) may well be > + * mm-managed - precisely the mappings which cannot be merged. > */ > - if (!in_pf && !smaps && (vm_flags & VM_NO_KHUGEPAGED)) > + if (!in_pf && !smaps && !vma_can_merge(vma)) > return 0; > > /* > diff --git a/mm/mremap.c b/mm/mremap.c > index 7c368440fafe..ed19b47c2caf 100644 > --- a/mm/mremap.c > +++ b/mm/mremap.c > @@ -1788,8 +1788,7 @@ static int check_prep_vma(struct vma_remap_struct *vrm) > return -EINVAL; > } > > - if ((vrm->flags & MREMAP_DONTUNMAP) && > - vma_test_any(vma, VMA_DONTEXPAND_BIT, VMA_PFNMAP_BIT)) > + if ((vrm->flags & MREMAP_DONTUNMAP) && vma_is_fixed_mapping(vma)) > return -EINVAL; > > /* > @@ -1827,7 +1826,7 @@ static int check_prep_vma(struct vma_remap_struct *vrm) > if (pgoff + (new_len >> PAGE_SHIFT) < pgoff) > return -EINVAL; > > - if (vma_test_any(vma, VMA_DONTEXPAND_BIT, VMA_PFNMAP_BIT)) > + if (vma_is_fixed_mapping(vma)) > return -EFAULT; > > if (!mlock_future_ok(mm, vma_test(vma, VMA_LOCKED_BIT), vrm->delta)) > diff --git a/tools/testing/vma/include/dup.h b/tools/testing/vma/include/dup.h > index 89c645a6ad60..442ea9eb098d 100644 > --- a/tools/testing/vma/include/dup.h > +++ b/tools/testing/vma/include/dup.h > @@ -1676,6 +1676,20 @@ static inline bool vma_is_mm_managed(const struct > vm_area_struct *vma) > return vma_flags_is_mm_managed(&vma->flags); > } > > +static inline bool vma_flags_is_fixed_mapping(const vma_flags_t *flags) > +{ > + /* > + * VMA_PFNMAP_BIT should imply VMA_DONTEXPAND_BIT, but some callers > set > + * only the former. > + */ > + return vma_flags_test_any(flags, VMA_PFNMAP_BIT, VMA_DONTEXPAND_BIT); > +} > + > +static inline bool vma_is_fixed_mapping(const struct vm_area_struct *vma) > +{ > + return vma_flags_is_fixed_mapping(&vma->flags); > +} > + > static inline bool vma_flags_can_merge(const vma_flags_t *flags) > { > /* > @@ -1691,7 +1705,7 @@ static inline bool vma_flags_can_merge(const > vma_flags_t *flags) > if (!vma_flags_is_mm_managed(flags)) > return false; > /* VMA explicitly marked as being unmergeable. */ > - if (vma_flags_test(flags, VMA_DONTEXPAND_BIT)) > + if (vma_flags_is_fixed_mapping(flags)) > return false; > > return true; > > -- > 2.55.0 >
