Skip to contentSkip to conversation

initial work on making VMA flags a bitmap

PATCH Applied Lorenzo Stoakes 5 participants 18 messages Nov 25, 2025 – Jan 13

Subsystems (11)
lore
Share & tools
lore
#0 lore raw

v3 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.

v3:
* Rebased against mm-new.
* Squashed fixups in to series.
* Propagated tags (thanks Vlasta!).
* After off-list discussion with Pedro Falcato, added defensive code in vm_flags_reset_once() to only clear bits higher than the first sytem word, retaining write-once semantics for the first system word, which is what callers are relying upon.

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.
https://lore.kernel.org/all/[email protected]>/

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               | 401 +++++++++++++++------------
 include/linux/mm_types.h         |  78 +++++-
 kernel/fork.c                    |   4 +-
 mm/khugepaged.c                  |   2 +-
 mm/madvise.c                     |   2 +-
 rust/bindgen_parameters          |  25 ++
 rust/bindings/bindings_helper.h  |  25 ++
 rust/kernel/mm/virt.rs           |   2 +-
 tools/testing/vma/vma.c          |  20 +-
 tools/testing/vma/vma_internal.h | 454 ++++++++++++++++++++++++++-----
 11 files changed, 742 insertions(+), 275 deletions(-)

--
2.51.2

#1 lore raw

PATCH v3 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               | 379 +++++++++++++++++--------------
 mm/khugepaged.c                  |   2 +-
 mm/madvise.c                     |   2 +-
 rust/bindgen_parameters          |  25 ++
 rust/bindings/bindings_helper.h  |  25 ++
 tools/testing/vma/vma_internal.h | 304 +++++++++++++++++++++----
 7 files changed, 524 insertions(+), 217 deletions(-)
fs/proc/task_mmu.c +2 -2
index 2b4ab5718ab5..d00ac179d973 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 +211 -168

471 lines not on this page · raw message

mm/khugepaged.c +1 -1
index 89c33ef7aac3..97d1b2824386 100644
@@ -1740,7 +1740,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 d8bc51e1bea7..b617b1be0f53 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/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
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 +259 -45

327 lines not on this page · raw message

Signature · 1 line
2.51.2
reviewer Reviewed-by on v3 1/4
#2 lore raw

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

Quoted 40 lines · Lorenzo Stoakes

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.

Quoted 8 lines

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.

Scary but cromulent-looking. Thanks :)

--
Pedro

#3 lore raw

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

In reply to Lorenzo Stoakes

On Tue, 25 Nov 2025 10:00:59 +0000 Lorenzo Stoakes <[email protected]> wrote:

[ ... ]

Quoted 4 lines

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

I did a run of all the MM commits from 6.18 to today's linus, and this one
had a copy/paste error. I'd normally just send a patch for this, but in
terms of showing the review output:

Quoted 5 lines
rust/bindings/bindings_helper.h +0 -0
index 2e43c66635a2c..4c327db01ca03 100644
@@ -108,7 +108,32 @@ const xa_mark_t RUST_CONST_HELPER_XA_PRESENT = XA_PRESENT;

[ ... ]

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

Quoted 4 lines
rust/bindings/bindings_helper.h +4 -0
+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;
                                                   ^^^^^^^^^^

Should this be VM_MAYSHARE instead of VM_MAYEXEC? This appears to be a copy-paste error that would cause Rust code using VmFlags::MAYSHARE to get bit 6 (VM_MAYEXEC) instead of bit 7 (VM_MAYSHARE).

The pattern of the preceding lines shows each constant should reference its matching flag:

RUST_CONST_HELPER_VM_MAYREAD = VM_MAYREAD RUST_CONST_HELPER_VM_MAYWRITE = VM_MAYWRITE RUST_CONST_HELPER_VM_MAYEXEC = VM_MAYEXEC RUST_CONST_HELPER_VM_MAYSHARE = VM_MAYSHARE <- expected

Quoted 1 line

+const vm_flags_t RUST_CONST_HELPER_VM_PFNMAP = VM_PFNMAP;

[ ... ]

maintainer
#4 lore raw

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

Quoted 31 lines · Chris Mason

On Tue, 25 Nov 2025 10:00:59 +0000 Lorenzo Stoakes <[email protected]> wrote:

[ ... ]

Quoted 4 lines

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

I did a run of all the MM commits from 6.18 to today's linus, and this one
had a copy/paste error. I'd normally just send a patch for this, but in
terms of showing the review output:

