| Message ID | 20261003-b4-mmap-prepare-vma-flag-sanify-v4-14-a1f052500fd7@kernel.org |
|---|---|
| State | New |
| Headers | show |
| Series | mm: make VMA flag semantics explicit, eliminate VM_SPECIAL | expand |
On Sat, Oct 3, 2026 at 6:38 PM Lorenzo Stoakes (ARM) <ljs@kernel.org> wrote: > > Rather than referring to VMA flags with uncertain meaning, add a new > predicate that explicitly describes what absence of the VMA_PFNMAP_BIT and > VMA_MIXEDMAP_BIT flags means, and then refer to that function for > determining VMA mergeability. > > If neither of these flags are set, that means the contents of the mapping > are managed by core mm. > > Otherwise they are instead owned by some other kernel component, usually a > driver: the memory may be MMIO, kernel-allocated pages or even ordinary > pages the driver maps itself, but core mm must not populate, reclaim, > migrate, copy-on-write or merge the range itself. > > We initially also treat VMA_IO_BIT as implying a mapping is not mm-managed, > as by implication it cannot be. (mlock() also sets VMA_IO_BIT transiently > on ordinary VMAs while locking them, which is addressed later in this > series.) > > However the intent is to in future remove this, as no mapping should be > marked as an I/O mapping without also being marked with VMA_PFNMAP_BIT. > > This forms the basis of further work intended to improve how we express VMA > properties such as this. > > Also update the VMA userland tests to reflect the change. > > No functional change intended. > > Reviewed-by: Zi Yan <ziy@nvidia.com> > Signed-off-by: Lorenzo Stoakes (ARM) <ljs@kernel.org> Reviewed-by: Suren Baghdasaryan <surenb@google.com> > --- > include/linux/mm.h | 53 ++++++++++++++++++++++++++++++++++++++++- > tools/testing/vma/include/dup.h | 29 +++++++++++++++++++++- > 2 files changed, 80 insertions(+), 2 deletions(-) > > diff --git a/include/linux/mm.h b/include/linux/mm.h > index 97e1eb4fe3a4..83953757735a 100644 > --- a/include/linux/mm.h > +++ b/include/linux/mm.h > @@ -1612,6 +1612,41 @@ static inline bool vma_is_shared_maywrite(const struct vm_area_struct *vma) > return is_shared_maywrite(&vma->flags); > } > > +/** > + * vma_flags_is_mm_managed() - Do the specified VMA flags indicate that the > + * contents of the VMA are managed by core mm? > + * @flags: The VMA flags to test. > + * > + * Such a mapping is one established by a simple mmap() or brk() with no driver > + * or other kernel component involved. > + * > + * They are rmappable, and core mm services rmap operations including reclaim, > + * as well as population, CoW and merge/split (if eligible). > + * > + * Mappings which fail this test are those where this is not the case - > + * e.g. MMIO, user-mapped kernel pages, udmabuf (pfnmap shmem), etc. > + * > + * Returns: true if the flags indicate an mm-managed mapping. > + */ > +static inline bool vma_flags_is_mm_managed(const vma_flags_t *flags) > +{ > + return !vma_flags_test_any(flags, VMA_PFNMAP_BIT, VMA_MIXEDMAP_BIT, > + VMA_IO_BIT); > +} > + > +/** > + * vma_is_mm_managed() - Are the contents of @vma managed by core mm? > + * @vma: The VMA to test. > + * > + * See vma_flags_is_mm_managed() for a description of this property. > + * > + * Returns: true if the VMA is mm-managed. > + */ > +static inline bool vma_is_mm_managed(const struct vm_area_struct *vma) > +{ > + return vma_flags_is_mm_managed(&vma->flags); > +} > + > /** > * vma_flags_can_merge() - Do the specified VMA flags permit the VMA to be > * merged with another? > @@ -1620,7 +1655,23 @@ static inline bool vma_is_shared_maywrite(const struct vm_area_struct *vma) > */ > static inline bool vma_flags_can_merge(const vma_flags_t *flags) > { > - return !vma_flags_test_any_mask(flags, VMA_SPECIAL_FLAGS); > + /* > + * VMA merging assumes that a VMA's flags and fields completely describe > + * its state. > + * > + * However, mappings which are not mm-managed may have established state > + * upon mapping not embodied in any attribute of the VMA. > + * > + * Additionally, private (CoW) PFN maps encode the source PFN of the > + * range in vma->vm_pgoff, which may otherwise cause spurious merges. > + */ > + if (!vma_flags_is_mm_managed(flags)) > + return false; > + /* VMA explicitly marked as being unmergeable. */ > + if (vma_flags_test(flags, VMA_DONTEXPAND_BIT)) > + return false; > + > + return true; > } > > /** > diff --git a/tools/testing/vma/include/dup.h b/tools/testing/vma/include/dup.h > index a6a8e53c4b38..89c645a6ad60 100644 > --- a/tools/testing/vma/include/dup.h > +++ b/tools/testing/vma/include/dup.h > @@ -1665,7 +1665,34 @@ static inline bool file_is_dev_zero(const struct file *file) > return file && file->f_op == &zero_fops; > } > > +static inline bool vma_flags_is_mm_managed(const vma_flags_t *flags) > +{ > + return !vma_flags_test_any(flags, VMA_PFNMAP_BIT, VMA_MIXEDMAP_BIT, > + VMA_IO_BIT); > +} > + > +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_can_merge(const vma_flags_t *flags) > { > - return !vma_flags_test_any_mask(flags, VMA_SPECIAL_FLAGS); > + /* > + * VMA merging assumes that a VMA's flags and fields completely describe > + * its state. > + * > + * However, mappings which are not mm-managed may have established state > + * upon mapping not embodied in any attribute of the VMA. > + * > + * Additionally, private (CoW) PFN maps encode the source PFN of the > + * range in vma->vm_pgoff, which may otherwise cause spurious merges. > + */ > + if (!vma_flags_is_mm_managed(flags)) > + return false; > + /* VMA explicitly marked as being unmergeable. */ > + if (vma_flags_test(flags, VMA_DONTEXPAND_BIT)) > + return false; > + > + return true; > } > > -- > 2.55.0 >
diff --git a/include/linux/mm.h b/include/linux/mm.h index 97e1eb4fe3a4..83953757735a 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1612,6 +1612,41 @@ static inline bool vma_is_shared_maywrite(const struct vm_area_struct *vma) return is_shared_maywrite(&vma->flags); } +/** + * vma_flags_is_mm_managed() - Do the specified VMA flags indicate that the + * contents of the VMA are managed by core mm? + * @flags: The VMA flags to test. + * + * Such a mapping is one established by a simple mmap() or brk() with no driver + * or other kernel component involved. + * + * They are rmappable, and core mm services rmap operations including reclaim, + * as well as population, CoW and merge/split (if eligible). + * + * Mappings which fail this test are those where this is not the case - + * e.g. MMIO, user-mapped kernel pages, udmabuf (pfnmap shmem), etc. + * + * Returns: true if the flags indicate an mm-managed mapping. + */ +static inline bool vma_flags_is_mm_managed(const vma_flags_t *flags) +{ + return !vma_flags_test_any(flags, VMA_PFNMAP_BIT, VMA_MIXEDMAP_BIT, + VMA_IO_BIT); +} + +/** + * vma_is_mm_managed() - Are the contents of @vma managed by core mm? + * @vma: The VMA to test. + * + * See vma_flags_is_mm_managed() for a description of this property. + * + * Returns: true if the VMA is mm-managed. + */ +static inline bool vma_is_mm_managed(const struct vm_area_struct *vma) +{ + return vma_flags_is_mm_managed(&vma->flags); +} + /** * vma_flags_can_merge() - Do the specified VMA flags permit the VMA to be * merged with another? @@ -1620,7 +1655,23 @@ static inline bool vma_is_shared_maywrite(const struct vm_area_struct *vma) */ static inline bool vma_flags_can_merge(const vma_flags_t *flags) { - return !vma_flags_test_any_mask(flags, VMA_SPECIAL_FLAGS); + /* + * VMA merging assumes that a VMA's flags and fields completely describe + * its state. + * + * However, mappings which are not mm-managed may have established state + * upon mapping not embodied in any attribute of the VMA. + * + * Additionally, private (CoW) PFN maps encode the source PFN of the + * range in vma->vm_pgoff, which may otherwise cause spurious merges. + */ + if (!vma_flags_is_mm_managed(flags)) + return false; + /* VMA explicitly marked as being unmergeable. */ + if (vma_flags_test(flags, VMA_DONTEXPAND_BIT)) + return false; + + return true; } /** diff --git a/tools/testing/vma/include/dup.h b/tools/testing/vma/include/dup.h index a6a8e53c4b38..89c645a6ad60 100644 --- a/tools/testing/vma/include/dup.h +++ b/tools/testing/vma/include/dup.h @@ -1665,7 +1665,34 @@ static inline bool file_is_dev_zero(const struct file *file) return file && file->f_op == &zero_fops; } +static inline bool vma_flags_is_mm_managed(const vma_flags_t *flags) +{ + return !vma_flags_test_any(flags, VMA_PFNMAP_BIT, VMA_MIXEDMAP_BIT, + VMA_IO_BIT); +} + +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_can_merge(const vma_flags_t *flags) { - return !vma_flags_test_any_mask(flags, VMA_SPECIAL_FLAGS); + /* + * VMA merging assumes that a VMA's flags and fields completely describe + * its state. + * + * However, mappings which are not mm-managed may have established state + * upon mapping not embodied in any attribute of the VMA. + * + * Additionally, private (CoW) PFN maps encode the source PFN of the + * range in vma->vm_pgoff, which may otherwise cause spurious merges. + */ + if (!vma_flags_is_mm_managed(flags)) + return false; + /* VMA explicitly marked as being unmergeable. */ + if (vma_flags_test(flags, VMA_DONTEXPAND_BIT)) + return false; + + return true; }