Re: [PATCH v3 00/23] mm/vma: convert vm_flags_t to vma_flags_t in vma code

Andrew Morton
2026-03-18T17:48:05Z

On Wed, 18 Mar 2026 15:50:11 +0000 "Lorenzo Stoakes (Oracle)" <ljs@kernel.org> wrote:

> This series converts a lot of the existing use of the legacy vm_flags_t
> data type to the new vma_flags_t type which replaces it.

Updated, thanks. Below is how v3 altered mm.git:

arch/arm64/include/asm/page.h | 4 +++
include/linux/mm_types.h | 32 +++++++++++++++---------------
mm/mseal.c | 1
mm/vma.c | 27 +++++++++++++------------
tools/testing/vma/include/dup.h | 22 +++++++++++---------
tools/testing/vma/tests/vma.c | 3 --
6 files changed, 48 insertions(+), 41 deletions(-)

--- a/arch/arm64/include/asm/page.h~b
+++ a/arch/arm64/include/asm/page.h
@@ -46,8 +46,12 @@ int pfn_is_map_memory(unsigned long pfn)

#endif /* !__ASSEMBLER__ */

+#ifdef CONFIG_ARM64_MTE
#define VMA_DATA_DEFAULT_FLAGS append_vma_flags(VMA_DATA_FLAGS_TSK_EXEC, \
VMA_MTE_ALLOWED_BIT)
+#else
+#define VMA_DATA_DEFAULT_FLAGS VMA_DATA_FLAGS_TSK_EXEC
+#endif

#include <asm-generic/getorder.h>

--- a/include/linux/mm_types.h~b
+++ a/include/linux/mm_types.h
@@ -871,9 +871,9 @@ typedef struct {
#define EMPTY_VMA_FLAGS ((vma_flags_t){ })

/* Are no flags set in the specified VMA flags? */
-static __always_inline bool vma_flags_empty(vma_flags_t *flags)
+static __always_inline bool vma_flags_empty(const vma_flags_t *flags)
{
- unsigned long *bitmap = flags->__vma_flags;
+ const unsigned long *bitmap = flags->__vma_flags;

return bitmap_empty(bitmap, NUM_VMA_FLAG_BITS);
}
@@ -1082,20 +1082,6 @@ static __always_inline vm_flags_t vma_fl
}