Quoted 5 lines
rust/bindings/bindings_helper.h +0 -0
index 2e43c66635a2c..4c327db01ca03 100644
@@ -108,7 +108,32 @@ const xa_mark_t RUST_CONST_HELPER_XA_PRESENT = XA_PRESENT;

[ ... ]

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

Quoted 4 lines
rust/bindings/bindings_helper.h +4 -0
+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;
                                                   ^^^^^^^^^^

Should this be VM_MAYSHARE instead of VM_MAYEXEC? This appears to be a copy-paste error that would cause Rust code using VmFlags::MAYSHARE to get bit 6 (VM_MAYEXEC) instead of bit 7 (VM_MAYSHARE).

Quoted 9 lines

The pattern of the preceding lines shows each constant should reference its matching flag:

RUST_CONST_HELPER_VM_MAYREAD = VM_MAYREAD RUST_CONST_HELPER_VM_MAYWRITE = VM_MAYWRITE RUST_CONST_HELPER_VM_MAYEXEC = VM_MAYEXEC RUST_CONST_HELPER_VM_MAYSHARE = VM_MAYSHARE <- expected

Quoted 1 line

+const vm_flags_t RUST_CONST_HELPER_VM_PFNMAP = VM_PFNMAP;

Uh, good catch. Do you want to send a fix patch?

Alice

#5 lore raw

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

Quoted 35 lines · Alice Ryhl
Quoted 34 lines · Chris Mason

On Tue, 25 Nov 2025 10:00:59 +0000 Lorenzo Stoakes <[email protected]> wrote:

[ ... ]

Quoted 4 lines

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

I did a run of all the MM commits from 6.18 to today's linus, and this one
had a copy/paste error. I'd normally just send a patch for this, but in
terms of showing the review output:

Quoted 5 lines
rust/bindings/bindings_helper.h +0 -0
index 2e43c66635a2c..4c327db01ca03 100644
@@ -108,7 +108,32 @@ const xa_mark_t RUST_CONST_HELPER_XA_PRESENT = XA_PRESENT;

[ ... ]

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

Quoted 4 lines
rust/bindings/bindings_helper.h +4 -0
+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;
                                                   ^^^^^^^^^^

Should this be VM_MAYSHARE instead of VM_MAYEXEC? This appears to be a copy-paste error that would cause Rust code using VmFlags::MAYSHARE to get bit 6 (VM_MAYEXEC) instead of bit 7 (VM_MAYSHARE).

The pattern of the preceding lines shows each constant should reference its matching flag:

Quoted 8 lines
Quoted 6 lines

RUST_CONST_HELPER_VM_MAYREAD = VM_MAYREAD RUST_CONST_HELPER_VM_MAYWRITE = VM_MAYWRITE RUST_CONST_HELPER_VM_MAYEXEC = VM_MAYEXEC RUST_CONST_HELPER_VM_MAYSHARE = VM_MAYSHARE <- expected

Quoted 1 line

+const vm_flags_t RUST_CONST_HELPER_VM_PFNMAP = VM_PFNMAP;

Uh, good catch. Do you want to send a fix patch?

It's in 6.18 so would need to be a Cc: stable patch with a Fixes etc. rather than a fix-patch, unless that's what you meant?

Quoted 2 lines

Alice

maintainer
#6 lore raw

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

Quoted 42 lines · Lorenzo Stoakes
Quoted 40 lines · Alice Ryhl
Quoted 39 lines · Chris Mason

On Tue, 25 Nov 2025 10:00:59 +0000 Lorenzo Stoakes <[email protected]> wrote:

[ ... ]

Quoted 4 lines

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

I did a run of all the MM commits from 6.18 to today's linus, and this one
had a copy/paste error. I'd normally just send a patch for this, but in
terms of showing the review output:

Quoted 5 lines
rust/bindings/bindings_helper.h +0 -0
index 2e43c66635a2c..4c327db01ca03 100644
@@ -108,7 +108,32 @@ const xa_mark_t RUST_CONST_HELPER_XA_PRESENT = XA_PRESENT;

[ ... ]

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

Quoted 4 lines
rust/bindings/bindings_helper.h +4 -0
+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;
                                                   ^^^^^^^^^^

Should this be VM_MAYSHARE instead of VM_MAYEXEC? This appears to be a copy-paste error that would cause Rust code using VmFlags::MAYSHARE to get bit 6 (VM_MAYEXEC) instead of bit 7 (VM_MAYSHARE).

