Skip to contentSkip to conversation

initial work on making VMA flags a bitmap

PATCH Superseded Lorenzo Stoakes 5 participants 23 messages Nov 14, 2025 – Nov 25, 2025

Subsystems (11)

v2 of 3 Superseded 3 of 4 applied Latest is v3 →

lore
Share & tools
lore
#0 lore raw

v2 cover initial work on making VMA flags a bitmap

We are in the rather silly situation that we are running out of VMA flags as they are currently limited to a system word in size.

This leads to absurd situations where we limit features to 64-bit architectures only because we simply do not have the ability to add a flag for 32-bit ones.

This is very constraining and leads to hacks or, in the worst case, simply an inability to implement features we want for entirely arbitrary reasons.

This also of course gives us something of a Y2K type situation in mm where we might eventually exhaust all of the VMA flags even on 64-bit systems.

This series lays the groundwork for getting away from this limitation by establishing VMA flags as a bitmap whose size we can increase in future beyond 64 bits if required.

This is necessarily a highly iterative process given the extensive use of VMA flags throughout the kernel, so we start by performing basic steps.

Firstly, we declare VMA flags by bit number rather than by value, retaining the VM_xxx fields but in terms of these newly introduced VMA_xxx_BIT fields.

While we are here, we use sparse annotations to ensure that, when dealing with VMA bit number parameters, we cannot be passed values which are not declared as such - providing some useful type safety.

We then introduce an opaque VMA flag type, much like the opaque mm_struct flag type introduced in commit bb6525f2f8c4 ("mm: add bitmap mm->flags field"), which we establish in union with vma->vm_flags (but still set at system word size meaning there is no functional or data type size change).

We update the vm_flags_xxx() helpers to use this new bitmap, introducing sensible helpers to do so.

This series lays the foundation for further work to expand the use of bitmap VMA flags and eventually eliminate these arbitrary restrictions.

v2:
* Corrected kdoc for vma_flag_t.
* Introduced DECLARE_VMA_BIT() as per Jason. We can't also declare the VMA flags in the enum as this breaks assumptions in the kernel, resulting in errors like 'enum constant in boolean context [-Werror=int-in-bool-context]'.
* Dropped the conversion patch - To make life simpler this cycle, let's just fixup the flag declarations and introduce the new field type and introduce vm_flags_*() changes. We can do more later.
* Split out VMA testing vma->__vm_flags change.
* Fixed vma_flag_*_atomic() helper functions for sparse purposes to work with vma_flag_t.
* Fixed rust breakages as reported by Nico and help provided by Alice. For now we are doing a minimal fix, we can do a more substantial one once the VMA flag helper functions are introduced in an upcoming series.

v1:
https://lore.kernel.org/all/[email protected]/

Lorenzo Stoakes (4):
mm: declare VMA flags by bit
mm: simplify and rename mm flags function for clarity tools/testing/vma: eliminate dependency on vma->__vm_flags
mm: introduce VMA flags bitmap type

 fs/proc/task_mmu.c               |   4 +-
 include/linux/mm.h               | 400 +++++++++++++++------------
 include/linux/mm_types.h         |  78 +++++-
 kernel/fork.c                    |   4 +-
 mm/khugepaged.c                  |   2 +-
 mm/madvise.c                     |   2 +-
 rust/bindings/bindings_helper.h  |  25 ++
 rust/kernel/mm/virt.rs           |   2 +-
 tools/testing/vma/vma.c          |  20 +-
 tools/testing/vma/vma_internal.h | 446 ++++++++++++++++++++++++++-----
 10 files changed, 716 insertions(+), 267 deletions(-)

--
2.51.0

#1 lore raw

PATCH v2 1/4 mm: declare VMA flags by bit

In order to lay the groundwork for VMA flags being a bitmap rather than a system word in size, we need to be able to consistently refer to VMA flags by bit number rather than value.

Take this opportunity to do so in an enum which we which is additionally useful for tooling to extract metadata from.

This additionally makes it very clear which bits are being used for what at a glance.

We use the VMA_ prefix for the bit values as it is logical to do so since these reference VMAs. We consistently suffix with _BIT to make it clear what the values refer to.

We declare bit values even when the flags that use them would not be enabled by config options as this is simply clearer and clearly defines what bit numbers are used for what, at no additional cost.

We declare a sparse-bitwise type vma_flag_t which ensures that users can't pass around invalid VMA flags by accident and prepares for future work towards VMA flags being a bitmap where we want to ensure bit values are type safe.

To make life easier, we declare some macro helpers - DECLARE_VMA_BIT() allows us to avoid duplication in the enum bit number declarations (and maintaining the sparse __bitwise attribute), and INIT_VM_FLAG() is used to assist with declaration of flags.

Unfortunately we can't declare both in the enum, as we run into issue with logic in the kernel requiring that flags are preprocessor definitions, and additionally we cannot have a macro which declares another macro so we must define each flag macro directly.

Additionally, update the VMA userland testing vma_internal.h header to include these changes.

We also have to fix the parameters to the vma_flag_*_atomic() functions since VMA_MAYBE_GUARD_BIT is now of type vma_flag_t and sparse will complain otherwise.

We have to update some rather silly if-deffery found in mm/task_mmu.c which would otherwise break.

Finally, we update the rust binding helper as now it cannot auto-detect the flags at all.

---
 fs/proc/task_mmu.c               |   4 +-
 include/linux/mm.h               | 384 +++++++++++++++++--------------
 mm/khugepaged.c                  |   2 +-
 mm/madvise.c                     |   2 +-
 rust/bindings/bindings_helper.h  |  25 ++
 tools/testing/vma/vma_internal.h | 303 ++++++++++++++++++++----
 6 files changed, 504 insertions(+), 216 deletions(-)
fs/proc/task_mmu.c +2 -2
index 41b062ce6ad8..720d70623209 100644
@@ -1183,10 +1183,10 @@ static void show_smap_vma_flags(struct seq_file *m, struct vm_area_struct *vma)
 		[ilog2(VM_PKEY_BIT0)]	= "",
 		[ilog2(VM_PKEY_BIT1)]	= "",
 		[ilog2(VM_PKEY_BIT2)]	= "",
-#if VM_PKEY_BIT3
+#if CONFIG_ARCH_PKEY_BITS > 3
 		[ilog2(VM_PKEY_BIT3)]	= "",
 #endif
-#if VM_PKEY_BIT4
+#if CONFIG_ARCH_PKEY_BITS > 4
 		[ilog2(VM_PKEY_BIT4)]	= "",
 #endif
 #endif /* CONFIG_ARCH_HAS_PKEYS */
include/linux/mm.h +217 -167

477 lines not on this page · raw message

mm/khugepaged.c +1 -1
index 7e8cb181d5bd..746cb16f6466 100644
@@ -1742,7 +1742,7 @@ static bool file_backed_vma_is_retractable(struct vm_area_struct *vma)
 	 * obtained on guard region installation after the flag is set, so this
 	 * check being performed under this lock excludes races.
 	 */
-	if (vma_flag_test_atomic(vma, VM_MAYBE_GUARD_BIT))
+	if (vma_flag_test_atomic(vma, VMA_MAYBE_GUARD_BIT))
 		return false;
 
 	return true;
mm/madvise.c +1 -1
index 52a10ed80c07..84fc0e63011f 100644
@@ -1142,7 +1142,7 @@ static long madvise_guard_install(struct madvise_behavior *madv_behavior)
 	 * acquire an mmap/VMA write lock to read it. All remaining readers may
 	 * or may not see the flag set, but we don't care.
 	 */