/*
- * Helper function which converts a legacy vm_flags_t value to a vma_flags_t
- * value.
- *
- * Will be removed once the conversion to VMA flags is complete.
- */
-static __always_inline vma_flags_t legacy_to_vma_flags(vm_flags_t flags)
-{
- vma_flags_t ret;
-
- ret.__vma_flags[0] = (unsigned long)flags;
- return ret;
-}
-
-/*
* Copy value to the first system word of VMA flags, non-atomically.
*
* IMPORTANT: This does not overwrite bytes past the first system word. The
@@ -1110,6 +1096,20 @@ static __always_inline void vma_flags_ov
}

/*
+ * Helper function which converts a legacy vm_flags_t value to a vma_flags_t
+ * value.
+ *
+ * Will be removed once the conversion to VMA flags is complete.
+ */
+static __always_inline vma_flags_t legacy_to_vma_flags(vm_flags_t flags)
+{
+ vma_flags_t ret = EMPTY_VMA_FLAGS;
+
+ vma_flags_overwrite_word(&ret, flags);
+ return ret;
+}
+
+/*
* 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
--- a/mm/mseal.c~b
+++ a/mm/mseal.c
@@ -77,6 +77,7 @@ static int mseal_apply(struct mm_struct
curr_end, &vma_flags);
if (IS_ERR(vma))
return PTR_ERR(vma);
+ vma_start_write(vma);
vma_set_flags(vma, VMA_SEALED_BIT);
}

--- a/mm/vma.c~b
+++ a/mm/vma.c
@@ -905,20 +905,21 @@ static __must_check struct vm_area_struc
vma_start_write(middle);

if (merge_right) {
- const vma_flags_t next_sticky =
- vma_flags_and_mask(&next->flags, VMA_STICKY_FLAGS);
+ vma_flags_t next_sticky;

vma_start_write(next);
vmg->target = next;
+ next_sticky = vma_flags_and_mask(&next->flags, VMA_STICKY_FLAGS);
vma_flags_set_mask(&sticky_flags, next_sticky);
}

if (merge_left) {
- const vma_flags_t prev_sticky =
- vma_flags_and_mask(&prev->flags, VMA_STICKY_FLAGS);
+ vma_flags_t prev_sticky;

vma_start_write(prev);
vmg->target = prev;
+
+ prev_sticky = vma_flags_and_mask(&prev->flags, VMA_STICKY_FLAGS);
vma_flags_set_mask(&sticky_flags, prev_sticky);
}

@@ -1170,13 +1171,14 @@ int vma_expand(struct vma_merge_struct *
bool remove_next = false;
vma_flags_t sticky_flags =
vma_flags_and_mask(&vmg->vma_flags, VMA_STICKY_FLAGS);
- const vma_flags_t target_sticky =
- vma_flags_and_mask(&target->flags, VMA_STICKY_FLAGS);
+ vma_flags_t target_sticky;
int ret = 0;

mmap_assert_write_locked(vmg->mm);
vma_start_write(target);

+ target_sticky = vma_flags_and_mask(&target->flags, VMA_STICKY_FLAGS);
+
if (next && target != next && vmg->end == next->vm_end)
remove_next = true;

@@ -1192,12 +1194,6 @@ int vma_expand(struct vma_merge_struct *
target->vm_end > vmg->end, vmg);

vma_flags_set_mask(&sticky_flags, target_sticky);
- if (remove_next) {
- const vma_flags_t next_sticky =
- vma_flags_and_mask(&next->flags, VMA_STICKY_FLAGS);
-
- vma_flags_set_mask(&sticky_flags, next_sticky);
- }

/*
* If we are removing the next VMA or copying from a VMA
@@ -1214,8 +1210,13 @@ int vma_expand(struct vma_merge_struct *
return ret;

if (remove_next) {
+ vma_flags_t next_sticky;
+
vma_start_write(next);
vmg->__remove_next = true;
+
+ next_sticky = vma_flags_and_mask(&next->flags, VMA_STICKY_FLAGS);
+ vma_flags_set_mask(&sticky_flags, next_sticky);
}
if (commit_merge(vmg))
goto nomem;
@@ -2950,7 +2951,7 @@ out:
if (vma_flags_test(&vma_flags, VMA_LOCKED_BIT))
mm->locked_vm += (len >> PAGE_SHIFT);
if (pgtable_supports_soft_dirty())
- vma_flags_set(&vma_flags, VMA_SOFTDIRTY_BIT);
+ vma_set_flags(vma, VMA_SOFTDIRTY_BIT);
return 0;

mas_store_fail:
--- a/tools/testing/vma/include/dup.h~b
+++ a/tools/testing/vma/include/dup.h
@@ -441,9 +441,9 @@ struct vma_iterator {
#define MAPCOUNT_ELF_CORE_MARGIN (5)
#define DEFAULT_MAX_MAP_COUNT (USHRT_MAX - MAPCOUNT_ELF_CORE_MARGIN)

-static __always_inline bool vma_flags_empty(vma_flags_t *flags)
+static __always_inline bool vma_flags_empty(const vma_flags_t *flags)
{
- unsigned long *bitmap = flags->__vma_flags;
+ const unsigned long *bitmap = flags->__vma_flags;

return bitmap_empty(bitmap, NUM_VMA_FLAG_BITS);
}
@@ -775,7 +775,9 @@ static inline bool mm_flags_test(int fla
static __always_inline void vma_flags_overwrite_word(vma_flags_t *flags,
unsigned long value)
{
- *ACCESS_PRIVATE(flags, __vma_flags) = value;
+ unsigned long *bitmap = flags->__vma_flags;
+
+ bitmap[0] = value;
}

/*
@@ -787,7 +789,7 @@ static __always_inline void vma_flags_ov
static __always_inline void vma_flags_overwrite_word_once(vma_flags_t *flags,
unsigned long value)
{
- unsigned long *bitmap = ACCESS_PRIVATE(flags, __vma_flags);
+ unsigned long *bitmap = flags->__vma_flags;

WRITE_ONCE(*bitmap, value);
}
@@ -796,7 +798,7 @@ static __always_inline void vma_flags_ov
static __always_inline void vma_flags_set_word(vma_flags_t *flags,
unsigned long value)
{
- unsigned long *bitmap = ACCESS_PRIVATE(flags, __vma_flags);
+ unsigned long *bitmap = flags->__vma_flags;

*bitmap |= value;
}
@@ -805,7 +807,7 @@ static __always_inline void vma_flags_se
static __always_inline void vma_flags_clear_word(vma_flags_t *flags,
unsigned long value)
{
- unsigned long *bitmap = ACCESS_PRIVATE(flags, __vma_flags);
+ unsigned long *bitmap = flags->__vma_flags;

*bitmap &= ~value;
}
@@ -835,9 +837,9 @@ static __always_inline vm_flags_t vma_fl
*/
static __always_inline vma_flags_t legacy_to_vma_flags(vm_flags_t flags)
{
- vma_flags_t ret;
+ vma_flags_t ret = EMPTY_VMA_FLAGS;

- ret.__vma_flags[0] = (unsigned long)flags;
+ vma_flags_overwrite_word(&ret, flags);
return ret;
}

@@ -1073,8 +1075,8 @@ static __always_inline void vma_clear_fl
vma_flags_clear_mask(&vma->flags, flags);
}

-#define vma_clear_flags(vmag, ...) \
- vma_clear_flags_mask(vmag, mk_vma_flags(__VA_ARGS__))
+#define vma_clear_flags(vma, ...) \
+ vma_clear_flags_mask(vma, mk_vma_flags(__VA_ARGS__))

static __always_inline bool vma_desc_test(const struct vm_area_desc *desc,
vma_flag_t bit)
--- a/tools/testing/vma/tests/vma.c~b
+++ a/tools/testing/vma/tests/vma.c
@@ -356,10 +356,9 @@ static bool test_vma_flags_clear(void)

/* Cursory check of _mask() variant, as the helper macros imply. */
vma_flags_clear_mask(&flags, mask);
- vma_flags_clear_mask(&vma.flags, mask);
+ vma_clear_flags_mask(&vma, mask);
vma_desc_clear_flags_mask(&desc, mask);
#if NUM_VMA_FLAG_BITS > 64
- vma_clear_flags_mask(&vma, mask);
ASSERT_FALSE(vma_flags_test_any(&flags, VMA_EXEC_BIT, 64));
ASSERT_FALSE(vma_test_any(&vma, VMA_EXEC_BIT, 64));
ASSERT_FALSE(vma_desc_test_any(&desc, VMA_EXEC_BIT, 64));
_