The pattern of the preceding lines shows each constant should reference its matching flag:

RUST_CONST_HELPER_VM_MAYREAD = VM_MAYREAD RUST_CONST_HELPER_VM_MAYWRITE = VM_MAYWRITE RUST_CONST_HELPER_VM_MAYEXEC = VM_MAYEXEC RUST_CONST_HELPER_VM_MAYSHARE = VM_MAYSHARE <- expected

Quoted 6 lines
Quoted 3 lines
Quoted 1 line
Quoted 1 line

+const vm_flags_t RUST_CONST_HELPER_VM_PFNMAP = VM_PFNMAP;

Uh, good catch. Do you want to send a fix patch?

It's in 6.18 so would need to be a Cc: stable patch with a Fixes etc. rather than a fix-patch, unless that's what you meant?

That's what I meant, yeah.

Alice

#7 lore raw

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

In reply to Chris Mason
Quoted 33 lines · Chris Mason

On Tue, 25 Nov 2025 10:00:59 +0000 Lorenzo Stoakes <[email protected]> wrote:

[ ... ]

Quoted 4 lines

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

I did a run of all the MM commits from 6.18 to today's linus, and this one
had a copy/paste error. I'd normally just send a patch for this, but in
terms of showing the review output:

Quoted 5 lines
rust/bindings/bindings_helper.h +0 -0
index 2e43c66635a2c..4c327db01ca03 100644
@@ -108,7 +108,32 @@ const xa_mark_t RUST_CONST_HELPER_XA_PRESENT = XA_PRESENT;

[ ... ]

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

Quoted 4 lines
rust/bindings/bindings_helper.h +4 -0
+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;
                                                   ^^^^^^^^^^

Should this be VM_MAYSHARE instead of VM_MAYEXEC? This appears to be a copy-paste error that would cause Rust code using VmFlags::MAYSHARE to get bit 6 (VM_MAYEXEC) instead of bit 7 (VM_MAYSHARE).

The pattern of the preceding lines shows each constant should reference its matching flag:

Quoted 10 lines

RUST_CONST_HELPER_VM_MAYREAD = VM_MAYREAD RUST_CONST_HELPER_VM_MAYWRITE = VM_MAYWRITE RUST_CONST_HELPER_VM_MAYEXEC = VM_MAYEXEC RUST_CONST_HELPER_VM_MAYSHARE = VM_MAYSHARE <- expected

Quoted 1 line

+const vm_flags_t RUST_CONST_HELPER_VM_PFNMAP = VM_PFNMAP;

[ ... ]

Oopsies!

I can send a patch unless you were planning to!

Cheers, Lorenzo

#8 lore raw

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

Quoted 41 lines · Lorenzo Stoakes
Quoted 40 lines · Chris Mason

On Tue, 25 Nov 2025 10:00:59 +0000 Lorenzo Stoakes <[email protected]> wrote:

[ ... ]

Quoted 4 lines

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

I did a run of all the MM commits from 6.18 to today's linus, and this one
had a copy/paste error. I'd normally just send a patch for this, but in
terms of showing the review output:

Quoted 5 lines
rust/bindings/bindings_helper.h +0 -0
index 2e43c66635a2c..4c327db01ca03 100644
@@ -108,7 +108,32 @@ const xa_mark_t RUST_CONST_HELPER_XA_PRESENT = XA_PRESENT;

[ ... ]

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

Quoted 4 lines
rust/bindings/bindings_helper.h +4 -0
+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;
                                                   ^^^^^^^^^^

Should this be VM_MAYSHARE instead of VM_MAYEXEC? This appears to be a copy-paste error that would cause Rust code using VmFlags::MAYSHARE to get bit 6 (VM_MAYEXEC) instead of bit 7 (VM_MAYSHARE).

The pattern of the preceding lines shows each constant should reference its matching flag:

RUST_CONST_HELPER_VM_MAYREAD = VM_MAYREAD RUST_CONST_HELPER_VM_MAYWRITE = VM_MAYWRITE RUST_CONST_HELPER_VM_MAYEXEC = VM_MAYEXEC RUST_CONST_HELPER_VM_MAYSHARE = VM_MAYSHARE <- expected

Quoted 1 line

+const vm_flags_t RUST_CONST_HELPER_VM_PFNMAP = VM_PFNMAP;

Quoted 7 lines
Quoted 3 lines

[ ... ]

Oopsies!