-	vma_flag_set_atomic(vma, VM_MAYBE_GUARD_BIT);
+	vma_flag_set_atomic(vma, VMA_MAYBE_GUARD_BIT);
 
 	/*
 	 * If anonymous and we are establishing page tables the VMA ought to
rust/bindings/bindings_helper.h +25 -0
index 2e43c66635a2..4c327db01ca0 100644
@@ -108,7 +108,32 @@ const xa_mark_t RUST_CONST_HELPER_XA_PRESENT = XA_PRESENT;
 
 const gfp_t RUST_CONST_HELPER_XA_FLAGS_ALLOC = XA_FLAGS_ALLOC;
 const gfp_t RUST_CONST_HELPER_XA_FLAGS_ALLOC1 = XA_FLAGS_ALLOC1;
+
 const vm_flags_t RUST_CONST_HELPER_VM_MERGEABLE = VM_MERGEABLE;
+const vm_flags_t RUST_CONST_HELPER_VM_READ = VM_READ;
+const vm_flags_t RUST_CONST_HELPER_VM_WRITE = VM_WRITE;
+const vm_flags_t RUST_CONST_HELPER_VM_EXEC = VM_EXEC;
+const vm_flags_t RUST_CONST_HELPER_VM_SHARED = VM_SHARED;
+const vm_flags_t RUST_CONST_HELPER_VM_MAYREAD = VM_MAYREAD;
+const vm_flags_t RUST_CONST_HELPER_VM_MAYWRITE = VM_MAYWRITE;
+const vm_flags_t RUST_CONST_HELPER_VM_MAYEXEC = VM_MAYEXEC;
+const vm_flags_t RUST_CONST_HELPER_VM_MAYSHARE = VM_MAYEXEC;
+const vm_flags_t RUST_CONST_HELPER_VM_PFNMAP = VM_PFNMAP;
+const vm_flags_t RUST_CONST_HELPER_VM_IO = VM_IO;
+const vm_flags_t RUST_CONST_HELPER_VM_DONTCOPY = VM_DONTCOPY;
+const vm_flags_t RUST_CONST_HELPER_VM_DONTEXPAND = VM_DONTEXPAND;
+const vm_flags_t RUST_CONST_HELPER_VM_LOCKONFAULT = VM_LOCKONFAULT;
+const vm_flags_t RUST_CONST_HELPER_VM_ACCOUNT = VM_ACCOUNT;
+const vm_flags_t RUST_CONST_HELPER_VM_NORESERVE = VM_NORESERVE;
+const vm_flags_t RUST_CONST_HELPER_VM_HUGETLB = VM_HUGETLB;
+const vm_flags_t RUST_CONST_HELPER_VM_SYNC = VM_SYNC;
+const vm_flags_t RUST_CONST_HELPER_VM_ARCH_1 = VM_ARCH_1;
+const vm_flags_t RUST_CONST_HELPER_VM_WIPEONFORK = VM_WIPEONFORK;
+const vm_flags_t RUST_CONST_HELPER_VM_DONTDUMP = VM_DONTDUMP;
+const vm_flags_t RUST_CONST_HELPER_VM_SOFTDIRTY = VM_SOFTDIRTY;
+const vm_flags_t RUST_CONST_HELPER_VM_MIXEDMAP = VM_MIXEDMAP;
+const vm_flags_t RUST_CONST_HELPER_VM_HUGEPAGE = VM_HUGEPAGE;
+const vm_flags_t RUST_CONST_HELPER_VM_NOHUGEPAGE = VM_NOHUGEPAGE;
 
 #if IS_ENABLED(CONFIG_ANDROID_BINDER_IPC_RUST)
 #include "../../drivers/android/binder/rust_binder.h"
tools/testing/vma/vma_internal.h +258 -45

326 lines not on this page · raw message

Signature · 1 line
2.51.0
maintainer
#2 lore raw

Re: [PATCH v2 1/4] mm: declare VMA flags by bit

Quoted 24 lines · Lorenzo Stoakes
rust/bindings/bindings_helper.h +15 -0
index 2e43c66635a2..4c327db01ca0 100644
@@ -108,7 +108,32 @@ const xa_mark_t RUST_CONST_HELPER_XA_PRESENT = XA_PRESENT;
 
 const gfp_t RUST_CONST_HELPER_XA_FLAGS_ALLOC = XA_FLAGS_ALLOC;
 const gfp_t RUST_CONST_HELPER_XA_FLAGS_ALLOC1 = XA_FLAGS_ALLOC1;
+
 const vm_flags_t RUST_CONST_HELPER_VM_MERGEABLE = VM_MERGEABLE;
+const vm_flags_t RUST_CONST_HELPER_VM_READ = VM_READ;
+const vm_flags_t RUST_CONST_HELPER_VM_WRITE = VM_WRITE;
+const vm_flags_t RUST_CONST_HELPER_VM_EXEC = VM_EXEC;
+const vm_flags_t RUST_CONST_HELPER_VM_SHARED = VM_SHARED;
+const vm_flags_t RUST_CONST_HELPER_VM_MAYREAD = VM_MAYREAD;
+const vm_flags_t RUST_CONST_HELPER_VM_MAYWRITE = VM_MAYWRITE;
+const vm_flags_t RUST_CONST_HELPER_VM_MAYEXEC = VM_MAYEXEC;
+const vm_flags_t RUST_CONST_HELPER_VM_MAYSHARE = VM_MAYEXEC;
+const vm_flags_t RUST_CONST_HELPER_VM_PFNMAP = VM_PFNMAP;
+const vm_flags_t RUST_CONST_HELPER_VM_IO = VM_IO;
+const vm_flags_t RUST_CONST_HELPER_VM_DONTCOPY = VM_DONTCOPY;
+const vm_flags_t RUST_CONST_HELPER_VM_DONTEXPAND = VM_DONTEXPAND;
+const vm_flags_t RUST_CONST_HELPER_VM_LOCKONFAULT = VM_LOCKONFAULT;
+const vm_flags_t RUST_CONST_HELPER_VM_ACCOUNT = VM_ACCOUNT;

rust/bindings/bindings_helper.h const xa_mark_t RUST_CONST_HELPER_XA_PRESENT = XA_PRESENT; · line 136

Quoted 10 lines
rust/bindings/bindings_helper.h +10 -0
+const vm_flags_t RUST_CONST_HELPER_VM_NORESERVE = VM_NORESERVE;
+const vm_flags_t RUST_CONST_HELPER_VM_HUGETLB = VM_HUGETLB;
+const vm_flags_t RUST_CONST_HELPER_VM_SYNC = VM_SYNC;
+const vm_flags_t RUST_CONST_HELPER_VM_ARCH_1 = VM_ARCH_1;
+const vm_flags_t RUST_CONST_HELPER_VM_WIPEONFORK = VM_WIPEONFORK;
+const vm_flags_t RUST_CONST_HELPER_VM_DONTDUMP = VM_DONTDUMP;
+const vm_flags_t RUST_CONST_HELPER_VM_SOFTDIRTY = VM_SOFTDIRTY;
+const vm_flags_t RUST_CONST_HELPER_VM_MIXEDMAP = VM_MIXEDMAP;
+const vm_flags_t RUST_CONST_HELPER_VM_HUGEPAGE = VM_HUGEPAGE;
+const vm_flags_t RUST_CONST_HELPER_VM_NOHUGEPAGE = VM_NOHUGEPAGE;

I got this error:

error[E0428]: the name VM_SOFTDIRTY is defined multiple times

      --> rust/bindings/bindings_generated.rs:115967:1
       |
13440  | pub const VM_SOFTDIRTY: u32 = 0;
       | -------------------------------- previous definition of the value `VM_SOFTDIRTY` here
...
115967 | pub const VM_SOFTDIRTY: vm_flags_t = 0;
       | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `VM_SOFTDIRTY` redefined here
       |

= note: VM_SOFTDIRTY must be defined only once in the value namespace of this module

Please add the constants in rust/bindgen_parameters next to ARCH_KMALLOC_MINALIGN to avoid this error. This ensures that only the version from bindings_helper.h is generated.

Alice

#3 lore raw

Re: [PATCH v2 1/4] mm: declare VMA flags by bit

Quoted 47 lines · Alice Ryhl
Quoted 24 lines · Lorenzo Stoakes
rust/bindings/bindings_helper.h +15 -0
index 2e43c66635a2..4c327db01ca0 100644
@@ -108,7 +108,32 @@ const xa_mark_t RUST_CONST_HELPER_XA_PRESENT = XA_PRESENT;
 
 const gfp_t RUST_CONST_HELPER_XA_FLAGS_ALLOC = XA_FLAGS_ALLOC;
 const gfp_t RUST_CONST_HELPER_XA_FLAGS_ALLOC1 = XA_FLAGS_ALLOC1;
+
 const vm_flags_t RUST_CONST_HELPER_VM_MERGEABLE = VM_MERGEABLE;
+const vm_flags_t RUST_CONST_HELPER_VM_READ = VM_READ;
+const vm_flags_t RUST_CONST_HELPER_VM_WRITE = VM_WRITE;
+const vm_flags_t RUST_CONST_HELPER_VM_EXEC = VM_EXEC;
+const vm_flags_t RUST_CONST_HELPER_VM_SHARED = VM_SHARED;
+const vm_flags_t RUST_CONST_HELPER_VM_MAYREAD = VM_MAYREAD;
+const vm_flags_t RUST_CONST_HELPER_VM_MAYWRITE = VM_MAYWRITE;
+const vm_flags_t RUST_CONST_HELPER_VM_MAYEXEC = VM_MAYEXEC;
+const vm_flags_t RUST_CONST_HELPER_VM_MAYSHARE = VM_MAYEXEC;
+const vm_flags_t RUST_CONST_HELPER_VM_PFNMAP = VM_PFNMAP;
+const vm_flags_t RUST_CONST_HELPER_VM_IO = VM_IO;
+const vm_flags_t RUST_CONST_HELPER_VM_DONTCOPY = VM_DONTCOPY;
+const vm_flags_t RUST_CONST_HELPER_VM_DONTEXPAND = VM_DONTEXPAND;
+const vm_flags_t RUST_CONST_HELPER_VM_LOCKONFAULT = VM_LOCKONFAULT;
+const vm_flags_t RUST_CONST_HELPER_VM_ACCOUNT = VM_ACCOUNT;

rust/bindings/bindings_helper.h const xa_mark_t RUST_CONST_HELPER_XA_PRESENT = XA_PRESENT; · line 136

Quoted 10 lines
rust/bindings/bindings_helper.h +10 -0
+const vm_flags_t RUST_CONST_HELPER_VM_NORESERVE = VM_NORESERVE;
+const vm_flags_t RUST_CONST_HELPER_VM_HUGETLB = VM_HUGETLB;
+const vm_flags_t RUST_CONST_HELPER_VM_SYNC = VM_SYNC;
+const vm_flags_t RUST_CONST_HELPER_VM_ARCH_1 = VM_ARCH_1;
+const vm_flags_t RUST_CONST_HELPER_VM_WIPEONFORK = VM_WIPEONFORK;
+const vm_flags_t RUST_CONST_HELPER_VM_DONTDUMP = VM_DONTDUMP;
+const vm_flags_t RUST_CONST_HELPER_VM_SOFTDIRTY = VM_SOFTDIRTY;
+const vm_flags_t RUST_CONST_HELPER_VM_MIXEDMAP = VM_MIXEDMAP;
+const vm_flags_t RUST_CONST_HELPER_VM_HUGEPAGE = VM_HUGEPAGE;
+const vm_flags_t RUST_CONST_HELPER_VM_NOHUGEPAGE = VM_NOHUGEPAGE;

I got this error:

error[E0428]: the name VM_SOFTDIRTY is defined multiple times

      --> rust/bindings/bindings_generated.rs:115967:1
       |
13440  | pub const VM_SOFTDIRTY: u32 = 0;
       | -------------------------------- previous definition of the value `VM_SOFTDIRTY` here
...
115967 | pub const VM_SOFTDIRTY: vm_flags_t = 0;
       | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `VM_SOFTDIRTY` redefined here
       |
Quoted 2 lines

= note: VM_SOFTDIRTY must be defined only once in the value namespace of this module

That's odd, obviously I build tested this and didn't get the same error.

Be good to know what config options to enable for testing for rust. I repro'd the previously reported issues, and new ones since I'm now declaring these values consistently using BIT().

But in my build locally, no errors with LLVM=1 and CONFIG_RUST=y.

Quoted 3 lines

Please add the constants in rust/bindgen_parameters next to ARCH_KMALLOC_MINALIGN to avoid this error. This ensures that only the version from bindings_helper.h is generated.

As in

--block-list-item <VM_blah> for every flag?

Quoted 2 lines

Alice

Thanks, Lorenzo

maintainer
#4 lore raw

Re: [PATCH v2 1/4] mm: declare VMA flags by bit

Quoted 52 lines · Lorenzo Stoakes
Quoted 47 lines · Alice Ryhl
Quoted 24 lines · Lorenzo Stoakes
rust/bindings/bindings_helper.h +15 -0
index 2e43c66635a2..4c327db01ca0 100644
@@ -108,7 +108,32 @@ const xa_mark_t RUST_CONST_HELPER_XA_PRESENT = XA_PRESENT;
 
 const gfp_t RUST_CONST_HELPER_XA_FLAGS_ALLOC = XA_FLAGS_ALLOC;
 const gfp_t RUST_CONST_HELPER_XA_FLAGS_ALLOC1 = XA_FLAGS_ALLOC1;
+
 const vm_flags_t RUST_CONST_HELPER_VM_MERGEABLE = VM_MERGEABLE;
+const vm_flags_t RUST_CONST_HELPER_VM_READ = VM_READ;
+const vm_flags_t RUST_CONST_HELPER_VM_WRITE = VM_WRITE;
+const vm_flags_t RUST_CONST_HELPER_VM_EXEC = VM_EXEC;
+const vm_flags_t RUST_CONST_HELPER_VM_SHARED = VM_SHARED;
+const vm_flags_t RUST_CONST_HELPER_VM_MAYREAD = VM_MAYREAD;
+const vm_flags_t RUST_CONST_HELPER_VM_MAYWRITE = VM_MAYWRITE;
+const vm_flags_t RUST_CONST_HELPER_VM_MAYEXEC = VM_MAYEXEC;
+const vm_flags_t RUST_CONST_HELPER_VM_MAYSHARE = VM_MAYEXEC;
+const vm_flags_t RUST_CONST_HELPER_VM_PFNMAP = VM_PFNMAP;
+const vm_flags_t RUST_CONST_HELPER_VM_IO = VM_IO;
+const vm_flags_t RUST_CONST_HELPER_VM_DONTCOPY = VM_DONTCOPY;
+const vm_flags_t RUST_CONST_HELPER_VM_DONTEXPAND = VM_DONTEXPAND;
+const vm_flags_t RUST_CONST_HELPER_VM_LOCKONFAULT = VM_LOCKONFAULT;
+const vm_flags_t RUST_CONST_HELPER_VM_ACCOUNT = VM_ACCOUNT;

rust/bindings/bindings_helper.h const xa_mark_t RUST_CONST_HELPER_XA_PRESENT = XA_PRESENT; · line 136

Quoted 10 lines
rust/bindings/bindings_helper.h +10 -0
+const vm_flags_t RUST_CONST_HELPER_VM_NORESERVE = VM_NORESERVE;
+const vm_flags_t RUST_CONST_HELPER_VM_HUGETLB = VM_HUGETLB;
+const vm_flags_t RUST_CONST_HELPER_VM_SYNC = VM_SYNC;
+const vm_flags_t RUST_CONST_HELPER_VM_ARCH_1 = VM_ARCH_1;
+const vm_flags_t RUST_CONST_HELPER_VM_WIPEONFORK = VM_WIPEONFORK;
+const vm_flags_t RUST_CONST_HELPER_VM_DONTDUMP = VM_DONTDUMP;
+const vm_flags_t RUST_CONST_HELPER_VM_SOFTDIRTY = VM_SOFTDIRTY;
+const vm_flags_t RUST_CONST_HELPER_VM_MIXEDMAP = VM_MIXEDMAP;
+const vm_flags_t RUST_CONST_HELPER_VM_HUGEPAGE = VM_HUGEPAGE;
+const vm_flags_t RUST_CONST_HELPER_VM_NOHUGEPAGE = VM_NOHUGEPAGE;

I got this error:

error[E0428]: the name VM_SOFTDIRTY is defined multiple times

      --> rust/bindings/bindings_generated.rs:115967:1
       |
13440  | pub const VM_SOFTDIRTY: u32 = 0;
       | -------------------------------- previous definition of the value `VM_SOFTDIRTY` here
...
115967 | pub const VM_SOFTDIRTY: vm_flags_t = 0;
       | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `VM_SOFTDIRTY` redefined here
       |
Quoted 2 lines

= note: VM_SOFTDIRTY must be defined only once in the value namespace of this module

Quoted 7 lines

That's odd, obviously I build tested this and didn't get the same error.

Be good to know what config options to enable for testing for rust. I repro'd the previously reported issues, and new ones since I'm now declaring these values consistently using BIT().

But in my build locally, no errors with LLVM=1 and CONFIG_RUST=y.

I got this error because my config defines VM_SOFTDIRTY as VM_NONE, which bindgen can resolve to zero. You probably have a config where it's defined using a function-like macro, so bindgen did not generate a duplicate for you.

Quoted 7 lines
Quoted 3 lines

Please add the constants in rust/bindgen_parameters next to ARCH_KMALLOC_MINALIGN to avoid this error. This ensures that only the version from bindings_helper.h is generated.

As in

--block-list-item <VM_blah> for every flag?

Yes.

Alice

#5 lore raw

Re: [PATCH v2 1/4] mm: declare VMA flags by bit

Quoted 60 lines · Alice Ryhl
Quoted 58 lines · Lorenzo Stoakes
Quoted 47 lines · Alice Ryhl
Quoted 24 lines · Lorenzo Stoakes
rust/bindings/bindings_helper.h +15 -0
index 2e43c66635a2..4c327db01ca0 100644
@@ -108,7 +108,32 @@ const xa_mark_t RUST_CONST_HELPER_XA_PRESENT = XA_PRESENT;
 
 const gfp_t RUST_CONST_HELPER_XA_FLAGS_ALLOC = XA_FLAGS_ALLOC;
 const gfp_t RUST_CONST_HELPER_XA_FLAGS_ALLOC1 = XA_FLAGS_ALLOC1;
+
 const vm_flags_t RUST_CONST_HELPER_VM_MERGEABLE = VM_MERGEABLE;
+const vm_flags_t RUST_CONST_HELPER_VM_READ = VM_READ;
+const vm_flags_t RUST_CONST_HELPER_VM_WRITE = VM_WRITE;
+const vm_flags_t RUST_CONST_HELPER_VM_EXEC = VM_EXEC;
+const vm_flags_t RUST_CONST_HELPER_VM_SHARED = VM_SHARED;
+const vm_flags_t RUST_CONST_HELPER_VM_MAYREAD = VM_MAYREAD;
+const vm_flags_t RUST_CONST_HELPER_VM_MAYWRITE = VM_MAYWRITE;
+const vm_flags_t RUST_CONST_HELPER_VM_MAYEXEC = VM_MAYEXEC;
+const vm_flags_t RUST_CONST_HELPER_VM_MAYSHARE = VM_MAYEXEC;
+const vm_flags_t RUST_CONST_HELPER_VM_PFNMAP = VM_PFNMAP;
+const vm_flags_t RUST_CONST_HELPER_VM_IO = VM_IO;
+const vm_flags_t RUST_CONST_HELPER_VM_DONTCOPY = VM_DONTCOPY;
+const vm_flags_t RUST_CONST_HELPER_VM_DONTEXPAND = VM_DONTEXPAND;
+const vm_flags_t RUST_CONST_HELPER_VM_LOCKONFAULT = VM_LOCKONFAULT;
+const vm_flags_t RUST_CONST_HELPER_VM_ACCOUNT = VM_ACCOUNT;

rust/bindings/bindings_helper.h const xa_mark_t RUST_CONST_HELPER_XA_PRESENT = XA_PRESENT; · line 136

Quoted 10 lines
rust/bindings/bindings_helper.h +10 -0
+const vm_flags_t RUST_CONST_HELPER_VM_NORESERVE = VM_NORESERVE;
+const vm_flags_t RUST_CONST_HELPER_VM_HUGETLB = VM_HUGETLB;
+const vm_flags_t RUST_CONST_HELPER_VM_SYNC = VM_SYNC;
+const vm_flags_t RUST_CONST_HELPER_VM_ARCH_1 = VM_ARCH_1;
+const vm_flags_t RUST_CONST_HELPER_VM_WIPEONFORK = VM_WIPEONFORK;
+const vm_flags_t RUST_CONST_HELPER_VM_DONTDUMP = VM_DONTDUMP;
+const vm_flags_t RUST_CONST_HELPER_VM_SOFTDIRTY = VM_SOFTDIRTY;
+const vm_flags_t RUST_CONST_HELPER_VM_MIXEDMAP = VM_MIXEDMAP;
+const vm_flags_t RUST_CONST_HELPER_VM_HUGEPAGE = VM_HUGEPAGE;
+const vm_flags_t RUST_CONST_HELPER_VM_NOHUGEPAGE = VM_NOHUGEPAGE;

I got this error:

error[E0428]: the name VM_SOFTDIRTY is defined multiple times

      --> rust/bindings/bindings_generated.rs:115967:1
       |
13440  | pub const VM_SOFTDIRTY: u32 = 0;
       | -------------------------------- previous definition of the value `VM_SOFTDIRTY` here
...
115967 | pub const VM_SOFTDIRTY: vm_flags_t = 0;
       | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `VM_SOFTDIRTY` redefined here
       |
Quoted 2 lines

= note: VM_SOFTDIRTY must be defined only once in the value namespace of this module

That's odd, obviously I build tested this and didn't get the same error.

Be good to know what config options to enable for testing for rust. I repro'd the previously reported issues, and new ones since I'm now declaring these values consistently using BIT().

Quoted 6 lines
Quoted 1 line

But in my build locally, no errors with LLVM=1 and CONFIG_RUST=y.

I got this error because my config defines VM_SOFTDIRTY as VM_NONE, which bindgen can resolve to zero. You probably have a config where it's defined using a function-like macro, so bindgen did not generate a duplicate for you.

Ugh yeah of course, damn.

Quoted 10 lines
Quoted 8 lines
Quoted 4 lines

Please add the constants in rust/bindgen_parameters next to ARCH_KMALLOC_MINALIGN to avoid this error. This ensures that only the version from bindings_helper.h is generated.

As in

--block-list-item <VM_blah> for every flag?

Yes.

OK will send a fixpatch, better to add them all to be safe.

Bit ugly but we can fix this up later when I add in the actual accessor helpers.

Quoted 3 lines

Alice

Thanks, Lorenzo

#6 lore raw

Re: [PATCH v2 1/4] mm: declare VMA flags by bit

In reply to Lorenzo Stoakes

Hi Andrew,

Please apply this fix-patch to solve an issue with the patch accidentally causing duplication in rust bindgen when a VMA flag resolves to something bindgen can generate itself.

To fix it, we simply blacklist all the VMA flags used by rust from bindgen auto-generating.

I repro'd the issue locally thanks to Alice for reporting and giving insight into the issue + explaining how to fix it! :)

Thanks, Lorenzo

----8<----
From f441480340ff608869f3655b2371ca70c77eb82b Mon Sep 17 00:00:00 2001
From: Lorenzo Stoakes <[email protected]>
Date: Fri, 14 Nov 2025 14:19:04 +0000
Subject: [PATCH] fixup

---
 rust/bindgen_parameters | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)
rust/bindgen_parameters +25 -0
index e13c6f9dd17b..fd2fd1c3cb9a 100644
@@ -35,6 +35,31 @@
 # recognized, block generation of the non-helper constants.
 --blocklist-item ARCH_SLAB_MINALIGN
 --blocklist-item ARCH_KMALLOC_MINALIGN
+--blocklist-item VM_MERGEABLE
+--blocklist-item VM_READ
+--blocklist-item VM_WRITE
+--blocklist-item VM_EXEC
+--blocklist-item VM_SHARED
+--blocklist-item VM_MAYREAD
+--blocklist-item VM_MAYWRITE
+--blocklist-item VM_MAYEXEC
+--blocklist-item VM_MAYEXEC
+--blocklist-item VM_PFNMAP
+--blocklist-item VM_IO
+--blocklist-item VM_DONTCOPY
+--blocklist-item VM_DONTEXPAND
+--blocklist-item VM_LOCKONFAULT
+--blocklist-item VM_ACCOUNT
+--blocklist-item VM_NORESERVE
+--blocklist-item VM_HUGETLB
+--blocklist-item VM_SYNC
+--blocklist-item VM_ARCH_1
+--blocklist-item VM_WIPEONFORK
+--blocklist-item VM_DONTDUMP
+--blocklist-item VM_SOFTDIRTY
+--blocklist-item VM_MIXEDMAP
+--blocklist-item VM_HUGEPAGE
+--blocklist-item VM_NOHUGEPAGE
 
 # Structs should implement `Zeroable` when all of their fields do.
 --with-derive-custom-struct .*=MaybeZeroable

--
2.51.0

#7 lore raw

Re: [PATCH v2 1/4] mm: declare VMA flags by bit

In reply to Lorenzo Stoakes
kernel test robot noticed the following build errors:

Hi Lorenzo,

kernel test robot noticed the following build errors:

[auto build test ERROR on akpm-mm/mm-everything]
[also build test ERROR on next-20251114]
[cannot apply to rust/rust-next tip/sched/core brauner-vfs/vfs.all kees/for-next/execve linus/master v6.18-rc5] [If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Lorenzo-Stoakes/mm-declare-VMA-flags-by-bit/20251114-213237
base:   https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git mm-everything
patch link:    https://lore.kernel.org/r/6289d60b6731ea7a111c87c87fb8486881151c25.1763126447.git.lorenzo.stoakes%40oracle.com
patch subject: [PATCH v2 1/4] mm: declare VMA flags by bit
config: m68k-allnoconfig (https://download.01.org/0day-ci/archive/20251114/[email protected]/config)
compiler: m68k-linux-gcc (GCC) 15.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251114/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All errors (new ones prefixed by >>):

In file included from kernel/sched/sched.h:46,
from kernel/sched/rq-offsets.c:5:
include/linux/mm.h: In function 'is_nommu_shared_mapping':

>> include/linux/mm.h:1734:39: error: 'VM_MAYOVERLAY' undeclared (first use in this function); did you mean 'VMA_MAYOVERLAY_BIT'?
    1734 |         return flags & (VM_MAYSHARE | VM_MAYOVERLAY);
         |                                       ^~~~~~~~~~~~~
         |                                       VMA_MAYOVERLAY_BIT

include/linux/mm.h:1734:39: note: each undeclared identifier is reported only once for each function it appears in make[3]: *** [scripts/Makefile.build:182: kernel/sched/rq-offsets.s] Error 1
make[3]: Target 'prepare' not remade because of errors.
make[2]: *** [Makefile:1280: prepare0] Error 2
make[2]: Target 'prepare' not remade because of errors.
make[1]: *** [Makefile:248: __sub-make] Error 2
make[1]: Target 'prepare' not remade because of errors.
make: *** [Makefile:248: __sub-make] Error 2
make: Target 'prepare' not remade because of errors.

vim +1734 include/linux/mm.h

97a7e4733b9b22 Peter Xu          2021-03-12  1722  
fc4f4be9b5271e David Hildenbrand 2023-01-02  1723  #ifndef CONFIG_MMU
fc4f4be9b5271e David Hildenbrand 2023-01-02  1724  static inline bool is_nommu_shared_mapping(vm_flags_t flags)
fc4f4be9b5271e David Hildenbrand 2023-01-02  1725  {
fc4f4be9b5271e David Hildenbrand 2023-01-02  1726  	/*
fc4f4be9b5271e David Hildenbrand 2023-01-02  1727  	 * NOMMU shared mappings are ordinary MAP_SHARED mappings and selected
fc4f4be9b5271e David Hildenbrand 2023-01-02  1728  	 * R/O MAP_PRIVATE file mappings that are an effective R/O overlay of
fc4f4be9b5271e David Hildenbrand 2023-01-02  1729  	 * a file mapping. R/O MAP_PRIVATE mappings might still modify
fc4f4be9b5271e David Hildenbrand 2023-01-02  1730  	 * underlying memory if ptrace is active, so this is only possible if
fc4f4be9b5271e David Hildenbrand 2023-01-02  1731  	 * ptrace does not apply. Note that there is no mprotect() to upgrade
fc4f4be9b5271e David Hildenbrand 2023-01-02  1732  	 * write permissions later.
fc4f4be9b5271e David Hildenbrand 2023-01-02  1733  	 */
b6b7a8faf05c70 David Hildenbrand 2023-01-02 @1734  	return flags & (VM_MAYSHARE | VM_MAYOVERLAY);
fc4f4be9b5271e David Hildenbrand 2023-01-02  1735  }
fc4f4be9b5271e David Hildenbrand 2023-01-02  1736  #endif