I can send a patch unless you were planning to!

Please do, I'm still going through the rest of the commits.

-chris

#9 lore raw

PATCH v3 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.2
reviewer Reviewed-by on v3 2/4
#10 lore raw

Re: [PATCH v3 2/4] mm: simplify and rename mm flags function for clarity

Quoted 6 lines · 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.

                          write_word()?
Quoted 6 lines

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).

Anyway:

Signature · 1 line
Pedro
#11 lore raw

PATCH v3 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 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 be79ab2ea44b..93d21bc7e112 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. */
@@ -714,7 +714,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);
@@ -736,7 +736,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.2
reviewer Acked-by on v3 3/4
#12 lore raw

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

Quoted 11 lines · 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 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.

Signature · 1 line
Pedro
#13 lore raw

PATCH v3 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 adapt vm_flags_reset_once() to only clear those bits above the first system word providing write-once semantics to the first system word (which it is presumed the caller requires - and in all current use cases this is so).

As we currently only specify that the VMA flags bitmap size is equal to BITS_PER_LONG number of bits, this is a noop, but is defensive in preparation for a future change that increases this.

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               |  24 +++--
 include/linux/mm_types.h         |  64 ++++++++++++-
 rust/kernel/mm/virt.rs           |   2 +-
 tools/testing/vma/vma_internal.h | 150 ++++++++++++++++++++++++-------
 4 files changed, 202 insertions(+), 38 deletions(-)
include/linux/mm.h +19 -5
index a2f38fb68840..2887d3b34d3e 100644
@@ -911,7 +911,8 @@ static inline void vm_flags_init(struct vm_area_struct *vma,
 				 vm_flags_t flags)
 {
 	VM_WARN_ON_ONCE(!pgtable_supports_soft_dirty() && (flags & VM_SOFTDIRTY));
-	ACCESS_PRIVATE(vma, __vm_flags) = flags;
+	vma_flags_clear_all(&vma->flags);
+	vma_flags_overwrite_word(&vma->flags, flags);
 }
 
 /*
@@ -931,14 +932,25 @@ 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);
+	/*
+	 * If VMA flags exist beyond the first system word, also clear these. It
+	 * is assumed the write once behaviour is required only for the first
+	 * system word.
+	 */
+	if (NUM_VMA_FLAG_BITS > BITS_PER_LONG) {
+		unsigned long *bitmap = ACCESS_PRIVATE(&vma->flags, __vma_flags);
+
+		bitmap_zero(&bitmap[1], NUM_VMA_FLAG_BITS - BITS_PER_LONG);
+	}
+
+	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,
@@ -946,7 +958,7 @@ static inline void vm_flags_clear(struct vm_area_struct *vma,
 {
 	VM_WARN_ON_ONCE(!pgtable_supports_soft_dirty() && (flags & VM_SOFTDIRTY));
 	vma_start_write(vma);
-	ACCESS_PRIVATE(vma, __vm_flags) &= ~flags;
+	vma_flags_clear_word(&vma->flags, flags);
 }
 
 /*
@@ -989,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 -30

190 lines not on this page · raw message

Signature · 1 line
2.51.2
reviewer Reviewed-by on v3 4/4
#14 lore raw

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

Quoted 54 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 adapt vm_flags_reset_once() to only clear those bits above the first system word providing write-once semantics to the first system word (which it is presumed the caller requires - and in all current use cases this is so).

As we currently only specify that the VMA flags bitmap size is equal to BITS_PER_LONG number of bits, this is a noop, but is defensive in preparation for a future change that increases this.

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.

Quoted 6 lines

Once we introduce flag helpers we can improve this more.

No functional change intended.

FWIW, I'm not a huge fan of this vma_flags vs vm_flags and hope we can get rid of this ASAP. But it's a necessary evil for now, anyway.

Signature · 1 line
Pedro
maintainer Acked-by on the v3 series
#15 lore raw
In reply to Lorenzo Stoakes
Quoted 33 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).

Quoted 5 lines

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.

LGTM from Rust perspective.

#16 lore raw
Quoted 37 lines · Alice Ryhl
Quoted 36 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.

Quoted 6 lines
Quoted 2 lines

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

LGTM from Rust perspective.

Thanks! :)

maintainer
#17 lore raw
In reply to Lorenzo Stoakes
Quoted 10 lines · On Tue, 25 Nov 2025 10:00:58 +0000 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.

Quoted 6 lines

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.

All added to mm-unstable, thanks.