fc4f4be9b5271e David Hildenbrand 2023-01-02 1737

Signature · 2 lines
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
#8 lore raw

Re: [PATCH v2 1/4] mm: declare VMA flags by bit

In reply to Lorenzo Stoakes
kernel test robot noticed the following build errors:

Hi Lorenzo,

kernel test robot noticed the following build errors:

[auto build test ERROR on akpm-mm/mm-everything]
[also build test ERROR on next-20251114]
[cannot apply to rust/rust-next tip/sched/core brauner-vfs/vfs.all kees/for-next/execve linus/master v6.18-rc5] [If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Lorenzo-Stoakes/mm-declare-VMA-flags-by-bit/20251114-213237
base:   https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git mm-everything
patch link:    https://lore.kernel.org/r/6289d60b6731ea7a111c87c87fb8486881151c25.1763126447.git.lorenzo.stoakes%40oracle.com
patch subject: [PATCH v2 1/4] mm: declare VMA flags by bit
config: arm-allnoconfig (https://download.01.org/0day-ci/archive/20251114/[email protected]/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project 0bba1e76581bad04e7d7f09f5115ae5e2989e0d9)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20251114/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All errors (new ones prefixed by >>):

In file included from arch/arm/kernel/asm-offsets.c:14:

>> include/linux/mm.h:1734:32: error: use of undeclared identifier 'VM_MAYOVERLAY'
    1734 |         return flags & (VM_MAYSHARE | VM_MAYOVERLAY);
         |                                       ^~~~~~~~~~~~~

1 error generated.
make[3]: *** [scripts/Makefile.build:182: arch/arm/kernel/asm-offsets.s] Error 1 make[3]: Target 'prepare' not remade because of errors.
make[2]: *** [Makefile:1280: prepare0] Error 2
make[2]: Target 'prepare' not remade because of errors.
make[1]: *** [Makefile:248: __sub-make] Error 2
make[1]: Target 'prepare' not remade because of errors.
make: *** [Makefile:248: __sub-make] Error 2
make: Target 'prepare' not remade because of errors.

vim +/VM_MAYOVERLAY +1734 include/linux/mm.h

97a7e4733b9b22 Peter Xu          2021-03-12  1722  
fc4f4be9b5271e David Hildenbrand 2023-01-02  1723  #ifndef CONFIG_MMU
fc4f4be9b5271e David Hildenbrand 2023-01-02  1724  static inline bool is_nommu_shared_mapping(vm_flags_t flags)
fc4f4be9b5271e David Hildenbrand 2023-01-02  1725  {
fc4f4be9b5271e David Hildenbrand 2023-01-02  1726  	/*
fc4f4be9b5271e David Hildenbrand 2023-01-02  1727  	 * NOMMU shared mappings are ordinary MAP_SHARED mappings and selected
fc4f4be9b5271e David Hildenbrand 2023-01-02  1728  	 * R/O MAP_PRIVATE file mappings that are an effective R/O overlay of
fc4f4be9b5271e David Hildenbrand 2023-01-02  1729  	 * a file mapping. R/O MAP_PRIVATE mappings might still modify
fc4f4be9b5271e David Hildenbrand 2023-01-02  1730  	 * underlying memory if ptrace is active, so this is only possible if
fc4f4be9b5271e David Hildenbrand 2023-01-02  1731  	 * ptrace does not apply. Note that there is no mprotect() to upgrade
fc4f4be9b5271e David Hildenbrand 2023-01-02  1732  	 * write permissions later.
fc4f4be9b5271e David Hildenbrand 2023-01-02  1733  	 */
b6b7a8faf05c70 David Hildenbrand 2023-01-02 @1734  	return flags & (VM_MAYSHARE | VM_MAYOVERLAY);
fc4f4be9b5271e David Hildenbrand 2023-01-02  1735  }
fc4f4be9b5271e David Hildenbrand 2023-01-02  1736  #endif

fc4f4be9b5271e David Hildenbrand 2023-01-02 1737

Signature · 2 lines
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
#9 lore raw

Re: [PATCH v2 1/4] mm: declare VMA flags by bit

In reply to Lorenzo Stoakes

Hi Andrew,

In typical fashion nommu has caused a problem. Sorry to send a couple in quick succession here, but nommu will nommu... :)

Thanks, Lorenzo

----8<----
From b14b98a2e78a06c6a3ff790bc2c188be94202e30 Mon Sep 17 00:00:00 2001
From: Lorenzo Stoakes <[email protected]>
Date: Fri, 14 Nov 2025 15:32:14 +0000
Subject: [PATCH] nommu fixup

---
 include/linux/mm.h | 1 +
 1 file changed, 1 insertion(+)
include/linux/mm.h +1 -0
index ad000c472bd5..9824211d3d8e 100644
@@ -409,6 +409,7 @@ enum {
 #define VM_UFFD_MISSING	INIT_VM_FLAG(UFFD_MISSING)
 #else
 #define VM_UFFD_MISSING	VM_NONE
+#define VM_MAYOVERLAY	INIT_VM_FLAG(MAYOVERLAY)
 #endif
 #define VM_PFNMAP	INIT_VM_FLAG(PFNMAP)
 #define VM_MAYBE_GUARD	INIT_VM_FLAG(MAYBE_GUARD)

--
2.51.0

#10 lore raw

Re: [PATCH v2 1/4] mm: declare VMA flags by bit

In reply to Lorenzo Stoakes

Hi Andrew,

Sorry to be a pain, seems build bots are sleeping on parisc32/64 as there was some accidental duplication of VM_STACK_EARLY when CONFIG_STACK_GROWSUP is specified (currently only a parisc thing :).

The attached fix-patch fixes this and some broken whitespace.

Many thanks to David H. who noticed this and pinged me off-list!

Cheers, Lorenzo

----8<----
From d706def8a4511b42bc7c7da0a01a3f30cd054e6e Mon Sep 17 00:00:00 2001
From: Lorenzo Stoakes <[email protected]>
Date: Thu, 20 Nov 2025 14:23:13 +0000
Subject: [PATCH] fixup

---
 include/linux/mm.h | 8 --------
 1 file changed, 8 deletions(-)
include/linux/mm.h +0 -8
index 3148be546e11..5f7f4aad1d26 100644
@@ -529,14 +529,6 @@ enum {
 
 #define VM_STARTGAP_FLAGS (VM_GROWSDOWN | VM_SHADOW_STACK)
 
-
-
-#ifdef CONFIG_STACK_GROWSUP
-#define VM_STACK_EARLY	VMA_BIT(VMA_STACK_EARLY_BIT)
-#else
-#define VM_STACK_EARLY	VM_NONE
-#endif
-
 #ifdef CONFIG_MSEAL_SYSTEM_MAPPINGS
 #define VM_SEALED_SYSMAP	VM_SEALED
 #else

--
2.51.2

#11 lore raw

PATCH v2 2/4 mm: simplify and rename mm flags function for clarity

In reply to Lorenzo Stoakes

The __mm_flags_set_word() function is slightly ambiguous - we use 'set' to refer to setting individual bits (such as in mm_flags_set()) but here we use it to refer to overwriting the value altogether.

Rename it to __mm_flags_overwrite_word() to eliminate this ambiguity.

We additionally simplify the functions, eliminating unnecessary bitmap_xxx() operations (the compiler would have optimised these out but it's worth being as clear as we can be here).

---
 include/linux/mm_types.h | 14 +++++---------
 kernel/fork.c            |  4 ++--
 2 files changed, 7 insertions(+), 11 deletions(-)
include/linux/mm_types.h +5 -9
index 4f66a3206a63..3550672e0f9e 100644
@@ -1314,15 +1314,13 @@ struct mm_struct {
 	unsigned long cpu_bitmap[];
 };
 
-/* Set the first system word of mm flags, non-atomically. */
-static inline void __mm_flags_set_word(struct mm_struct *mm, unsigned long value)
+/* Copy value to the first system word of mm flags, non-atomically. */
+static inline void __mm_flags_overwrite_word(struct mm_struct *mm, unsigned long value)
 {
-	unsigned long *bitmap = ACCESS_PRIVATE(&mm->flags, __mm_flags);
-
-	bitmap_copy(bitmap, &value, BITS_PER_LONG);
+	*ACCESS_PRIVATE(&mm->flags, __mm_flags) = value;
 }
 
-/* Obtain a read-only view of the bitmap. */
+/* Obtain a read-only view of the mm flags bitmap. */
 static inline const unsigned long *__mm_flags_get_bitmap(const struct mm_struct *mm)
 {
 	return (const unsigned long *)ACCESS_PRIVATE(&mm->flags, __mm_flags);
@@ -1331,9 +1329,7 @@ static inline const unsigned long *__mm_flags_get_bitmap(const struct mm_struct
 /* Read the first system word of mm flags, non-atomically. */
 static inline unsigned long __mm_flags_get_word(const struct mm_struct *mm)
 {
-	const unsigned long *bitmap = __mm_flags_get_bitmap(mm);
-
-	return bitmap_read(bitmap, 0, BITS_PER_LONG);
+	return *__mm_flags_get_bitmap(mm);
 }
 
 /*
kernel/fork.c +2 -2
index dd0bb5fe4305..5e3309a2332c 100644
@@ -1061,10 +1061,10 @@ static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p,
 	if (current->mm) {
 		unsigned long flags = __mm_flags_get_word(current->mm);
 
-		__mm_flags_set_word(mm, mmf_init_legacy_flags(flags));
+		__mm_flags_overwrite_word(mm, mmf_init_legacy_flags(flags));
 		mm->def_flags = current->mm->def_flags & VM_INIT_DEF_MASK;
 	} else {
-		__mm_flags_set_word(mm, default_dump_filter);
+		__mm_flags_overwrite_word(mm, default_dump_filter);
 		mm->def_flags = 0;
 	}
 
Signature · 1 line
2.51.0
#12 lore raw

PATCH v2 3/4 tools/testing/vma: eliminate dependency on vma->__vm_flags

In reply to Lorenzo Stoakes

The userland VMA test code relied on an internal implementation detail - the existence of vma->__vm_flags to directly access VMA flags. There is no need to do so when we have the vm_flags_*() helper functions available.

This is both ugly, but also a subsequent commit will eliminate this field altogether so this will shortly become broken.

This patch has us utilise the helper functions instead.

---
 tools/testing/vma/vma.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)
tools/testing/vma/vma.c +10 -10
index ee9d3547c421..fc77fa3f66f0 100644
@@ -69,18 +69,18 @@ static struct vm_area_struct *alloc_vma(struct mm_struct *mm,
 					pgoff_t pgoff,
 					vm_flags_t vm_flags)
 {
-	struct vm_area_struct *ret = vm_area_alloc(mm);
+	struct vm_area_struct *vma = vm_area_alloc(mm);
 
-	if (ret == NULL)
+	if (vma == NULL)
 		return NULL;
 
-	ret->vm_start = start;
-	ret->vm_end = end;
-	ret->vm_pgoff = pgoff;
-	ret->__vm_flags = vm_flags;
-	vma_assert_detached(ret);
+	vma->vm_start = start;
+	vma->vm_end = end;
+	vma->vm_pgoff = pgoff;
+	vm_flags_reset(vma, vm_flags);
+	vma_assert_detached(vma);
 
-	return ret;
+	return vma;
 }
 
 /* Helper function to allocate a VMA and link it to the tree. */
@@ -713,7 +713,7 @@ static bool test_vma_merge_special_flags(void)
 	for (i = 0; i < ARRAY_SIZE(special_flags); i++) {
 		vm_flags_t special_flag = special_flags[i];
 
-		vma_left->__vm_flags = vm_flags | special_flag;
+		vm_flags_reset(vma_left, vm_flags | special_flag);
 		vmg.vm_flags = vm_flags | special_flag;
 		vma = merge_new(&vmg);
 		ASSERT_EQ(vma, NULL);
@@ -735,7 +735,7 @@ static bool test_vma_merge_special_flags(void)
 	for (i = 0; i < ARRAY_SIZE(special_flags); i++) {
 		vm_flags_t special_flag = special_flags[i];
 
-		vma_left->__vm_flags = vm_flags | special_flag;
+		vm_flags_reset(vma_left, vm_flags | special_flag);
 		vmg.vm_flags = vm_flags | special_flag;
 		vma = merge_existing(&vmg);
 		ASSERT_EQ(vma, NULL);
Signature · 1 line
2.51.0
#13 lore raw

Re: [PATCH v2 3/4] tools/testing/vma: eliminate dependency on vma->__vm_flags

Hi Andrew,

Some small silly issue here, for some reason I seemed to have vm_flags_reset() available from the VMA tests when I tested but err, that doesn't seem to be the case at all.

Again I realise this is in mm-stable so this might be fiddly so we might have to live with minor bisect pain :(

Cheers, Lorenzo

----8<----
From afe5af105e7d64e39a4280c7fc8b34ad67cf0db0 Mon Sep 17 00:00:00 2001
From: Lorenzo Stoakes <[email protected]>
Date: Fri, 21 Nov 2025 17:25:18 +0000
Subject: [PATCH] tools/testing/vma: add missing stub

The vm_flags_reset() function is not available in the userland VMA tests, so add a stub which const-casts vma->vm_flags and avoids the upcoming removal of the vma->__vm_flags field.

---
 tools/testing/vma/vma_internal.h | 7 +++++++
 1 file changed, 7 insertions(+)
tools/testing/vma/vma_internal.h +7 -0
index 37fd479d49ce..f90a9b3c1880 100644
@@ -1760,4 +1760,11 @@ static inline int do_munmap(struct mm_struct *, unsigned long, size_t,
 	return 0;
 }
 
+static inline void vm_flags_reset(struct vm_area_struct *vma, vm_flags_t flags)
+{
+	vm_flags_t *dst = (vm_flags_t *)(&vma->vm_flags);
+
+	*dst = flags;
+}
+
 #endif	/* __MM_VMA_INTERNAL_H */

--
2.51.2

#14 lore raw

Re: [PATCH v2 3/4] tools/testing/vma: eliminate dependency on vma->__vm_flags

Hi Andrew,

It seems that the ordering of things has messed us up a bit here!

So this patch (3/4) currently introduces an issue where vm_flags_reset() is missing from the VMA userland tests.

Then 4/4, now with the vma_internal.h fixes in place, puts vm_flags_reset() back in place (this was my mistake in the series originally!).

But then this fix-patch, now applied as the latest patch from me in mm-new, breaks the tests again by duplicating this function :)

So, I'm not sure if too late for rebases - if not, then just squash this into 3/4.

If it is - then just drop this patch altogether and we'll live with this being broken for a single commit!

Cheers, Lorenzo

Quoted 44 lines · Lorenzo Stoakes

Hi Andrew,

Some small silly issue here, for some reason I seemed to have vm_flags_reset() available from the VMA tests when I tested but err, that doesn't seem to be the case at all.

Again I realise this is in mm-stable so this might be fiddly so we might have to live with minor bisect pain :(

Cheers, Lorenzo

----8<----
From afe5af105e7d64e39a4280c7fc8b34ad67cf0db0 Mon Sep 17 00:00:00 2001
From: Lorenzo Stoakes <[email protected]>
Date: Fri, 21 Nov 2025 17:25:18 +0000
Subject: [PATCH] tools/testing/vma: add missing stub

The vm_flags_reset() function is not available in the userland VMA tests, so add a stub which const-casts vma->vm_flags and avoids the upcoming removal of the vma->__vm_flags field.

---
 tools/testing/vma/vma_internal.h | 7 +++++++
 1 file changed, 7 insertions(+)
tools/testing/vma/vma_internal.h +7 -1
index 37fd479d49ce..f90a9b3c1880 100644
@@ -1760,4 +1760,11 @@ static inline int do_munmap(struct mm_struct *, unsigned long, size_t,
 	return 0;
 }
 
+static inline void vm_flags_reset(struct vm_area_struct *vma, vm_flags_t flags)
+{
+	vm_flags_t *dst = (vm_flags_t *)(&vma->vm_flags);
+
+	*dst = flags;
+}
+
 #endif	/* __MM_VMA_INTERNAL_H */
--

2.51.2

maintainer
#15 lore raw

Re: [PATCH v2 3/4] tools/testing/vma: eliminate dependency on vma->__vm_flags

Quoted 8 lines · On Mon, 24 Nov 2025 12:43:18 +0000 Lorenzo Stoakes…

It seems that the ordering of things has messed us up a bit here!

So this patch (3/4) currently introduces an issue where vm_flags_reset() is missing from the VMA userland tests.

Then 4/4, now with the vma_internal.h fixes in place, puts vm_flags_reset() back in place (this was my mistake in the series originally!).

Quoted 8 lines

But then this fix-patch, now applied as the latest patch from me in mm-new, breaks the tests again by duplicating this function :)

So, I'm not sure if too late for rebases - if not, then just squash this into 3/4.

If it is - then just drop this patch altogether and we'll live with this being broken for a single commit!

All confused. I dropped the whole series - please resend?

#16 lore raw

Re: [PATCH v2 3/4] tools/testing/vma: eliminate dependency on vma->__vm_flags

Quoted 13 lines · Andrew Morton
Quoted 11 lines · On Mon, 24 Nov 2025 12:43:18 +0000 Lorenzo Stoakes…

It seems that the ordering of things has messed us up a bit here!

So this patch (3/4) currently introduces an issue where vm_flags_reset() is missing from the VMA userland tests.

Then 4/4, now with the vma_internal.h fixes in place, puts vm_flags_reset() back in place (this was my mistake in the series originally!).

But then this fix-patch, now applied as the latest patch from me in mm-new, breaks the tests again by duplicating this function :)

Quoted 7 lines
Quoted 5 lines

So, I'm not sure if too late for rebases - if not, then just squash this into 3/4.

If it is - then just drop this patch altogether and we'll live with this being broken for a single commit!

All confused. I dropped the whole series - please resend?

Ack will do shortly.

#17 lore raw

PATCH v2 4/4 mm: introduce VMA flags bitmap type

In reply to Lorenzo Stoakes

It is useful to transition to using a bitmap for VMA flags so we can avoid running out of flags, especially for 32-bit kernels which are constrained to 32 flags, necessitating some features to be limited to 64-bit kernels only.

By doing so, we remove any constraint on the number of VMA flags moving forwards no matter the platform and can decide in future to extend beyond 64 if required.

We start by declaring an opaque types, vma_flags_t (which resembles mm_struct flags of type mm_flags_t), setting it to precisely the same size as vm_flags_t, and place it in union with vm_flags in the VMA declaration.

We additionally update struct vm_area_desc equivalently placing the new opaque type in union with vm_flags.

This change therefore does not impact the size of struct vm_area_struct or struct vm_area_desc.

In order for the change to be iterative and to avoid impacting performance, we designate VM_xxx declared bitmap flag values as those which must exist in the first system word of the VMA flags bitmap.

We therefore declare vma_flags_clear_all(), vma_flags_overwrite_word(), vma_flags_overwrite_word(), vma_flags_overwrite_word_once(), vma_flags_set_word() and vma_flags_clear_word() in order to allow us to update the existing vm_flags_*() functions to utilise these helpers.

This is a stepping stone towards converting users to the VMA flags bitmap and behaves precisely as before.

By doing this, we can eliminate the existing private vma->__vm_flags field in the vma->vm_flags union and replace it with the newly introduced opaque type vma_flags, which we call flags so we refer to the new bitmap field as vma->flags.

We update vma_flag_[test, set]_atomic() to account for the change also.

We additionally update the VMA userland test declarations to implement the same changes there.

Finally, we update the rust code to reference vma->vm_flags on update rather than vma->__vm_flags which has been removed. This is safe for now, albeit it is implicitly performing a const cast.

Once we introduce flag helpers we can improve this more.

No functional change intended.

---
 include/linux/mm.h               |  18 ++--
 include/linux/mm_types.h         |  64 +++++++++++++-
 rust/kernel/mm/virt.rs           |   2 +-
 tools/testing/vma/vma_internal.h | 143 ++++++++++++++++++++++++++-----
 4 files changed, 196 insertions(+), 31 deletions(-)
include/linux/mm.h +13 -5
index ad000c472bd5..79345c44a350 100644
@@ -919,7 +919,8 @@ static inline void vma_init(struct vm_area_struct *vma, struct mm_struct *mm)
 static inline void vm_flags_init(struct vm_area_struct *vma,
 				 vm_flags_t flags)
 {
-	ACCESS_PRIVATE(vma, __vm_flags) = flags;
+	vma_flags_clear_all(&vma->flags);
+	vma_flags_overwrite_word(&vma->flags, flags);
 }
 
 /*
@@ -938,21 +939,26 @@ static inline void vm_flags_reset_once(struct vm_area_struct *vma,
 				       vm_flags_t flags)
 {
 	vma_assert_write_locked(vma);
-	WRITE_ONCE(ACCESS_PRIVATE(vma, __vm_flags), flags);
+	/*
+	 * The user should only be interested in avoiding reordering of
+	 * assignment to the first word.
+	 */
+	vma_flags_clear_all(&vma->flags);
+	vma_flags_overwrite_word_once(&vma->flags, flags);
 }
 
 static inline void vm_flags_set(struct vm_area_struct *vma,
 				vm_flags_t flags)
 {
 	vma_start_write(vma);
-	ACCESS_PRIVATE(vma, __vm_flags) |= flags;
+	vma_flags_set_word(&vma->flags, flags);
 }
 
 static inline void vm_flags_clear(struct vm_area_struct *vma,
 				  vm_flags_t flags)
 {
 	vma_start_write(vma);
-	ACCESS_PRIVATE(vma, __vm_flags) &= ~flags;
+	vma_flags_clear_word(&vma->flags, flags);
 }
 
 /*
@@ -995,12 +1001,14 @@ static inline bool __vma_flag_atomic_valid(struct vm_area_struct *vma,
 static inline void vma_flag_set_atomic(struct vm_area_struct *vma,
 				       vma_flag_t bit)
 {
+	unsigned long *bitmap = ACCESS_PRIVATE(&vma->flags, __vma_flags);
+
 	/* mmap read lock/VMA read lock must be held. */
 	if (!rwsem_is_locked(&vma->vm_mm->mmap_lock))
 		vma_assert_locked(vma);
 
 	if (__vma_flag_atomic_valid(vma, bit))
-		set_bit((__force int)bit, &ACCESS_PRIVATE(vma, __vm_flags));
+		set_bit((__force int)bit, bitmap);
 }
 
 /*
include/linux/mm_types.h +62 -2

91 lines not on this page · raw message

rust/kernel/mm/virt.rs +1 -1
index a1bfa4e19293..da21d65ccd20 100644
@@ -250,7 +250,7 @@ unsafe fn update_flags(&self, set: vm_flags_t, unset: vm_flags_t) {
         // SAFETY: This is not a data race: the vma is undergoing initial setup, so it's not yet
         // shared. Additionally, `VmaNew` is `!Sync`, so it cannot be used to write in parallel.
         // The caller promises that this does not set the flags to an invalid value.
-        unsafe { (*self.as_ptr()).__bindgen_anon_2.__vm_flags = flags };
+        unsafe { (*self.as_ptr()).__bindgen_anon_2.vm_flags = flags };
     }
 
     /// Set the `VM_MIXEDMAP` flag on this vma.
tools/testing/vma/vma_internal.h +120 -23

179 lines not on this page · raw message

Signature · 1 line
2.51.0
#18 lore raw

Re: [PATCH v2 4/4] mm: introduce VMA flags bitmap type

As Vlastimil noticed, something has gone fairly horribly wrong here in the actual commit [0] vs. the patch here for tools/testing/vma/vma_internal.h.

We should only have the delta shown here, let me know if I need to help with a conflict resolution! :)

Thanks, Lorenzo

[0]: https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git/commit/?h=mm-stable&id=c3f7c506e8f122a31b9cc01d234e7fcda46b0eca

Quoted 420 lines · Lorenzo Stoakes

It is useful to transition to using a bitmap for VMA flags so we can avoid running out of flags, especially for 32-bit kernels which are constrained to 32 flags, necessitating some features to be limited to 64-bit kernels only.

By doing so, we remove any constraint on the number of VMA flags moving forwards no matter the platform and can decide in future to extend beyond 64 if required.

We start by declaring an opaque types, vma_flags_t (which resembles mm_struct flags of type mm_flags_t), setting it to precisely the same size as vm_flags_t, and place it in union with vm_flags in the VMA declaration.

We additionally update struct vm_area_desc equivalently placing the new opaque type in union with vm_flags.

This change therefore does not impact the size of struct vm_area_struct or struct vm_area_desc.

In order for the change to be iterative and to avoid impacting performance, we designate VM_xxx declared bitmap flag values as those which must exist in the first system word of the VMA flags bitmap.

We therefore declare vma_flags_clear_all(), vma_flags_overwrite_word(), vma_flags_overwrite_word(), vma_flags_overwrite_word_once(), vma_flags_set_word() and vma_flags_clear_word() in order to allow us to update the existing vm_flags_*() functions to utilise these helpers.

This is a stepping stone towards converting users to the VMA flags bitmap and behaves precisely as before.

By doing this, we can eliminate the existing private vma->__vm_flags field in the vma->vm_flags union and replace it with the newly introduced opaque type vma_flags, which we call flags so we refer to the new bitmap field as vma->flags.

We update vma_flag_[test, set]_atomic() to account for the change also.

We additionally update the VMA userland test declarations to implement the same changes there.

Finally, we update the rust code to reference vma->vm_flags on update rather than vma->__vm_flags which has been removed. This is safe for now, albeit it is implicitly performing a const cast.

Once we introduce flag helpers we can improve this more.

No functional change intended.

---
 include/linux/mm.h               |  18 ++--
 include/linux/mm_types.h         |  64 +++++++++++++-
 rust/kernel/mm/virt.rs           |   2 +-
 tools/testing/vma/vma_internal.h | 143 ++++++++++++++++++++++++++-----
 4 files changed, 196 insertions(+), 31 deletions(-)
include/linux/mm.h +13 -5
index ad000c472bd5..79345c44a350 100644
@@ -919,7 +919,8 @@ static inline void vma_init(struct vm_area_struct *vma, struct mm_struct *mm)
 static inline void vm_flags_init(struct vm_area_struct *vma,
 				 vm_flags_t flags)
 {
-	ACCESS_PRIVATE(vma, __vm_flags) = flags;
+	vma_flags_clear_all(&vma->flags);
+	vma_flags_overwrite_word(&vma->flags, flags);
 }
 
 /*
@@ -938,21 +939,26 @@ static inline void vm_flags_reset_once(struct vm_area_struct *vma,
 				       vm_flags_t flags)
 {
 	vma_assert_write_locked(vma);
-	WRITE_ONCE(ACCESS_PRIVATE(vma, __vm_flags), flags);
+	/*
+	 * The user should only be interested in avoiding reordering of
+	 * assignment to the first word.
+	 */
+	vma_flags_clear_all(&vma->flags);
+	vma_flags_overwrite_word_once(&vma->flags, flags);
 }
 
 static inline void vm_flags_set(struct vm_area_struct *vma,
 				vm_flags_t flags)
 {
 	vma_start_write(vma);
-	ACCESS_PRIVATE(vma, __vm_flags) |= flags;
+	vma_flags_set_word(&vma->flags, flags);
 }
 
 static inline void vm_flags_clear(struct vm_area_struct *vma,
 				  vm_flags_t flags)
 {
 	vma_start_write(vma);
-	ACCESS_PRIVATE(vma, __vm_flags) &= ~flags;
+	vma_flags_clear_word(&vma->flags, flags);
 }
 
 /*
@@ -995,12 +1001,14 @@ static inline bool __vma_flag_atomic_valid(struct vm_area_struct *vma,
 static inline void vma_flag_set_atomic(struct vm_area_struct *vma,
 				       vma_flag_t bit)
 {
+	unsigned long *bitmap = ACCESS_PRIVATE(&vma->flags, __vma_flags);
+
 	/* mmap read lock/VMA read lock must be held. */
 	if (!rwsem_is_locked(&vma->vm_mm->mmap_lock))
 		vma_assert_locked(vma);
 
 	if (__vma_flag_atomic_valid(vma, bit))
-		set_bit((__force int)bit, &ACCESS_PRIVATE(vma, __vm_flags));
+		set_bit((__force int)bit, bitmap);
 }
 
 /*
include/linux/mm_types.h +62 -2
index 3550672e0f9e..b71625378ce3 100644
@@ -848,6 +848,15 @@ struct mmap_action {
 	bool hide_from_rmap_until_complete :1;
 };
 
+/*
+ * Opaque type representing current VMA (vm_area_struct) flag state. Must be
+ * accessed via vma_flags_xxx() helper functions.
+ */
+#define NUM_VMA_FLAG_BITS BITS_PER_LONG
+typedef struct {
+	DECLARE_BITMAP(__vma_flags, NUM_VMA_FLAG_BITS);
+} __private vma_flags_t;
+
 /*
  * Describes a VMA that is about to be mmap()'ed. Drivers may choose to
  * manipulate mutable fields which will cause those fields to be updated in the
@@ -865,7 +874,10 @@ struct vm_area_desc {
 	/* Mutable fields. Populated with initial state. */
 	pgoff_t pgoff;
 	struct file *vm_file;
-	vm_flags_t vm_flags;
+	union {
+		vm_flags_t vm_flags;
+		vma_flags_t vma_flags;
+	};
 	pgprot_t page_prot;
 
 	/* Write-only fields. */
@@ -910,10 +922,12 @@ struct vm_area_struct {
 	/*
 	 * Flags, see mm.h.
 	 * To modify use vm_flags_{init|reset|set|clear|mod} functions.
+	 * Preferably, use vma_flags_xxx() functions.
 	 */
 	union {
+		/* Temporary while VMA flags are being converted. */
 		const vm_flags_t vm_flags;
-		vm_flags_t __private __vm_flags;
+		vma_flags_t flags;
 	};
 
 #ifdef CONFIG_PER_VMA_LOCK
@@ -994,6 +1008,52 @@ struct vm_area_struct {
 #endif
 } __randomize_layout;
 
+/* Clears all bits in the VMA flags bitmap, non-atomically. */
+static inline void vma_flags_clear_all(vma_flags_t *flags)
+{
+	bitmap_zero(ACCESS_PRIVATE(flags, __vma_flags), NUM_VMA_FLAG_BITS);
+}
+
+/*
+ * Copy value to the first system word of VMA flags, non-atomically.
+ *
+ * IMPORTANT: This does not overwrite bytes past the first system word. The
+ * caller must account for this.
+ */
+static inline void vma_flags_overwrite_word(vma_flags_t *flags, unsigned long value)
+{
+	*ACCESS_PRIVATE(flags, __vma_flags) = value;
+}
+
+/*
+ * Copy value to the first system word of VMA flags ONCE, non-atomically.
+ *
+ * IMPORTANT: This does not overwrite bytes past the first system word. The
+ * caller must account for this.
+ */
+static inline void vma_flags_overwrite_word_once(vma_flags_t *flags, unsigned long value)
+{
+	unsigned long *bitmap = ACCESS_PRIVATE(flags, __vma_flags);
+
+	WRITE_ONCE(*bitmap, value);
+}
+
+/* Update the first system word of VMA flags setting bits, non-atomically. */
+static inline void vma_flags_set_word(vma_flags_t *flags, unsigned long value)
+{
+	unsigned long *bitmap = ACCESS_PRIVATE(flags, __vma_flags);
+
+	*bitmap |= value;
+}
+
+/* Update the first system word of VMA flags clearing bits, non-atomically. */
+static inline void vma_flags_clear_word(vma_flags_t *flags, unsigned long value)
+{
+	unsigned long *bitmap = ACCESS_PRIVATE(flags, __vma_flags);
+
+	*bitmap &= ~value;
+}
+
 #ifdef CONFIG_NUMA
 #define vma_policy(vma) ((vma)->vm_policy)
 #else
rust/kernel/mm/virt.rs +1 -1
index a1bfa4e19293..da21d65ccd20 100644
@@ -250,7 +250,7 @@ unsafe fn update_flags(&self, set: vm_flags_t, unset: vm_flags_t) {
         // SAFETY: This is not a data race: the vma is undergoing initial setup, so it's not yet
         // shared. Additionally, `VmaNew` is `!Sync`, so it cannot be used to write in parallel.
         // The caller promises that this does not set the flags to an invalid value.
-        unsafe { (*self.as_ptr()).__bindgen_anon_2.__vm_flags = flags };
+        unsafe { (*self.as_ptr()).__bindgen_anon_2.vm_flags = flags };
     }
 
     /// Set the `VM_MIXEDMAP` flag on this vma.
tools/testing/vma/vma_internal.h +120 -24
index 18659214e262..13ee825bdfcf 100644
@@ -528,6 +528,15 @@ typedef struct {
 	__private DECLARE_BITMAP(__mm_flags, NUM_MM_FLAG_BITS);
 } mm_flags_t;
 
+/*
+ * Opaque type representing current VMA (vm_area_struct) flag state. Must be
+ * accessed via vma_flags_xxx() helper functions.
+ */
+#define NUM_VMA_FLAG_BITS BITS_PER_LONG
+typedef struct {
+	DECLARE_BITMAP(__vma_flags, NUM_VMA_FLAG_BITS);
+} __private vma_flags_t;
+
 struct mm_struct {
 	struct maple_tree mm_mt;
 	int map_count;			/* number of VMAs */
@@ -612,7 +621,10 @@ struct vm_area_desc {
 	/* Mutable fields. Populated with initial state. */
 	pgoff_t pgoff;
 	struct file *vm_file;
-	vm_flags_t vm_flags;
+	union {
+		vm_flags_t vm_flags;
+		vma_flags_t vma_flags;
+	};
 	pgprot_t page_prot;
 
 	/* Write-only fields. */
@@ -658,7 +670,7 @@ struct vm_area_struct {
 	 */
 	union {
 		const vm_flags_t vm_flags;
-		vm_flags_t __private __vm_flags;
+		vma_flags_t flags;
 	};
 
 #ifdef CONFIG_PER_VMA_LOCK
@@ -1372,26 +1384,6 @@ static inline bool may_expand_vm(struct mm_struct *mm, vm_flags_t flags,
 	return true;
 }
 
-static inline void vm_flags_init(struct vm_area_struct *vma,
-				 vm_flags_t flags)
-{
-	vma->__vm_flags = flags;
-}
-
-static inline void vm_flags_set(struct vm_area_struct *vma,
-				vm_flags_t flags)
-{
-	vma_start_write(vma);
-	vma->__vm_flags |= flags;
-}
-
-static inline void vm_flags_clear(struct vm_area_struct *vma,
-				  vm_flags_t flags)
-{
-	vma_start_write(vma);
-	vma->__vm_flags &= ~flags;
-}
-
 static inline int shmem_zero_setup(struct vm_area_struct *vma)
 {
 	return 0;
@@ -1548,13 +1540,118 @@ static inline void userfaultfd_unmap_complete(struct mm_struct *mm,
 {
 }
 
-# define ACCESS_PRIVATE(p, member) ((p)->member)
+#define ACCESS_PRIVATE(p, member) ((p)->member)
+
+#define bitmap_size(nbits)	(ALIGN(nbits, BITS_PER_LONG) / BITS_PER_BYTE)
+
+static __always_inline void bitmap_zero(unsigned long *dst, unsigned int nbits)
+{
+	unsigned int len = bitmap_size(nbits);
+
+	if (small_const_nbits(nbits))
+		*dst = 0;
+	else
+		memset(dst, 0, len);
+}
 
 static inline bool mm_flags_test(int flag, const struct mm_struct *mm)
 {
 	return test_bit(flag, ACCESS_PRIVATE(&mm->flags, __mm_flags));
 }
 
+/* Clears all bits in the VMA flags bitmap, non-atomically. */
+static inline void vma_flags_clear_all(vma_flags_t *flags)
+{
+	bitmap_zero(ACCESS_PRIVATE(flags, __vma_flags), NUM_VMA_FLAG_BITS);
+}
+
+/*
+ * Copy value to the first system word of VMA flags, non-atomically.
+ *
+ * IMPORTANT: This does not overwrite bytes past the first system word. The
+ * caller must account for this.
+ */
+static inline void vma_flags_overwrite_word(vma_flags_t *flags, unsigned long value)
+{
+	*ACCESS_PRIVATE(flags, __vma_flags) = value;
+}
+
+/*
+ * Copy value to the first system word of VMA flags ONCE, non-atomically.
+ *
+ * IMPORTANT: This does not overwrite bytes past the first system word. The
+ * caller must account for this.
+ */
+static inline void vma_flags_overwrite_word_once(vma_flags_t *flags, unsigned long value)
+{
+	unsigned long *bitmap = ACCESS_PRIVATE(flags, __vma_flags);
+
+	WRITE_ONCE(*bitmap, value);
+}
+
+/* Update the first system word of VMA flags setting bits, non-atomically. */
+static inline void vma_flags_set_word(vma_flags_t *flags, unsigned long value)
+{
+	unsigned long *bitmap = ACCESS_PRIVATE(flags, __vma_flags);
+
+	*bitmap |= value;
+}
+
+/* Update the first system word of VMA flags clearing bits, non-atomically. */
+static inline void vma_flags_clear_word(vma_flags_t *flags, unsigned long value)
+{
+	unsigned long *bitmap = ACCESS_PRIVATE(flags, __vma_flags);
+
+	*bitmap &= ~value;
+}
+
+
+/* Use when VMA is not part of the VMA tree and needs no locking */
+static inline void vm_flags_init(struct vm_area_struct *vma,
+				 vm_flags_t flags)
+{
+	vma_flags_clear_all(&vma->flags);
+	vma_flags_overwrite_word(&vma->flags, flags);
+}
+
+/*
+ * Use when VMA is part of the VMA tree and modifications need coordination
+ * Note: vm_flags_reset and vm_flags_reset_once do not lock the vma and
+ * it should be locked explicitly beforehand.
+ */
+static inline void vm_flags_reset(struct vm_area_struct *vma,
+				  vm_flags_t flags)
+{
+	vma_assert_write_locked(vma);
+	vm_flags_init(vma, flags);
+}
+
+static inline void vm_flags_reset_once(struct vm_area_struct *vma,
+				       vm_flags_t flags)
+{
+	vma_assert_write_locked(vma);
+	/*
+	 * The user should only be interested in avoiding reordering of
+	 * assignment to the first word.
+	 */
+	vma_flags_clear_all(&vma->flags);
+	vma_flags_overwrite_word_once(&vma->flags, flags);
+}
+
+static inline void vm_flags_set(struct vm_area_struct *vma,
+				vm_flags_t flags)
+{
+	vma_start_write(vma);
+	vma_flags_set_word(&vma->flags, flags);
+}
+
+static inline void vm_flags_clear(struct vm_area_struct *vma,
+				  vm_flags_t flags)
+{
+	vma_start_write(vma);
+	vma_flags_clear_word(&vma->flags, flags);
+}
+
 /*
  * Denies creating a writable executable mapping or gaining executable permissions.
  *
--

2.51.0

maintainer
#19 lore raw

Re: [PATCH v2 4/4] mm: introduce VMA flags bitmap type

Quoted 5 lines · On Fri, 21 Nov 2025 17:44:43 +0000 Lorenzo Stoakes…

As Vlastimil noticed, something has gone fairly horribly wrong here in the actual commit [0] vs. the patch here for tools/testing/vma/vma_internal.h.

We should only have the delta shown here, let me know if I need to help with a conflict resolution! :)

OK, thanks, easy fix.

#20 lore raw

Re: [PATCH v2 4/4] mm: introduce VMA flags bitmap type

Quoted 9 lines · Andrew Morton
Quoted 5 lines · On Fri, 21 Nov 2025 17:44:43 +0000 Lorenzo Stoakes…

As Vlastimil noticed, something has gone fairly horribly wrong here in the actual commit [0] vs. the patch here for tools/testing/vma/vma_internal.h.

We should only have the delta shown here, let me know if I need to help with a conflict resolution! :)

OK, thanks, easy fix.

Perfect, thanks! :)

Cheers, Lorenzo

Acked-by on the v2 series
#21 lore raw
In reply to Lorenzo Stoakes
Quoted 56 lines · Lorenzo Stoakes

We are in the rather silly situation that we are running out of VMA flags as they are currently limited to a system word in size.

This leads to absurd situations where we limit features to 64-bit architectures only because we simply do not have the ability to add a flag for 32-bit ones.

This is very constraining and leads to hacks or, in the worst case, simply an inability to implement features we want for entirely arbitrary reasons.

This also of course gives us something of a Y2K type situation in mm where we might eventually exhaust all of the VMA flags even on 64-bit systems.

This series lays the groundwork for getting away from this limitation by establishing VMA flags as a bitmap whose size we can increase in future beyond 64 bits if required.

This is necessarily a highly iterative process given the extensive use of VMA flags throughout the kernel, so we start by performing basic steps.

Firstly, we declare VMA flags by bit number rather than by value, retaining the VM_xxx fields but in terms of these newly introduced VMA_xxx_BIT fields.

While we are here, we use sparse annotations to ensure that, when dealing with VMA bit number parameters, we cannot be passed values which are not declared as such - providing some useful type safety.

We then introduce an opaque VMA flag type, much like the opaque mm_struct flag type introduced in commit bb6525f2f8c4 ("mm: add bitmap mm->flags field"), which we establish in union with vma->vm_flags (but still set at system word size meaning there is no functional or data type size change).

We update the vm_flags_xxx() helpers to use this new bitmap, introducing sensible helpers to do so.

This series lays the foundation for further work to expand the use of bitmap VMA flags and eventually eliminate these arbitrary restrictions.

v2:
* Corrected kdoc for vma_flag_t.
* Introduced DECLARE_VMA_BIT() as per Jason. We can't also declare the VMA flags in the enum as this breaks assumptions in the kernel, resulting in errors like 'enum constant in boolean context [-Werror=int-in-bool-context]'.
* Dropped the conversion patch - To make life simpler this cycle, let's just fixup the flag declarations and introduce the new field type and introduce vm_flags_*() changes. We can do more later.
* Split out VMA testing vma->__vm_flags change.
* Fixed vma_flag_*_atomic() helper functions for sparse purposes to work with vma_flag_t.
* Fixed rust breakages as reported by Nico and help provided by Alice. For now we are doing a minimal fix, we can do a more substantial one once the VMA flag helper functions are introduced in an upcoming series.

Quoted 8 lines

v1:
https://lore.kernel.org/all/[email protected]/

Lorenzo Stoakes (4):
mm: declare VMA flags by bit
mm: simplify and rename mm flags function for clarity tools/testing/vma: eliminate dependency on vma->__vm_flags
mm: introduce VMA flags bitmap type

However something has happened to patch 4/4 in git, it has a very different tools/testing/vma/vma_internal.h:

https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git/commit/?h=mm-stable&id=c3f7c506e8f122a31b9cc01d234e7fcda46b0eca

Quoted 15 lines
 fs/proc/task_mmu.c               |   4 +-
 include/linux/mm.h               | 400 +++++++++++++++------------
 include/linux/mm_types.h         |  78 +++++-
 kernel/fork.c                    |   4 +-
 mm/khugepaged.c                  |   2 +-
 mm/madvise.c                     |   2 +-
 rust/bindings/bindings_helper.h  |  25 ++
 rust/kernel/mm/virt.rs           |   2 +-
 tools/testing/vma/vma.c          |  20 +-
 tools/testing/vma/vma_internal.h | 446 ++++++++++++++++++++++++++-----
 10 files changed, 716 insertions(+), 267 deletions(-)

--
2.51.0

#22 lore raw
Quoted 60 lines · Vlastimil Babka
Quoted 59 lines · Lorenzo Stoakes

We are in the rather silly situation that we are running out of VMA flags as they are currently limited to a system word in size.

This leads to absurd situations where we limit features to 64-bit architectures only because we simply do not have the ability to add a flag for 32-bit ones.

This is very constraining and leads to hacks or, in the worst case, simply an inability to implement features we want for entirely arbitrary reasons.

This also of course gives us something of a Y2K type situation in mm where we might eventually exhaust all of the VMA flags even on 64-bit systems.

This series lays the groundwork for getting away from this limitation by establishing VMA flags as a bitmap whose size we can increase in future beyond 64 bits if required.

This is necessarily a highly iterative process given the extensive use of VMA flags throughout the kernel, so we start by performing basic steps.

Firstly, we declare VMA flags by bit number rather than by value, retaining the VM_xxx fields but in terms of these newly introduced VMA_xxx_BIT fields.

While we are here, we use sparse annotations to ensure that, when dealing with VMA bit number parameters, we cannot be passed values which are not declared as such - providing some useful type safety.

We then introduce an opaque VMA flag type, much like the opaque mm_struct flag type introduced in commit bb6525f2f8c4 ("mm: add bitmap mm->flags field"), which we establish in union with vma->vm_flags (but still set at system word size meaning there is no functional or data type size change).

We update the vm_flags_xxx() helpers to use this new bitmap, introducing sensible helpers to do so.

This series lays the foundation for further work to expand the use of bitmap VMA flags and eventually eliminate these arbitrary restrictions.

v2:
* Corrected kdoc for vma_flag_t.
* Introduced DECLARE_VMA_BIT() as per Jason. We can't also declare the VMA flags in the enum as this breaks assumptions in the kernel, resulting in errors like 'enum constant in boolean context [-Werror=int-in-bool-context]'.
* Dropped the conversion patch - To make life simpler this cycle, let's just fixup the flag declarations and introduce the new field type and introduce vm_flags_*() changes. We can do more later.
* Split out VMA testing vma->__vm_flags change.
* Fixed vma_flag_*_atomic() helper functions for sparse purposes to work with vma_flag_t.
* Fixed rust breakages as reported by Nico and help provided by Alice. For now we are doing a minimal fix, we can do a more substantial one once the VMA flag helper functions are introduced in an upcoming series.

v1:
https://lore.kernel.org/all/[email protected]/

Quoted 7 lines
Quoted 5 lines

Lorenzo Stoakes (4):
mm: declare VMA flags by bit
mm: simplify and rename mm flags function for clarity tools/testing/vma: eliminate dependency on vma->__vm_flags
mm: introduce VMA flags bitmap type

Thanks!

Quoted 5 lines

However something has happened to patch 4/4 in git, it has a very different tools/testing/vma/vma_internal.h:

https://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm.git/commit/?h=mm-stable&id=c3f7c506e8f122a31b9cc01d234e7fcda46b0eca

Yeah something has gone very wrong here :)

3/4 also has an issue annoyingly, I tested it locally with no issues but now it seems to have issues... but also it seems like it should _always_ have.

Anyway let me address each at a time I guess... :)

Quoted 17 lines
Quoted 16 lines

 fs/proc/task_mmu.c               |   4 +-
 include/linux/mm.h               | 400 +++++++++++++++------------
 include/linux/mm_types.h         |  78 +++++-
 kernel/fork.c                    |   4 +-
 mm/khugepaged.c                  |   2 +-
 mm/madvise.c                     |   2 +-
 rust/bindings/bindings_helper.h  |  25 ++
 rust/kernel/mm/virt.rs           |   2 +-
 tools/testing/vma/vma.c          |  20 +-
 tools/testing/vma/vma_internal.h | 446 ++++++++++++++++++++++++++-----
 10 files changed, 716 insertions(+), 267 deletions(-)

--
2.51.0