* [PATCH v2 01/13] mm/vma: remove __private sparse decoration from vma_flags_t
2026-01-22 16:06 [PATCH v2 00/13] mm: add bitmap VMA flag helpers and convert all mmap_prepare to use them Lorenzo Stoakes
@ 2026-01-22 16:06 ` Lorenzo Stoakes
2026-02-06 17:02 ` Pedro Falcato
2026-02-09 18:38 ` Liam R. Howlett
2026-01-22 16:06 ` [PATCH v2 02/13] mm: rename vma_flag_test/set_atomic() to vma_test/set_atomic_flag() Lorenzo Stoakes
` (13 subsequent siblings)
14 siblings, 2 replies; 56+ messages in thread
From: Lorenzo Stoakes @ 2026-01-22 16:06 UTC (permalink / raw)
To: Andrew Morton
Cc: Jarkko Sakkinen, Dave Hansen, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, x86, H . Peter Anvin, Arnd Bergmann,
Greg Kroah-Hartman, Dan Williams, Vishal Verma, Dave Jiang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
We need to pass around these values and access them in a way that sparse
does not allow, as __private implies noderef, i.e. disallowing dereference
of the value, which manifests as sparse warnings even when passed around
benignly.
Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
---
include/linux/mm.h | 4 ++--
include/linux/mm_types.h | 14 ++++++++------
2 files changed, 10 insertions(+), 8 deletions(-)
diff --git a/include/linux/mm.h b/include/linux/mm.h
index d7ca837dd8a5..776a7e03f88b 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -943,7 +943,7 @@ static inline void vm_flags_reset_once(struct vm_area_struct *vma,
* system word.
*/
if (NUM_VMA_FLAG_BITS > BITS_PER_LONG) {
- unsigned long *bitmap = ACCESS_PRIVATE(&vma->flags, __vma_flags);
+ unsigned long *bitmap = vma->flags.__vma_flags;
bitmap_zero(&bitmap[1], NUM_VMA_FLAG_BITS - BITS_PER_LONG);
}
@@ -1006,7 +1006,7 @@ 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);
+ unsigned long *bitmap = vma->flags.__vma_flags;
vma_assert_stabilised(vma);
if (__vma_flag_atomic_valid(vma, bit))
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index e5ee66f84d9a..592ad065fa75 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -866,7 +866,7 @@ struct mmap_action {
#define NUM_VMA_FLAG_BITS BITS_PER_LONG
typedef struct {
DECLARE_BITMAP(__vma_flags, NUM_VMA_FLAG_BITS);
-} __private vma_flags_t;
+} vma_flags_t;
/*
* Describes a VMA that is about to be mmap()'ed. Drivers may choose to
@@ -1056,7 +1056,7 @@ struct vm_area_struct {
/* 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);
+ bitmap_zero(flags->__vma_flags, NUM_VMA_FLAG_BITS);
}
/*
@@ -1067,7 +1067,9 @@ static inline void vma_flags_clear_all(vma_flags_t *flags)
*/
static 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;
}
/*
@@ -1078,7 +1080,7 @@ static inline void vma_flags_overwrite_word(vma_flags_t *flags, unsigned long va
*/
static 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);
}
@@ -1086,7 +1088,7 @@ static inline void vma_flags_overwrite_word_once(vma_flags_t *flags, unsigned lo
/* 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);
+ unsigned long *bitmap = flags->__vma_flags;
*bitmap |= value;
}
@@ -1094,7 +1096,7 @@ static inline void vma_flags_set_word(vma_flags_t *flags, unsigned long 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);
+ unsigned long *bitmap = flags->__vma_flags;
*bitmap &= ~value;
}
--
2.52.0
^ permalink raw reply [flat|nested] 56+ messages in thread* Re: [PATCH v2 01/13] mm/vma: remove __private sparse decoration from vma_flags_t
2026-01-22 16:06 ` [PATCH v2 01/13] mm/vma: remove __private sparse decoration from vma_flags_t Lorenzo Stoakes
@ 2026-02-06 17:02 ` Pedro Falcato
2026-02-09 18:38 ` Liam R. Howlett
1 sibling, 0 replies; 56+ messages in thread
From: Pedro Falcato @ 2026-02-06 17:02 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin,
Arnd Bergmann, Greg Kroah-Hartman, Dan Williams, Vishal Verma,
Dave Jiang, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, David Howells, Paul Moore, James Morris,
Serge E . Hallyn, Yury Norov, Rasmus Villemoes, linux-sgx,
linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
On Thu, Jan 22, 2026 at 04:06:10PM +0000, Lorenzo Stoakes wrote:
> We need to pass around these values and access them in a way that sparse
> does not allow, as __private implies noderef, i.e. disallowing dereference
> of the value, which manifests as sparse warnings even when passed around
> benignly.
>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Reviewed-by: Pedro Falcato <pfalcato@suse.de>
--
Pedro
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH v2 01/13] mm/vma: remove __private sparse decoration from vma_flags_t
2026-01-22 16:06 ` [PATCH v2 01/13] mm/vma: remove __private sparse decoration from vma_flags_t Lorenzo Stoakes
2026-02-06 17:02 ` Pedro Falcato
@ 2026-02-09 18:38 ` Liam R. Howlett
1 sibling, 0 replies; 56+ messages in thread
From: Liam R. Howlett @ 2026-02-09 18:38 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin,
Arnd Bergmann, Greg Kroah-Hartman, Dan Williams, Vishal Verma,
Dave Jiang, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Hugh Dickins, Baolin Wang, Zi Yan, Nico Pache, Ryan Roberts,
Dev Jain, Barry Song, Lance Yang, Jann Horn, Pedro Falcato,
David Howells, Paul Moore, James Morris, Serge E . Hallyn,
Yury Norov, Rasmus Villemoes, linux-sgx, linux-kernel, nvdimm,
linux-cxl, dri-devel, intel-gfx, linux-fsdevel, linux-aio,
linux-erofs, linux-ext4, linux-mm, ntfs3, devel, linux-xfs,
keyrings, linux-security-module, Jason Gunthorpe
* Lorenzo Stoakes <lorenzo.stoakes@oracle.com> [260122 16:06]:
> We need to pass around these values and access them in a way that sparse
> does not allow, as __private implies noderef, i.e. disallowing dereference
> of the value, which manifests as sparse warnings even when passed around
> benignly.
>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Reviewed-by: Liam R. Howlett <Liam.Howlett@oracle.com>
> ---
> include/linux/mm.h | 4 ++--
> include/linux/mm_types.h | 14 ++++++++------
> 2 files changed, 10 insertions(+), 8 deletions(-)
>
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index d7ca837dd8a5..776a7e03f88b 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -943,7 +943,7 @@ static inline void vm_flags_reset_once(struct vm_area_struct *vma,
> * system word.
> */
> if (NUM_VMA_FLAG_BITS > BITS_PER_LONG) {
> - unsigned long *bitmap = ACCESS_PRIVATE(&vma->flags, __vma_flags);
> + unsigned long *bitmap = vma->flags.__vma_flags;
>
> bitmap_zero(&bitmap[1], NUM_VMA_FLAG_BITS - BITS_PER_LONG);
> }
> @@ -1006,7 +1006,7 @@ 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);
> + unsigned long *bitmap = vma->flags.__vma_flags;
>
> vma_assert_stabilised(vma);
> if (__vma_flag_atomic_valid(vma, bit))
> diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
> index e5ee66f84d9a..592ad065fa75 100644
> --- a/include/linux/mm_types.h
> +++ b/include/linux/mm_types.h
> @@ -866,7 +866,7 @@ struct mmap_action {
> #define NUM_VMA_FLAG_BITS BITS_PER_LONG
> typedef struct {
> DECLARE_BITMAP(__vma_flags, NUM_VMA_FLAG_BITS);
> -} __private vma_flags_t;
> +} vma_flags_t;
>
> /*
> * Describes a VMA that is about to be mmap()'ed. Drivers may choose to
> @@ -1056,7 +1056,7 @@ struct vm_area_struct {
> /* 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);
> + bitmap_zero(flags->__vma_flags, NUM_VMA_FLAG_BITS);
> }
>
> /*
> @@ -1067,7 +1067,9 @@ static inline void vma_flags_clear_all(vma_flags_t *flags)
> */
> static 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;
> }
>
> /*
> @@ -1078,7 +1080,7 @@ static inline void vma_flags_overwrite_word(vma_flags_t *flags, unsigned long va
> */
> static 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);
> }
> @@ -1086,7 +1088,7 @@ static inline void vma_flags_overwrite_word_once(vma_flags_t *flags, unsigned lo
> /* 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);
> + unsigned long *bitmap = flags->__vma_flags;
>
> *bitmap |= value;
> }
> @@ -1094,7 +1096,7 @@ static inline void vma_flags_set_word(vma_flags_t *flags, unsigned long 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);
> + unsigned long *bitmap = flags->__vma_flags;
>
> *bitmap &= ~value;
> }
> --
> 2.52.0
>
^ permalink raw reply [flat|nested] 56+ messages in thread
* [PATCH v2 02/13] mm: rename vma_flag_test/set_atomic() to vma_test/set_atomic_flag()
2026-01-22 16:06 [PATCH v2 00/13] mm: add bitmap VMA flag helpers and convert all mmap_prepare to use them Lorenzo Stoakes
2026-01-22 16:06 ` [PATCH v2 01/13] mm/vma: remove __private sparse decoration from vma_flags_t Lorenzo Stoakes
@ 2026-01-22 16:06 ` Lorenzo Stoakes
2026-02-06 17:04 ` Pedro Falcato
2026-02-09 18:40 ` Liam R. Howlett
2026-01-22 16:06 ` [PATCH v2 03/13] mm: add mk_vma_flags() bitmap flag macro helper Lorenzo Stoakes
` (12 subsequent siblings)
14 siblings, 2 replies; 56+ messages in thread
From: Lorenzo Stoakes @ 2026-01-22 16:06 UTC (permalink / raw)
To: Andrew Morton
Cc: Jarkko Sakkinen, Dave Hansen, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, x86, H . Peter Anvin, Arnd Bergmann,
Greg Kroah-Hartman, Dan Williams, Vishal Verma, Dave Jiang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
In order to stay consistent between functions which manipulate a vm_flags_t
argument of the form of vma_flags_...() and those which manipulate a
VMA (in this case the flags field of a VMA), rename
vma_flag_[test/set]_atomic() to vma_[test/set]_atomic_flag().
This lays the groundwork for adding VMA flag manipulation functions in a
subsequent commit.
Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
---
include/linux/mm.h | 13 +++++--------
mm/khugepaged.c | 2 +-
mm/madvise.c | 2 +-
3 files changed, 7 insertions(+), 10 deletions(-)
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 776a7e03f88b..e0d31238097c 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -987,8 +987,7 @@ static inline void vm_flags_mod(struct vm_area_struct *vma,
__vm_flags_mod(vma, set, clear);
}
-static inline bool __vma_flag_atomic_valid(struct vm_area_struct *vma,
- vma_flag_t bit)
+static inline bool __vma_atomic_valid_flag(struct vm_area_struct *vma, vma_flag_t bit)
{
const vm_flags_t mask = BIT((__force int)bit);
@@ -1003,13 +1002,12 @@ static inline bool __vma_flag_atomic_valid(struct vm_area_struct *vma,
* Set VMA flag atomically. Requires only VMA/mmap read lock. Only specific
* valid flags are allowed to do this.
*/
-static inline void vma_flag_set_atomic(struct vm_area_struct *vma,
- vma_flag_t bit)
+static inline void vma_set_atomic_flag(struct vm_area_struct *vma, vma_flag_t bit)
{
unsigned long *bitmap = vma->flags.__vma_flags;
vma_assert_stabilised(vma);
- if (__vma_flag_atomic_valid(vma, bit))
+ if (__vma_atomic_valid_flag(vma, bit))
set_bit((__force int)bit, bitmap);
}
@@ -1020,10 +1018,9 @@ static inline void vma_flag_set_atomic(struct vm_area_struct *vma,
* This is necessarily racey, so callers must ensure that serialisation is
* achieved through some other means, or that races are permissible.
*/
-static inline bool vma_flag_test_atomic(struct vm_area_struct *vma,
- vma_flag_t bit)
+static inline bool vma_test_atomic_flag(struct vm_area_struct *vma, vma_flag_t bit)
{
- if (__vma_flag_atomic_valid(vma, bit))
+ if (__vma_atomic_valid_flag(vma, bit))
return test_bit((__force int)bit, &vma->vm_flags);
return false;
diff --git a/mm/khugepaged.c b/mm/khugepaged.c
index fba6aea5bea6..e76f42243534 100644
--- a/mm/khugepaged.c
+++ b/mm/khugepaged.c
@@ -1741,7 +1741,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, VMA_MAYBE_GUARD_BIT))
+ if (vma_test_atomic_flag(vma, VMA_MAYBE_GUARD_BIT))
return false;
return true;
diff --git a/mm/madvise.c b/mm/madvise.c
index 1f3040688f04..8debb2d434aa 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -1140,7 +1140,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, VMA_MAYBE_GUARD_BIT);
+ vma_set_atomic_flag(vma, VMA_MAYBE_GUARD_BIT);
/*
* If anonymous and we are establishing page tables the VMA ought to
--
2.52.0
^ permalink raw reply [flat|nested] 56+ messages in thread* Re: [PATCH v2 02/13] mm: rename vma_flag_test/set_atomic() to vma_test/set_atomic_flag()
2026-01-22 16:06 ` [PATCH v2 02/13] mm: rename vma_flag_test/set_atomic() to vma_test/set_atomic_flag() Lorenzo Stoakes
@ 2026-02-06 17:04 ` Pedro Falcato
2026-02-09 18:40 ` Liam R. Howlett
1 sibling, 0 replies; 56+ messages in thread
From: Pedro Falcato @ 2026-02-06 17:04 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin,
Arnd Bergmann, Greg Kroah-Hartman, Dan Williams, Vishal Verma,
Dave Jiang, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, David Howells, Paul Moore, James Morris,
Serge E . Hallyn, Yury Norov, Rasmus Villemoes, linux-sgx,
linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
On Thu, Jan 22, 2026 at 04:06:11PM +0000, Lorenzo Stoakes wrote:
> In order to stay consistent between functions which manipulate a vm_flags_t
> argument of the form of vma_flags_...() and those which manipulate a
> VMA (in this case the flags field of a VMA), rename
> vma_flag_[test/set]_atomic() to vma_[test/set]_atomic_flag().
>
> This lays the groundwork for adding VMA flag manipulation functions in a
> subsequent commit.
>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Reviewed-by: Pedro Falcato <pfalcato@suse.de>
--
Pedro
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH v2 02/13] mm: rename vma_flag_test/set_atomic() to vma_test/set_atomic_flag()
2026-01-22 16:06 ` [PATCH v2 02/13] mm: rename vma_flag_test/set_atomic() to vma_test/set_atomic_flag() Lorenzo Stoakes
2026-02-06 17:04 ` Pedro Falcato
@ 2026-02-09 18:40 ` Liam R. Howlett
1 sibling, 0 replies; 56+ messages in thread
From: Liam R. Howlett @ 2026-02-09 18:40 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin,
Arnd Bergmann, Greg Kroah-Hartman, Dan Williams, Vishal Verma,
Dave Jiang, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Hugh Dickins, Baolin Wang, Zi Yan, Nico Pache, Ryan Roberts,
Dev Jain, Barry Song, Lance Yang, Jann Horn, Pedro Falcato,
David Howells, Paul Moore, James Morris, Serge E . Hallyn,
Yury Norov, Rasmus Villemoes, linux-sgx, linux-kernel, nvdimm,
linux-cxl, dri-devel, intel-gfx, linux-fsdevel, linux-aio,
linux-erofs, linux-ext4, linux-mm, ntfs3, devel, linux-xfs,
keyrings, linux-security-module, Jason Gunthorpe
* Lorenzo Stoakes <lorenzo.stoakes@oracle.com> [260122 16:06]:
> In order to stay consistent between functions which manipulate a vm_flags_t
> argument of the form of vma_flags_...() and those which manipulate a
> VMA (in this case the flags field of a VMA), rename
> vma_flag_[test/set]_atomic() to vma_[test/set]_atomic_flag().
>
> This lays the groundwork for adding VMA flag manipulation functions in a
> subsequent commit.
>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Reviewed-by: Liam R. Howlett <Liam.Howlett@oracle.com>
> ---
> include/linux/mm.h | 13 +++++--------
> mm/khugepaged.c | 2 +-
> mm/madvise.c | 2 +-
> 3 files changed, 7 insertions(+), 10 deletions(-)
>
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index 776a7e03f88b..e0d31238097c 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -987,8 +987,7 @@ static inline void vm_flags_mod(struct vm_area_struct *vma,
> __vm_flags_mod(vma, set, clear);
> }
>
> -static inline bool __vma_flag_atomic_valid(struct vm_area_struct *vma,
> - vma_flag_t bit)
> +static inline bool __vma_atomic_valid_flag(struct vm_area_struct *vma, vma_flag_t bit)
> {
> const vm_flags_t mask = BIT((__force int)bit);
>
> @@ -1003,13 +1002,12 @@ static inline bool __vma_flag_atomic_valid(struct vm_area_struct *vma,
> * Set VMA flag atomically. Requires only VMA/mmap read lock. Only specific
> * valid flags are allowed to do this.
> */
> -static inline void vma_flag_set_atomic(struct vm_area_struct *vma,
> - vma_flag_t bit)
> +static inline void vma_set_atomic_flag(struct vm_area_struct *vma, vma_flag_t bit)
> {
> unsigned long *bitmap = vma->flags.__vma_flags;
>
> vma_assert_stabilised(vma);
> - if (__vma_flag_atomic_valid(vma, bit))
> + if (__vma_atomic_valid_flag(vma, bit))
> set_bit((__force int)bit, bitmap);
> }
>
> @@ -1020,10 +1018,9 @@ static inline void vma_flag_set_atomic(struct vm_area_struct *vma,
> * This is necessarily racey, so callers must ensure that serialisation is
> * achieved through some other means, or that races are permissible.
> */
> -static inline bool vma_flag_test_atomic(struct vm_area_struct *vma,
> - vma_flag_t bit)
> +static inline bool vma_test_atomic_flag(struct vm_area_struct *vma, vma_flag_t bit)
> {
> - if (__vma_flag_atomic_valid(vma, bit))
> + if (__vma_atomic_valid_flag(vma, bit))
> return test_bit((__force int)bit, &vma->vm_flags);
>
> return false;
> diff --git a/mm/khugepaged.c b/mm/khugepaged.c
> index fba6aea5bea6..e76f42243534 100644
> --- a/mm/khugepaged.c
> +++ b/mm/khugepaged.c
> @@ -1741,7 +1741,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, VMA_MAYBE_GUARD_BIT))
> + if (vma_test_atomic_flag(vma, VMA_MAYBE_GUARD_BIT))
> return false;
>
> return true;
> diff --git a/mm/madvise.c b/mm/madvise.c
> index 1f3040688f04..8debb2d434aa 100644
> --- a/mm/madvise.c
> +++ b/mm/madvise.c
> @@ -1140,7 +1140,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, VMA_MAYBE_GUARD_BIT);
> + vma_set_atomic_flag(vma, VMA_MAYBE_GUARD_BIT);
>
> /*
> * If anonymous and we are establishing page tables the VMA ought to
> --
> 2.52.0
>
^ permalink raw reply [flat|nested] 56+ messages in thread
* [PATCH v2 03/13] mm: add mk_vma_flags() bitmap flag macro helper
2026-01-22 16:06 [PATCH v2 00/13] mm: add bitmap VMA flag helpers and convert all mmap_prepare to use them Lorenzo Stoakes
2026-01-22 16:06 ` [PATCH v2 01/13] mm/vma: remove __private sparse decoration from vma_flags_t Lorenzo Stoakes
2026-01-22 16:06 ` [PATCH v2 02/13] mm: rename vma_flag_test/set_atomic() to vma_test/set_atomic_flag() Lorenzo Stoakes
@ 2026-01-22 16:06 ` Lorenzo Stoakes
2026-02-06 17:14 ` Pedro Falcato
2026-02-09 18:44 ` Liam R. Howlett
2026-01-22 16:06 ` [PATCH v2 04/13] tools: bitmap: add missing bitmap_[subset(), andnot()] Lorenzo Stoakes
` (11 subsequent siblings)
14 siblings, 2 replies; 56+ messages in thread
From: Lorenzo Stoakes @ 2026-01-22 16:06 UTC (permalink / raw)
To: Andrew Morton
Cc: Jarkko Sakkinen, Dave Hansen, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, x86, H . Peter Anvin, Arnd Bergmann,
Greg Kroah-Hartman, Dan Williams, Vishal Verma, Dave Jiang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
This patch introduces the mk_vma_flags() macro helper to allow easy
manipulation of VMA flags utilising the new bitmap representation
implemented of VMA flags defined by the vma_flags_t type.
It is a variadic macro which provides a bitwise-or'd representation of all
of each individual VMA flag specified.
Note that, while we maintain VM_xxx flags for backwards compatibility until
the conversion is complete, we define VMA flags of type vma_flag_t using
VMA_xxx_BIT to avoid confusing the two.
This helper macro therefore can be used thusly:
vma_flags_t flags = mk_vma_flags(VMA_READ_BIT, VMA_WRITE_BIT);
We allow for up to 5 flags to specified at a time which should accommodate
all current kernel uses of combined VMA flags.
Testing has demonstrated that the compiler optimises this code such that it
generates the same assembly utilising this macro as it does if the flags
were specified manually, for instance:
vma_flags_t get_flags(void)
{
return mk_vma_flags(VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT);
}
Generates the same code as:
vma_flags_t get_flags(void)
{
vma_flags_t flags;
vma_flags_clear_all(&flags);
vma_flag_set(&flags, VMA_READ_BIT);
vma_flag_set(&flags, VMA_WRITE_BIT);
vma_flag_set(&flags, VMA_EXEC_BIT);
return flags;
}
And:
vma_flags_t get_flags(void)
{
vma_flags_t flags;
unsigned long *bitmap = ACCESS_PRIVATE(&flags, __vma_flags);
*bitmap = 1UL << (__force int)VMA_READ_BIT;
*bitmap |= 1UL << (__force int)VMA_WRITE_BIT;
*bitmap |= 1UL << (__force int)VMA_EXEC_BIT;
return flags;
}
That is:
get_flags:
movl $7, %eax
ret
Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
---
include/linux/mm.h | 33 +++++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)
diff --git a/include/linux/mm.h b/include/linux/mm.h
index e0d31238097c..32c3b5347dc6 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2,6 +2,7 @@
#ifndef _LINUX_MM_H
#define _LINUX_MM_H
+#include <linux/args.h>
#include <linux/errno.h>
#include <linux/mmdebug.h>
#include <linux/gfp.h>
@@ -1026,6 +1027,38 @@ static inline bool vma_test_atomic_flag(struct vm_area_struct *vma, vma_flag_t b
return false;
}
+/* Set an individual VMA flag in flags, non-atomically. */
+static inline void vma_flag_set(vma_flags_t *flags, vma_flag_t bit)
+{
+ unsigned long *bitmap = flags->__vma_flags;
+
+ __set_bit((__force int)bit, bitmap);
+}
+
+static inline vma_flags_t __mk_vma_flags(size_t count, const vma_flag_t *bits)
+{
+ vma_flags_t flags;
+ int i;
+
+ vma_flags_clear_all(&flags);
+ for (i = 0; i < count; i++)
+ vma_flag_set(&flags, bits[i]);
+ return flags;
+}
+
+/*
+ * Helper macro which bitwise-or combines the specified input flags into a
+ * vma_flags_t bitmap value. E.g.:
+ *
+ * vma_flags_t flags = mk_vma_flags(VMA_IO_BIT, VMA_PFNMAP_BIT,
+ * VMA_DONTEXPAND_BIT, VMA_DONTDUMP_BIT);
+ *
+ * The compiler cleverly optimises away all of the work and this ends up being
+ * equivalent to aggregating the values manually.
+ */
+#define mk_vma_flags(...) __mk_vma_flags(COUNT_ARGS(__VA_ARGS__), \
+ (const vma_flag_t []){__VA_ARGS__})
+
static inline void vma_set_anonymous(struct vm_area_struct *vma)
{
vma->vm_ops = NULL;
--
2.52.0
^ permalink raw reply [flat|nested] 56+ messages in thread* Re: [PATCH v2 03/13] mm: add mk_vma_flags() bitmap flag macro helper
2026-01-22 16:06 ` [PATCH v2 03/13] mm: add mk_vma_flags() bitmap flag macro helper Lorenzo Stoakes
@ 2026-02-06 17:14 ` Pedro Falcato
2026-02-09 14:02 ` Lorenzo Stoakes
2026-02-09 18:44 ` Liam R. Howlett
1 sibling, 1 reply; 56+ messages in thread
From: Pedro Falcato @ 2026-02-06 17:14 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin,
Arnd Bergmann, Greg Kroah-Hartman, Dan Williams, Vishal Verma,
Dave Jiang, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, David Howells, Paul Moore, James Morris,
Serge E . Hallyn, Yury Norov, Rasmus Villemoes, linux-sgx,
linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
On Thu, Jan 22, 2026 at 04:06:12PM +0000, Lorenzo Stoakes wrote:
> This patch introduces the mk_vma_flags() macro helper to allow easy
> manipulation of VMA flags utilising the new bitmap representation
> implemented of VMA flags defined by the vma_flags_t type.
>
> It is a variadic macro which provides a bitwise-or'd representation of all
> of each individual VMA flag specified.
>
> Note that, while we maintain VM_xxx flags for backwards compatibility until
> the conversion is complete, we define VMA flags of type vma_flag_t using
> VMA_xxx_BIT to avoid confusing the two.
>
> This helper macro therefore can be used thusly:
>
> vma_flags_t flags = mk_vma_flags(VMA_READ_BIT, VMA_WRITE_BIT);
>
> We allow for up to 5 flags to specified at a time which should accommodate
> all current kernel uses of combined VMA flags.
>
How do you allow up to 5 flags? I don't see any such limitation in the code?
> Testing has demonstrated that the compiler optimises this code such that it
> generates the same assembly utilising this macro as it does if the flags
> were specified manually, for instance:
>
> vma_flags_t get_flags(void)
> {
> return mk_vma_flags(VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT);
> }
>
> Generates the same code as:
>
> vma_flags_t get_flags(void)
> {
> vma_flags_t flags;
>
> vma_flags_clear_all(&flags);
> vma_flag_set(&flags, VMA_READ_BIT);
> vma_flag_set(&flags, VMA_WRITE_BIT);
> vma_flag_set(&flags, VMA_EXEC_BIT);
>
> return flags;
> }
>
> And:
>
> vma_flags_t get_flags(void)
> {
> vma_flags_t flags;
> unsigned long *bitmap = ACCESS_PRIVATE(&flags, __vma_flags);
>
> *bitmap = 1UL << (__force int)VMA_READ_BIT;
> *bitmap |= 1UL << (__force int)VMA_WRITE_BIT;
> *bitmap |= 1UL << (__force int)VMA_EXEC_BIT;
>
> return flags;
> }
>
> That is:
>
> get_flags:
> movl $7, %eax
> ret
>
> Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Reviewed-by: Pedro Falcato <pfalcato@suse.de>
--
Pedro
^ permalink raw reply [flat|nested] 56+ messages in thread* Re: [PATCH v2 03/13] mm: add mk_vma_flags() bitmap flag macro helper
2026-02-06 17:14 ` Pedro Falcato
@ 2026-02-09 14:02 ` Lorenzo Stoakes
0 siblings, 0 replies; 56+ messages in thread
From: Lorenzo Stoakes @ 2026-02-09 14:02 UTC (permalink / raw)
To: Pedro Falcato
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin,
Arnd Bergmann, Greg Kroah-Hartman, Dan Williams, Vishal Verma,
Dave Jiang, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, David Howells, Paul Moore, James Morris,
Serge E . Hallyn, Yury Norov, Rasmus Villemoes, linux-sgx,
linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
On Fri, Feb 06, 2026 at 05:14:10PM +0000, Pedro Falcato wrote:
> On Thu, Jan 22, 2026 at 04:06:12PM +0000, Lorenzo Stoakes wrote:
> > This patch introduces the mk_vma_flags() macro helper to allow easy
> > manipulation of VMA flags utilising the new bitmap representation
> > implemented of VMA flags defined by the vma_flags_t type.
> >
> > It is a variadic macro which provides a bitwise-or'd representation of all
> > of each individual VMA flag specified.
> >
> > Note that, while we maintain VM_xxx flags for backwards compatibility until
> > the conversion is complete, we define VMA flags of type vma_flag_t using
> > VMA_xxx_BIT to avoid confusing the two.
> >
> > This helper macro therefore can be used thusly:
> >
> > vma_flags_t flags = mk_vma_flags(VMA_READ_BIT, VMA_WRITE_BIT);
> >
> > We allow for up to 5 flags to specified at a time which should accommodate
> > all current kernel uses of combined VMA flags.
> >
>
> How do you allow up to 5 flags? I don't see any such limitation in the code?
Yeah oops :) This is from a previous implementation.
Andrew could you drop this paragraph? Thanks!
>
> > Testing has demonstrated that the compiler optimises this code such that it
> > generates the same assembly utilising this macro as it does if the flags
> > were specified manually, for instance:
> >
> > vma_flags_t get_flags(void)
> > {
> > return mk_vma_flags(VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT);
> > }
> >
> > Generates the same code as:
> >
> > vma_flags_t get_flags(void)
> > {
> > vma_flags_t flags;
> >
> > vma_flags_clear_all(&flags);
> > vma_flag_set(&flags, VMA_READ_BIT);
> > vma_flag_set(&flags, VMA_WRITE_BIT);
> > vma_flag_set(&flags, VMA_EXEC_BIT);
> >
> > return flags;
> > }
> >
> > And:
> >
> > vma_flags_t get_flags(void)
> > {
> > vma_flags_t flags;
> > unsigned long *bitmap = ACCESS_PRIVATE(&flags, __vma_flags);
> >
> > *bitmap = 1UL << (__force int)VMA_READ_BIT;
> > *bitmap |= 1UL << (__force int)VMA_WRITE_BIT;
> > *bitmap |= 1UL << (__force int)VMA_EXEC_BIT;
> >
> > return flags;
> > }
> >
> > That is:
> >
> > get_flags:
> > movl $7, %eax
> > ret
> >
> > Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
> > Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
>
> Reviewed-by: Pedro Falcato <pfalcato@suse.de>
Thanks!
>
> --
> Pedro
Cheers, Lorenzo
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH v2 03/13] mm: add mk_vma_flags() bitmap flag macro helper
2026-01-22 16:06 ` [PATCH v2 03/13] mm: add mk_vma_flags() bitmap flag macro helper Lorenzo Stoakes
2026-02-06 17:14 ` Pedro Falcato
@ 2026-02-09 18:44 ` Liam R. Howlett
1 sibling, 0 replies; 56+ messages in thread
From: Liam R. Howlett @ 2026-02-09 18:44 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin,
Arnd Bergmann, Greg Kroah-Hartman, Dan Williams, Vishal Verma,
Dave Jiang, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Hugh Dickins, Baolin Wang, Zi Yan, Nico Pache, Ryan Roberts,
Dev Jain, Barry Song, Lance Yang, Jann Horn, Pedro Falcato,
David Howells, Paul Moore, James Morris, Serge E . Hallyn,
Yury Norov, Rasmus Villemoes, linux-sgx, linux-kernel, nvdimm,
linux-cxl, dri-devel, intel-gfx, linux-fsdevel, linux-aio,
linux-erofs, linux-ext4, linux-mm, ntfs3, devel, linux-xfs,
keyrings, linux-security-module, Jason Gunthorpe
* Lorenzo Stoakes <lorenzo.stoakes@oracle.com> [260122 16:06]:
> This patch introduces the mk_vma_flags() macro helper to allow easy
> manipulation of VMA flags utilising the new bitmap representation
> implemented of VMA flags defined by the vma_flags_t type.
>
> It is a variadic macro which provides a bitwise-or'd representation of all
> of each individual VMA flag specified.
>
> Note that, while we maintain VM_xxx flags for backwards compatibility until
> the conversion is complete, we define VMA flags of type vma_flag_t using
> VMA_xxx_BIT to avoid confusing the two.
>
> This helper macro therefore can be used thusly:
>
> vma_flags_t flags = mk_vma_flags(VMA_READ_BIT, VMA_WRITE_BIT);
>
> We allow for up to 5 flags to specified at a time which should accommodate
> all current kernel uses of combined VMA flags.
>
> Testing has demonstrated that the compiler optimises this code such that it
> generates the same assembly utilising this macro as it does if the flags
> were specified manually, for instance:
>
> vma_flags_t get_flags(void)
> {
> return mk_vma_flags(VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT);
> }
>
> Generates the same code as:
>
> vma_flags_t get_flags(void)
> {
> vma_flags_t flags;
>
> vma_flags_clear_all(&flags);
> vma_flag_set(&flags, VMA_READ_BIT);
> vma_flag_set(&flags, VMA_WRITE_BIT);
> vma_flag_set(&flags, VMA_EXEC_BIT);
>
> return flags;
> }
>
> And:
>
> vma_flags_t get_flags(void)
> {
> vma_flags_t flags;
> unsigned long *bitmap = ACCESS_PRIVATE(&flags, __vma_flags);
>
> *bitmap = 1UL << (__force int)VMA_READ_BIT;
> *bitmap |= 1UL << (__force int)VMA_WRITE_BIT;
> *bitmap |= 1UL << (__force int)VMA_EXEC_BIT;
>
> return flags;
> }
>
> That is:
>
> get_flags:
> movl $7, %eax
> ret
>
> Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Besides the part about 5 arguments that has been discussed,
Reviewed-by: Liam R. Howlett <Liam.Howlett@oracle.com>
> ---
> include/linux/mm.h | 33 +++++++++++++++++++++++++++++++++
> 1 file changed, 33 insertions(+)
>
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index e0d31238097c..32c3b5347dc6 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -2,6 +2,7 @@
> #ifndef _LINUX_MM_H
> #define _LINUX_MM_H
>
> +#include <linux/args.h>
> #include <linux/errno.h>
> #include <linux/mmdebug.h>
> #include <linux/gfp.h>
> @@ -1026,6 +1027,38 @@ static inline bool vma_test_atomic_flag(struct vm_area_struct *vma, vma_flag_t b
> return false;
> }
>
> +/* Set an individual VMA flag in flags, non-atomically. */
> +static inline void vma_flag_set(vma_flags_t *flags, vma_flag_t bit)
> +{
> + unsigned long *bitmap = flags->__vma_flags;
> +
> + __set_bit((__force int)bit, bitmap);
> +}
> +
> +static inline vma_flags_t __mk_vma_flags(size_t count, const vma_flag_t *bits)
> +{
> + vma_flags_t flags;
> + int i;
> +
> + vma_flags_clear_all(&flags);
> + for (i = 0; i < count; i++)
> + vma_flag_set(&flags, bits[i]);
> + return flags;
> +}
> +
> +/*
> + * Helper macro which bitwise-or combines the specified input flags into a
> + * vma_flags_t bitmap value. E.g.:
> + *
> + * vma_flags_t flags = mk_vma_flags(VMA_IO_BIT, VMA_PFNMAP_BIT,
> + * VMA_DONTEXPAND_BIT, VMA_DONTDUMP_BIT);
> + *
> + * The compiler cleverly optimises away all of the work and this ends up being
> + * equivalent to aggregating the values manually.
> + */
> +#define mk_vma_flags(...) __mk_vma_flags(COUNT_ARGS(__VA_ARGS__), \
> + (const vma_flag_t []){__VA_ARGS__})
> +
> static inline void vma_set_anonymous(struct vm_area_struct *vma)
> {
> vma->vm_ops = NULL;
> --
> 2.52.0
>
^ permalink raw reply [flat|nested] 56+ messages in thread
* [PATCH v2 04/13] tools: bitmap: add missing bitmap_[subset(), andnot()]
2026-01-22 16:06 [PATCH v2 00/13] mm: add bitmap VMA flag helpers and convert all mmap_prepare to use them Lorenzo Stoakes
` (2 preceding siblings ...)
2026-01-22 16:06 ` [PATCH v2 03/13] mm: add mk_vma_flags() bitmap flag macro helper Lorenzo Stoakes
@ 2026-01-22 16:06 ` Lorenzo Stoakes
2026-02-09 18:45 ` Liam R. Howlett
2026-01-22 16:06 ` [PATCH v2 05/13] mm: add basic VMA flag operation helper functions Lorenzo Stoakes
` (10 subsequent siblings)
14 siblings, 1 reply; 56+ messages in thread
From: Lorenzo Stoakes @ 2026-01-22 16:06 UTC (permalink / raw)
To: Andrew Morton
Cc: Jarkko Sakkinen, Dave Hansen, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, x86, H . Peter Anvin, Arnd Bergmann,
Greg Kroah-Hartman, Dan Williams, Vishal Verma, Dave Jiang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
The bitmap_subset() and bitmap_andnot() functions are not present in the
tools version of include/linux/bitmap.h, so add them as subsequent patches
implement test code that requires them.
We also add the missing __bitmap_subset() to tools/lib/bitmap.c.
Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
---
tools/include/linux/bitmap.h | 22 ++++++++++++++++++++++
tools/lib/bitmap.c | 29 +++++++++++++++++++++++++++++
2 files changed, 51 insertions(+)
diff --git a/tools/include/linux/bitmap.h b/tools/include/linux/bitmap.h
index 0d992245c600..250883090a5d 100644
--- a/tools/include/linux/bitmap.h
+++ b/tools/include/linux/bitmap.h
@@ -24,6 +24,10 @@ void __bitmap_set(unsigned long *map, unsigned int start, int len);
void __bitmap_clear(unsigned long *map, unsigned int start, int len);
bool __bitmap_intersects(const unsigned long *bitmap1,
const unsigned long *bitmap2, unsigned int bits);
+bool __bitmap_subset(const unsigned long *bitmap1,
+ const unsigned long *bitmap2, unsigned int nbits);
+bool __bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1,
+ const unsigned long *bitmap2, unsigned int nbits);
#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) & (BITS_PER_LONG - 1)))
#define BITMAP_LAST_WORD_MASK(nbits) (~0UL >> (-(nbits) & (BITS_PER_LONG - 1)))
@@ -81,6 +85,15 @@ static inline void bitmap_or(unsigned long *dst, const unsigned long *src1,
__bitmap_or(dst, src1, src2, nbits);
}
+static __always_inline
+bool bitmap_andnot(unsigned long *dst, const unsigned long *src1,
+ const unsigned long *src2, unsigned int nbits)
+{
+ if (small_const_nbits(nbits))
+ return (*dst = *src1 & ~(*src2) & BITMAP_LAST_WORD_MASK(nbits)) != 0;
+ return __bitmap_andnot(dst, src1, src2, nbits);
+}
+
static inline unsigned long *bitmap_alloc(unsigned int nbits, gfp_t flags __maybe_unused)
{
return malloc(bitmap_size(nbits));
@@ -157,6 +170,15 @@ static inline bool bitmap_intersects(const unsigned long *src1,
return __bitmap_intersects(src1, src2, nbits);
}
+static __always_inline
+bool bitmap_subset(const unsigned long *src1, const unsigned long *src2, unsigned int nbits)
+{
+ if (small_const_nbits(nbits))
+ return ! ((*src1 & ~(*src2)) & BITMAP_LAST_WORD_MASK(nbits));
+ else
+ return __bitmap_subset(src1, src2, nbits);
+}
+
static inline void bitmap_set(unsigned long *map, unsigned int start, unsigned int nbits)
{
if (__builtin_constant_p(nbits) && nbits == 1)
diff --git a/tools/lib/bitmap.c b/tools/lib/bitmap.c
index 51255c69754d..aa83d22c45e3 100644
--- a/tools/lib/bitmap.c
+++ b/tools/lib/bitmap.c
@@ -140,3 +140,32 @@ void __bitmap_clear(unsigned long *map, unsigned int start, int len)
*p &= ~mask_to_clear;
}
}
+
+bool __bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1,
+ const unsigned long *bitmap2, unsigned int bits)
+{
+ unsigned int k;
+ unsigned int lim = bits/BITS_PER_LONG;
+ unsigned long result = 0;
+
+ for (k = 0; k < lim; k++)
+ result |= (dst[k] = bitmap1[k] & ~bitmap2[k]);
+ if (bits % BITS_PER_LONG)
+ result |= (dst[k] = bitmap1[k] & ~bitmap2[k] &
+ BITMAP_LAST_WORD_MASK(bits));
+ return result != 0;
+}
+
+bool __bitmap_subset(const unsigned long *bitmap1,
+ const unsigned long *bitmap2, unsigned int bits)
+{
+ unsigned int k, lim = bits/BITS_PER_LONG;
+ for (k = 0; k < lim; ++k)
+ if (bitmap1[k] & ~bitmap2[k])
+ return false;
+
+ if (bits % BITS_PER_LONG)
+ if ((bitmap1[k] & ~bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits))
+ return false;
+ return true;
+}
--
2.52.0
^ permalink raw reply [flat|nested] 56+ messages in thread* Re: [PATCH v2 04/13] tools: bitmap: add missing bitmap_[subset(), andnot()]
2026-01-22 16:06 ` [PATCH v2 04/13] tools: bitmap: add missing bitmap_[subset(), andnot()] Lorenzo Stoakes
@ 2026-02-09 18:45 ` Liam R. Howlett
0 siblings, 0 replies; 56+ messages in thread
From: Liam R. Howlett @ 2026-02-09 18:45 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin,
Arnd Bergmann, Greg Kroah-Hartman, Dan Williams, Vishal Verma,
Dave Jiang, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Hugh Dickins, Baolin Wang, Zi Yan, Nico Pache, Ryan Roberts,
Dev Jain, Barry Song, Lance Yang, Jann Horn, Pedro Falcato,
David Howells, Paul Moore, James Morris, Serge E . Hallyn,
Yury Norov, Rasmus Villemoes, linux-sgx, linux-kernel, nvdimm,
linux-cxl, dri-devel, intel-gfx, linux-fsdevel, linux-aio,
linux-erofs, linux-ext4, linux-mm, ntfs3, devel, linux-xfs,
keyrings, linux-security-module, Jason Gunthorpe
* Lorenzo Stoakes <lorenzo.stoakes@oracle.com> [260122 16:06]:
> The bitmap_subset() and bitmap_andnot() functions are not present in the
> tools version of include/linux/bitmap.h, so add them as subsequent patches
> implement test code that requires them.
>
> We also add the missing __bitmap_subset() to tools/lib/bitmap.c.
>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Acked-by: Liam R. Howlett <Liam.Howlett@oracle.com>
> ---
> tools/include/linux/bitmap.h | 22 ++++++++++++++++++++++
> tools/lib/bitmap.c | 29 +++++++++++++++++++++++++++++
> 2 files changed, 51 insertions(+)
>
> diff --git a/tools/include/linux/bitmap.h b/tools/include/linux/bitmap.h
> index 0d992245c600..250883090a5d 100644
> --- a/tools/include/linux/bitmap.h
> +++ b/tools/include/linux/bitmap.h
> @@ -24,6 +24,10 @@ void __bitmap_set(unsigned long *map, unsigned int start, int len);
> void __bitmap_clear(unsigned long *map, unsigned int start, int len);
> bool __bitmap_intersects(const unsigned long *bitmap1,
> const unsigned long *bitmap2, unsigned int bits);
> +bool __bitmap_subset(const unsigned long *bitmap1,
> + const unsigned long *bitmap2, unsigned int nbits);
> +bool __bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1,
> + const unsigned long *bitmap2, unsigned int nbits);
>
> #define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) & (BITS_PER_LONG - 1)))
> #define BITMAP_LAST_WORD_MASK(nbits) (~0UL >> (-(nbits) & (BITS_PER_LONG - 1)))
> @@ -81,6 +85,15 @@ static inline void bitmap_or(unsigned long *dst, const unsigned long *src1,
> __bitmap_or(dst, src1, src2, nbits);
> }
>
> +static __always_inline
> +bool bitmap_andnot(unsigned long *dst, const unsigned long *src1,
> + const unsigned long *src2, unsigned int nbits)
> +{
> + if (small_const_nbits(nbits))
> + return (*dst = *src1 & ~(*src2) & BITMAP_LAST_WORD_MASK(nbits)) != 0;
> + return __bitmap_andnot(dst, src1, src2, nbits);
> +}
> +
> static inline unsigned long *bitmap_alloc(unsigned int nbits, gfp_t flags __maybe_unused)
> {
> return malloc(bitmap_size(nbits));
> @@ -157,6 +170,15 @@ static inline bool bitmap_intersects(const unsigned long *src1,
> return __bitmap_intersects(src1, src2, nbits);
> }
>
> +static __always_inline
> +bool bitmap_subset(const unsigned long *src1, const unsigned long *src2, unsigned int nbits)
> +{
> + if (small_const_nbits(nbits))
> + return ! ((*src1 & ~(*src2)) & BITMAP_LAST_WORD_MASK(nbits));
> + else
> + return __bitmap_subset(src1, src2, nbits);
> +}
> +
> static inline void bitmap_set(unsigned long *map, unsigned int start, unsigned int nbits)
> {
> if (__builtin_constant_p(nbits) && nbits == 1)
> diff --git a/tools/lib/bitmap.c b/tools/lib/bitmap.c
> index 51255c69754d..aa83d22c45e3 100644
> --- a/tools/lib/bitmap.c
> +++ b/tools/lib/bitmap.c
> @@ -140,3 +140,32 @@ void __bitmap_clear(unsigned long *map, unsigned int start, int len)
> *p &= ~mask_to_clear;
> }
> }
> +
> +bool __bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1,
> + const unsigned long *bitmap2, unsigned int bits)
> +{
> + unsigned int k;
> + unsigned int lim = bits/BITS_PER_LONG;
> + unsigned long result = 0;
> +
> + for (k = 0; k < lim; k++)
> + result |= (dst[k] = bitmap1[k] & ~bitmap2[k]);
> + if (bits % BITS_PER_LONG)
> + result |= (dst[k] = bitmap1[k] & ~bitmap2[k] &
> + BITMAP_LAST_WORD_MASK(bits));
> + return result != 0;
> +}
> +
> +bool __bitmap_subset(const unsigned long *bitmap1,
> + const unsigned long *bitmap2, unsigned int bits)
> +{
> + unsigned int k, lim = bits/BITS_PER_LONG;
> + for (k = 0; k < lim; ++k)
> + if (bitmap1[k] & ~bitmap2[k])
> + return false;
> +
> + if (bits % BITS_PER_LONG)
> + if ((bitmap1[k] & ~bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits))
> + return false;
> + return true;
> +}
> --
> 2.52.0
>
^ permalink raw reply [flat|nested] 56+ messages in thread
* [PATCH v2 05/13] mm: add basic VMA flag operation helper functions
2026-01-22 16:06 [PATCH v2 00/13] mm: add bitmap VMA flag helpers and convert all mmap_prepare to use them Lorenzo Stoakes
` (3 preceding siblings ...)
2026-01-22 16:06 ` [PATCH v2 04/13] tools: bitmap: add missing bitmap_[subset(), andnot()] Lorenzo Stoakes
@ 2026-01-22 16:06 ` Lorenzo Stoakes
2026-02-06 17:35 ` Pedro Falcato
2026-02-09 18:53 ` Liam R. Howlett
2026-01-22 16:06 ` [PATCH v2 06/13] mm: update hugetlbfs to use VMA flags on mmap_prepare Lorenzo Stoakes
` (9 subsequent siblings)
14 siblings, 2 replies; 56+ messages in thread
From: Lorenzo Stoakes @ 2026-01-22 16:06 UTC (permalink / raw)
To: Andrew Morton
Cc: Jarkko Sakkinen, Dave Hansen, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, x86, H . Peter Anvin, Arnd Bergmann,
Greg Kroah-Hartman, Dan Williams, Vishal Verma, Dave Jiang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
Now we have the mk_vma_flags() macro helper which permits easy
specification of any number of VMA flags, add helper functions which
operate with vma_flags_t parameters.
This patch provides vma_flags_test[_mask](), vma_flags_set[_mask]() and
vma_flags_clear[_mask]() respectively testing, setting and clearing flags
with the _mask variants accepting vma_flag_t parameters, and the non-mask
variants implemented as macros which accept a list of flags.
This allows us to trivially test/set/clear aggregate VMA flag values as
necessary, for instance:
if (vma_flags_test(&flags, VMA_READ_BIT, VMA_WRITE_BIT))
goto readwrite;
vma_flags_set(&flags, VMA_READ_BIT, VMA_WRITE_BIT);
vma_flags_clear(&flags, VMA_READ_BIT, VMA_WRITE_BIT);
We also add a function for testing that ALL flags are set for convenience,
e.g.:
if (vma_flags_test_all(&flags, VMA_READ_BIT, VMA_MAYREAD_BIT)) {
/* Both READ and MAYREAD flags set */
...
}
The compiler generates optimal assembly for each such that they behave as
if the caller were setting the bitmap flags manually.
This is important for e.g. drivers which manipulate flag values rather than
a VMA's specific flag values.
We also add helpers for testing, setting and clearing flags for VMA's and
VMA descriptors to reduce boilerplate.
Also add the EMPTY_VMA_FLAGS define to aid initialisation of empty flags.
Finally, update the userland VMA tests to add the helpers there so they can
be utilised as part of userland testing.
Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
---
include/linux/mm.h | 165 +++++++++++++++++++++++++++++++
include/linux/mm_types.h | 4 +-
tools/testing/vma/vma_internal.h | 147 +++++++++++++++++++++++----
3 files changed, 295 insertions(+), 21 deletions(-)
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 32c3b5347dc6..fd93317193e0 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1059,6 +1059,171 @@ static inline vma_flags_t __mk_vma_flags(size_t count, const vma_flag_t *bits)
#define mk_vma_flags(...) __mk_vma_flags(COUNT_ARGS(__VA_ARGS__), \
(const vma_flag_t []){__VA_ARGS__})
+/* Test each of to_test flags in flags, non-atomically. */
+static __always_inline bool vma_flags_test_mask(const vma_flags_t *flags,
+ vma_flags_t to_test)
+{
+ const unsigned long *bitmap = flags->__vma_flags;
+ const unsigned long *bitmap_to_test = to_test.__vma_flags;
+
+ return bitmap_intersects(bitmap_to_test, bitmap, NUM_VMA_FLAG_BITS);
+}
+
+/*
+ * Test whether any specified VMA flag is set, e.g.:
+ *
+ * if (vma_flags_test(flags, VMA_READ_BIT, VMA_MAYREAD_BIT)) { ... }
+ */
+#define vma_flags_test(flags, ...) \
+ vma_flags_test_mask(flags, mk_vma_flags(__VA_ARGS__))
+
+/* Test that ALL of the to_test flags are set, non-atomically. */
+static __always_inline bool vma_flags_test_all_mask(const vma_flags_t *flags,
+ vma_flags_t to_test)
+{
+ const unsigned long *bitmap = flags->__vma_flags;
+ const unsigned long *bitmap_to_test = to_test.__vma_flags;
+
+ return bitmap_subset(bitmap_to_test, bitmap, NUM_VMA_FLAG_BITS);
+}
+
+/*
+ * Test whether ALL specified VMA flags are set, e.g.:
+ *
+ * if (vma_flags_test_all(flags, VMA_READ_BIT, VMA_MAYREAD_BIT)) { ... }
+ */
+#define vma_flags_test_all(flags, ...) \
+ vma_flags_test_all_mask(flags, mk_vma_flags(__VA_ARGS__))
+
+/* Set each of the to_set flags in flags, non-atomically. */
+static __always_inline void vma_flags_set_mask(vma_flags_t *flags, vma_flags_t to_set)
+{
+ unsigned long *bitmap = flags->__vma_flags;
+ const unsigned long *bitmap_to_set = to_set.__vma_flags;
+
+ bitmap_or(bitmap, bitmap, bitmap_to_set, NUM_VMA_FLAG_BITS);
+}
+
+/*
+ * Set all specified VMA flags, e.g.:
+ *
+ * vma_flags_set(&flags, VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT);
+ */
+#define vma_flags_set(flags, ...) \
+ vma_flags_set_mask(flags, mk_vma_flags(__VA_ARGS__))
+
+/* Clear all of the to-clear flags in flags, non-atomically. */
+static __always_inline void vma_flags_clear_mask(vma_flags_t *flags, vma_flags_t to_clear)
+{
+ unsigned long *bitmap = flags->__vma_flags;
+ const unsigned long *bitmap_to_clear = to_clear.__vma_flags;
+
+ bitmap_andnot(bitmap, bitmap, bitmap_to_clear, NUM_VMA_FLAG_BITS);
+}
+
+/*
+ * Clear all specified individual flags, e.g.:
+ *
+ * vma_flags_clear(&flags, VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT);
+ */
+#define vma_flags_clear(flags, ...) \
+ vma_flags_clear_mask(flags, mk_vma_flags(__VA_ARGS__))
+
+/*
+ * Helper to test that ALL specified flags are set in a VMA.
+ *
+ * Note: appropriate locks must be held, this function does not acquire them for
+ * you.
+ */
+static inline bool vma_test_all_flags_mask(const struct vm_area_struct *vma,
+ vma_flags_t flags)
+{
+ return vma_flags_test_all_mask(&vma->flags, flags);
+}
+
+/*
+ * Helper macro for checking that ALL specified flags are set in a VMA, e.g.:
+ *
+ * if (vma_test_all_flags(vma, VMA_READ_BIT, VMA_MAYREAD_BIT) { ... }
+ */
+#define vma_test_all_flags(vma, ...) \
+ vma_test_all_flags_mask(vma, mk_vma_flags(__VA_ARGS__))
+
+/*
+ * Helper to set all VMA flags in a VMA.
+ *
+ * Note: appropriate locks must be held, this function does not acquire them for
+ * you.
+ */
+static inline void vma_set_flags_mask(struct vm_area_struct *vma,
+ vma_flags_t flags)
+{
+ vma_flags_set_mask(&vma->flags, flags);
+}
+
+/*
+ * Helper macro for specifying VMA flags in a VMA, e.g.:
+ *
+ * vma_set_flags(vma, VMA_IO_BIT, VMA_PFNMAP_BIT, VMA_DONTEXPAND_BIT,
+ * VMA_DONTDUMP_BIT);
+ *
+ * Note: appropriate locks must be held, this function does not acquire them for
+ * you.
+ */
+#define vma_set_flags(vma, ...) \
+ vma_set_flags_mask(vma, mk_vma_flags(__VA_ARGS__))
+
+/* Helper to test all VMA flags in a VMA descriptor. */
+static inline bool vma_desc_test_flags_mask(const struct vm_area_desc *desc,
+ vma_flags_t flags)
+{
+ return vma_flags_test_mask(&desc->vma_flags, flags);
+}
+
+/*
+ * Helper macro for testing VMA flags for an input pointer to a struct
+ * vm_area_desc object describing a proposed VMA, e.g.:
+ *
+ * if (vma_desc_test_flags(desc, VMA_IO_BIT, VMA_PFNMAP_BIT,
+ * VMA_DONTEXPAND_BIT, VMA_DONTDUMP_BIT)) { ... }
+ */
+#define vma_desc_test_flags(desc, ...) \
+ vma_desc_test_flags_mask(desc, mk_vma_flags(__VA_ARGS__))
+
+/* Helper to set all VMA flags in a VMA descriptor. */
+static inline void vma_desc_set_flags_mask(struct vm_area_desc *desc,
+ vma_flags_t flags)
+{
+ vma_flags_set_mask(&desc->vma_flags, flags);
+}
+
+/*
+ * Helper macro for specifying VMA flags for an input pointer to a struct
+ * vm_area_desc object describing a proposed VMA, e.g.:
+ *
+ * vma_desc_set_flags(desc, VMA_IO_BIT, VMA_PFNMAP_BIT, VMA_DONTEXPAND_BIT,
+ * VMA_DONTDUMP_BIT);
+ */
+#define vma_desc_set_flags(desc, ...) \
+ vma_desc_set_flags_mask(desc, mk_vma_flags(__VA_ARGS__))
+
+/* Helper to clear all VMA flags in a VMA descriptor. */
+static inline void vma_desc_clear_flags_mask(struct vm_area_desc *desc,
+ vma_flags_t flags)
+{
+ vma_flags_clear_mask(&desc->vma_flags, flags);
+}
+
+/*
+ * Helper macro for clearing VMA flags for an input pointer to a struct
+ * vm_area_desc object describing a proposed VMA, e.g.:
+ *
+ * vma_desc_clear_flags(desc, VMA_IO_BIT, VMA_PFNMAP_BIT, VMA_DONTEXPAND_BIT,
+ * VMA_DONTDUMP_BIT);
+ */
+#define vma_desc_clear_flags(desc, ...) \
+ vma_desc_clear_flags_mask(desc, mk_vma_flags(__VA_ARGS__))
+
static inline void vma_set_anonymous(struct vm_area_struct *vma)
{
vma->vm_ops = NULL;
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 592ad065fa75..cdac328b46dc 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -844,7 +844,7 @@ struct mmap_action {
/*
* If specified, this hook is invoked when an error occurred when
- * attempting the selection action.
+ * attempting the selected action.
*
* The hook can return an error code in order to filter the error, but
* it is not valid to clear the error here.
@@ -868,6 +868,8 @@ typedef struct {
DECLARE_BITMAP(__vma_flags, NUM_VMA_FLAG_BITS);
} vma_flags_t;
+#define EMPTY_VMA_FLAGS ((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
diff --git a/tools/testing/vma/vma_internal.h b/tools/testing/vma/vma_internal.h
index ca4eb563b29b..2b01794cbd61 100644
--- a/tools/testing/vma/vma_internal.h
+++ b/tools/testing/vma/vma_internal.h
@@ -21,7 +21,13 @@
#include <stdlib.h>
+#ifdef __CONCAT
+#undef __CONCAT
+#endif
+
+#include <linux/args.h>
#include <linux/atomic.h>
+#include <linux/bitmap.h>
#include <linux/list.h>
#include <linux/maple_tree.h>
#include <linux/mm.h>
@@ -38,6 +44,8 @@ extern unsigned long dac_mmap_min_addr;
#define dac_mmap_min_addr 0UL
#endif
+#define ACCESS_PRIVATE(p, member) ((p)->member)
+
#define VM_WARN_ON(_expr) (WARN_ON(_expr))
#define VM_WARN_ON_ONCE(_expr) (WARN_ON_ONCE(_expr))
#define VM_WARN_ON_VMG(_expr, _vmg) (WARN_ON(_expr))
@@ -533,6 +541,8 @@ typedef struct {
DECLARE_BITMAP(__vma_flags, NUM_VMA_FLAG_BITS);
} __private vma_flags_t;
+#define EMPTY_VMA_FLAGS ((vma_flags_t){ })
+
struct mm_struct {
struct maple_tree mm_mt;
int map_count; /* number of VMAs */
@@ -882,6 +892,123 @@ static inline pgprot_t vm_get_page_prot(vm_flags_t vm_flags)
return __pgprot(vm_flags);
}
+static inline void vma_flags_clear_all(vma_flags_t *flags)
+{
+ bitmap_zero(flags->__vma_flags, NUM_VMA_FLAG_BITS);
+}
+
+static inline void vma_flag_set(vma_flags_t *flags, vma_flag_t bit)
+{
+ unsigned long *bitmap = flags->__vma_flags;
+
+ __set_bit((__force int)bit, bitmap);
+}
+
+static inline vma_flags_t __mk_vma_flags(size_t count, const vma_flag_t *bits)
+{
+ vma_flags_t flags;
+ int i;
+
+ vma_flags_clear_all(&flags);
+ for (i = 0; i < count; i++)
+ vma_flag_set(&flags, bits[i]);
+ return flags;
+}
+
+#define mk_vma_flags(...) __mk_vma_flags(COUNT_ARGS(__VA_ARGS__), \
+ (const vma_flag_t []){__VA_ARGS__})
+
+static __always_inline bool vma_flags_test_mask(const vma_flags_t *flags,
+ vma_flags_t to_test)
+{
+ const unsigned long *bitmap = flags->__vma_flags;
+ const unsigned long *bitmap_to_test = to_test.__vma_flags;
+
+ return bitmap_intersects(bitmap_to_test, bitmap, NUM_VMA_FLAG_BITS);
+}
+
+#define vma_flags_test(flags, ...) \
+ vma_flags_test_mask(flags, mk_vma_flags(__VA_ARGS__))
+
+static __always_inline bool vma_flags_test_all_mask(const vma_flags_t *flags,
+ vma_flags_t to_test)
+{
+ const unsigned long *bitmap = flags->__vma_flags;
+ const unsigned long *bitmap_to_test = to_test.__vma_flags;
+
+ return bitmap_subset(bitmap_to_test, bitmap, NUM_VMA_FLAG_BITS);
+}
+
+#define vma_flags_test_all(flags, ...) \
+ vma_flags_test_all_mask(flags, mk_vma_flags(__VA_ARGS__))
+
+static __always_inline void vma_flags_set_mask(vma_flags_t *flags, vma_flags_t to_set)
+{
+ unsigned long *bitmap = flags->__vma_flags;
+ const unsigned long *bitmap_to_set = to_set.__vma_flags;
+
+ bitmap_or(bitmap, bitmap, bitmap_to_set, NUM_VMA_FLAG_BITS);
+}
+
+#define vma_flags_set(flags, ...) \
+ vma_flags_set_mask(flags, mk_vma_flags(__VA_ARGS__))
+
+static __always_inline void vma_flags_clear_mask(vma_flags_t *flags, vma_flags_t to_clear)
+{
+ unsigned long *bitmap = flags->__vma_flags;
+ const unsigned long *bitmap_to_clear = to_clear.__vma_flags;
+
+ bitmap_andnot(bitmap, bitmap, bitmap_to_clear, NUM_VMA_FLAG_BITS);
+}
+
+#define vma_flags_clear(flags, ...) \
+ vma_flags_clear_mask(flags, mk_vma_flags(__VA_ARGS__))
+
+static inline bool vma_test_all_flags_mask(const struct vm_area_struct *vma,
+ vma_flags_t flags)
+{
+ return vma_flags_test_all_mask(&vma->flags, flags);
+}
+
+#define vma_test_all_flags(vma, ...) \
+ vma_test_all_flags_mask(vma, mk_vma_flags(__VA_ARGS__))
+
+static inline void vma_set_flags_mask(struct vm_area_struct *vma,
+ vma_flags_t flags)
+{
+ vma_flags_set_mask(&vma->flags, flags);
+}
+
+#define vma_set_flags(vma, ...) \
+ vma_set_flags_mask(vma, mk_vma_flags(__VA_ARGS__))
+
+static inline bool vma_desc_test_flags_mask(const struct vm_area_desc *desc,
+ vma_flags_t flags)
+{
+ return vma_flags_test_mask(&desc->vma_flags, flags);
+}
+
+#define vma_desc_test_flags(desc, ...) \
+ vma_desc_test_flags_mask(desc, mk_vma_flags(__VA_ARGS__))
+
+static inline void vma_desc_set_flags_mask(struct vm_area_desc *desc,
+ vma_flags_t flags)
+{
+ vma_flags_set_mask(&desc->vma_flags, flags);
+}
+
+#define vma_desc_set_flags(desc, ...) \
+ vma_desc_set_flags_mask(desc, mk_vma_flags(__VA_ARGS__))
+
+static inline void vma_desc_clear_flags_mask(struct vm_area_desc *desc,
+ vma_flags_t flags)
+{
+ vma_flags_clear_mask(&desc->vma_flags, flags);
+}
+
+#define vma_desc_clear_flags(desc, ...) \
+ vma_desc_clear_flags_mask(desc, mk_vma_flags(__VA_ARGS__))
+
static inline bool is_shared_maywrite(vm_flags_t vm_flags)
{
return (vm_flags & (VM_SHARED | VM_MAYWRITE)) ==
@@ -1540,31 +1667,11 @@ static inline void userfaultfd_unmap_complete(struct mm_struct *mm,
{
}
-#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.
*
--
2.52.0
^ permalink raw reply [flat|nested] 56+ messages in thread* Re: [PATCH v2 05/13] mm: add basic VMA flag operation helper functions
2026-01-22 16:06 ` [PATCH v2 05/13] mm: add basic VMA flag operation helper functions Lorenzo Stoakes
@ 2026-02-06 17:35 ` Pedro Falcato
2026-02-09 14:04 ` Lorenzo Stoakes
2026-02-09 18:53 ` Liam R. Howlett
1 sibling, 1 reply; 56+ messages in thread
From: Pedro Falcato @ 2026-02-06 17:35 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin,
Arnd Bergmann, Greg Kroah-Hartman, Dan Williams, Vishal Verma,
Dave Jiang, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, David Howells, Paul Moore, James Morris,
Serge E . Hallyn, Yury Norov, Rasmus Villemoes, linux-sgx,
linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
On Thu, Jan 22, 2026 at 04:06:14PM +0000, Lorenzo Stoakes wrote:
> Now we have the mk_vma_flags() macro helper which permits easy
> specification of any number of VMA flags, add helper functions which
> operate with vma_flags_t parameters.
>
> This patch provides vma_flags_test[_mask](), vma_flags_set[_mask]() and
> vma_flags_clear[_mask]() respectively testing, setting and clearing flags
> with the _mask variants accepting vma_flag_t parameters, and the non-mask
> variants implemented as macros which accept a list of flags.
>
> This allows us to trivially test/set/clear aggregate VMA flag values as
> necessary, for instance:
>
> if (vma_flags_test(&flags, VMA_READ_BIT, VMA_WRITE_BIT))
> goto readwrite;
I'm not a huge fan of the _test ambiguity here, but more words makes it uglier :/
I think I can live with it though.
>
> vma_flags_set(&flags, VMA_READ_BIT, VMA_WRITE_BIT);
>
> vma_flags_clear(&flags, VMA_READ_BIT, VMA_WRITE_BIT);
>
The variadic-ness here is very nice though.
> We also add a function for testing that ALL flags are set for convenience,
> e.g.:
>
> if (vma_flags_test_all(&flags, VMA_READ_BIT, VMA_MAYREAD_BIT)) {
> /* Both READ and MAYREAD flags set */
> ...
> }
>
> The compiler generates optimal assembly for each such that they behave as
> if the caller were setting the bitmap flags manually.
>
> This is important for e.g. drivers which manipulate flag values rather than
> a VMA's specific flag values.
>
> We also add helpers for testing, setting and clearing flags for VMA's and
> VMA descriptors to reduce boilerplate.
>
> Also add the EMPTY_VMA_FLAGS define to aid initialisation of empty flags.
>
> Finally, update the userland VMA tests to add the helpers there so they can
> be utilised as part of userland testing.
>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Reviewed-by: Pedro Falcato <pfalcato@suse.de>
--
Pedro
^ permalink raw reply [flat|nested] 56+ messages in thread* Re: [PATCH v2 05/13] mm: add basic VMA flag operation helper functions
2026-02-06 17:35 ` Pedro Falcato
@ 2026-02-09 14:04 ` Lorenzo Stoakes
0 siblings, 0 replies; 56+ messages in thread
From: Lorenzo Stoakes @ 2026-02-09 14:04 UTC (permalink / raw)
To: Pedro Falcato
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin,
Arnd Bergmann, Greg Kroah-Hartman, Dan Williams, Vishal Verma,
Dave Jiang, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, David Howells, Paul Moore, James Morris,
Serge E . Hallyn, Yury Norov, Rasmus Villemoes, linux-sgx,
linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
On Fri, Feb 06, 2026 at 05:35:49PM +0000, Pedro Falcato wrote:
> On Thu, Jan 22, 2026 at 04:06:14PM +0000, Lorenzo Stoakes wrote:
> > Now we have the mk_vma_flags() macro helper which permits easy
> > specification of any number of VMA flags, add helper functions which
> > operate with vma_flags_t parameters.
> >
> > This patch provides vma_flags_test[_mask](), vma_flags_set[_mask]() and
> > vma_flags_clear[_mask]() respectively testing, setting and clearing flags
> > with the _mask variants accepting vma_flag_t parameters, and the non-mask
> > variants implemented as macros which accept a list of flags.
> >
> > This allows us to trivially test/set/clear aggregate VMA flag values as
> > necessary, for instance:
> >
> > if (vma_flags_test(&flags, VMA_READ_BIT, VMA_WRITE_BIT))
> > goto readwrite;
>
> I'm not a huge fan of the _test ambiguity here, but more words makes it uglier :/
> I think I can live with it though.
Yeah, as discussed on IRC it's a bit of a trade off here unfortunately.
I don't love having the _BIT stuff there but is necessary for now I feel until
VM_xxx flags are finally fully deprecated.
>
> >
> > vma_flags_set(&flags, VMA_READ_BIT, VMA_WRITE_BIT);
> >
> > vma_flags_clear(&flags, VMA_READ_BIT, VMA_WRITE_BIT);
> >
>
> The variadic-ness here is very nice though.
Thanks!
>
> > We also add a function for testing that ALL flags are set for convenience,
> > e.g.:
> >
> > if (vma_flags_test_all(&flags, VMA_READ_BIT, VMA_MAYREAD_BIT)) {
> > /* Both READ and MAYREAD flags set */
> > ...
> > }
> >
> > The compiler generates optimal assembly for each such that they behave as
> > if the caller were setting the bitmap flags manually.
> >
> > This is important for e.g. drivers which manipulate flag values rather than
> > a VMA's specific flag values.
> >
> > We also add helpers for testing, setting and clearing flags for VMA's and
> > VMA descriptors to reduce boilerplate.
> >
> > Also add the EMPTY_VMA_FLAGS define to aid initialisation of empty flags.
> >
> > Finally, update the userland VMA tests to add the helpers there so they can
> > be utilised as part of userland testing.
> >
> > Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
>
> Reviewed-by: Pedro Falcato <pfalcato@suse.de>
Thanks (also for other tags :P)
>
> --
> Pedro
Cheers, Lorenzo
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH v2 05/13] mm: add basic VMA flag operation helper functions
2026-01-22 16:06 ` [PATCH v2 05/13] mm: add basic VMA flag operation helper functions Lorenzo Stoakes
2026-02-06 17:35 ` Pedro Falcato
@ 2026-02-09 18:53 ` Liam R. Howlett
1 sibling, 0 replies; 56+ messages in thread
From: Liam R. Howlett @ 2026-02-09 18:53 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin,
Arnd Bergmann, Greg Kroah-Hartman, Dan Williams, Vishal Verma,
Dave Jiang, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Hugh Dickins, Baolin Wang, Zi Yan, Nico Pache, Ryan Roberts,
Dev Jain, Barry Song, Lance Yang, Jann Horn, Pedro Falcato,
David Howells, Paul Moore, James Morris, Serge E . Hallyn,
Yury Norov, Rasmus Villemoes, linux-sgx, linux-kernel, nvdimm,
linux-cxl, dri-devel, intel-gfx, linux-fsdevel, linux-aio,
linux-erofs, linux-ext4, linux-mm, ntfs3, devel, linux-xfs,
keyrings, linux-security-module, Jason Gunthorpe
* Lorenzo Stoakes <lorenzo.stoakes@oracle.com> [260122 16:06]:
> Now we have the mk_vma_flags() macro helper which permits easy
> specification of any number of VMA flags, add helper functions which
> operate with vma_flags_t parameters.
>
> This patch provides vma_flags_test[_mask](), vma_flags_set[_mask]() and
> vma_flags_clear[_mask]() respectively testing, setting and clearing flags
> with the _mask variants accepting vma_flag_t parameters, and the non-mask
> variants implemented as macros which accept a list of flags.
>
> This allows us to trivially test/set/clear aggregate VMA flag values as
> necessary, for instance:
>
> if (vma_flags_test(&flags, VMA_READ_BIT, VMA_WRITE_BIT))
> goto readwrite;
>
> vma_flags_set(&flags, VMA_READ_BIT, VMA_WRITE_BIT);
>
> vma_flags_clear(&flags, VMA_READ_BIT, VMA_WRITE_BIT);
>
> We also add a function for testing that ALL flags are set for convenience,
> e.g.:
>
> if (vma_flags_test_all(&flags, VMA_READ_BIT, VMA_MAYREAD_BIT)) {
> /* Both READ and MAYREAD flags set */
> ...
> }
>
> The compiler generates optimal assembly for each such that they behave as
> if the caller were setting the bitmap flags manually.
>
> This is important for e.g. drivers which manipulate flag values rather than
> a VMA's specific flag values.
>
> We also add helpers for testing, setting and clearing flags for VMA's and
> VMA descriptors to reduce boilerplate.
>
> Also add the EMPTY_VMA_FLAGS define to aid initialisation of empty flags.
>
> Finally, update the userland VMA tests to add the helpers there so they can
> be utilised as part of userland testing.
>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Reviewed-by: Liam R. Howlett <Liam.Howlett@oracle.com>
> ---
> include/linux/mm.h | 165 +++++++++++++++++++++++++++++++
> include/linux/mm_types.h | 4 +-
> tools/testing/vma/vma_internal.h | 147 +++++++++++++++++++++++----
> 3 files changed, 295 insertions(+), 21 deletions(-)
>
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index 32c3b5347dc6..fd93317193e0 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -1059,6 +1059,171 @@ static inline vma_flags_t __mk_vma_flags(size_t count, const vma_flag_t *bits)
> #define mk_vma_flags(...) __mk_vma_flags(COUNT_ARGS(__VA_ARGS__), \
> (const vma_flag_t []){__VA_ARGS__})
>
> +/* Test each of to_test flags in flags, non-atomically. */
> +static __always_inline bool vma_flags_test_mask(const vma_flags_t *flags,
> + vma_flags_t to_test)
> +{
> + const unsigned long *bitmap = flags->__vma_flags;
> + const unsigned long *bitmap_to_test = to_test.__vma_flags;
> +
> + return bitmap_intersects(bitmap_to_test, bitmap, NUM_VMA_FLAG_BITS);
> +}
> +
> +/*
> + * Test whether any specified VMA flag is set, e.g.:
> + *
> + * if (vma_flags_test(flags, VMA_READ_BIT, VMA_MAYREAD_BIT)) { ... }
> + */
> +#define vma_flags_test(flags, ...) \
> + vma_flags_test_mask(flags, mk_vma_flags(__VA_ARGS__))
> +
> +/* Test that ALL of the to_test flags are set, non-atomically. */
> +static __always_inline bool vma_flags_test_all_mask(const vma_flags_t *flags,
> + vma_flags_t to_test)
> +{
> + const unsigned long *bitmap = flags->__vma_flags;
> + const unsigned long *bitmap_to_test = to_test.__vma_flags;
> +
> + return bitmap_subset(bitmap_to_test, bitmap, NUM_VMA_FLAG_BITS);
> +}
> +
> +/*
> + * Test whether ALL specified VMA flags are set, e.g.:
> + *
> + * if (vma_flags_test_all(flags, VMA_READ_BIT, VMA_MAYREAD_BIT)) { ... }
> + */
> +#define vma_flags_test_all(flags, ...) \
> + vma_flags_test_all_mask(flags, mk_vma_flags(__VA_ARGS__))
> +
> +/* Set each of the to_set flags in flags, non-atomically. */
> +static __always_inline void vma_flags_set_mask(vma_flags_t *flags, vma_flags_t to_set)
> +{
> + unsigned long *bitmap = flags->__vma_flags;
> + const unsigned long *bitmap_to_set = to_set.__vma_flags;
> +
> + bitmap_or(bitmap, bitmap, bitmap_to_set, NUM_VMA_FLAG_BITS);
> +}
> +
> +/*
> + * Set all specified VMA flags, e.g.:
> + *
> + * vma_flags_set(&flags, VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT);
> + */
> +#define vma_flags_set(flags, ...) \
> + vma_flags_set_mask(flags, mk_vma_flags(__VA_ARGS__))
> +
> +/* Clear all of the to-clear flags in flags, non-atomically. */
> +static __always_inline void vma_flags_clear_mask(vma_flags_t *flags, vma_flags_t to_clear)
> +{
> + unsigned long *bitmap = flags->__vma_flags;
> + const unsigned long *bitmap_to_clear = to_clear.__vma_flags;
> +
> + bitmap_andnot(bitmap, bitmap, bitmap_to_clear, NUM_VMA_FLAG_BITS);
> +}
> +
> +/*
> + * Clear all specified individual flags, e.g.:
> + *
> + * vma_flags_clear(&flags, VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT);
> + */
> +#define vma_flags_clear(flags, ...) \
> + vma_flags_clear_mask(flags, mk_vma_flags(__VA_ARGS__))
> +
> +/*
> + * Helper to test that ALL specified flags are set in a VMA.
> + *
> + * Note: appropriate locks must be held, this function does not acquire them for
> + * you.
> + */
> +static inline bool vma_test_all_flags_mask(const struct vm_area_struct *vma,
> + vma_flags_t flags)
> +{
> + return vma_flags_test_all_mask(&vma->flags, flags);
> +}
> +
> +/*
> + * Helper macro for checking that ALL specified flags are set in a VMA, e.g.:
> + *
> + * if (vma_test_all_flags(vma, VMA_READ_BIT, VMA_MAYREAD_BIT) { ... }
> + */
> +#define vma_test_all_flags(vma, ...) \
> + vma_test_all_flags_mask(vma, mk_vma_flags(__VA_ARGS__))
> +
> +/*
> + * Helper to set all VMA flags in a VMA.
> + *
> + * Note: appropriate locks must be held, this function does not acquire them for
> + * you.
> + */
> +static inline void vma_set_flags_mask(struct vm_area_struct *vma,
> + vma_flags_t flags)
> +{
> + vma_flags_set_mask(&vma->flags, flags);
> +}
> +
> +/*
> + * Helper macro for specifying VMA flags in a VMA, e.g.:
> + *
> + * vma_set_flags(vma, VMA_IO_BIT, VMA_PFNMAP_BIT, VMA_DONTEXPAND_BIT,
> + * VMA_DONTDUMP_BIT);
> + *
> + * Note: appropriate locks must be held, this function does not acquire them for
> + * you.
> + */
> +#define vma_set_flags(vma, ...) \
> + vma_set_flags_mask(vma, mk_vma_flags(__VA_ARGS__))
> +
> +/* Helper to test all VMA flags in a VMA descriptor. */
> +static inline bool vma_desc_test_flags_mask(const struct vm_area_desc *desc,
> + vma_flags_t flags)
> +{
> + return vma_flags_test_mask(&desc->vma_flags, flags);
> +}
> +
> +/*
> + * Helper macro for testing VMA flags for an input pointer to a struct
> + * vm_area_desc object describing a proposed VMA, e.g.:
> + *
> + * if (vma_desc_test_flags(desc, VMA_IO_BIT, VMA_PFNMAP_BIT,
> + * VMA_DONTEXPAND_BIT, VMA_DONTDUMP_BIT)) { ... }
> + */
> +#define vma_desc_test_flags(desc, ...) \
> + vma_desc_test_flags_mask(desc, mk_vma_flags(__VA_ARGS__))
> +
> +/* Helper to set all VMA flags in a VMA descriptor. */
> +static inline void vma_desc_set_flags_mask(struct vm_area_desc *desc,
> + vma_flags_t flags)
> +{
> + vma_flags_set_mask(&desc->vma_flags, flags);
> +}
> +
> +/*
> + * Helper macro for specifying VMA flags for an input pointer to a struct
> + * vm_area_desc object describing a proposed VMA, e.g.:
> + *
> + * vma_desc_set_flags(desc, VMA_IO_BIT, VMA_PFNMAP_BIT, VMA_DONTEXPAND_BIT,
> + * VMA_DONTDUMP_BIT);
> + */
> +#define vma_desc_set_flags(desc, ...) \
> + vma_desc_set_flags_mask(desc, mk_vma_flags(__VA_ARGS__))
> +
> +/* Helper to clear all VMA flags in a VMA descriptor. */
> +static inline void vma_desc_clear_flags_mask(struct vm_area_desc *desc,
> + vma_flags_t flags)
> +{
> + vma_flags_clear_mask(&desc->vma_flags, flags);
> +}
> +
> +/*
> + * Helper macro for clearing VMA flags for an input pointer to a struct
> + * vm_area_desc object describing a proposed VMA, e.g.:
> + *
> + * vma_desc_clear_flags(desc, VMA_IO_BIT, VMA_PFNMAP_BIT, VMA_DONTEXPAND_BIT,
> + * VMA_DONTDUMP_BIT);
> + */
> +#define vma_desc_clear_flags(desc, ...) \
> + vma_desc_clear_flags_mask(desc, mk_vma_flags(__VA_ARGS__))
> +
> static inline void vma_set_anonymous(struct vm_area_struct *vma)
> {
> vma->vm_ops = NULL;
> diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
> index 592ad065fa75..cdac328b46dc 100644
> --- a/include/linux/mm_types.h
> +++ b/include/linux/mm_types.h
> @@ -844,7 +844,7 @@ struct mmap_action {
>
> /*
> * If specified, this hook is invoked when an error occurred when
> - * attempting the selection action.
> + * attempting the selected action.
> *
> * The hook can return an error code in order to filter the error, but
> * it is not valid to clear the error here.
> @@ -868,6 +868,8 @@ typedef struct {
> DECLARE_BITMAP(__vma_flags, NUM_VMA_FLAG_BITS);
> } vma_flags_t;
>
> +#define EMPTY_VMA_FLAGS ((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
> diff --git a/tools/testing/vma/vma_internal.h b/tools/testing/vma/vma_internal.h
> index ca4eb563b29b..2b01794cbd61 100644
> --- a/tools/testing/vma/vma_internal.h
> +++ b/tools/testing/vma/vma_internal.h
> @@ -21,7 +21,13 @@
>
> #include <stdlib.h>
>
> +#ifdef __CONCAT
> +#undef __CONCAT
> +#endif
> +
> +#include <linux/args.h>
> #include <linux/atomic.h>
> +#include <linux/bitmap.h>
> #include <linux/list.h>
> #include <linux/maple_tree.h>
> #include <linux/mm.h>
> @@ -38,6 +44,8 @@ extern unsigned long dac_mmap_min_addr;
> #define dac_mmap_min_addr 0UL
> #endif
>
> +#define ACCESS_PRIVATE(p, member) ((p)->member)
> +
> #define VM_WARN_ON(_expr) (WARN_ON(_expr))
> #define VM_WARN_ON_ONCE(_expr) (WARN_ON_ONCE(_expr))
> #define VM_WARN_ON_VMG(_expr, _vmg) (WARN_ON(_expr))
> @@ -533,6 +541,8 @@ typedef struct {
> DECLARE_BITMAP(__vma_flags, NUM_VMA_FLAG_BITS);
> } __private vma_flags_t;
>
> +#define EMPTY_VMA_FLAGS ((vma_flags_t){ })
> +
> struct mm_struct {
> struct maple_tree mm_mt;
> int map_count; /* number of VMAs */
> @@ -882,6 +892,123 @@ static inline pgprot_t vm_get_page_prot(vm_flags_t vm_flags)
> return __pgprot(vm_flags);
> }
>
> +static inline void vma_flags_clear_all(vma_flags_t *flags)
> +{
> + bitmap_zero(flags->__vma_flags, NUM_VMA_FLAG_BITS);
> +}
> +
> +static inline void vma_flag_set(vma_flags_t *flags, vma_flag_t bit)
> +{
> + unsigned long *bitmap = flags->__vma_flags;
> +
> + __set_bit((__force int)bit, bitmap);
> +}
> +
> +static inline vma_flags_t __mk_vma_flags(size_t count, const vma_flag_t *bits)
> +{
> + vma_flags_t flags;
> + int i;
> +
> + vma_flags_clear_all(&flags);
> + for (i = 0; i < count; i++)
> + vma_flag_set(&flags, bits[i]);
> + return flags;
> +}
> +
> +#define mk_vma_flags(...) __mk_vma_flags(COUNT_ARGS(__VA_ARGS__), \
> + (const vma_flag_t []){__VA_ARGS__})
> +
> +static __always_inline bool vma_flags_test_mask(const vma_flags_t *flags,
> + vma_flags_t to_test)
> +{
> + const unsigned long *bitmap = flags->__vma_flags;
> + const unsigned long *bitmap_to_test = to_test.__vma_flags;
> +
> + return bitmap_intersects(bitmap_to_test, bitmap, NUM_VMA_FLAG_BITS);
> +}
> +
> +#define vma_flags_test(flags, ...) \
> + vma_flags_test_mask(flags, mk_vma_flags(__VA_ARGS__))
> +
> +static __always_inline bool vma_flags_test_all_mask(const vma_flags_t *flags,
> + vma_flags_t to_test)
> +{
> + const unsigned long *bitmap = flags->__vma_flags;
> + const unsigned long *bitmap_to_test = to_test.__vma_flags;
> +
> + return bitmap_subset(bitmap_to_test, bitmap, NUM_VMA_FLAG_BITS);
> +}
> +
> +#define vma_flags_test_all(flags, ...) \
> + vma_flags_test_all_mask(flags, mk_vma_flags(__VA_ARGS__))
> +
> +static __always_inline void vma_flags_set_mask(vma_flags_t *flags, vma_flags_t to_set)
> +{
> + unsigned long *bitmap = flags->__vma_flags;
> + const unsigned long *bitmap_to_set = to_set.__vma_flags;
> +
> + bitmap_or(bitmap, bitmap, bitmap_to_set, NUM_VMA_FLAG_BITS);
> +}
> +
> +#define vma_flags_set(flags, ...) \
> + vma_flags_set_mask(flags, mk_vma_flags(__VA_ARGS__))
> +
> +static __always_inline void vma_flags_clear_mask(vma_flags_t *flags, vma_flags_t to_clear)
> +{
> + unsigned long *bitmap = flags->__vma_flags;
> + const unsigned long *bitmap_to_clear = to_clear.__vma_flags;
> +
> + bitmap_andnot(bitmap, bitmap, bitmap_to_clear, NUM_VMA_FLAG_BITS);
> +}
> +
> +#define vma_flags_clear(flags, ...) \
> + vma_flags_clear_mask(flags, mk_vma_flags(__VA_ARGS__))
> +
> +static inline bool vma_test_all_flags_mask(const struct vm_area_struct *vma,
> + vma_flags_t flags)
> +{
> + return vma_flags_test_all_mask(&vma->flags, flags);
> +}
> +
> +#define vma_test_all_flags(vma, ...) \
> + vma_test_all_flags_mask(vma, mk_vma_flags(__VA_ARGS__))
> +
> +static inline void vma_set_flags_mask(struct vm_area_struct *vma,
> + vma_flags_t flags)
> +{
> + vma_flags_set_mask(&vma->flags, flags);
> +}
> +
> +#define vma_set_flags(vma, ...) \
> + vma_set_flags_mask(vma, mk_vma_flags(__VA_ARGS__))
> +
> +static inline bool vma_desc_test_flags_mask(const struct vm_area_desc *desc,
> + vma_flags_t flags)
> +{
> + return vma_flags_test_mask(&desc->vma_flags, flags);
> +}
> +
> +#define vma_desc_test_flags(desc, ...) \
> + vma_desc_test_flags_mask(desc, mk_vma_flags(__VA_ARGS__))
> +
> +static inline void vma_desc_set_flags_mask(struct vm_area_desc *desc,
> + vma_flags_t flags)
> +{
> + vma_flags_set_mask(&desc->vma_flags, flags);
> +}
> +
> +#define vma_desc_set_flags(desc, ...) \
> + vma_desc_set_flags_mask(desc, mk_vma_flags(__VA_ARGS__))
> +
> +static inline void vma_desc_clear_flags_mask(struct vm_area_desc *desc,
> + vma_flags_t flags)
> +{
> + vma_flags_clear_mask(&desc->vma_flags, flags);
> +}
> +
> +#define vma_desc_clear_flags(desc, ...) \
> + vma_desc_clear_flags_mask(desc, mk_vma_flags(__VA_ARGS__))
> +
> static inline bool is_shared_maywrite(vm_flags_t vm_flags)
> {
> return (vm_flags & (VM_SHARED | VM_MAYWRITE)) ==
> @@ -1540,31 +1667,11 @@ static inline void userfaultfd_unmap_complete(struct mm_struct *mm,
> {
> }
>
> -#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.
> *
> --
> 2.52.0
>
^ permalink raw reply [flat|nested] 56+ messages in thread
* [PATCH v2 06/13] mm: update hugetlbfs to use VMA flags on mmap_prepare
2026-01-22 16:06 [PATCH v2 00/13] mm: add bitmap VMA flag helpers and convert all mmap_prepare to use them Lorenzo Stoakes
` (4 preceding siblings ...)
2026-01-22 16:06 ` [PATCH v2 05/13] mm: add basic VMA flag operation helper functions Lorenzo Stoakes
@ 2026-01-22 16:06 ` Lorenzo Stoakes
2026-02-09 19:03 ` Liam R. Howlett
2026-01-22 16:06 ` [PATCH v2 07/13] mm: update secretmem " Lorenzo Stoakes
` (8 subsequent siblings)
14 siblings, 1 reply; 56+ messages in thread
From: Lorenzo Stoakes @ 2026-01-22 16:06 UTC (permalink / raw)
To: Andrew Morton
Cc: Jarkko Sakkinen, Dave Hansen, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, x86, H . Peter Anvin, Arnd Bergmann,
Greg Kroah-Hartman, Dan Williams, Vishal Verma, Dave Jiang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
In order to update all mmap_prepare users to utilising the new VMA flags
type vma_flags_t and associated helper functions, we start by updating
hugetlbfs which has a lot of additional logic that requires updating to
make this change.
This is laying the groundwork for eliminating the vm_flags_t from struct
vm_area_desc and using vma_flags_t only, which further lays the ground for
removing the deprecated vm_flags_t type altogether.
No functional changes intended.
Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
---
fs/hugetlbfs/inode.c | 14 +++++++-------
include/linux/hugetlb.h | 6 +++---
include/linux/hugetlb_inline.h | 10 ++++++++++
ipc/shm.c | 12 +++++++-----
mm/hugetlb.c | 22 +++++++++++-----------
mm/memfd.c | 4 ++--
mm/mmap.c | 2 +-
7 files changed, 41 insertions(+), 29 deletions(-)
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 3b4c152c5c73..95a5b23b4808 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -109,7 +109,7 @@ static int hugetlbfs_file_mmap_prepare(struct vm_area_desc *desc)
loff_t len, vma_len;
int ret;
struct hstate *h = hstate_file(file);
- vm_flags_t vm_flags;
+ vma_flags_t vma_flags;
/*
* vma address alignment (but not the pgoff alignment) has
@@ -119,7 +119,7 @@ static int hugetlbfs_file_mmap_prepare(struct vm_area_desc *desc)
* way when do_mmap unwinds (may be important on powerpc
* and ia64).
*/
- desc->vm_flags |= VM_HUGETLB | VM_DONTEXPAND;
+ vma_desc_set_flags(desc, VMA_HUGETLB_BIT, VMA_DONTEXPAND_BIT);
desc->vm_ops = &hugetlb_vm_ops;
/*
@@ -148,23 +148,23 @@ static int hugetlbfs_file_mmap_prepare(struct vm_area_desc *desc)
ret = -ENOMEM;
- vm_flags = desc->vm_flags;
+ vma_flags = desc->vma_flags;
/*
* for SHM_HUGETLB, the pages are reserved in the shmget() call so skip
* reserving here. Note: only for SHM hugetlbfs file, the inode
* flag S_PRIVATE is set.
*/
if (inode->i_flags & S_PRIVATE)
- vm_flags |= VM_NORESERVE;
+ vma_flags_set(&vma_flags, VMA_NORESERVE_BIT);
if (hugetlb_reserve_pages(inode,
desc->pgoff >> huge_page_order(h),
len >> huge_page_shift(h), desc,
- vm_flags) < 0)
+ vma_flags) < 0)
goto out;
ret = 0;
- if ((desc->vm_flags & VM_WRITE) && inode->i_size < len)
+ if (vma_desc_test_flags(desc, VMA_WRITE_BIT) && inode->i_size < len)
i_size_write(inode, len);
out:
inode_unlock(inode);
@@ -1527,7 +1527,7 @@ static int get_hstate_idx(int page_size_log)
* otherwise hugetlb_reserve_pages reserves one less hugepages than intended.
*/
struct file *hugetlb_file_setup(const char *name, size_t size,
- vm_flags_t acctflag, int creat_flags,
+ vma_flags_t acctflag, int creat_flags,
int page_size_log)
{
struct inode *inode;
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index 94a03591990c..4e72bf66077e 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -150,7 +150,7 @@ int hugetlb_mfill_atomic_pte(pte_t *dst_pte,
struct folio **foliop);
#endif /* CONFIG_USERFAULTFD */
long hugetlb_reserve_pages(struct inode *inode, long from, long to,
- struct vm_area_desc *desc, vm_flags_t vm_flags);
+ struct vm_area_desc *desc, vma_flags_t vma_flags);
long hugetlb_unreserve_pages(struct inode *inode, long start, long end,
long freed);
bool folio_isolate_hugetlb(struct folio *folio, struct list_head *list);
@@ -529,7 +529,7 @@ static inline struct hugetlbfs_inode_info *HUGETLBFS_I(struct inode *inode)
}
extern const struct vm_operations_struct hugetlb_vm_ops;
-struct file *hugetlb_file_setup(const char *name, size_t size, vm_flags_t acct,
+struct file *hugetlb_file_setup(const char *name, size_t size, vma_flags_t acct,
int creat_flags, int page_size_log);
static inline bool is_file_hugepages(const struct file *file)
@@ -545,7 +545,7 @@ static inline struct hstate *hstate_inode(struct inode *i)
#define is_file_hugepages(file) false
static inline struct file *
-hugetlb_file_setup(const char *name, size_t size, vm_flags_t acctflag,
+hugetlb_file_setup(const char *name, size_t size, vma_flags_t acctflag,
int creat_flags, int page_size_log)
{
return ERR_PTR(-ENOSYS);
diff --git a/include/linux/hugetlb_inline.h b/include/linux/hugetlb_inline.h
index a27aa0162918..593f5d4e108b 100644
--- a/include/linux/hugetlb_inline.h
+++ b/include/linux/hugetlb_inline.h
@@ -11,6 +11,11 @@ static inline bool is_vm_hugetlb_flags(vm_flags_t vm_flags)
return !!(vm_flags & VM_HUGETLB);
}
+static inline bool is_vma_hugetlb_flags(const vma_flags_t *flags)
+{
+ return vma_flags_test(flags, VMA_HUGETLB_BIT);
+}
+
#else
static inline bool is_vm_hugetlb_flags(vm_flags_t vm_flags)
@@ -18,6 +23,11 @@ static inline bool is_vm_hugetlb_flags(vm_flags_t vm_flags)
return false;
}
+static inline bool is_vma_hugetlb_flags(const vma_flags_t *flags)
+{
+ return false;
+}
+
#endif
static inline bool is_vm_hugetlb_page(struct vm_area_struct *vma)
diff --git a/ipc/shm.c b/ipc/shm.c
index 3db36773dd10..2c7379c4c647 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -707,9 +707,9 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
int error;
struct shmid_kernel *shp;
size_t numpages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ const bool has_no_reserve = shmflg & SHM_NORESERVE;
struct file *file;
char name[13];
- vm_flags_t acctflag = 0;
if (size < SHMMIN || size > ns->shm_ctlmax)
return -EINVAL;
@@ -738,6 +738,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
sprintf(name, "SYSV%08x", key);
if (shmflg & SHM_HUGETLB) {
+ vma_flags_t acctflag = EMPTY_VMA_FLAGS;
struct hstate *hs;
size_t hugesize;
@@ -749,17 +750,18 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
hugesize = ALIGN(size, huge_page_size(hs));
/* hugetlb_file_setup applies strict accounting */
- if (shmflg & SHM_NORESERVE)
- acctflag = VM_NORESERVE;
+ if (has_no_reserve)
+ vma_flags_set(&acctflag, VMA_NORESERVE_BIT);
file = hugetlb_file_setup(name, hugesize, acctflag,
HUGETLB_SHMFS_INODE, (shmflg >> SHM_HUGE_SHIFT) & SHM_HUGE_MASK);
} else {
+ vm_flags_t acctflag = 0;
+
/*
* Do not allow no accounting for OVERCOMMIT_NEVER, even
* if it's asked for.
*/
- if ((shmflg & SHM_NORESERVE) &&
- sysctl_overcommit_memory != OVERCOMMIT_NEVER)
+ if (has_no_reserve && sysctl_overcommit_memory != OVERCOMMIT_NEVER)
acctflag = VM_NORESERVE;
file = shmem_kernel_file_setup(name, size, acctflag);
}
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 4f4494251f5c..e6955061d751 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -1193,16 +1193,16 @@ static void set_vma_resv_flags(struct vm_area_struct *vma, unsigned long flags)
static void set_vma_desc_resv_map(struct vm_area_desc *desc, struct resv_map *map)
{
- VM_WARN_ON_ONCE(!is_vm_hugetlb_flags(desc->vm_flags));
- VM_WARN_ON_ONCE(desc->vm_flags & VM_MAYSHARE);
+ VM_WARN_ON_ONCE(!is_vma_hugetlb_flags(&desc->vma_flags));
+ VM_WARN_ON_ONCE(vma_desc_test_flags(desc, VMA_MAYSHARE_BIT));
desc->private_data = map;
}
static void set_vma_desc_resv_flags(struct vm_area_desc *desc, unsigned long flags)
{
- VM_WARN_ON_ONCE(!is_vm_hugetlb_flags(desc->vm_flags));
- VM_WARN_ON_ONCE(desc->vm_flags & VM_MAYSHARE);
+ VM_WARN_ON_ONCE(!is_vma_hugetlb_flags(&desc->vma_flags));
+ VM_WARN_ON_ONCE(vma_desc_test_flags(desc, VMA_MAYSHARE_BIT));
desc->private_data = (void *)((unsigned long)desc->private_data | flags);
}
@@ -1216,7 +1216,7 @@ static int is_vma_resv_set(struct vm_area_struct *vma, unsigned long flag)
static bool is_vma_desc_resv_set(struct vm_area_desc *desc, unsigned long flag)
{
- VM_WARN_ON_ONCE(!is_vm_hugetlb_flags(desc->vm_flags));
+ VM_WARN_ON_ONCE(!is_vma_hugetlb_flags(&desc->vma_flags));
return ((unsigned long)desc->private_data) & flag;
}
@@ -6564,7 +6564,7 @@ long hugetlb_change_protection(struct vm_area_struct *vma,
long hugetlb_reserve_pages(struct inode *inode,
long from, long to,
struct vm_area_desc *desc,
- vm_flags_t vm_flags)
+ vma_flags_t vma_flags)
{
long chg = -1, add = -1, spool_resv, gbl_resv;
struct hstate *h = hstate_inode(inode);
@@ -6585,7 +6585,7 @@ long hugetlb_reserve_pages(struct inode *inode,
* attempt will be made for VM_NORESERVE to allocate a page
* without using reserves
*/
- if (vm_flags & VM_NORESERVE)
+ if (vma_flags_test(&vma_flags, VMA_NORESERVE_BIT))
return 0;
/*
@@ -6594,7 +6594,7 @@ long hugetlb_reserve_pages(struct inode *inode,
* to reserve the full area even if read-only as mprotect() may be
* called to make the mapping read-write. Assume !desc is a shm mapping
*/
- if (!desc || desc->vm_flags & VM_MAYSHARE) {
+ if (!desc || vma_desc_test_flags(desc, VMA_MAYSHARE_BIT)) {
/*
* resv_map can not be NULL as hugetlb_reserve_pages is only
* called for inodes for which resv_maps were created (see
@@ -6628,7 +6628,7 @@ long hugetlb_reserve_pages(struct inode *inode,
if (err < 0)
goto out_err;
- if (desc && !(desc->vm_flags & VM_MAYSHARE) && h_cg) {
+ if (desc && !vma_desc_test_flags(desc, VMA_MAYSHARE_BIT) && h_cg) {
/* For private mappings, the hugetlb_cgroup uncharge info hangs
* of the resv_map.
*/
@@ -6665,7 +6665,7 @@ long hugetlb_reserve_pages(struct inode *inode,
* consumed reservations are stored in the map. Hence, nothing
* else has to be done for private mappings here
*/
- if (!desc || desc->vm_flags & VM_MAYSHARE) {
+ if (!desc || vma_desc_test_flags(desc, VMA_MAYSHARE_BIT)) {
add = region_add(resv_map, from, to, regions_needed, h, h_cg);
if (unlikely(add < 0)) {
@@ -6729,7 +6729,7 @@ long hugetlb_reserve_pages(struct inode *inode,
hugetlb_cgroup_uncharge_cgroup_rsvd(hstate_index(h),
chg * pages_per_huge_page(h), h_cg);
out_err:
- if (!desc || desc->vm_flags & VM_MAYSHARE)
+ if (!desc || vma_desc_test_flags(desc, VMA_MAYSHARE_BIT))
/* Only call region_abort if the region_chg succeeded but the
* region_add failed or didn't run.
*/
diff --git a/mm/memfd.c b/mm/memfd.c
index ab5312aff14b..5f95f639550c 100644
--- a/mm/memfd.c
+++ b/mm/memfd.c
@@ -87,7 +87,7 @@ struct folio *memfd_alloc_folio(struct file *memfd, pgoff_t idx)
gfp_mask &= ~(__GFP_HIGHMEM | __GFP_MOVABLE);
idx >>= huge_page_order(h);
- nr_resv = hugetlb_reserve_pages(inode, idx, idx + 1, NULL, 0);
+ nr_resv = hugetlb_reserve_pages(inode, idx, idx + 1, NULL, EMPTY_VMA_FLAGS);
if (nr_resv < 0)
return ERR_PTR(nr_resv);
@@ -464,7 +464,7 @@ static struct file *alloc_file(const char *name, unsigned int flags)
int err = 0;
if (flags & MFD_HUGETLB) {
- file = hugetlb_file_setup(name, 0, VM_NORESERVE,
+ file = hugetlb_file_setup(name, 0, mk_vma_flags(VMA_NORESERVE_BIT),
HUGETLB_ANONHUGE_INODE,
(flags >> MFD_HUGE_SHIFT) &
MFD_HUGE_MASK);
diff --git a/mm/mmap.c b/mm/mmap.c
index 8771b276d63d..038ff5f09df0 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -594,7 +594,7 @@ unsigned long ksys_mmap_pgoff(unsigned long addr, unsigned long len,
* taken when vm_ops->mmap() is called
*/
file = hugetlb_file_setup(HUGETLB_ANON_FILE, len,
- VM_NORESERVE,
+ mk_vma_flags(VMA_NORESERVE_BIT),
HUGETLB_ANONHUGE_INODE,
(flags >> MAP_HUGE_SHIFT) & MAP_HUGE_MASK);
if (IS_ERR(file))
--
2.52.0
^ permalink raw reply [flat|nested] 56+ messages in thread* Re: [PATCH v2 06/13] mm: update hugetlbfs to use VMA flags on mmap_prepare
2026-01-22 16:06 ` [PATCH v2 06/13] mm: update hugetlbfs to use VMA flags on mmap_prepare Lorenzo Stoakes
@ 2026-02-09 19:03 ` Liam R. Howlett
0 siblings, 0 replies; 56+ messages in thread
From: Liam R. Howlett @ 2026-02-09 19:03 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin,
Arnd Bergmann, Greg Kroah-Hartman, Dan Williams, Vishal Verma,
Dave Jiang, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Hugh Dickins, Baolin Wang, Zi Yan, Nico Pache, Ryan Roberts,
Dev Jain, Barry Song, Lance Yang, Jann Horn, Pedro Falcato,
David Howells, Paul Moore, James Morris, Serge E . Hallyn,
Yury Norov, Rasmus Villemoes, linux-sgx, linux-kernel, nvdimm,
linux-cxl, dri-devel, intel-gfx, linux-fsdevel, linux-aio,
linux-erofs, linux-ext4, linux-mm, ntfs3, devel, linux-xfs,
keyrings, linux-security-module, Jason Gunthorpe
* Lorenzo Stoakes <lorenzo.stoakes@oracle.com> [260122 16:06]:
> In order to update all mmap_prepare users to utilising the new VMA flags
> type vma_flags_t and associated helper functions, we start by updating
> hugetlbfs which has a lot of additional logic that requires updating to
> make this change.
>
> This is laying the groundwork for eliminating the vm_flags_t from struct
> vm_area_desc and using vma_flags_t only, which further lays the ground for
> removing the deprecated vm_flags_t type altogether.
>
> No functional changes intended.
>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Reviewed-by: Liam R. Howlett <Liam.Howlett@oracle.com>
> ---
> fs/hugetlbfs/inode.c | 14 +++++++-------
> include/linux/hugetlb.h | 6 +++---
> include/linux/hugetlb_inline.h | 10 ++++++++++
> ipc/shm.c | 12 +++++++-----
> mm/hugetlb.c | 22 +++++++++++-----------
> mm/memfd.c | 4 ++--
> mm/mmap.c | 2 +-
> 7 files changed, 41 insertions(+), 29 deletions(-)
>
> diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
> index 3b4c152c5c73..95a5b23b4808 100644
> --- a/fs/hugetlbfs/inode.c
> +++ b/fs/hugetlbfs/inode.c
> @@ -109,7 +109,7 @@ static int hugetlbfs_file_mmap_prepare(struct vm_area_desc *desc)
> loff_t len, vma_len;
> int ret;
> struct hstate *h = hstate_file(file);
> - vm_flags_t vm_flags;
> + vma_flags_t vma_flags;
>
> /*
> * vma address alignment (but not the pgoff alignment) has
> @@ -119,7 +119,7 @@ static int hugetlbfs_file_mmap_prepare(struct vm_area_desc *desc)
> * way when do_mmap unwinds (may be important on powerpc
> * and ia64).
> */
> - desc->vm_flags |= VM_HUGETLB | VM_DONTEXPAND;
> + vma_desc_set_flags(desc, VMA_HUGETLB_BIT, VMA_DONTEXPAND_BIT);
> desc->vm_ops = &hugetlb_vm_ops;
>
> /*
> @@ -148,23 +148,23 @@ static int hugetlbfs_file_mmap_prepare(struct vm_area_desc *desc)
>
> ret = -ENOMEM;
>
> - vm_flags = desc->vm_flags;
> + vma_flags = desc->vma_flags;
> /*
> * for SHM_HUGETLB, the pages are reserved in the shmget() call so skip
> * reserving here. Note: only for SHM hugetlbfs file, the inode
> * flag S_PRIVATE is set.
> */
> if (inode->i_flags & S_PRIVATE)
> - vm_flags |= VM_NORESERVE;
> + vma_flags_set(&vma_flags, VMA_NORESERVE_BIT);
>
> if (hugetlb_reserve_pages(inode,
> desc->pgoff >> huge_page_order(h),
> len >> huge_page_shift(h), desc,
> - vm_flags) < 0)
> + vma_flags) < 0)
> goto out;
>
> ret = 0;
> - if ((desc->vm_flags & VM_WRITE) && inode->i_size < len)
> + if (vma_desc_test_flags(desc, VMA_WRITE_BIT) && inode->i_size < len)
> i_size_write(inode, len);
> out:
> inode_unlock(inode);
> @@ -1527,7 +1527,7 @@ static int get_hstate_idx(int page_size_log)
> * otherwise hugetlb_reserve_pages reserves one less hugepages than intended.
> */
> struct file *hugetlb_file_setup(const char *name, size_t size,
> - vm_flags_t acctflag, int creat_flags,
> + vma_flags_t acctflag, int creat_flags,
> int page_size_log)
> {
> struct inode *inode;
> diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
> index 94a03591990c..4e72bf66077e 100644
> --- a/include/linux/hugetlb.h
> +++ b/include/linux/hugetlb.h
> @@ -150,7 +150,7 @@ int hugetlb_mfill_atomic_pte(pte_t *dst_pte,
> struct folio **foliop);
> #endif /* CONFIG_USERFAULTFD */
> long hugetlb_reserve_pages(struct inode *inode, long from, long to,
> - struct vm_area_desc *desc, vm_flags_t vm_flags);
> + struct vm_area_desc *desc, vma_flags_t vma_flags);
> long hugetlb_unreserve_pages(struct inode *inode, long start, long end,
> long freed);
> bool folio_isolate_hugetlb(struct folio *folio, struct list_head *list);
> @@ -529,7 +529,7 @@ static inline struct hugetlbfs_inode_info *HUGETLBFS_I(struct inode *inode)
> }
>
> extern const struct vm_operations_struct hugetlb_vm_ops;
> -struct file *hugetlb_file_setup(const char *name, size_t size, vm_flags_t acct,
> +struct file *hugetlb_file_setup(const char *name, size_t size, vma_flags_t acct,
> int creat_flags, int page_size_log);
>
> static inline bool is_file_hugepages(const struct file *file)
> @@ -545,7 +545,7 @@ static inline struct hstate *hstate_inode(struct inode *i)
>
> #define is_file_hugepages(file) false
> static inline struct file *
> -hugetlb_file_setup(const char *name, size_t size, vm_flags_t acctflag,
> +hugetlb_file_setup(const char *name, size_t size, vma_flags_t acctflag,
> int creat_flags, int page_size_log)
> {
> return ERR_PTR(-ENOSYS);
> diff --git a/include/linux/hugetlb_inline.h b/include/linux/hugetlb_inline.h
> index a27aa0162918..593f5d4e108b 100644
> --- a/include/linux/hugetlb_inline.h
> +++ b/include/linux/hugetlb_inline.h
> @@ -11,6 +11,11 @@ static inline bool is_vm_hugetlb_flags(vm_flags_t vm_flags)
> return !!(vm_flags & VM_HUGETLB);
> }
>
> +static inline bool is_vma_hugetlb_flags(const vma_flags_t *flags)
> +{
> + return vma_flags_test(flags, VMA_HUGETLB_BIT);
> +}
> +
> #else
>
> static inline bool is_vm_hugetlb_flags(vm_flags_t vm_flags)
> @@ -18,6 +23,11 @@ static inline bool is_vm_hugetlb_flags(vm_flags_t vm_flags)
> return false;
> }
>
> +static inline bool is_vma_hugetlb_flags(const vma_flags_t *flags)
> +{
> + return false;
> +}
> +
> #endif
>
> static inline bool is_vm_hugetlb_page(struct vm_area_struct *vma)
> diff --git a/ipc/shm.c b/ipc/shm.c
> index 3db36773dd10..2c7379c4c647 100644
> --- a/ipc/shm.c
> +++ b/ipc/shm.c
> @@ -707,9 +707,9 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
> int error;
> struct shmid_kernel *shp;
> size_t numpages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
> + const bool has_no_reserve = shmflg & SHM_NORESERVE;
> struct file *file;
> char name[13];
> - vm_flags_t acctflag = 0;
>
> if (size < SHMMIN || size > ns->shm_ctlmax)
> return -EINVAL;
> @@ -738,6 +738,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
>
> sprintf(name, "SYSV%08x", key);
> if (shmflg & SHM_HUGETLB) {
> + vma_flags_t acctflag = EMPTY_VMA_FLAGS;
> struct hstate *hs;
> size_t hugesize;
>
> @@ -749,17 +750,18 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
> hugesize = ALIGN(size, huge_page_size(hs));
>
> /* hugetlb_file_setup applies strict accounting */
> - if (shmflg & SHM_NORESERVE)
> - acctflag = VM_NORESERVE;
> + if (has_no_reserve)
> + vma_flags_set(&acctflag, VMA_NORESERVE_BIT);
> file = hugetlb_file_setup(name, hugesize, acctflag,
> HUGETLB_SHMFS_INODE, (shmflg >> SHM_HUGE_SHIFT) & SHM_HUGE_MASK);
> } else {
> + vm_flags_t acctflag = 0;
> +
> /*
> * Do not allow no accounting for OVERCOMMIT_NEVER, even
> * if it's asked for.
> */
> - if ((shmflg & SHM_NORESERVE) &&
> - sysctl_overcommit_memory != OVERCOMMIT_NEVER)
> + if (has_no_reserve && sysctl_overcommit_memory != OVERCOMMIT_NEVER)
> acctflag = VM_NORESERVE;
> file = shmem_kernel_file_setup(name, size, acctflag);
> }
> diff --git a/mm/hugetlb.c b/mm/hugetlb.c
> index 4f4494251f5c..e6955061d751 100644
> --- a/mm/hugetlb.c
> +++ b/mm/hugetlb.c
> @@ -1193,16 +1193,16 @@ static void set_vma_resv_flags(struct vm_area_struct *vma, unsigned long flags)
>
> static void set_vma_desc_resv_map(struct vm_area_desc *desc, struct resv_map *map)
> {
> - VM_WARN_ON_ONCE(!is_vm_hugetlb_flags(desc->vm_flags));
> - VM_WARN_ON_ONCE(desc->vm_flags & VM_MAYSHARE);
> + VM_WARN_ON_ONCE(!is_vma_hugetlb_flags(&desc->vma_flags));
> + VM_WARN_ON_ONCE(vma_desc_test_flags(desc, VMA_MAYSHARE_BIT));
>
> desc->private_data = map;
> }
>
> static void set_vma_desc_resv_flags(struct vm_area_desc *desc, unsigned long flags)
> {
> - VM_WARN_ON_ONCE(!is_vm_hugetlb_flags(desc->vm_flags));
> - VM_WARN_ON_ONCE(desc->vm_flags & VM_MAYSHARE);
> + VM_WARN_ON_ONCE(!is_vma_hugetlb_flags(&desc->vma_flags));
> + VM_WARN_ON_ONCE(vma_desc_test_flags(desc, VMA_MAYSHARE_BIT));
>
> desc->private_data = (void *)((unsigned long)desc->private_data | flags);
> }
> @@ -1216,7 +1216,7 @@ static int is_vma_resv_set(struct vm_area_struct *vma, unsigned long flag)
>
> static bool is_vma_desc_resv_set(struct vm_area_desc *desc, unsigned long flag)
> {
> - VM_WARN_ON_ONCE(!is_vm_hugetlb_flags(desc->vm_flags));
> + VM_WARN_ON_ONCE(!is_vma_hugetlb_flags(&desc->vma_flags));
>
> return ((unsigned long)desc->private_data) & flag;
> }
> @@ -6564,7 +6564,7 @@ long hugetlb_change_protection(struct vm_area_struct *vma,
> long hugetlb_reserve_pages(struct inode *inode,
> long from, long to,
> struct vm_area_desc *desc,
> - vm_flags_t vm_flags)
> + vma_flags_t vma_flags)
> {
> long chg = -1, add = -1, spool_resv, gbl_resv;
> struct hstate *h = hstate_inode(inode);
> @@ -6585,7 +6585,7 @@ long hugetlb_reserve_pages(struct inode *inode,
> * attempt will be made for VM_NORESERVE to allocate a page
> * without using reserves
> */
> - if (vm_flags & VM_NORESERVE)
> + if (vma_flags_test(&vma_flags, VMA_NORESERVE_BIT))
> return 0;
>
> /*
> @@ -6594,7 +6594,7 @@ long hugetlb_reserve_pages(struct inode *inode,
> * to reserve the full area even if read-only as mprotect() may be
> * called to make the mapping read-write. Assume !desc is a shm mapping
> */
> - if (!desc || desc->vm_flags & VM_MAYSHARE) {
> + if (!desc || vma_desc_test_flags(desc, VMA_MAYSHARE_BIT)) {
> /*
> * resv_map can not be NULL as hugetlb_reserve_pages is only
> * called for inodes for which resv_maps were created (see
> @@ -6628,7 +6628,7 @@ long hugetlb_reserve_pages(struct inode *inode,
> if (err < 0)
> goto out_err;
>
> - if (desc && !(desc->vm_flags & VM_MAYSHARE) && h_cg) {
> + if (desc && !vma_desc_test_flags(desc, VMA_MAYSHARE_BIT) && h_cg) {
> /* For private mappings, the hugetlb_cgroup uncharge info hangs
> * of the resv_map.
> */
> @@ -6665,7 +6665,7 @@ long hugetlb_reserve_pages(struct inode *inode,
> * consumed reservations are stored in the map. Hence, nothing
> * else has to be done for private mappings here
> */
> - if (!desc || desc->vm_flags & VM_MAYSHARE) {
> + if (!desc || vma_desc_test_flags(desc, VMA_MAYSHARE_BIT)) {
> add = region_add(resv_map, from, to, regions_needed, h, h_cg);
>
> if (unlikely(add < 0)) {
> @@ -6729,7 +6729,7 @@ long hugetlb_reserve_pages(struct inode *inode,
> hugetlb_cgroup_uncharge_cgroup_rsvd(hstate_index(h),
> chg * pages_per_huge_page(h), h_cg);
> out_err:
> - if (!desc || desc->vm_flags & VM_MAYSHARE)
> + if (!desc || vma_desc_test_flags(desc, VMA_MAYSHARE_BIT))
> /* Only call region_abort if the region_chg succeeded but the
> * region_add failed or didn't run.
> */
> diff --git a/mm/memfd.c b/mm/memfd.c
> index ab5312aff14b..5f95f639550c 100644
> --- a/mm/memfd.c
> +++ b/mm/memfd.c
> @@ -87,7 +87,7 @@ struct folio *memfd_alloc_folio(struct file *memfd, pgoff_t idx)
> gfp_mask &= ~(__GFP_HIGHMEM | __GFP_MOVABLE);
> idx >>= huge_page_order(h);
>
> - nr_resv = hugetlb_reserve_pages(inode, idx, idx + 1, NULL, 0);
> + nr_resv = hugetlb_reserve_pages(inode, idx, idx + 1, NULL, EMPTY_VMA_FLAGS);
> if (nr_resv < 0)
> return ERR_PTR(nr_resv);
>
> @@ -464,7 +464,7 @@ static struct file *alloc_file(const char *name, unsigned int flags)
> int err = 0;
>
> if (flags & MFD_HUGETLB) {
> - file = hugetlb_file_setup(name, 0, VM_NORESERVE,
> + file = hugetlb_file_setup(name, 0, mk_vma_flags(VMA_NORESERVE_BIT),
> HUGETLB_ANONHUGE_INODE,
> (flags >> MFD_HUGE_SHIFT) &
> MFD_HUGE_MASK);
> diff --git a/mm/mmap.c b/mm/mmap.c
> index 8771b276d63d..038ff5f09df0 100644
> --- a/mm/mmap.c
> +++ b/mm/mmap.c
> @@ -594,7 +594,7 @@ unsigned long ksys_mmap_pgoff(unsigned long addr, unsigned long len,
> * taken when vm_ops->mmap() is called
> */
> file = hugetlb_file_setup(HUGETLB_ANON_FILE, len,
> - VM_NORESERVE,
> + mk_vma_flags(VMA_NORESERVE_BIT),
> HUGETLB_ANONHUGE_INODE,
> (flags >> MAP_HUGE_SHIFT) & MAP_HUGE_MASK);
> if (IS_ERR(file))
> --
> 2.52.0
>
^ permalink raw reply [flat|nested] 56+ messages in thread
* [PATCH v2 07/13] mm: update secretmem to use VMA flags on mmap_prepare
2026-01-22 16:06 [PATCH v2 00/13] mm: add bitmap VMA flag helpers and convert all mmap_prepare to use them Lorenzo Stoakes
` (5 preceding siblings ...)
2026-01-22 16:06 ` [PATCH v2 06/13] mm: update hugetlbfs to use VMA flags on mmap_prepare Lorenzo Stoakes
@ 2026-01-22 16:06 ` Lorenzo Stoakes
2026-01-28 12:08 ` Chris Mason
` (2 more replies)
2026-01-22 16:06 ` [PATCH v2 08/13] mm: update shmem_[kernel]_file_*() functions to use vma_flags_t Lorenzo Stoakes
` (7 subsequent siblings)
14 siblings, 3 replies; 56+ messages in thread
From: Lorenzo Stoakes @ 2026-01-22 16:06 UTC (permalink / raw)
To: Andrew Morton
Cc: Jarkko Sakkinen, Dave Hansen, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, x86, H . Peter Anvin, Arnd Bergmann,
Greg Kroah-Hartman, Dan Williams, Vishal Verma, Dave Jiang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
This patch updates secretmem to use the new vma_flags_t type which will
soon supersede vm_flags_t altogether.
In order to make this change we also have to update mlock_future_ok(), we
replace the vm_flags_t parameter with a simple boolean is_vma_locked one,
which also simplifies the invocation here.
This is laying the groundwork for eliminating the vm_flags_t in
vm_area_desc and more broadly throughout the kernel.
No functional changes intended.
Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
---
mm/internal.h | 2 +-
mm/mmap.c | 8 ++++----
mm/mremap.c | 2 +-
mm/secretmem.c | 7 +++----
mm/vma.c | 2 +-
5 files changed, 10 insertions(+), 11 deletions(-)
diff --git a/mm/internal.h b/mm/internal.h
index ef71a1d9991f..d67e8bb75734 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -1046,7 +1046,7 @@ extern long populate_vma_page_range(struct vm_area_struct *vma,
unsigned long start, unsigned long end, int *locked);
extern long faultin_page_range(struct mm_struct *mm, unsigned long start,
unsigned long end, bool write, int *locked);
-bool mlock_future_ok(const struct mm_struct *mm, vm_flags_t vm_flags,
+bool mlock_future_ok(const struct mm_struct *mm, bool is_vma_locked,
unsigned long bytes);
/*
diff --git a/mm/mmap.c b/mm/mmap.c
index 038ff5f09df0..354479c95896 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -225,12 +225,12 @@ static inline unsigned long round_hint_to_min(unsigned long hint)
return hint;
}
-bool mlock_future_ok(const struct mm_struct *mm, vm_flags_t vm_flags,
- unsigned long bytes)
+bool mlock_future_ok(const struct mm_struct *mm, bool is_vma_locked,
+ unsigned long bytes)
{
unsigned long locked_pages, limit_pages;
- if (!(vm_flags & VM_LOCKED) || capable(CAP_IPC_LOCK))
+ if (!is_vma_locked || capable(CAP_IPC_LOCK))
return true;
locked_pages = bytes >> PAGE_SHIFT;
@@ -416,7 +416,7 @@ unsigned long do_mmap(struct file *file, unsigned long addr,
if (!can_do_mlock())
return -EPERM;
- if (!mlock_future_ok(mm, vm_flags, len))
+ if (!mlock_future_ok(mm, vm_flags & VM_LOCKED, len))
return -EAGAIN;
if (file) {
diff --git a/mm/mremap.c b/mm/mremap.c
index 8391ae17de64..2be876a70cc0 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -1740,7 +1740,7 @@ static int check_prep_vma(struct vma_remap_struct *vrm)
if (vma->vm_flags & (VM_DONTEXPAND | VM_PFNMAP))
return -EFAULT;
- if (!mlock_future_ok(mm, vma->vm_flags, vrm->delta))
+ if (!mlock_future_ok(mm, vma->vm_flags & VM_LOCKED, vrm->delta))
return -EAGAIN;
if (!may_expand_vm(mm, vma->vm_flags, vrm->delta >> PAGE_SHIFT))
diff --git a/mm/secretmem.c b/mm/secretmem.c
index edf111e0a1bb..11a779c812a7 100644
--- a/mm/secretmem.c
+++ b/mm/secretmem.c
@@ -122,13 +122,12 @@ static int secretmem_mmap_prepare(struct vm_area_desc *desc)
{
const unsigned long len = vma_desc_size(desc);
- if ((desc->vm_flags & (VM_SHARED | VM_MAYSHARE)) == 0)
+ if (!vma_desc_test_flags(desc, VMA_SHARED_BIT, VMA_MAYSHARE_BIT))
return -EINVAL;
- if (!mlock_future_ok(desc->mm, desc->vm_flags | VM_LOCKED, len))
+ vma_desc_set_flags(desc, VMA_LOCKED_BIT, VMA_DONTDUMP_BIT);
+ if (!mlock_future_ok(desc->mm, /*is_vma_locked=*/ true, len))
return -EAGAIN;
-
- desc->vm_flags |= VM_LOCKED | VM_DONTDUMP;
desc->vm_ops = &secretmem_vm_ops;
return 0;
diff --git a/mm/vma.c b/mm/vma.c
index f352d5c72212..39dcd9ddd4ba 100644
--- a/mm/vma.c
+++ b/mm/vma.c
@@ -3053,7 +3053,7 @@ static int acct_stack_growth(struct vm_area_struct *vma,
return -ENOMEM;
/* mlock limit tests */
- if (!mlock_future_ok(mm, vma->vm_flags, grow << PAGE_SHIFT))
+ if (!mlock_future_ok(mm, vma->vm_flags & VM_LOCKED, grow << PAGE_SHIFT))
return -ENOMEM;
/* Check to ensure the stack will not grow into a hugetlb-only region */
--
2.52.0
^ permalink raw reply [flat|nested] 56+ messages in thread* Re: [PATCH v2 07/13] mm: update secretmem to use VMA flags on mmap_prepare
2026-01-22 16:06 ` [PATCH v2 07/13] mm: update secretmem " Lorenzo Stoakes
@ 2026-01-28 12:08 ` Chris Mason
2026-01-28 16:04 ` Lorenzo Stoakes
2026-01-28 16:44 ` Lorenzo Stoakes
2026-02-09 19:06 ` Liam R. Howlett
2 siblings, 1 reply; 56+ messages in thread
From: Chris Mason @ 2026-01-28 12:08 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin,
Arnd Bergmann, Greg Kroah-Hartman, Dan Williams, Vishal Verma,
Dave Jiang, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
Lorenzo Stoakes <lorenzo.stoakes@oracle.com> wrote:
> This patch updates secretmem to use the new vma_flags_t type which will
> soon supersede vm_flags_t altogether.
>
> In order to make this change we also have to update mlock_future_ok(), we
> replace the vm_flags_t parameter with a simple boolean is_vma_locked one,
> which also simplifies the invocation here.
>
> This is laying the groundwork for eliminating the vm_flags_t in
> vm_area_desc and more broadly throughout the kernel.
>
Hi everyone,
Running mm-new through AI review flagged this one:
> diff --git a/mm/mmap.c b/mm/mmap.c
> --- a/mm/mmap.c
> +++ b/mm/mmap.c
> @@ -225,12 +225,12 @@ static inline unsigned long round_hint_to_min(unsigned long hint)
> return hint;
> }
>
> -bool mlock_future_ok(const struct mm_struct *mm, vm_flags_t vm_flags,
> - unsigned long bytes)
> +bool mlock_future_ok(const struct mm_struct *mm, bool is_vma_locked,
> + unsigned long bytes)
> {
> unsigned long locked_pages, limit_pages;
>
> - if (!(vm_flags & VM_LOCKED) || capable(CAP_IPC_LOCK))
> + if (!is_vma_locked || capable(CAP_IPC_LOCK))
> return true;
[ ... ]
> @@ -416,7 +416,7 @@
> if (!can_do_mlock())
> return -EPERM;
>
> - if (!mlock_future_ok(mm, vm_flags, len))
> + if (!mlock_future_ok(mm, vm_flags & VM_LOCKED, len))
> return -EAGAIN;
This looks correct - do_mmap() now extracts the VM_LOCKED bit from
vm_flags and passes that to mlock_future_ok().
However, it appears check_brk_limits() was not updated when
mlock_future_ok() changed its signature. The function at mm/mmap.c:111
still passes the raw def_flags value:
return mlock_future_ok(current->mm, current->mm->def_flags, len)
? 0 : -EAGAIN;
When def_flags has any bit set, this converts to true, incorrectly
triggering mlock limit checks even when VM_LOCKED is not set. Should
this be passing (current->mm->def_flags & VM_LOCKED) instead?
[ ... ]
Additionally, the test stub at tools/testing/vma/vma_internal.h:1627
still has the old signature (mm, vm_flags_t vm_flags, bytes) while the
production code now uses (mm, bool is_vma_locked, bytes). This could
cause compilation issues or mask bugs in the test suite.
^ permalink raw reply [flat|nested] 56+ messages in thread* Re: [PATCH v2 07/13] mm: update secretmem to use VMA flags on mmap_prepare
2026-01-28 12:08 ` Chris Mason
@ 2026-01-28 16:04 ` Lorenzo Stoakes
0 siblings, 0 replies; 56+ messages in thread
From: Lorenzo Stoakes @ 2026-01-28 16:04 UTC (permalink / raw)
To: Chris Mason
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin,
Arnd Bergmann, Greg Kroah-Hartman, Dan Williams, Vishal Verma,
Dave Jiang, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
On Wed, Jan 28, 2026 at 04:08:36AM -0800, Chris Mason wrote:
> Lorenzo Stoakes <lorenzo.stoakes@oracle.com> wrote:
> > This patch updates secretmem to use the new vma_flags_t type which will
> > soon supersede vm_flags_t altogether.
> >
> > In order to make this change we also have to update mlock_future_ok(), we
> > replace the vm_flags_t parameter with a simple boolean is_vma_locked one,
> > which also simplifies the invocation here.
> >
> > This is laying the groundwork for eliminating the vm_flags_t in
> > vm_area_desc and more broadly throughout the kernel.
> >
>
> Hi everyone,
>
> Running mm-new through AI review flagged this one:
>
> > diff --git a/mm/mmap.c b/mm/mmap.c
> > --- a/mm/mmap.c
> > +++ b/mm/mmap.c
> > @@ -225,12 +225,12 @@ static inline unsigned long round_hint_to_min(unsigned long hint)
> > return hint;
> > }
> >
> > -bool mlock_future_ok(const struct mm_struct *mm, vm_flags_t vm_flags,
> > - unsigned long bytes)
> > +bool mlock_future_ok(const struct mm_struct *mm, bool is_vma_locked,
> > + unsigned long bytes)
> > {
> > unsigned long locked_pages, limit_pages;
> >
> > - if (!(vm_flags & VM_LOCKED) || capable(CAP_IPC_LOCK))
> > + if (!is_vma_locked || capable(CAP_IPC_LOCK))
> > return true;
>
> [ ... ]
>
> > @@ -416,7 +416,7 @@
> > if (!can_do_mlock())
> > return -EPERM;
> >
> > - if (!mlock_future_ok(mm, vm_flags, len))
> > + if (!mlock_future_ok(mm, vm_flags & VM_LOCKED, len))
> > return -EAGAIN;
>
> This looks correct - do_mmap() now extracts the VM_LOCKED bit from
> vm_flags and passes that to mlock_future_ok().
>
> However, it appears check_brk_limits() was not updated when
> mlock_future_ok() changed its signature. The function at mm/mmap.c:111
> still passes the raw def_flags value:
>
> return mlock_future_ok(current->mm, current->mm->def_flags, len)
> ? 0 : -EAGAIN;
Ack, the C 'type system' strikes again :) will send a fix-patch.
>
> When def_flags has any bit set, this converts to true, incorrectly
> triggering mlock limit checks even when VM_LOCKED is not set. Should
> this be passing (current->mm->def_flags & VM_LOCKED) instead?
>
> [ ... ]
>
> Additionally, the test stub at tools/testing/vma/vma_internal.h:1627
> still has the old signature (mm, vm_flags_t vm_flags, bytes) while the
> production code now uses (mm, bool is_vma_locked, bytes). This could
> cause compilation issues or mask bugs in the test suite.
Ack, I can fix that later. The VMA test headers have been split and it's too
much merge pain to address at this point given the tests aren't impacted by this
yet. Is on todo!
>
>
Cheers, Lorenzo
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH v2 07/13] mm: update secretmem to use VMA flags on mmap_prepare
2026-01-22 16:06 ` [PATCH v2 07/13] mm: update secretmem " Lorenzo Stoakes
2026-01-28 12:08 ` Chris Mason
@ 2026-01-28 16:44 ` Lorenzo Stoakes
2026-02-09 19:06 ` Liam R. Howlett
2 siblings, 0 replies; 56+ messages in thread
From: Lorenzo Stoakes @ 2026-01-28 16:44 UTC (permalink / raw)
To: Andrew Morton
Cc: Jarkko Sakkinen, Dave Hansen, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, x86, H . Peter Anvin, Arnd Bergmann,
Greg Kroah-Hartman, Dan Williams, Vishal Verma, Dave Jiang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
Hi Andrew,
Could you apply the below fix-patch to resolve the issue Chris's AI checks
detected, I missed out one caller of mlock_future_ok() (a very human mistake
;)).
Cheers, Lorenzo
----8<----
From 652146b4d93a31bb6f9da9428ddaab8a4a53e170 Mon Sep 17 00:00:00 2001
From: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Date: Wed, 28 Jan 2026 16:41:55 +0000
Subject: [PATCH] fix
Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
---
mm/mmap.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/mm/mmap.c b/mm/mmap.c
index 354479c95896..5dfe57b6d69a 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -108,7 +108,8 @@ static int check_brk_limits(unsigned long addr, unsigned long len)
if (IS_ERR_VALUE(mapped_addr))
return mapped_addr;
- return mlock_future_ok(current->mm, current->mm->def_flags, len)
+ return mlock_future_ok(current->mm,
+ current->mm->def_flags & VM_LOCKED, len)
? 0 : -EAGAIN;
}
--
2.52.0
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH v2 07/13] mm: update secretmem to use VMA flags on mmap_prepare
2026-01-22 16:06 ` [PATCH v2 07/13] mm: update secretmem " Lorenzo Stoakes
2026-01-28 12:08 ` Chris Mason
2026-01-28 16:44 ` Lorenzo Stoakes
@ 2026-02-09 19:06 ` Liam R. Howlett
2 siblings, 0 replies; 56+ messages in thread
From: Liam R. Howlett @ 2026-02-09 19:06 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin,
Arnd Bergmann, Greg Kroah-Hartman, Dan Williams, Vishal Verma,
Dave Jiang, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Hugh Dickins, Baolin Wang, Zi Yan, Nico Pache, Ryan Roberts,
Dev Jain, Barry Song, Lance Yang, Jann Horn, Pedro Falcato,
David Howells, Paul Moore, James Morris, Serge E . Hallyn,
Yury Norov, Rasmus Villemoes, linux-sgx, linux-kernel, nvdimm,
linux-cxl, dri-devel, intel-gfx, linux-fsdevel, linux-aio,
linux-erofs, linux-ext4, linux-mm, ntfs3, devel, linux-xfs,
keyrings, linux-security-module, Jason Gunthorpe
* Lorenzo Stoakes <lorenzo.stoakes@oracle.com> [260122 16:06]:
> This patch updates secretmem to use the new vma_flags_t type which will
> soon supersede vm_flags_t altogether.
>
> In order to make this change we also have to update mlock_future_ok(), we
> replace the vm_flags_t parameter with a simple boolean is_vma_locked one,
> which also simplifies the invocation here.
>
> This is laying the groundwork for eliminating the vm_flags_t in
> vm_area_desc and more broadly throughout the kernel.
>
> No functional changes intended.
>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
With the type fix for brk - I assume sparse would have detected this as
well.
Reviewed-by: Liam R. Howlett <Liam.Howlett@oracle.com>
> ---
> mm/internal.h | 2 +-
> mm/mmap.c | 8 ++++----
> mm/mremap.c | 2 +-
> mm/secretmem.c | 7 +++----
> mm/vma.c | 2 +-
> 5 files changed, 10 insertions(+), 11 deletions(-)
>
> diff --git a/mm/internal.h b/mm/internal.h
> index ef71a1d9991f..d67e8bb75734 100644
> --- a/mm/internal.h
> +++ b/mm/internal.h
> @@ -1046,7 +1046,7 @@ extern long populate_vma_page_range(struct vm_area_struct *vma,
> unsigned long start, unsigned long end, int *locked);
> extern long faultin_page_range(struct mm_struct *mm, unsigned long start,
> unsigned long end, bool write, int *locked);
> -bool mlock_future_ok(const struct mm_struct *mm, vm_flags_t vm_flags,
> +bool mlock_future_ok(const struct mm_struct *mm, bool is_vma_locked,
> unsigned long bytes);
>
> /*
> diff --git a/mm/mmap.c b/mm/mmap.c
> index 038ff5f09df0..354479c95896 100644
> --- a/mm/mmap.c
> +++ b/mm/mmap.c
> @@ -225,12 +225,12 @@ static inline unsigned long round_hint_to_min(unsigned long hint)
> return hint;
> }
>
> -bool mlock_future_ok(const struct mm_struct *mm, vm_flags_t vm_flags,
> - unsigned long bytes)
> +bool mlock_future_ok(const struct mm_struct *mm, bool is_vma_locked,
> + unsigned long bytes)
> {
> unsigned long locked_pages, limit_pages;
>
> - if (!(vm_flags & VM_LOCKED) || capable(CAP_IPC_LOCK))
> + if (!is_vma_locked || capable(CAP_IPC_LOCK))
> return true;
>
> locked_pages = bytes >> PAGE_SHIFT;
> @@ -416,7 +416,7 @@ unsigned long do_mmap(struct file *file, unsigned long addr,
> if (!can_do_mlock())
> return -EPERM;
>
> - if (!mlock_future_ok(mm, vm_flags, len))
> + if (!mlock_future_ok(mm, vm_flags & VM_LOCKED, len))
> return -EAGAIN;
>
> if (file) {
> diff --git a/mm/mremap.c b/mm/mremap.c
> index 8391ae17de64..2be876a70cc0 100644
> --- a/mm/mremap.c
> +++ b/mm/mremap.c
> @@ -1740,7 +1740,7 @@ static int check_prep_vma(struct vma_remap_struct *vrm)
> if (vma->vm_flags & (VM_DONTEXPAND | VM_PFNMAP))
> return -EFAULT;
>
> - if (!mlock_future_ok(mm, vma->vm_flags, vrm->delta))
> + if (!mlock_future_ok(mm, vma->vm_flags & VM_LOCKED, vrm->delta))
> return -EAGAIN;
>
> if (!may_expand_vm(mm, vma->vm_flags, vrm->delta >> PAGE_SHIFT))
> diff --git a/mm/secretmem.c b/mm/secretmem.c
> index edf111e0a1bb..11a779c812a7 100644
> --- a/mm/secretmem.c
> +++ b/mm/secretmem.c
> @@ -122,13 +122,12 @@ static int secretmem_mmap_prepare(struct vm_area_desc *desc)
> {
> const unsigned long len = vma_desc_size(desc);
>
> - if ((desc->vm_flags & (VM_SHARED | VM_MAYSHARE)) == 0)
> + if (!vma_desc_test_flags(desc, VMA_SHARED_BIT, VMA_MAYSHARE_BIT))
> return -EINVAL;
>
> - if (!mlock_future_ok(desc->mm, desc->vm_flags | VM_LOCKED, len))
> + vma_desc_set_flags(desc, VMA_LOCKED_BIT, VMA_DONTDUMP_BIT);
> + if (!mlock_future_ok(desc->mm, /*is_vma_locked=*/ true, len))
> return -EAGAIN;
> -
> - desc->vm_flags |= VM_LOCKED | VM_DONTDUMP;
> desc->vm_ops = &secretmem_vm_ops;
>
> return 0;
> diff --git a/mm/vma.c b/mm/vma.c
> index f352d5c72212..39dcd9ddd4ba 100644
> --- a/mm/vma.c
> +++ b/mm/vma.c
> @@ -3053,7 +3053,7 @@ static int acct_stack_growth(struct vm_area_struct *vma,
> return -ENOMEM;
>
> /* mlock limit tests */
> - if (!mlock_future_ok(mm, vma->vm_flags, grow << PAGE_SHIFT))
> + if (!mlock_future_ok(mm, vma->vm_flags & VM_LOCKED, grow << PAGE_SHIFT))
> return -ENOMEM;
>
> /* Check to ensure the stack will not grow into a hugetlb-only region */
> --
> 2.52.0
>
^ permalink raw reply [flat|nested] 56+ messages in thread
* [PATCH v2 08/13] mm: update shmem_[kernel]_file_*() functions to use vma_flags_t
2026-01-22 16:06 [PATCH v2 00/13] mm: add bitmap VMA flag helpers and convert all mmap_prepare to use them Lorenzo Stoakes
` (6 preceding siblings ...)
2026-01-22 16:06 ` [PATCH v2 07/13] mm: update secretmem " Lorenzo Stoakes
@ 2026-01-22 16:06 ` Lorenzo Stoakes
2026-01-23 6:20 ` Baolin Wang
` (4 more replies)
2026-01-22 16:06 ` [PATCH v2 09/13] mm: update all remaining mmap_prepare users " Lorenzo Stoakes
` (6 subsequent siblings)
14 siblings, 5 replies; 56+ messages in thread
From: Lorenzo Stoakes @ 2026-01-22 16:06 UTC (permalink / raw)
To: Andrew Morton
Cc: Jarkko Sakkinen, Dave Hansen, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, x86, H . Peter Anvin, Arnd Bergmann,
Greg Kroah-Hartman, Dan Williams, Vishal Verma, Dave Jiang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
In order to be able to use only vma_flags_t in vm_area_desc we must adjust
shmem file setup functions to operate in terms of vma_flags_t rather than
vm_flags_t.
This patch makes this change and updates all callers to use the new
functions.
No functional changes intended.
Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
---
arch/x86/kernel/cpu/sgx/ioctl.c | 2 +-
drivers/gpu/drm/drm_gem.c | 5 +-
drivers/gpu/drm/i915/gem/i915_gem_shmem.c | 2 +-
drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 3 +-
drivers/gpu/drm/i915/gt/shmem_utils.c | 3 +-
drivers/gpu/drm/ttm/tests/ttm_tt_test.c | 2 +-
drivers/gpu/drm/ttm/ttm_backup.c | 3 +-
drivers/gpu/drm/ttm/ttm_tt.c | 2 +-
fs/xfs/scrub/xfile.c | 3 +-
fs/xfs/xfs_buf_mem.c | 2 +-
include/linux/shmem_fs.h | 8 ++-
ipc/shm.c | 6 +--
mm/memfd.c | 2 +-
mm/memfd_luo.c | 2 +-
mm/shmem.c | 59 +++++++++++++----------
security/keys/big_key.c | 2 +-
16 files changed, 57 insertions(+), 49 deletions(-)
diff --git a/arch/x86/kernel/cpu/sgx/ioctl.c b/arch/x86/kernel/cpu/sgx/ioctl.c
index 9322a9287dc7..0bc36957979d 100644
--- a/arch/x86/kernel/cpu/sgx/ioctl.c
+++ b/arch/x86/kernel/cpu/sgx/ioctl.c
@@ -83,7 +83,7 @@ static int sgx_encl_create(struct sgx_encl *encl, struct sgx_secs *secs)
encl_size = secs->size + PAGE_SIZE;
backing = shmem_file_setup("SGX backing", encl_size + (encl_size >> 5),
- VM_NORESERVE);
+ mk_vma_flags(VMA_NORESERVE_BIT));
if (IS_ERR(backing)) {
ret = PTR_ERR(backing);
goto err_out_shrink;
diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
index e4df43427394..be4dca2bc34e 100644
--- a/drivers/gpu/drm/drm_gem.c
+++ b/drivers/gpu/drm/drm_gem.c
@@ -130,14 +130,15 @@ int drm_gem_object_init_with_mnt(struct drm_device *dev,
struct vfsmount *gemfs)
{
struct file *filp;
+ const vma_flags_t flags = mk_vma_flags(VMA_NORESERVE_BIT);
drm_gem_private_object_init(dev, obj, size);
if (gemfs)
filp = shmem_file_setup_with_mnt(gemfs, "drm mm object", size,
- VM_NORESERVE);
+ flags);
else
- filp = shmem_file_setup("drm mm object", size, VM_NORESERVE);
+ filp = shmem_file_setup("drm mm object", size, flags);
if (IS_ERR(filp))
return PTR_ERR(filp);
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
index 26dda55a07ff..fe1843497b27 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
@@ -496,7 +496,7 @@ static int __create_shmem(struct drm_i915_private *i915,
struct drm_gem_object *obj,
resource_size_t size)
{
- unsigned long flags = VM_NORESERVE;
+ const vma_flags_t flags = mk_vma_flags(VMA_NORESERVE_BIT);
struct file *filp;
drm_gem_private_object_init(&i915->drm, obj, size);
diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
index f65fe86c02b5..7b1a7d01db2b 100644
--- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
+++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
@@ -200,7 +200,8 @@ static int i915_ttm_tt_shmem_populate(struct ttm_device *bdev,
struct address_space *mapping;
gfp_t mask;
- filp = shmem_file_setup("i915-shmem-tt", size, VM_NORESERVE);
+ filp = shmem_file_setup("i915-shmem-tt", size,
+ mk_vma_flags(VMA_NORESERVE_BIT));
if (IS_ERR(filp))
return PTR_ERR(filp);
diff --git a/drivers/gpu/drm/i915/gt/shmem_utils.c b/drivers/gpu/drm/i915/gt/shmem_utils.c
index 365c4b8b04f4..5f37c699a320 100644
--- a/drivers/gpu/drm/i915/gt/shmem_utils.c
+++ b/drivers/gpu/drm/i915/gt/shmem_utils.c
@@ -19,7 +19,8 @@ struct file *shmem_create_from_data(const char *name, void *data, size_t len)
struct file *file;
int err;
- file = shmem_file_setup(name, PAGE_ALIGN(len), VM_NORESERVE);
+ file = shmem_file_setup(name, PAGE_ALIGN(len),
+ mk_vma_flags(VMA_NORESERVE_BIT));
if (IS_ERR(file))
return file;
diff --git a/drivers/gpu/drm/ttm/tests/ttm_tt_test.c b/drivers/gpu/drm/ttm/tests/ttm_tt_test.c
index 61ec6f580b62..bd5f7d0b9b62 100644
--- a/drivers/gpu/drm/ttm/tests/ttm_tt_test.c
+++ b/drivers/gpu/drm/ttm/tests/ttm_tt_test.c
@@ -143,7 +143,7 @@ static void ttm_tt_fini_shmem(struct kunit *test)
err = ttm_tt_init(tt, bo, 0, caching, 0);
KUNIT_ASSERT_EQ(test, err, 0);
- shmem = shmem_file_setup("ttm swap", BO_SIZE, 0);
+ shmem = shmem_file_setup("ttm swap", BO_SIZE, EMPTY_VMA_FLAGS);
tt->swap_storage = shmem;
ttm_tt_fini(tt);
diff --git a/drivers/gpu/drm/ttm/ttm_backup.c b/drivers/gpu/drm/ttm/ttm_backup.c
index 32530c75f038..6bd4c123d94c 100644
--- a/drivers/gpu/drm/ttm/ttm_backup.c
+++ b/drivers/gpu/drm/ttm/ttm_backup.c
@@ -178,5 +178,6 @@ EXPORT_SYMBOL_GPL(ttm_backup_bytes_avail);
*/
struct file *ttm_backup_shmem_create(loff_t size)
{
- return shmem_file_setup("ttm shmem backup", size, 0);
+ return shmem_file_setup("ttm shmem backup", size,
+ EMPTY_VMA_FLAGS);
}
diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c
index 611d20ab966d..f73a5ce87645 100644
--- a/drivers/gpu/drm/ttm/ttm_tt.c
+++ b/drivers/gpu/drm/ttm/ttm_tt.c
@@ -330,7 +330,7 @@ int ttm_tt_swapout(struct ttm_device *bdev, struct ttm_tt *ttm,
struct page *to_page;
int i, ret;
- swap_storage = shmem_file_setup("ttm swap", size, 0);
+ swap_storage = shmem_file_setup("ttm swap", size, EMPTY_VMA_FLAGS);
if (IS_ERR(swap_storage)) {
pr_err("Failed allocating swap storage\n");
return PTR_ERR(swap_storage);
diff --git a/fs/xfs/scrub/xfile.c b/fs/xfs/scrub/xfile.c
index c753c79df203..fe0584a39f16 100644
--- a/fs/xfs/scrub/xfile.c
+++ b/fs/xfs/scrub/xfile.c
@@ -61,7 +61,8 @@ xfile_create(
if (!xf)
return -ENOMEM;
- xf->file = shmem_kernel_file_setup(description, isize, VM_NORESERVE);
+ xf->file = shmem_kernel_file_setup(description, isize,
+ mk_vma_flags(VMA_NORESERVE_BIT));
if (IS_ERR(xf->file)) {
error = PTR_ERR(xf->file);
goto out_xfile;
diff --git a/fs/xfs/xfs_buf_mem.c b/fs/xfs/xfs_buf_mem.c
index dcbfa274e06d..fd6f0a5bc0ea 100644
--- a/fs/xfs/xfs_buf_mem.c
+++ b/fs/xfs/xfs_buf_mem.c
@@ -62,7 +62,7 @@ xmbuf_alloc(
if (!btp)
return -ENOMEM;
- file = shmem_kernel_file_setup(descr, 0, 0);
+ file = shmem_kernel_file_setup(descr, 0, EMPTY_VMA_FLAGS);
if (IS_ERR(file)) {
error = PTR_ERR(file);
goto out_free_btp;
diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
index e2069b3179c4..a8273b32e041 100644
--- a/include/linux/shmem_fs.h
+++ b/include/linux/shmem_fs.h
@@ -102,12 +102,10 @@ static inline struct shmem_inode_info *SHMEM_I(struct inode *inode)
extern const struct fs_parameter_spec shmem_fs_parameters[];
extern void shmem_init(void);
extern int shmem_init_fs_context(struct fs_context *fc);
-extern struct file *shmem_file_setup(const char *name,
- loff_t size, unsigned long flags);
-extern struct file *shmem_kernel_file_setup(const char *name, loff_t size,
- unsigned long flags);
+struct file *shmem_file_setup(const char *name, loff_t size, vma_flags_t flags);
+struct file *shmem_kernel_file_setup(const char *name, loff_t size, vma_flags_t vma_flags);
extern struct file *shmem_file_setup_with_mnt(struct vfsmount *mnt,
- const char *name, loff_t size, unsigned long flags);
+ const char *name, loff_t size, vma_flags_t flags);
int shmem_zero_setup(struct vm_area_struct *vma);
int shmem_zero_setup_desc(struct vm_area_desc *desc);
extern unsigned long shmem_get_unmapped_area(struct file *, unsigned long addr,
diff --git a/ipc/shm.c b/ipc/shm.c
index 2c7379c4c647..e8c7d1924c50 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -708,6 +708,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
struct shmid_kernel *shp;
size_t numpages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
const bool has_no_reserve = shmflg & SHM_NORESERVE;
+ vma_flags_t acctflag = EMPTY_VMA_FLAGS;
struct file *file;
char name[13];
@@ -738,7 +739,6 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
sprintf(name, "SYSV%08x", key);
if (shmflg & SHM_HUGETLB) {
- vma_flags_t acctflag = EMPTY_VMA_FLAGS;
struct hstate *hs;
size_t hugesize;
@@ -755,14 +755,12 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
file = hugetlb_file_setup(name, hugesize, acctflag,
HUGETLB_SHMFS_INODE, (shmflg >> SHM_HUGE_SHIFT) & SHM_HUGE_MASK);
} else {
- vm_flags_t acctflag = 0;
-
/*
* Do not allow no accounting for OVERCOMMIT_NEVER, even
* if it's asked for.
*/
if (has_no_reserve && sysctl_overcommit_memory != OVERCOMMIT_NEVER)
- acctflag = VM_NORESERVE;
+ vma_flags_set(&acctflag, VMA_NORESERVE_BIT);
file = shmem_kernel_file_setup(name, size, acctflag);
}
error = PTR_ERR(file);
diff --git a/mm/memfd.c b/mm/memfd.c
index 5f95f639550c..f3a8950850a2 100644
--- a/mm/memfd.c
+++ b/mm/memfd.c
@@ -469,7 +469,7 @@ static struct file *alloc_file(const char *name, unsigned int flags)
(flags >> MFD_HUGE_SHIFT) &
MFD_HUGE_MASK);
} else {
- file = shmem_file_setup(name, 0, VM_NORESERVE);
+ file = shmem_file_setup(name, 0, mk_vma_flags(VMA_NORESERVE_BIT));
}
if (IS_ERR(file))
return file;
diff --git a/mm/memfd_luo.c b/mm/memfd_luo.c
index 4f6ba63b4310..a2629dcfd0f1 100644
--- a/mm/memfd_luo.c
+++ b/mm/memfd_luo.c
@@ -443,7 +443,7 @@ static int memfd_luo_retrieve(struct liveupdate_file_op_args *args)
if (!ser)
return -EINVAL;
- file = shmem_file_setup("", 0, VM_NORESERVE);
+ file = shmem_file_setup("", 0, mk_vma_flags(VMA_NORESERVE_BIT));
if (IS_ERR(file)) {
pr_err("failed to setup file: %pe\n", file);
diff --git a/mm/shmem.c b/mm/shmem.c
index 0adde3f4df27..97a8f55c7296 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -3057,9 +3057,9 @@ static struct offset_ctx *shmem_get_offset_ctx(struct inode *inode)
}
static struct inode *__shmem_get_inode(struct mnt_idmap *idmap,
- struct super_block *sb,
- struct inode *dir, umode_t mode,
- dev_t dev, unsigned long flags)
+ struct super_block *sb,
+ struct inode *dir, umode_t mode,
+ dev_t dev, vma_flags_t flags)
{
struct inode *inode;
struct shmem_inode_info *info;
@@ -3087,7 +3087,8 @@ static struct inode *__shmem_get_inode(struct mnt_idmap *idmap,
spin_lock_init(&info->lock);
atomic_set(&info->stop_eviction, 0);
info->seals = F_SEAL_SEAL;
- info->flags = (flags & VM_NORESERVE) ? SHMEM_F_NORESERVE : 0;
+ info->flags = vma_flags_test(&flags, VMA_NORESERVE_BIT)
+ ? SHMEM_F_NORESERVE : 0;
info->i_crtime = inode_get_mtime(inode);
info->fsflags = (dir == NULL) ? 0 :
SHMEM_I(dir)->fsflags & SHMEM_FL_INHERITED;
@@ -3140,7 +3141,7 @@ static struct inode *__shmem_get_inode(struct mnt_idmap *idmap,
#ifdef CONFIG_TMPFS_QUOTA
static struct inode *shmem_get_inode(struct mnt_idmap *idmap,
struct super_block *sb, struct inode *dir,
- umode_t mode, dev_t dev, unsigned long flags)
+ umode_t mode, dev_t dev, vma_flags_t flags)
{
int err;
struct inode *inode;
@@ -3166,9 +3167,9 @@ static struct inode *shmem_get_inode(struct mnt_idmap *idmap,
return ERR_PTR(err);
}
#else
-static inline struct inode *shmem_get_inode(struct mnt_idmap *idmap,
+static struct inode *shmem_get_inode(struct mnt_idmap *idmap,
struct super_block *sb, struct inode *dir,
- umode_t mode, dev_t dev, unsigned long flags)
+ umode_t mode, dev_t dev, vma_flags_t flags)
{
return __shmem_get_inode(idmap, sb, dir, mode, dev, flags);
}
@@ -3875,7 +3876,8 @@ shmem_mknod(struct mnt_idmap *idmap, struct inode *dir,
if (!generic_ci_validate_strict_name(dir, &dentry->d_name))
return -EINVAL;
- inode = shmem_get_inode(idmap, dir->i_sb, dir, mode, dev, VM_NORESERVE);
+ inode = shmem_get_inode(idmap, dir->i_sb, dir, mode, dev,
+ mk_vma_flags(VMA_NORESERVE_BIT));
if (IS_ERR(inode))
return PTR_ERR(inode);
@@ -3910,7 +3912,8 @@ shmem_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
struct inode *inode;
int error;
- inode = shmem_get_inode(idmap, dir->i_sb, dir, mode, 0, VM_NORESERVE);
+ inode = shmem_get_inode(idmap, dir->i_sb, dir, mode, 0,
+ mk_vma_flags(VMA_NORESERVE_BIT));
if (IS_ERR(inode)) {
error = PTR_ERR(inode);
goto err_out;
@@ -4107,7 +4110,7 @@ static int shmem_symlink(struct mnt_idmap *idmap, struct inode *dir,
return -ENAMETOOLONG;
inode = shmem_get_inode(idmap, dir->i_sb, dir, S_IFLNK | 0777, 0,
- VM_NORESERVE);
+ mk_vma_flags(VMA_NORESERVE_BIT));
if (IS_ERR(inode))
return PTR_ERR(inode);
@@ -5108,7 +5111,8 @@ static int shmem_fill_super(struct super_block *sb, struct fs_context *fc)
#endif /* CONFIG_TMPFS_QUOTA */
inode = shmem_get_inode(&nop_mnt_idmap, sb, NULL,
- S_IFDIR | sbinfo->mode, 0, VM_NORESERVE);
+ S_IFDIR | sbinfo->mode, 0,
+ mk_vma_flags(VMA_NORESERVE_BIT));
if (IS_ERR(inode)) {
error = PTR_ERR(inode);
goto failed;
@@ -5808,7 +5812,7 @@ static inline void shmem_unacct_size(unsigned long flags, loff_t size)
static inline struct inode *shmem_get_inode(struct mnt_idmap *idmap,
struct super_block *sb, struct inode *dir,
- umode_t mode, dev_t dev, unsigned long flags)
+ umode_t mode, dev_t dev, vma_flags_t flags)
{
struct inode *inode = ramfs_get_inode(sb, dir, mode, dev);
return inode ? inode : ERR_PTR(-ENOSPC);
@@ -5819,10 +5823,11 @@ static inline struct inode *shmem_get_inode(struct mnt_idmap *idmap,
/* common code */
static struct file *__shmem_file_setup(struct vfsmount *mnt, const char *name,
- loff_t size, unsigned long vm_flags,
+ loff_t size, vma_flags_t flags,
unsigned int i_flags)
{
- unsigned long flags = (vm_flags & VM_NORESERVE) ? SHMEM_F_NORESERVE : 0;
+ const unsigned long shmem_flags =
+ vma_flags_test(&flags, VMA_NORESERVE_BIT) ? SHMEM_F_NORESERVE : 0;
struct inode *inode;
struct file *res;
@@ -5835,13 +5840,13 @@ static struct file *__shmem_file_setup(struct vfsmount *mnt, const char *name,
if (is_idmapped_mnt(mnt))
return ERR_PTR(-EINVAL);
- if (shmem_acct_size(flags, size))
+ if (shmem_acct_size(shmem_flags, size))
return ERR_PTR(-ENOMEM);
inode = shmem_get_inode(&nop_mnt_idmap, mnt->mnt_sb, NULL,
- S_IFREG | S_IRWXUGO, 0, vm_flags);
+ S_IFREG | S_IRWXUGO, 0, flags);
if (IS_ERR(inode)) {
- shmem_unacct_size(flags, size);
+ shmem_unacct_size(shmem_flags, size);
return ERR_CAST(inode);
}
inode->i_flags |= i_flags;
@@ -5864,9 +5869,10 @@ static struct file *__shmem_file_setup(struct vfsmount *mnt, const char *name,
* checks are provided at the key or shm level rather than the inode.
* @name: name for dentry (to be seen in /proc/<pid>/maps)
* @size: size to be set for the file
- * @flags: VM_NORESERVE suppresses pre-accounting of the entire object size
+ * @vma_flags: VMA_NORESERVE_BIT suppresses pre-accounting of the entire object size
*/
-struct file *shmem_kernel_file_setup(const char *name, loff_t size, unsigned long flags)
+struct file *shmem_kernel_file_setup(const char *name, loff_t size,
+ vma_flags_t flags)
{
return __shmem_file_setup(shm_mnt, name, size, flags, S_PRIVATE);
}
@@ -5878,7 +5884,7 @@ EXPORT_SYMBOL_GPL(shmem_kernel_file_setup);
* @size: size to be set for the file
* @flags: VM_NORESERVE suppresses pre-accounting of the entire object size
*/
-struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags)
+struct file *shmem_file_setup(const char *name, loff_t size, vma_flags_t flags)
{
return __shmem_file_setup(shm_mnt, name, size, flags, 0);
}
@@ -5889,16 +5895,17 @@ EXPORT_SYMBOL_GPL(shmem_file_setup);
* @mnt: the tmpfs mount where the file will be created
* @name: name for dentry (to be seen in /proc/<pid>/maps)
* @size: size to be set for the file
- * @flags: VM_NORESERVE suppresses pre-accounting of the entire object size
+ * @flags: VMA_NORESERVE_BIT suppresses pre-accounting of the entire object size
*/
struct file *shmem_file_setup_with_mnt(struct vfsmount *mnt, const char *name,
- loff_t size, unsigned long flags)
+ loff_t size, vma_flags_t flags)
{
return __shmem_file_setup(mnt, name, size, flags, 0);
}
EXPORT_SYMBOL_GPL(shmem_file_setup_with_mnt);
-static struct file *__shmem_zero_setup(unsigned long start, unsigned long end, vm_flags_t vm_flags)
+static struct file *__shmem_zero_setup(unsigned long start, unsigned long end,
+ vma_flags_t flags)
{
loff_t size = end - start;
@@ -5908,7 +5915,7 @@ static struct file *__shmem_zero_setup(unsigned long start, unsigned long end, v
* accessible to the user through its mapping, use S_PRIVATE flag to
* bypass file security, in the same way as shmem_kernel_file_setup().
*/
- return shmem_kernel_file_setup("dev/zero", size, vm_flags);
+ return shmem_kernel_file_setup("dev/zero", size, flags);
}
/**
@@ -5918,7 +5925,7 @@ static struct file *__shmem_zero_setup(unsigned long start, unsigned long end, v
*/
int shmem_zero_setup(struct vm_area_struct *vma)
{
- struct file *file = __shmem_zero_setup(vma->vm_start, vma->vm_end, vma->vm_flags);
+ struct file *file = __shmem_zero_setup(vma->vm_start, vma->vm_end, vma->flags);
if (IS_ERR(file))
return PTR_ERR(file);
@@ -5939,7 +5946,7 @@ int shmem_zero_setup(struct vm_area_struct *vma)
*/
int shmem_zero_setup_desc(struct vm_area_desc *desc)
{
- struct file *file = __shmem_zero_setup(desc->start, desc->end, desc->vm_flags);
+ struct file *file = __shmem_zero_setup(desc->start, desc->end, desc->vma_flags);
if (IS_ERR(file))
return PTR_ERR(file);
diff --git a/security/keys/big_key.c b/security/keys/big_key.c
index d46862ab90d6..268f702df380 100644
--- a/security/keys/big_key.c
+++ b/security/keys/big_key.c
@@ -103,7 +103,7 @@ int big_key_preparse(struct key_preparsed_payload *prep)
0, enckey);
/* save aligned data to file */
- file = shmem_kernel_file_setup("", enclen, 0);
+ file = shmem_kernel_file_setup("", enclen, EMPTY_VMA_FLAGS);
if (IS_ERR(file)) {
ret = PTR_ERR(file);
goto err_enckey;
--
2.52.0
^ permalink raw reply [flat|nested] 56+ messages in thread* Re: [PATCH v2 08/13] mm: update shmem_[kernel]_file_*() functions to use vma_flags_t
2026-01-22 16:06 ` [PATCH v2 08/13] mm: update shmem_[kernel]_file_*() functions to use vma_flags_t Lorenzo Stoakes
@ 2026-01-23 6:20 ` Baolin Wang
2026-01-23 12:30 ` Lorenzo Stoakes
2026-01-23 7:46 ` Darrick J. Wong
` (3 subsequent siblings)
4 siblings, 1 reply; 56+ messages in thread
From: Baolin Wang @ 2026-01-23 6:20 UTC (permalink / raw)
To: Lorenzo Stoakes, Andrew Morton
Cc: x86, linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel,
intel-gfx, linux-fsdevel, linux-aio, linux-erofs, linux-ext4,
linux-mm, ntfs3, devel, linux-xfs, keyrings,
linux-security-module
On 1/23/26 12:06 AM, Lorenzo Stoakes wrote:
> In order to be able to use only vma_flags_t in vm_area_desc we must adjust
> shmem file setup functions to operate in terms of vma_flags_t rather than
> vm_flags_t.
>
> This patch makes this change and updates all callers to use the new
> functions.
>
> No functional changes intended.
>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
(reduced distribution list too)
Thanks. The shmem part looks good to me with some nits below.
Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
> ---
> arch/x86/kernel/cpu/sgx/ioctl.c | 2 +-
> drivers/gpu/drm/drm_gem.c | 5 +-
> drivers/gpu/drm/i915/gem/i915_gem_shmem.c | 2 +-
> drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 3 +-
> drivers/gpu/drm/i915/gt/shmem_utils.c | 3 +-
> drivers/gpu/drm/ttm/tests/ttm_tt_test.c | 2 +-
> drivers/gpu/drm/ttm/ttm_backup.c | 3 +-
> drivers/gpu/drm/ttm/ttm_tt.c | 2 +-
> fs/xfs/scrub/xfile.c | 3 +-
> fs/xfs/xfs_buf_mem.c | 2 +-
> include/linux/shmem_fs.h | 8 ++-
> ipc/shm.c | 6 +--
> mm/memfd.c | 2 +-
> mm/memfd_luo.c | 2 +-
> mm/shmem.c | 59 +++++++++++++----------
> security/keys/big_key.c | 2 +-
> 16 files changed, 57 insertions(+), 49 deletions(-)
[snip]
> inode->i_flags |= i_flags;
> @@ -5864,9 +5869,10 @@ static struct file *__shmem_file_setup(struct vfsmount *mnt, const char *name,
> * checks are provided at the key or shm level rather than the inode.
> * @name: name for dentry (to be seen in /proc/<pid>/maps)
> * @size: size to be set for the file
> - * @flags: VM_NORESERVE suppresses pre-accounting of the entire object size
> + * @vma_flags: VMA_NORESERVE_BIT suppresses pre-accounting of the entire object size
nit: s/vma_flags/flags
> */
> -struct file *shmem_kernel_file_setup(const char *name, loff_t size, unsigned long flags)
> +struct file *shmem_kernel_file_setup(const char *name, loff_t size,
> + vma_flags_t flags)
> {
> return __shmem_file_setup(shm_mnt, name, size, flags, S_PRIVATE);
> }
> @@ -5878,7 +5884,7 @@ EXPORT_SYMBOL_GPL(shmem_kernel_file_setup);
> * @size: size to be set for the file
> * @flags: VM_NORESERVE suppresses pre-accounting of the entire object size
nit: s/VM_NORESERVE/VMA_NORESERVE_BIT
> */
> -struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags)
> +struct file *shmem_file_setup(const char *name, loff_t size, vma_flags_t flags)
> {
> return __shmem_file_setup(shm_mnt, name, size, flags, 0);
> }
> @@ -5889,16 +5895,17 @@ EXPORT_SYMBOL_GPL(shmem_file_setup);
> * @mnt: the tmpfs mount where the file will be created
> * @name: name for dentry (to be seen in /proc/<pid>/maps)
> * @size: size to be set for the file
> - * @flags: VM_NORESERVE suppresses pre-accounting of the entire object size
> + * @flags: VMA_NORESERVE_BIT suppresses pre-accounting of the entire object size
> */
> struct file *shmem_file_setup_with_mnt(struct vfsmount *mnt, const char *name,
> - loff_t size, unsigned long flags)
> + loff_t size, vma_flags_t flags)
> {
> return __shmem_file_setup(mnt, name, size, flags, 0);
> }
> EXPORT_SYMBOL_GPL(shmem_file_setup_with_mnt);
>
> -static struct file *__shmem_zero_setup(unsigned long start, unsigned long end, vm_flags_t vm_flags)
> +static struct file *__shmem_zero_setup(unsigned long start, unsigned long end,
> + vma_flags_t flags)
> {
> loff_t size = end - start;
>
> @@ -5908,7 +5915,7 @@ static struct file *__shmem_zero_setup(unsigned long start, unsigned long end, v
> * accessible to the user through its mapping, use S_PRIVATE flag to
> * bypass file security, in the same way as shmem_kernel_file_setup().
> */
> - return shmem_kernel_file_setup("dev/zero", size, vm_flags);
> + return shmem_kernel_file_setup("dev/zero", size, flags);
> }
>
> /**
> @@ -5918,7 +5925,7 @@ static struct file *__shmem_zero_setup(unsigned long start, unsigned long end, v
> */
> int shmem_zero_setup(struct vm_area_struct *vma)
> {
> - struct file *file = __shmem_zero_setup(vma->vm_start, vma->vm_end, vma->vm_flags);
> + struct file *file = __shmem_zero_setup(vma->vm_start, vma->vm_end, vma->flags);
>
> if (IS_ERR(file))
> return PTR_ERR(file);
> @@ -5939,7 +5946,7 @@ int shmem_zero_setup(struct vm_area_struct *vma)
> */
> int shmem_zero_setup_desc(struct vm_area_desc *desc)
> {
> - struct file *file = __shmem_zero_setup(desc->start, desc->end, desc->vm_flags);
> + struct file *file = __shmem_zero_setup(desc->start, desc->end, desc->vma_flags);
>
> if (IS_ERR(file))
> return PTR_ERR(file);
> diff --git a/security/keys/big_key.c b/security/keys/big_key.c
> index d46862ab90d6..268f702df380 100644
> --- a/security/keys/big_key.c
> +++ b/security/keys/big_key.c
> @@ -103,7 +103,7 @@ int big_key_preparse(struct key_preparsed_payload *prep)
> 0, enckey);
>
> /* save aligned data to file */
> - file = shmem_kernel_file_setup("", enclen, 0);
> + file = shmem_kernel_file_setup("", enclen, EMPTY_VMA_FLAGS);
> if (IS_ERR(file)) {
> ret = PTR_ERR(file);
> goto err_enckey;
^ permalink raw reply [flat|nested] 56+ messages in thread* Re: [PATCH v2 08/13] mm: update shmem_[kernel]_file_*() functions to use vma_flags_t
2026-01-23 6:20 ` Baolin Wang
@ 2026-01-23 12:30 ` Lorenzo Stoakes
0 siblings, 0 replies; 56+ messages in thread
From: Lorenzo Stoakes @ 2026-01-23 12:30 UTC (permalink / raw)
To: Baolin Wang
Cc: Andrew Morton, x86, linux-sgx, linux-kernel, nvdimm, linux-cxl,
dri-devel, intel-gfx, linux-fsdevel, linux-aio, linux-erofs,
linux-ext4, linux-mm, ntfs3, devel, linux-xfs, keyrings,
linux-security-module
On Fri, Jan 23, 2026 at 02:20:51PM +0800, Baolin Wang wrote:
>
>
> On 1/23/26 12:06 AM, Lorenzo Stoakes wrote:
> > In order to be able to use only vma_flags_t in vm_area_desc we must adjust
> > shmem file setup functions to operate in terms of vma_flags_t rather than
> > vm_flags_t.
> >
> > This patch makes this change and updates all callers to use the new
> > functions.
> >
> > No functional changes intended.
> >
> > Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
>
> (reduced distribution list too)
>
> Thanks. The shmem part looks good to me with some nits below.
>
> Reviewed-by: Baolin Wang <baolin.wang@linux.alibaba.com>
Thanks!
>
> > ---
> > arch/x86/kernel/cpu/sgx/ioctl.c | 2 +-
> > drivers/gpu/drm/drm_gem.c | 5 +-
> > drivers/gpu/drm/i915/gem/i915_gem_shmem.c | 2 +-
> > drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 3 +-
> > drivers/gpu/drm/i915/gt/shmem_utils.c | 3 +-
> > drivers/gpu/drm/ttm/tests/ttm_tt_test.c | 2 +-
> > drivers/gpu/drm/ttm/ttm_backup.c | 3 +-
> > drivers/gpu/drm/ttm/ttm_tt.c | 2 +-
> > fs/xfs/scrub/xfile.c | 3 +-
> > fs/xfs/xfs_buf_mem.c | 2 +-
> > include/linux/shmem_fs.h | 8 ++-
> > ipc/shm.c | 6 +--
> > mm/memfd.c | 2 +-
> > mm/memfd_luo.c | 2 +-
> > mm/shmem.c | 59 +++++++++++++----------
> > security/keys/big_key.c | 2 +-
> > 16 files changed, 57 insertions(+), 49 deletions(-)
>
> [snip]
>
> > inode->i_flags |= i_flags;
> > @@ -5864,9 +5869,10 @@ static struct file *__shmem_file_setup(struct vfsmount *mnt, const char *name,
> > * checks are provided at the key or shm level rather than the inode.
> > * @name: name for dentry (to be seen in /proc/<pid>/maps)
> > * @size: size to be set for the file
> > - * @flags: VM_NORESERVE suppresses pre-accounting of the entire object size
> > + * @vma_flags: VMA_NORESERVE_BIT suppresses pre-accounting of the entire object size
>
> nit: s/vma_flags/flags
>
> > */
> > -struct file *shmem_kernel_file_setup(const char *name, loff_t size, unsigned long flags)
> > +struct file *shmem_kernel_file_setup(const char *name, loff_t size,
> > + vma_flags_t flags)
> > {
> > return __shmem_file_setup(shm_mnt, name, size, flags, S_PRIVATE);
> > }
> > @@ -5878,7 +5884,7 @@ EXPORT_SYMBOL_GPL(shmem_kernel_file_setup);
> > * @size: size to be set for the file
> > * @flags: VM_NORESERVE suppresses pre-accounting of the entire object size
>
> nit: s/VM_NORESERVE/VMA_NORESERVE_BIT
Good spots, will send fix-patch.
Cheers, Lorenzo
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH v2 08/13] mm: update shmem_[kernel]_file_*() functions to use vma_flags_t
2026-01-22 16:06 ` [PATCH v2 08/13] mm: update shmem_[kernel]_file_*() functions to use vma_flags_t Lorenzo Stoakes
2026-01-23 6:20 ` Baolin Wang
@ 2026-01-23 7:46 ` Darrick J. Wong
2026-01-23 12:26 ` Lorenzo Stoakes
2026-01-23 12:33 ` Lorenzo Stoakes
` (2 subsequent siblings)
4 siblings, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2026-01-23 7:46 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin,
Arnd Bergmann, Greg Kroah-Hartman, Dan Williams, Vishal Verma,
Dave Jiang, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
On Thu, Jan 22, 2026 at 04:06:17PM +0000, Lorenzo Stoakes wrote:
> In order to be able to use only vma_flags_t in vm_area_desc we must adjust
> shmem file setup functions to operate in terms of vma_flags_t rather than
> vm_flags_t.
>
> This patch makes this change and updates all callers to use the new
> functions.
>
> No functional changes intended.
>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
> ---
> arch/x86/kernel/cpu/sgx/ioctl.c | 2 +-
> drivers/gpu/drm/drm_gem.c | 5 +-
> drivers/gpu/drm/i915/gem/i915_gem_shmem.c | 2 +-
> drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 3 +-
> drivers/gpu/drm/i915/gt/shmem_utils.c | 3 +-
> drivers/gpu/drm/ttm/tests/ttm_tt_test.c | 2 +-
> drivers/gpu/drm/ttm/ttm_backup.c | 3 +-
> drivers/gpu/drm/ttm/ttm_tt.c | 2 +-
> fs/xfs/scrub/xfile.c | 3 +-
> fs/xfs/xfs_buf_mem.c | 2 +-
> include/linux/shmem_fs.h | 8 ++-
> ipc/shm.c | 6 +--
> mm/memfd.c | 2 +-
> mm/memfd_luo.c | 2 +-
> mm/shmem.c | 59 +++++++++++++----------
> security/keys/big_key.c | 2 +-
> 16 files changed, 57 insertions(+), 49 deletions(-)
>
<snip to xfs>
> diff --git a/fs/xfs/scrub/xfile.c b/fs/xfs/scrub/xfile.c
> index c753c79df203..fe0584a39f16 100644
> --- a/fs/xfs/scrub/xfile.c
> +++ b/fs/xfs/scrub/xfile.c
> @@ -61,7 +61,8 @@ xfile_create(
> if (!xf)
> return -ENOMEM;
>
> - xf->file = shmem_kernel_file_setup(description, isize, VM_NORESERVE);
> + xf->file = shmem_kernel_file_setup(description, isize,
> + mk_vma_flags(VMA_NORESERVE_BIT));
Seems fine, macro sorcery aside...
> if (IS_ERR(xf->file)) {
> error = PTR_ERR(xf->file);
> goto out_xfile;
> diff --git a/fs/xfs/xfs_buf_mem.c b/fs/xfs/xfs_buf_mem.c
> index dcbfa274e06d..fd6f0a5bc0ea 100644
> --- a/fs/xfs/xfs_buf_mem.c
> +++ b/fs/xfs/xfs_buf_mem.c
> @@ -62,7 +62,7 @@ xmbuf_alloc(
> if (!btp)
> return -ENOMEM;
>
> - file = shmem_kernel_file_setup(descr, 0, 0);
> + file = shmem_kernel_file_setup(descr, 0, EMPTY_VMA_FLAGS);
...but does mk_vma_flags() produce the same result?
--D
> if (IS_ERR(file)) {
> error = PTR_ERR(file);
> goto out_free_btp;
^ permalink raw reply [flat|nested] 56+ messages in thread* Re: [PATCH v2 08/13] mm: update shmem_[kernel]_file_*() functions to use vma_flags_t
2026-01-23 7:46 ` Darrick J. Wong
@ 2026-01-23 12:26 ` Lorenzo Stoakes
0 siblings, 0 replies; 56+ messages in thread
From: Lorenzo Stoakes @ 2026-01-23 12:26 UTC (permalink / raw)
To: Darrick J. Wong
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin,
Arnd Bergmann, Greg Kroah-Hartman, Dan Williams, Vishal Verma,
Dave Jiang, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
On Thu, Jan 22, 2026 at 11:46:52PM -0800, Darrick J. Wong wrote:
> On Thu, Jan 22, 2026 at 04:06:17PM +0000, Lorenzo Stoakes wrote:
> > In order to be able to use only vma_flags_t in vm_area_desc we must adjust
> > shmem file setup functions to operate in terms of vma_flags_t rather than
> > vm_flags_t.
> >
> > This patch makes this change and updates all callers to use the new
> > functions.
> >
> > No functional changes intended.
> >
> > Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
> > ---
> > arch/x86/kernel/cpu/sgx/ioctl.c | 2 +-
> > drivers/gpu/drm/drm_gem.c | 5 +-
> > drivers/gpu/drm/i915/gem/i915_gem_shmem.c | 2 +-
> > drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 3 +-
> > drivers/gpu/drm/i915/gt/shmem_utils.c | 3 +-
> > drivers/gpu/drm/ttm/tests/ttm_tt_test.c | 2 +-
> > drivers/gpu/drm/ttm/ttm_backup.c | 3 +-
> > drivers/gpu/drm/ttm/ttm_tt.c | 2 +-
> > fs/xfs/scrub/xfile.c | 3 +-
> > fs/xfs/xfs_buf_mem.c | 2 +-
> > include/linux/shmem_fs.h | 8 ++-
> > ipc/shm.c | 6 +--
> > mm/memfd.c | 2 +-
> > mm/memfd_luo.c | 2 +-
> > mm/shmem.c | 59 +++++++++++++----------
> > security/keys/big_key.c | 2 +-
> > 16 files changed, 57 insertions(+), 49 deletions(-)
> >
>
> <snip to xfs>
>
> > diff --git a/fs/xfs/scrub/xfile.c b/fs/xfs/scrub/xfile.c
> > index c753c79df203..fe0584a39f16 100644
> > --- a/fs/xfs/scrub/xfile.c
> > +++ b/fs/xfs/scrub/xfile.c
> > @@ -61,7 +61,8 @@ xfile_create(
> > if (!xf)
> > return -ENOMEM;
> >
> > - xf->file = shmem_kernel_file_setup(description, isize, VM_NORESERVE);
> > + xf->file = shmem_kernel_file_setup(description, isize,
> > + mk_vma_flags(VMA_NORESERVE_BIT));
>
> Seems fine, macro sorcery aside...
Thanks.
>
> > if (IS_ERR(xf->file)) {
> > error = PTR_ERR(xf->file);
> > goto out_xfile;
> > diff --git a/fs/xfs/xfs_buf_mem.c b/fs/xfs/xfs_buf_mem.c
> > index dcbfa274e06d..fd6f0a5bc0ea 100644
> > --- a/fs/xfs/xfs_buf_mem.c
> > +++ b/fs/xfs/xfs_buf_mem.c
> > @@ -62,7 +62,7 @@ xmbuf_alloc(
> > if (!btp)
> > return -ENOMEM;
> >
> > - file = shmem_kernel_file_setup(descr, 0, 0);
> > + file = shmem_kernel_file_setup(descr, 0, EMPTY_VMA_FLAGS);
>
> ...but does mk_vma_flags() produce the same result?
Doing a quick fs/xfs/xfs_buf_mem.s build suggests so:
Before:
movq %rax, %rbx
movq %r15, %rdi
xorl %esi, %esi
xorl %edx, %edx
callq shmem_kernel_file_setup
After:
movq %rax, %rbx
movq %r15, %rdi
xorl %esi, %esi
xorl %edx, %edx
callq shmem_kernel_file_setup
Quick google to remind myself of x86-64 sysv calling convention and RDI, RSI,
RDX = param 1,2,3, presumably top 32-bits of registers already cleared and so
params 2, 3 being 0 is correct.
So yeah mk_vma_flags() would work too, I guess EMPTY_VMA_FLAGS is more
semantically nice.
But actually could be nice to define EMPTY_VMA_FLAGS that way rather than the
empty initialiser I use now... :) Still no delta anyway afaict.
>
> --D
>
> > if (IS_ERR(file)) {
> > error = PTR_ERR(file);
> > goto out_free_btp;
Cheers, Lorenzo
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH v2 08/13] mm: update shmem_[kernel]_file_*() functions to use vma_flags_t
2026-01-22 16:06 ` [PATCH v2 08/13] mm: update shmem_[kernel]_file_*() functions to use vma_flags_t Lorenzo Stoakes
2026-01-23 6:20 ` Baolin Wang
2026-01-23 7:46 ` Darrick J. Wong
@ 2026-01-23 12:33 ` Lorenzo Stoakes
2026-01-25 14:50 ` Jarkko Sakkinen
2026-02-09 19:13 ` Liam R. Howlett
4 siblings, 0 replies; 56+ messages in thread
From: Lorenzo Stoakes @ 2026-01-23 12:33 UTC (permalink / raw)
To: Andrew Morton
Cc: Jarkko Sakkinen, Dave Hansen, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, x86, H . Peter Anvin, Arnd Bergmann,
Greg Kroah-Hartman, Dan Williams, Vishal Verma, Dave Jiang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
Hi Andrew,
Please apply this fix-patch which addresses some minor issues in the kdoc
comments for this patch.
Thanks, Lorenzo
----8<----
From 0283ddb073248f00bfa9694901fcba25362bdc58 Mon Sep 17 00:00:00 2001
From: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Date: Fri, 23 Jan 2026 12:30:34 +0000
Subject: [PATCH] fix
Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
---
mm/shmem.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/mm/shmem.c b/mm/shmem.c
index 97a8f55c7296..b9ddd38621a0 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -5869,7 +5869,7 @@ static struct file *__shmem_file_setup(struct vfsmount *mnt, const char *name,
* checks are provided at the key or shm level rather than the inode.
* @name: name for dentry (to be seen in /proc/<pid>/maps)
* @size: size to be set for the file
- * @vma_flags: VMA_NORESERVE_BIT suppresses pre-accounting of the entire object size
+ * @flags: VMA_NORESERVE_BIT suppresses pre-accounting of the entire object size
*/
struct file *shmem_kernel_file_setup(const char *name, loff_t size,
vma_flags_t flags)
@@ -5882,7 +5882,7 @@ EXPORT_SYMBOL_GPL(shmem_kernel_file_setup);
* shmem_file_setup - get an unlinked file living in tmpfs
* @name: name for dentry (to be seen in /proc/<pid>/maps)
* @size: size to be set for the file
- * @flags: VM_NORESERVE suppresses pre-accounting of the entire object size
+ * @flags: VMA_NORESERVE_BIT suppresses pre-accounting of the entire object size
*/
struct file *shmem_file_setup(const char *name, loff_t size, vma_flags_t flags)
{
--
2.52.0
^ permalink raw reply [flat|nested] 56+ messages in thread* Re: [PATCH v2 08/13] mm: update shmem_[kernel]_file_*() functions to use vma_flags_t
2026-01-22 16:06 ` [PATCH v2 08/13] mm: update shmem_[kernel]_file_*() functions to use vma_flags_t Lorenzo Stoakes
` (2 preceding siblings ...)
2026-01-23 12:33 ` Lorenzo Stoakes
@ 2026-01-25 14:50 ` Jarkko Sakkinen
2026-02-09 19:13 ` Liam R. Howlett
4 siblings, 0 replies; 56+ messages in thread
From: Jarkko Sakkinen @ 2026-01-25 14:50 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Dave Hansen, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, x86, H . Peter Anvin, Arnd Bergmann,
Greg Kroah-Hartman, Dan Williams, Vishal Verma, Dave Jiang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
On Thu, Jan 22, 2026 at 04:06:17PM +0000, Lorenzo Stoakes wrote:
> In order to be able to use only vma_flags_t in vm_area_desc we must adjust
> shmem file setup functions to operate in terms of vma_flags_t rather than
> vm_flags_t.
>
> This patch makes this change and updates all callers to use the new
> functions.
>
> No functional changes intended.
>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
> ---
> arch/x86/kernel/cpu/sgx/ioctl.c | 2 +-
> drivers/gpu/drm/drm_gem.c | 5 +-
> drivers/gpu/drm/i915/gem/i915_gem_shmem.c | 2 +-
> drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 3 +-
> drivers/gpu/drm/i915/gt/shmem_utils.c | 3 +-
> drivers/gpu/drm/ttm/tests/ttm_tt_test.c | 2 +-
> drivers/gpu/drm/ttm/ttm_backup.c | 3 +-
> drivers/gpu/drm/ttm/ttm_tt.c | 2 +-
> fs/xfs/scrub/xfile.c | 3 +-
> fs/xfs/xfs_buf_mem.c | 2 +-
> include/linux/shmem_fs.h | 8 ++-
> ipc/shm.c | 6 +--
> mm/memfd.c | 2 +-
> mm/memfd_luo.c | 2 +-
> mm/shmem.c | 59 +++++++++++++----------
> security/keys/big_key.c | 2 +-
> 16 files changed, 57 insertions(+), 49 deletions(-)
>
> diff --git a/arch/x86/kernel/cpu/sgx/ioctl.c b/arch/x86/kernel/cpu/sgx/ioctl.c
> index 9322a9287dc7..0bc36957979d 100644
> --- a/arch/x86/kernel/cpu/sgx/ioctl.c
> +++ b/arch/x86/kernel/cpu/sgx/ioctl.c
> @@ -83,7 +83,7 @@ static int sgx_encl_create(struct sgx_encl *encl, struct sgx_secs *secs)
> encl_size = secs->size + PAGE_SIZE;
>
> backing = shmem_file_setup("SGX backing", encl_size + (encl_size >> 5),
> - VM_NORESERVE);
> + mk_vma_flags(VMA_NORESERVE_BIT));
> if (IS_ERR(backing)) {
> ret = PTR_ERR(backing);
> goto err_out_shrink;
As per this diff:
Reviewed-by: Jarkko Sakkinen <jarkko@kernel.org>
> diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
> index e4df43427394..be4dca2bc34e 100644
> --- a/drivers/gpu/drm/drm_gem.c
> +++ b/drivers/gpu/drm/drm_gem.c
> @@ -130,14 +130,15 @@ int drm_gem_object_init_with_mnt(struct drm_device *dev,
> struct vfsmount *gemfs)
> {
> struct file *filp;
> + const vma_flags_t flags = mk_vma_flags(VMA_NORESERVE_BIT);
>
> drm_gem_private_object_init(dev, obj, size);
>
> if (gemfs)
> filp = shmem_file_setup_with_mnt(gemfs, "drm mm object", size,
> - VM_NORESERVE);
> + flags);
> else
> - filp = shmem_file_setup("drm mm object", size, VM_NORESERVE);
> + filp = shmem_file_setup("drm mm object", size, flags);
>
> if (IS_ERR(filp))
> return PTR_ERR(filp);
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
> index 26dda55a07ff..fe1843497b27 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
> @@ -496,7 +496,7 @@ static int __create_shmem(struct drm_i915_private *i915,
> struct drm_gem_object *obj,
> resource_size_t size)
> {
> - unsigned long flags = VM_NORESERVE;
> + const vma_flags_t flags = mk_vma_flags(VMA_NORESERVE_BIT);
> struct file *filp;
>
> drm_gem_private_object_init(&i915->drm, obj, size);
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
> index f65fe86c02b5..7b1a7d01db2b 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
> @@ -200,7 +200,8 @@ static int i915_ttm_tt_shmem_populate(struct ttm_device *bdev,
> struct address_space *mapping;
> gfp_t mask;
>
> - filp = shmem_file_setup("i915-shmem-tt", size, VM_NORESERVE);
> + filp = shmem_file_setup("i915-shmem-tt", size,
> + mk_vma_flags(VMA_NORESERVE_BIT));
> if (IS_ERR(filp))
> return PTR_ERR(filp);
>
> diff --git a/drivers/gpu/drm/i915/gt/shmem_utils.c b/drivers/gpu/drm/i915/gt/shmem_utils.c
> index 365c4b8b04f4..5f37c699a320 100644
> --- a/drivers/gpu/drm/i915/gt/shmem_utils.c
> +++ b/drivers/gpu/drm/i915/gt/shmem_utils.c
> @@ -19,7 +19,8 @@ struct file *shmem_create_from_data(const char *name, void *data, size_t len)
> struct file *file;
> int err;
>
> - file = shmem_file_setup(name, PAGE_ALIGN(len), VM_NORESERVE);
> + file = shmem_file_setup(name, PAGE_ALIGN(len),
> + mk_vma_flags(VMA_NORESERVE_BIT));
> if (IS_ERR(file))
> return file;
>
> diff --git a/drivers/gpu/drm/ttm/tests/ttm_tt_test.c b/drivers/gpu/drm/ttm/tests/ttm_tt_test.c
> index 61ec6f580b62..bd5f7d0b9b62 100644
> --- a/drivers/gpu/drm/ttm/tests/ttm_tt_test.c
> +++ b/drivers/gpu/drm/ttm/tests/ttm_tt_test.c
> @@ -143,7 +143,7 @@ static void ttm_tt_fini_shmem(struct kunit *test)
> err = ttm_tt_init(tt, bo, 0, caching, 0);
> KUNIT_ASSERT_EQ(test, err, 0);
>
> - shmem = shmem_file_setup("ttm swap", BO_SIZE, 0);
> + shmem = shmem_file_setup("ttm swap", BO_SIZE, EMPTY_VMA_FLAGS);
> tt->swap_storage = shmem;
>
> ttm_tt_fini(tt);
> diff --git a/drivers/gpu/drm/ttm/ttm_backup.c b/drivers/gpu/drm/ttm/ttm_backup.c
> index 32530c75f038..6bd4c123d94c 100644
> --- a/drivers/gpu/drm/ttm/ttm_backup.c
> +++ b/drivers/gpu/drm/ttm/ttm_backup.c
> @@ -178,5 +178,6 @@ EXPORT_SYMBOL_GPL(ttm_backup_bytes_avail);
> */
> struct file *ttm_backup_shmem_create(loff_t size)
> {
> - return shmem_file_setup("ttm shmem backup", size, 0);
> + return shmem_file_setup("ttm shmem backup", size,
> + EMPTY_VMA_FLAGS);
> }
> diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c
> index 611d20ab966d..f73a5ce87645 100644
> --- a/drivers/gpu/drm/ttm/ttm_tt.c
> +++ b/drivers/gpu/drm/ttm/ttm_tt.c
> @@ -330,7 +330,7 @@ int ttm_tt_swapout(struct ttm_device *bdev, struct ttm_tt *ttm,
> struct page *to_page;
> int i, ret;
>
> - swap_storage = shmem_file_setup("ttm swap", size, 0);
> + swap_storage = shmem_file_setup("ttm swap", size, EMPTY_VMA_FLAGS);
> if (IS_ERR(swap_storage)) {
> pr_err("Failed allocating swap storage\n");
> return PTR_ERR(swap_storage);
> diff --git a/fs/xfs/scrub/xfile.c b/fs/xfs/scrub/xfile.c
> index c753c79df203..fe0584a39f16 100644
> --- a/fs/xfs/scrub/xfile.c
> +++ b/fs/xfs/scrub/xfile.c
> @@ -61,7 +61,8 @@ xfile_create(
> if (!xf)
> return -ENOMEM;
>
> - xf->file = shmem_kernel_file_setup(description, isize, VM_NORESERVE);
> + xf->file = shmem_kernel_file_setup(description, isize,
> + mk_vma_flags(VMA_NORESERVE_BIT));
> if (IS_ERR(xf->file)) {
> error = PTR_ERR(xf->file);
> goto out_xfile;
> diff --git a/fs/xfs/xfs_buf_mem.c b/fs/xfs/xfs_buf_mem.c
> index dcbfa274e06d..fd6f0a5bc0ea 100644
> --- a/fs/xfs/xfs_buf_mem.c
> +++ b/fs/xfs/xfs_buf_mem.c
> @@ -62,7 +62,7 @@ xmbuf_alloc(
> if (!btp)
> return -ENOMEM;
>
> - file = shmem_kernel_file_setup(descr, 0, 0);
> + file = shmem_kernel_file_setup(descr, 0, EMPTY_VMA_FLAGS);
> if (IS_ERR(file)) {
> error = PTR_ERR(file);
> goto out_free_btp;
> diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
> index e2069b3179c4..a8273b32e041 100644
> --- a/include/linux/shmem_fs.h
> +++ b/include/linux/shmem_fs.h
> @@ -102,12 +102,10 @@ static inline struct shmem_inode_info *SHMEM_I(struct inode *inode)
> extern const struct fs_parameter_spec shmem_fs_parameters[];
> extern void shmem_init(void);
> extern int shmem_init_fs_context(struct fs_context *fc);
> -extern struct file *shmem_file_setup(const char *name,
> - loff_t size, unsigned long flags);
> -extern struct file *shmem_kernel_file_setup(const char *name, loff_t size,
> - unsigned long flags);
> +struct file *shmem_file_setup(const char *name, loff_t size, vma_flags_t flags);
> +struct file *shmem_kernel_file_setup(const char *name, loff_t size, vma_flags_t vma_flags);
> extern struct file *shmem_file_setup_with_mnt(struct vfsmount *mnt,
> - const char *name, loff_t size, unsigned long flags);
> + const char *name, loff_t size, vma_flags_t flags);
> int shmem_zero_setup(struct vm_area_struct *vma);
> int shmem_zero_setup_desc(struct vm_area_desc *desc);
> extern unsigned long shmem_get_unmapped_area(struct file *, unsigned long addr,
> diff --git a/ipc/shm.c b/ipc/shm.c
> index 2c7379c4c647..e8c7d1924c50 100644
> --- a/ipc/shm.c
> +++ b/ipc/shm.c
> @@ -708,6 +708,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
> struct shmid_kernel *shp;
> size_t numpages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
> const bool has_no_reserve = shmflg & SHM_NORESERVE;
> + vma_flags_t acctflag = EMPTY_VMA_FLAGS;
> struct file *file;
> char name[13];
>
> @@ -738,7 +739,6 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
>
> sprintf(name, "SYSV%08x", key);
> if (shmflg & SHM_HUGETLB) {
> - vma_flags_t acctflag = EMPTY_VMA_FLAGS;
> struct hstate *hs;
> size_t hugesize;
>
> @@ -755,14 +755,12 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
> file = hugetlb_file_setup(name, hugesize, acctflag,
> HUGETLB_SHMFS_INODE, (shmflg >> SHM_HUGE_SHIFT) & SHM_HUGE_MASK);
> } else {
> - vm_flags_t acctflag = 0;
> -
> /*
> * Do not allow no accounting for OVERCOMMIT_NEVER, even
> * if it's asked for.
> */
> if (has_no_reserve && sysctl_overcommit_memory != OVERCOMMIT_NEVER)
> - acctflag = VM_NORESERVE;
> + vma_flags_set(&acctflag, VMA_NORESERVE_BIT);
> file = shmem_kernel_file_setup(name, size, acctflag);
> }
> error = PTR_ERR(file);
> diff --git a/mm/memfd.c b/mm/memfd.c
> index 5f95f639550c..f3a8950850a2 100644
> --- a/mm/memfd.c
> +++ b/mm/memfd.c
> @@ -469,7 +469,7 @@ static struct file *alloc_file(const char *name, unsigned int flags)
> (flags >> MFD_HUGE_SHIFT) &
> MFD_HUGE_MASK);
> } else {
> - file = shmem_file_setup(name, 0, VM_NORESERVE);
> + file = shmem_file_setup(name, 0, mk_vma_flags(VMA_NORESERVE_BIT));
> }
> if (IS_ERR(file))
> return file;
> diff --git a/mm/memfd_luo.c b/mm/memfd_luo.c
> index 4f6ba63b4310..a2629dcfd0f1 100644
> --- a/mm/memfd_luo.c
> +++ b/mm/memfd_luo.c
> @@ -443,7 +443,7 @@ static int memfd_luo_retrieve(struct liveupdate_file_op_args *args)
> if (!ser)
> return -EINVAL;
>
> - file = shmem_file_setup("", 0, VM_NORESERVE);
> + file = shmem_file_setup("", 0, mk_vma_flags(VMA_NORESERVE_BIT));
>
> if (IS_ERR(file)) {
> pr_err("failed to setup file: %pe\n", file);
> diff --git a/mm/shmem.c b/mm/shmem.c
> index 0adde3f4df27..97a8f55c7296 100644
> --- a/mm/shmem.c
> +++ b/mm/shmem.c
> @@ -3057,9 +3057,9 @@ static struct offset_ctx *shmem_get_offset_ctx(struct inode *inode)
> }
>
> static struct inode *__shmem_get_inode(struct mnt_idmap *idmap,
> - struct super_block *sb,
> - struct inode *dir, umode_t mode,
> - dev_t dev, unsigned long flags)
> + struct super_block *sb,
> + struct inode *dir, umode_t mode,
> + dev_t dev, vma_flags_t flags)
> {
> struct inode *inode;
> struct shmem_inode_info *info;
> @@ -3087,7 +3087,8 @@ static struct inode *__shmem_get_inode(struct mnt_idmap *idmap,
> spin_lock_init(&info->lock);
> atomic_set(&info->stop_eviction, 0);
> info->seals = F_SEAL_SEAL;
> - info->flags = (flags & VM_NORESERVE) ? SHMEM_F_NORESERVE : 0;
> + info->flags = vma_flags_test(&flags, VMA_NORESERVE_BIT)
> + ? SHMEM_F_NORESERVE : 0;
> info->i_crtime = inode_get_mtime(inode);
> info->fsflags = (dir == NULL) ? 0 :
> SHMEM_I(dir)->fsflags & SHMEM_FL_INHERITED;
> @@ -3140,7 +3141,7 @@ static struct inode *__shmem_get_inode(struct mnt_idmap *idmap,
> #ifdef CONFIG_TMPFS_QUOTA
> static struct inode *shmem_get_inode(struct mnt_idmap *idmap,
> struct super_block *sb, struct inode *dir,
> - umode_t mode, dev_t dev, unsigned long flags)
> + umode_t mode, dev_t dev, vma_flags_t flags)
> {
> int err;
> struct inode *inode;
> @@ -3166,9 +3167,9 @@ static struct inode *shmem_get_inode(struct mnt_idmap *idmap,
> return ERR_PTR(err);
> }
> #else
> -static inline struct inode *shmem_get_inode(struct mnt_idmap *idmap,
> +static struct inode *shmem_get_inode(struct mnt_idmap *idmap,
> struct super_block *sb, struct inode *dir,
> - umode_t mode, dev_t dev, unsigned long flags)
> + umode_t mode, dev_t dev, vma_flags_t flags)
> {
> return __shmem_get_inode(idmap, sb, dir, mode, dev, flags);
> }
> @@ -3875,7 +3876,8 @@ shmem_mknod(struct mnt_idmap *idmap, struct inode *dir,
> if (!generic_ci_validate_strict_name(dir, &dentry->d_name))
> return -EINVAL;
>
> - inode = shmem_get_inode(idmap, dir->i_sb, dir, mode, dev, VM_NORESERVE);
> + inode = shmem_get_inode(idmap, dir->i_sb, dir, mode, dev,
> + mk_vma_flags(VMA_NORESERVE_BIT));
> if (IS_ERR(inode))
> return PTR_ERR(inode);
>
> @@ -3910,7 +3912,8 @@ shmem_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
> struct inode *inode;
> int error;
>
> - inode = shmem_get_inode(idmap, dir->i_sb, dir, mode, 0, VM_NORESERVE);
> + inode = shmem_get_inode(idmap, dir->i_sb, dir, mode, 0,
> + mk_vma_flags(VMA_NORESERVE_BIT));
> if (IS_ERR(inode)) {
> error = PTR_ERR(inode);
> goto err_out;
> @@ -4107,7 +4110,7 @@ static int shmem_symlink(struct mnt_idmap *idmap, struct inode *dir,
> return -ENAMETOOLONG;
>
> inode = shmem_get_inode(idmap, dir->i_sb, dir, S_IFLNK | 0777, 0,
> - VM_NORESERVE);
> + mk_vma_flags(VMA_NORESERVE_BIT));
> if (IS_ERR(inode))
> return PTR_ERR(inode);
>
> @@ -5108,7 +5111,8 @@ static int shmem_fill_super(struct super_block *sb, struct fs_context *fc)
> #endif /* CONFIG_TMPFS_QUOTA */
>
> inode = shmem_get_inode(&nop_mnt_idmap, sb, NULL,
> - S_IFDIR | sbinfo->mode, 0, VM_NORESERVE);
> + S_IFDIR | sbinfo->mode, 0,
> + mk_vma_flags(VMA_NORESERVE_BIT));
> if (IS_ERR(inode)) {
> error = PTR_ERR(inode);
> goto failed;
> @@ -5808,7 +5812,7 @@ static inline void shmem_unacct_size(unsigned long flags, loff_t size)
>
> static inline struct inode *shmem_get_inode(struct mnt_idmap *idmap,
> struct super_block *sb, struct inode *dir,
> - umode_t mode, dev_t dev, unsigned long flags)
> + umode_t mode, dev_t dev, vma_flags_t flags)
> {
> struct inode *inode = ramfs_get_inode(sb, dir, mode, dev);
> return inode ? inode : ERR_PTR(-ENOSPC);
> @@ -5819,10 +5823,11 @@ static inline struct inode *shmem_get_inode(struct mnt_idmap *idmap,
> /* common code */
>
> static struct file *__shmem_file_setup(struct vfsmount *mnt, const char *name,
> - loff_t size, unsigned long vm_flags,
> + loff_t size, vma_flags_t flags,
> unsigned int i_flags)
> {
> - unsigned long flags = (vm_flags & VM_NORESERVE) ? SHMEM_F_NORESERVE : 0;
> + const unsigned long shmem_flags =
> + vma_flags_test(&flags, VMA_NORESERVE_BIT) ? SHMEM_F_NORESERVE : 0;
> struct inode *inode;
> struct file *res;
>
> @@ -5835,13 +5840,13 @@ static struct file *__shmem_file_setup(struct vfsmount *mnt, const char *name,
> if (is_idmapped_mnt(mnt))
> return ERR_PTR(-EINVAL);
>
> - if (shmem_acct_size(flags, size))
> + if (shmem_acct_size(shmem_flags, size))
> return ERR_PTR(-ENOMEM);
>
> inode = shmem_get_inode(&nop_mnt_idmap, mnt->mnt_sb, NULL,
> - S_IFREG | S_IRWXUGO, 0, vm_flags);
> + S_IFREG | S_IRWXUGO, 0, flags);
> if (IS_ERR(inode)) {
> - shmem_unacct_size(flags, size);
> + shmem_unacct_size(shmem_flags, size);
> return ERR_CAST(inode);
> }
> inode->i_flags |= i_flags;
> @@ -5864,9 +5869,10 @@ static struct file *__shmem_file_setup(struct vfsmount *mnt, const char *name,
> * checks are provided at the key or shm level rather than the inode.
> * @name: name for dentry (to be seen in /proc/<pid>/maps)
> * @size: size to be set for the file
> - * @flags: VM_NORESERVE suppresses pre-accounting of the entire object size
> + * @vma_flags: VMA_NORESERVE_BIT suppresses pre-accounting of the entire object size
> */
> -struct file *shmem_kernel_file_setup(const char *name, loff_t size, unsigned long flags)
> +struct file *shmem_kernel_file_setup(const char *name, loff_t size,
> + vma_flags_t flags)
> {
> return __shmem_file_setup(shm_mnt, name, size, flags, S_PRIVATE);
> }
> @@ -5878,7 +5884,7 @@ EXPORT_SYMBOL_GPL(shmem_kernel_file_setup);
> * @size: size to be set for the file
> * @flags: VM_NORESERVE suppresses pre-accounting of the entire object size
> */
> -struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags)
> +struct file *shmem_file_setup(const char *name, loff_t size, vma_flags_t flags)
> {
> return __shmem_file_setup(shm_mnt, name, size, flags, 0);
> }
> @@ -5889,16 +5895,17 @@ EXPORT_SYMBOL_GPL(shmem_file_setup);
> * @mnt: the tmpfs mount where the file will be created
> * @name: name for dentry (to be seen in /proc/<pid>/maps)
> * @size: size to be set for the file
> - * @flags: VM_NORESERVE suppresses pre-accounting of the entire object size
> + * @flags: VMA_NORESERVE_BIT suppresses pre-accounting of the entire object size
> */
> struct file *shmem_file_setup_with_mnt(struct vfsmount *mnt, const char *name,
> - loff_t size, unsigned long flags)
> + loff_t size, vma_flags_t flags)
> {
> return __shmem_file_setup(mnt, name, size, flags, 0);
> }
> EXPORT_SYMBOL_GPL(shmem_file_setup_with_mnt);
>
> -static struct file *__shmem_zero_setup(unsigned long start, unsigned long end, vm_flags_t vm_flags)
> +static struct file *__shmem_zero_setup(unsigned long start, unsigned long end,
> + vma_flags_t flags)
> {
> loff_t size = end - start;
>
> @@ -5908,7 +5915,7 @@ static struct file *__shmem_zero_setup(unsigned long start, unsigned long end, v
> * accessible to the user through its mapping, use S_PRIVATE flag to
> * bypass file security, in the same way as shmem_kernel_file_setup().
> */
> - return shmem_kernel_file_setup("dev/zero", size, vm_flags);
> + return shmem_kernel_file_setup("dev/zero", size, flags);
> }
>
> /**
> @@ -5918,7 +5925,7 @@ static struct file *__shmem_zero_setup(unsigned long start, unsigned long end, v
> */
> int shmem_zero_setup(struct vm_area_struct *vma)
> {
> - struct file *file = __shmem_zero_setup(vma->vm_start, vma->vm_end, vma->vm_flags);
> + struct file *file = __shmem_zero_setup(vma->vm_start, vma->vm_end, vma->flags);
>
> if (IS_ERR(file))
> return PTR_ERR(file);
> @@ -5939,7 +5946,7 @@ int shmem_zero_setup(struct vm_area_struct *vma)
> */
> int shmem_zero_setup_desc(struct vm_area_desc *desc)
> {
> - struct file *file = __shmem_zero_setup(desc->start, desc->end, desc->vm_flags);
> + struct file *file = __shmem_zero_setup(desc->start, desc->end, desc->vma_flags);
>
> if (IS_ERR(file))
> return PTR_ERR(file);
> diff --git a/security/keys/big_key.c b/security/keys/big_key.c
> index d46862ab90d6..268f702df380 100644
> --- a/security/keys/big_key.c
> +++ b/security/keys/big_key.c
> @@ -103,7 +103,7 @@ int big_key_preparse(struct key_preparsed_payload *prep)
> 0, enckey);
>
> /* save aligned data to file */
> - file = shmem_kernel_file_setup("", enclen, 0);
> + file = shmem_kernel_file_setup("", enclen, EMPTY_VMA_FLAGS);
> if (IS_ERR(file)) {
> ret = PTR_ERR(file);
> goto err_enckey;
> --
> 2.52.0
>
BR, Jarkko
^ permalink raw reply [flat|nested] 56+ messages in thread* Re: [PATCH v2 08/13] mm: update shmem_[kernel]_file_*() functions to use vma_flags_t
2026-01-22 16:06 ` [PATCH v2 08/13] mm: update shmem_[kernel]_file_*() functions to use vma_flags_t Lorenzo Stoakes
` (3 preceding siblings ...)
2026-01-25 14:50 ` Jarkko Sakkinen
@ 2026-02-09 19:13 ` Liam R. Howlett
4 siblings, 0 replies; 56+ messages in thread
From: Liam R. Howlett @ 2026-02-09 19:13 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin,
Arnd Bergmann, Greg Kroah-Hartman, Dan Williams, Vishal Verma,
Dave Jiang, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Hugh Dickins, Baolin Wang, Zi Yan, Nico Pache, Ryan Roberts,
Dev Jain, Barry Song, Lance Yang, Jann Horn, Pedro Falcato,
David Howells, Paul Moore, James Morris, Serge E . Hallyn,
Yury Norov, Rasmus Villemoes, linux-sgx, linux-kernel, nvdimm,
linux-cxl, dri-devel, intel-gfx, linux-fsdevel, linux-aio,
linux-erofs, linux-ext4, linux-mm, ntfs3, devel, linux-xfs,
keyrings, linux-security-module, Jason Gunthorpe
* Lorenzo Stoakes <lorenzo.stoakes@oracle.com> [260122 16:06]:
> In order to be able to use only vma_flags_t in vm_area_desc we must adjust
> shmem file setup functions to operate in terms of vma_flags_t rather than
> vm_flags_t.
>
> This patch makes this change and updates all callers to use the new
> functions.
>
> No functional changes intended.
A few nits, but
Reviewed-by: Liam R. Howlett <Liam.Howlett@oracle.com>
>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
> ---
> arch/x86/kernel/cpu/sgx/ioctl.c | 2 +-
> drivers/gpu/drm/drm_gem.c | 5 +-
> drivers/gpu/drm/i915/gem/i915_gem_shmem.c | 2 +-
> drivers/gpu/drm/i915/gem/i915_gem_ttm.c | 3 +-
> drivers/gpu/drm/i915/gt/shmem_utils.c | 3 +-
> drivers/gpu/drm/ttm/tests/ttm_tt_test.c | 2 +-
> drivers/gpu/drm/ttm/ttm_backup.c | 3 +-
> drivers/gpu/drm/ttm/ttm_tt.c | 2 +-
> fs/xfs/scrub/xfile.c | 3 +-
> fs/xfs/xfs_buf_mem.c | 2 +-
> include/linux/shmem_fs.h | 8 ++-
> ipc/shm.c | 6 +--
> mm/memfd.c | 2 +-
> mm/memfd_luo.c | 2 +-
> mm/shmem.c | 59 +++++++++++++----------
> security/keys/big_key.c | 2 +-
> 16 files changed, 57 insertions(+), 49 deletions(-)
>
> diff --git a/arch/x86/kernel/cpu/sgx/ioctl.c b/arch/x86/kernel/cpu/sgx/ioctl.c
> index 9322a9287dc7..0bc36957979d 100644
> --- a/arch/x86/kernel/cpu/sgx/ioctl.c
> +++ b/arch/x86/kernel/cpu/sgx/ioctl.c
> @@ -83,7 +83,7 @@ static int sgx_encl_create(struct sgx_encl *encl, struct sgx_secs *secs)
> encl_size = secs->size + PAGE_SIZE;
>
> backing = shmem_file_setup("SGX backing", encl_size + (encl_size >> 5),
> - VM_NORESERVE);
> + mk_vma_flags(VMA_NORESERVE_BIT));
> if (IS_ERR(backing)) {
> ret = PTR_ERR(backing);
> goto err_out_shrink;
> diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
> index e4df43427394..be4dca2bc34e 100644
> --- a/drivers/gpu/drm/drm_gem.c
> +++ b/drivers/gpu/drm/drm_gem.c
> @@ -130,14 +130,15 @@ int drm_gem_object_init_with_mnt(struct drm_device *dev,
> struct vfsmount *gemfs)
> {
> struct file *filp;
> + const vma_flags_t flags = mk_vma_flags(VMA_NORESERVE_BIT);
>
> drm_gem_private_object_init(dev, obj, size);
>
> if (gemfs)
> filp = shmem_file_setup_with_mnt(gemfs, "drm mm object", size,
> - VM_NORESERVE);
> + flags);
> else
> - filp = shmem_file_setup("drm mm object", size, VM_NORESERVE);
> + filp = shmem_file_setup("drm mm object", size, flags);
>
> if (IS_ERR(filp))
> return PTR_ERR(filp);
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
> index 26dda55a07ff..fe1843497b27 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_shmem.c
> @@ -496,7 +496,7 @@ static int __create_shmem(struct drm_i915_private *i915,
> struct drm_gem_object *obj,
> resource_size_t size)
> {
> - unsigned long flags = VM_NORESERVE;
> + const vma_flags_t flags = mk_vma_flags(VMA_NORESERVE_BIT);
> struct file *filp;
>
> drm_gem_private_object_init(&i915->drm, obj, size);
> diff --git a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
> index f65fe86c02b5..7b1a7d01db2b 100644
> --- a/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
> +++ b/drivers/gpu/drm/i915/gem/i915_gem_ttm.c
> @@ -200,7 +200,8 @@ static int i915_ttm_tt_shmem_populate(struct ttm_device *bdev,
> struct address_space *mapping;
> gfp_t mask;
>
> - filp = shmem_file_setup("i915-shmem-tt", size, VM_NORESERVE);
> + filp = shmem_file_setup("i915-shmem-tt", size,
> + mk_vma_flags(VMA_NORESERVE_BIT));
> if (IS_ERR(filp))
> return PTR_ERR(filp);
>
> diff --git a/drivers/gpu/drm/i915/gt/shmem_utils.c b/drivers/gpu/drm/i915/gt/shmem_utils.c
> index 365c4b8b04f4..5f37c699a320 100644
> --- a/drivers/gpu/drm/i915/gt/shmem_utils.c
> +++ b/drivers/gpu/drm/i915/gt/shmem_utils.c
> @@ -19,7 +19,8 @@ struct file *shmem_create_from_data(const char *name, void *data, size_t len)
> struct file *file;
> int err;
>
> - file = shmem_file_setup(name, PAGE_ALIGN(len), VM_NORESERVE);
> + file = shmem_file_setup(name, PAGE_ALIGN(len),
> + mk_vma_flags(VMA_NORESERVE_BIT));
> if (IS_ERR(file))
> return file;
>
> diff --git a/drivers/gpu/drm/ttm/tests/ttm_tt_test.c b/drivers/gpu/drm/ttm/tests/ttm_tt_test.c
> index 61ec6f580b62..bd5f7d0b9b62 100644
> --- a/drivers/gpu/drm/ttm/tests/ttm_tt_test.c
> +++ b/drivers/gpu/drm/ttm/tests/ttm_tt_test.c
> @@ -143,7 +143,7 @@ static void ttm_tt_fini_shmem(struct kunit *test)
> err = ttm_tt_init(tt, bo, 0, caching, 0);
> KUNIT_ASSERT_EQ(test, err, 0);
>
> - shmem = shmem_file_setup("ttm swap", BO_SIZE, 0);
> + shmem = shmem_file_setup("ttm swap", BO_SIZE, EMPTY_VMA_FLAGS);
> tt->swap_storage = shmem;
>
> ttm_tt_fini(tt);
> diff --git a/drivers/gpu/drm/ttm/ttm_backup.c b/drivers/gpu/drm/ttm/ttm_backup.c
> index 32530c75f038..6bd4c123d94c 100644
> --- a/drivers/gpu/drm/ttm/ttm_backup.c
> +++ b/drivers/gpu/drm/ttm/ttm_backup.c
> @@ -178,5 +178,6 @@ EXPORT_SYMBOL_GPL(ttm_backup_bytes_avail);
> */
> struct file *ttm_backup_shmem_create(loff_t size)
> {
> - return shmem_file_setup("ttm shmem backup", size, 0);
> + return shmem_file_setup("ttm shmem backup", size,
> + EMPTY_VMA_FLAGS);
> }
> diff --git a/drivers/gpu/drm/ttm/ttm_tt.c b/drivers/gpu/drm/ttm/ttm_tt.c
> index 611d20ab966d..f73a5ce87645 100644
> --- a/drivers/gpu/drm/ttm/ttm_tt.c
> +++ b/drivers/gpu/drm/ttm/ttm_tt.c
> @@ -330,7 +330,7 @@ int ttm_tt_swapout(struct ttm_device *bdev, struct ttm_tt *ttm,
> struct page *to_page;
> int i, ret;
>
> - swap_storage = shmem_file_setup("ttm swap", size, 0);
> + swap_storage = shmem_file_setup("ttm swap", size, EMPTY_VMA_FLAGS);
> if (IS_ERR(swap_storage)) {
> pr_err("Failed allocating swap storage\n");
> return PTR_ERR(swap_storage);
> diff --git a/fs/xfs/scrub/xfile.c b/fs/xfs/scrub/xfile.c
> index c753c79df203..fe0584a39f16 100644
> --- a/fs/xfs/scrub/xfile.c
> +++ b/fs/xfs/scrub/xfile.c
> @@ -61,7 +61,8 @@ xfile_create(
> if (!xf)
> return -ENOMEM;
>
> - xf->file = shmem_kernel_file_setup(description, isize, VM_NORESERVE);
> + xf->file = shmem_kernel_file_setup(description, isize,
> + mk_vma_flags(VMA_NORESERVE_BIT));
> if (IS_ERR(xf->file)) {
> error = PTR_ERR(xf->file);
> goto out_xfile;
> diff --git a/fs/xfs/xfs_buf_mem.c b/fs/xfs/xfs_buf_mem.c
> index dcbfa274e06d..fd6f0a5bc0ea 100644
> --- a/fs/xfs/xfs_buf_mem.c
> +++ b/fs/xfs/xfs_buf_mem.c
> @@ -62,7 +62,7 @@ xmbuf_alloc(
> if (!btp)
> return -ENOMEM;
>
> - file = shmem_kernel_file_setup(descr, 0, 0);
> + file = shmem_kernel_file_setup(descr, 0, EMPTY_VMA_FLAGS);
> if (IS_ERR(file)) {
> error = PTR_ERR(file);
> goto out_free_btp;
> diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
> index e2069b3179c4..a8273b32e041 100644
> --- a/include/linux/shmem_fs.h
> +++ b/include/linux/shmem_fs.h
> @@ -102,12 +102,10 @@ static inline struct shmem_inode_info *SHMEM_I(struct inode *inode)
> extern const struct fs_parameter_spec shmem_fs_parameters[];
> extern void shmem_init(void);
> extern int shmem_init_fs_context(struct fs_context *fc);
> -extern struct file *shmem_file_setup(const char *name,
> - loff_t size, unsigned long flags);
> -extern struct file *shmem_kernel_file_setup(const char *name, loff_t size,
> - unsigned long flags);
> +struct file *shmem_file_setup(const char *name, loff_t size, vma_flags_t flags);
> +struct file *shmem_kernel_file_setup(const char *name, loff_t size, vma_flags_t vma_flags);
> extern struct file *shmem_file_setup_with_mnt(struct vfsmount *mnt,
> - const char *name, loff_t size, unsigned long flags);
> + const char *name, loff_t size, vma_flags_t flags);
> int shmem_zero_setup(struct vm_area_struct *vma);
> int shmem_zero_setup_desc(struct vm_area_desc *desc);
> extern unsigned long shmem_get_unmapped_area(struct file *, unsigned long addr,
> diff --git a/ipc/shm.c b/ipc/shm.c
> index 2c7379c4c647..e8c7d1924c50 100644
> --- a/ipc/shm.c
> +++ b/ipc/shm.c
> @@ -708,6 +708,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
> struct shmid_kernel *shp;
> size_t numpages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
> const bool has_no_reserve = shmflg & SHM_NORESERVE;
> + vma_flags_t acctflag = EMPTY_VMA_FLAGS;
> struct file *file;
> char name[13];
>
> @@ -738,7 +739,6 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
>
> sprintf(name, "SYSV%08x", key);
> if (shmflg & SHM_HUGETLB) {
> - vma_flags_t acctflag = EMPTY_VMA_FLAGS;
> struct hstate *hs;
> size_t hugesize;
>
> @@ -755,14 +755,12 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
> file = hugetlb_file_setup(name, hugesize, acctflag,
> HUGETLB_SHMFS_INODE, (shmflg >> SHM_HUGE_SHIFT) & SHM_HUGE_MASK);
> } else {
> - vm_flags_t acctflag = 0;
> -
> /*
> * Do not allow no accounting for OVERCOMMIT_NEVER, even
> * if it's asked for.
> */
> if (has_no_reserve && sysctl_overcommit_memory != OVERCOMMIT_NEVER)
> - acctflag = VM_NORESERVE;
> + vma_flags_set(&acctflag, VMA_NORESERVE_BIT);
> file = shmem_kernel_file_setup(name, size, acctflag);
> }
> error = PTR_ERR(file);
> diff --git a/mm/memfd.c b/mm/memfd.c
> index 5f95f639550c..f3a8950850a2 100644
> --- a/mm/memfd.c
> +++ b/mm/memfd.c
> @@ -469,7 +469,7 @@ static struct file *alloc_file(const char *name, unsigned int flags)
> (flags >> MFD_HUGE_SHIFT) &
> MFD_HUGE_MASK);
> } else {
> - file = shmem_file_setup(name, 0, VM_NORESERVE);
> + file = shmem_file_setup(name, 0, mk_vma_flags(VMA_NORESERVE_BIT));
> }
> if (IS_ERR(file))
> return file;
> diff --git a/mm/memfd_luo.c b/mm/memfd_luo.c
> index 4f6ba63b4310..a2629dcfd0f1 100644
> --- a/mm/memfd_luo.c
> +++ b/mm/memfd_luo.c
> @@ -443,7 +443,7 @@ static int memfd_luo_retrieve(struct liveupdate_file_op_args *args)
> if (!ser)
> return -EINVAL;
>
> - file = shmem_file_setup("", 0, VM_NORESERVE);
> + file = shmem_file_setup("", 0, mk_vma_flags(VMA_NORESERVE_BIT));
>
> if (IS_ERR(file)) {
> pr_err("failed to setup file: %pe\n", file);
> diff --git a/mm/shmem.c b/mm/shmem.c
> index 0adde3f4df27..97a8f55c7296 100644
> --- a/mm/shmem.c
> +++ b/mm/shmem.c
> @@ -3057,9 +3057,9 @@ static struct offset_ctx *shmem_get_offset_ctx(struct inode *inode)
> }
>
> static struct inode *__shmem_get_inode(struct mnt_idmap *idmap,
> - struct super_block *sb,
> - struct inode *dir, umode_t mode,
> - dev_t dev, unsigned long flags)
> + struct super_block *sb,
> + struct inode *dir, umode_t mode,
> + dev_t dev, vma_flags_t flags)
Using two tabs here would have been less ugly, and below too.
> {
> struct inode *inode;
> struct shmem_inode_info *info;
> @@ -3087,7 +3087,8 @@ static struct inode *__shmem_get_inode(struct mnt_idmap *idmap,
> spin_lock_init(&info->lock);
> atomic_set(&info->stop_eviction, 0);
> info->seals = F_SEAL_SEAL;
> - info->flags = (flags & VM_NORESERVE) ? SHMEM_F_NORESERVE : 0;
> + info->flags = vma_flags_test(&flags, VMA_NORESERVE_BIT)
> + ? SHMEM_F_NORESERVE : 0;
> info->i_crtime = inode_get_mtime(inode);
> info->fsflags = (dir == NULL) ? 0 :
> SHMEM_I(dir)->fsflags & SHMEM_FL_INHERITED;
> @@ -3140,7 +3141,7 @@ static struct inode *__shmem_get_inode(struct mnt_idmap *idmap,
> #ifdef CONFIG_TMPFS_QUOTA
> static struct inode *shmem_get_inode(struct mnt_idmap *idmap,
> struct super_block *sb, struct inode *dir,
> - umode_t mode, dev_t dev, unsigned long flags)
> + umode_t mode, dev_t dev, vma_flags_t flags)
A variable named flags is often incorrectly passed along as the wrong
flags, so I try to avoid it.
> {
> int err;
> struct inode *inode;
> @@ -3166,9 +3167,9 @@ static struct inode *shmem_get_inode(struct mnt_idmap *idmap,
> return ERR_PTR(err);
> }
> #else
> -static inline struct inode *shmem_get_inode(struct mnt_idmap *idmap,
> +static struct inode *shmem_get_inode(struct mnt_idmap *idmap,
> struct super_block *sb, struct inode *dir,
> - umode_t mode, dev_t dev, unsigned long flags)
> + umode_t mode, dev_t dev, vma_flags_t flags)
> {
> return __shmem_get_inode(idmap, sb, dir, mode, dev, flags);
> }
> @@ -3875,7 +3876,8 @@ shmem_mknod(struct mnt_idmap *idmap, struct inode *dir,
> if (!generic_ci_validate_strict_name(dir, &dentry->d_name))
> return -EINVAL;
>
> - inode = shmem_get_inode(idmap, dir->i_sb, dir, mode, dev, VM_NORESERVE);
> + inode = shmem_get_inode(idmap, dir->i_sb, dir, mode, dev,
> + mk_vma_flags(VMA_NORESERVE_BIT));
> if (IS_ERR(inode))
> return PTR_ERR(inode);
>
> @@ -3910,7 +3912,8 @@ shmem_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
> struct inode *inode;
> int error;
>
> - inode = shmem_get_inode(idmap, dir->i_sb, dir, mode, 0, VM_NORESERVE);
> + inode = shmem_get_inode(idmap, dir->i_sb, dir, mode, 0,
> + mk_vma_flags(VMA_NORESERVE_BIT));
> if (IS_ERR(inode)) {
> error = PTR_ERR(inode);
> goto err_out;
> @@ -4107,7 +4110,7 @@ static int shmem_symlink(struct mnt_idmap *idmap, struct inode *dir,
> return -ENAMETOOLONG;
>
> inode = shmem_get_inode(idmap, dir->i_sb, dir, S_IFLNK | 0777, 0,
> - VM_NORESERVE);
> + mk_vma_flags(VMA_NORESERVE_BIT));
> if (IS_ERR(inode))
> return PTR_ERR(inode);
>
> @@ -5108,7 +5111,8 @@ static int shmem_fill_super(struct super_block *sb, struct fs_context *fc)
> #endif /* CONFIG_TMPFS_QUOTA */
>
> inode = shmem_get_inode(&nop_mnt_idmap, sb, NULL,
> - S_IFDIR | sbinfo->mode, 0, VM_NORESERVE);
> + S_IFDIR | sbinfo->mode, 0,
> + mk_vma_flags(VMA_NORESERVE_BIT));
> if (IS_ERR(inode)) {
> error = PTR_ERR(inode);
> goto failed;
> @@ -5808,7 +5812,7 @@ static inline void shmem_unacct_size(unsigned long flags, loff_t size)
>
> static inline struct inode *shmem_get_inode(struct mnt_idmap *idmap,
> struct super_block *sb, struct inode *dir,
> - umode_t mode, dev_t dev, unsigned long flags)
> + umode_t mode, dev_t dev, vma_flags_t flags)
> {
> struct inode *inode = ramfs_get_inode(sb, dir, mode, dev);
> return inode ? inode : ERR_PTR(-ENOSPC);
> @@ -5819,10 +5823,11 @@ static inline struct inode *shmem_get_inode(struct mnt_idmap *idmap,
> /* common code */
>
> static struct file *__shmem_file_setup(struct vfsmount *mnt, const char *name,
> - loff_t size, unsigned long vm_flags,
> + loff_t size, vma_flags_t flags,
> unsigned int i_flags)
> {
> - unsigned long flags = (vm_flags & VM_NORESERVE) ? SHMEM_F_NORESERVE : 0;
> + const unsigned long shmem_flags =
> + vma_flags_test(&flags, VMA_NORESERVE_BIT) ? SHMEM_F_NORESERVE : 0;
> struct inode *inode;
> struct file *res;
>
> @@ -5835,13 +5840,13 @@ static struct file *__shmem_file_setup(struct vfsmount *mnt, const char *name,
> if (is_idmapped_mnt(mnt))
> return ERR_PTR(-EINVAL);
>
> - if (shmem_acct_size(flags, size))
> + if (shmem_acct_size(shmem_flags, size))
> return ERR_PTR(-ENOMEM);
>
> inode = shmem_get_inode(&nop_mnt_idmap, mnt->mnt_sb, NULL,
> - S_IFREG | S_IRWXUGO, 0, vm_flags);
> + S_IFREG | S_IRWXUGO, 0, flags);
> if (IS_ERR(inode)) {
> - shmem_unacct_size(flags, size);
> + shmem_unacct_size(shmem_flags, size);
> return ERR_CAST(inode);
> }
> inode->i_flags |= i_flags;
> @@ -5864,9 +5869,10 @@ static struct file *__shmem_file_setup(struct vfsmount *mnt, const char *name,
> * checks are provided at the key or shm level rather than the inode.
> * @name: name for dentry (to be seen in /proc/<pid>/maps)
> * @size: size to be set for the file
> - * @flags: VM_NORESERVE suppresses pre-accounting of the entire object size
> + * @vma_flags: VMA_NORESERVE_BIT suppresses pre-accounting of the entire object size
> */
> -struct file *shmem_kernel_file_setup(const char *name, loff_t size, unsigned long flags)
> +struct file *shmem_kernel_file_setup(const char *name, loff_t size,
> + vma_flags_t flags)
> {
> return __shmem_file_setup(shm_mnt, name, size, flags, S_PRIVATE);
> }
> @@ -5878,7 +5884,7 @@ EXPORT_SYMBOL_GPL(shmem_kernel_file_setup);
> * @size: size to be set for the file
> * @flags: VM_NORESERVE suppresses pre-accounting of the entire object size
> */
> -struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags)
> +struct file *shmem_file_setup(const char *name, loff_t size, vma_flags_t flags)
> {
> return __shmem_file_setup(shm_mnt, name, size, flags, 0);
> }
> @@ -5889,16 +5895,17 @@ EXPORT_SYMBOL_GPL(shmem_file_setup);
> * @mnt: the tmpfs mount where the file will be created
> * @name: name for dentry (to be seen in /proc/<pid>/maps)
> * @size: size to be set for the file
> - * @flags: VM_NORESERVE suppresses pre-accounting of the entire object size
> + * @flags: VMA_NORESERVE_BIT suppresses pre-accounting of the entire object size
> */
> struct file *shmem_file_setup_with_mnt(struct vfsmount *mnt, const char *name,
> - loff_t size, unsigned long flags)
> + loff_t size, vma_flags_t flags)
> {
> return __shmem_file_setup(mnt, name, size, flags, 0);
> }
> EXPORT_SYMBOL_GPL(shmem_file_setup_with_mnt);
>
> -static struct file *__shmem_zero_setup(unsigned long start, unsigned long end, vm_flags_t vm_flags)
> +static struct file *__shmem_zero_setup(unsigned long start, unsigned long end,
> + vma_flags_t flags)
> {
> loff_t size = end - start;
>
> @@ -5908,7 +5915,7 @@ static struct file *__shmem_zero_setup(unsigned long start, unsigned long end, v
> * accessible to the user through its mapping, use S_PRIVATE flag to
> * bypass file security, in the same way as shmem_kernel_file_setup().
> */
> - return shmem_kernel_file_setup("dev/zero", size, vm_flags);
> + return shmem_kernel_file_setup("dev/zero", size, flags);
> }
>
> /**
> @@ -5918,7 +5925,7 @@ static struct file *__shmem_zero_setup(unsigned long start, unsigned long end, v
> */
> int shmem_zero_setup(struct vm_area_struct *vma)
> {
> - struct file *file = __shmem_zero_setup(vma->vm_start, vma->vm_end, vma->vm_flags);
> + struct file *file = __shmem_zero_setup(vma->vm_start, vma->vm_end, vma->flags);
>
> if (IS_ERR(file))
> return PTR_ERR(file);
> @@ -5939,7 +5946,7 @@ int shmem_zero_setup(struct vm_area_struct *vma)
> */
> int shmem_zero_setup_desc(struct vm_area_desc *desc)
> {
> - struct file *file = __shmem_zero_setup(desc->start, desc->end, desc->vm_flags);
> + struct file *file = __shmem_zero_setup(desc->start, desc->end, desc->vma_flags);
>
> if (IS_ERR(file))
> return PTR_ERR(file);
> diff --git a/security/keys/big_key.c b/security/keys/big_key.c
> index d46862ab90d6..268f702df380 100644
> --- a/security/keys/big_key.c
> +++ b/security/keys/big_key.c
> @@ -103,7 +103,7 @@ int big_key_preparse(struct key_preparsed_payload *prep)
> 0, enckey);
>
> /* save aligned data to file */
> - file = shmem_kernel_file_setup("", enclen, 0);
> + file = shmem_kernel_file_setup("", enclen, EMPTY_VMA_FLAGS);
> if (IS_ERR(file)) {
> ret = PTR_ERR(file);
> goto err_enckey;
> --
> 2.52.0
>
^ permalink raw reply [flat|nested] 56+ messages in thread
* [PATCH v2 09/13] mm: update all remaining mmap_prepare users to use vma_flags_t
2026-01-22 16:06 [PATCH v2 00/13] mm: add bitmap VMA flag helpers and convert all mmap_prepare to use them Lorenzo Stoakes
` (7 preceding siblings ...)
2026-01-22 16:06 ` [PATCH v2 08/13] mm: update shmem_[kernel]_file_*() functions to use vma_flags_t Lorenzo Stoakes
@ 2026-01-22 16:06 ` Lorenzo Stoakes
2026-01-22 23:31 ` Damien Le Moal
` (2 more replies)
2026-01-22 16:06 ` [PATCH v2 10/13] mm: make vm_area_desc utilise vma_flags_t only Lorenzo Stoakes
` (5 subsequent siblings)
14 siblings, 3 replies; 56+ messages in thread
From: Lorenzo Stoakes @ 2026-01-22 16:06 UTC (permalink / raw)
To: Andrew Morton
Cc: Jarkko Sakkinen, Dave Hansen, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, x86, H . Peter Anvin, Arnd Bergmann,
Greg Kroah-Hartman, Dan Williams, Vishal Verma, Dave Jiang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
We will be shortly removing the vm_flags_t field from vm_area_desc so we
need to update all mmap_prepare users to only use the dessc->vma_flags
field.
This patch achieves that and makes all ancillary changes required to make
this possible.
This lays the groundwork for future work to eliminate the use of vm_flags_t
in vm_area_desc altogether and more broadly throughout the kernel.
While we're here, we take the opportunity to replace VM_REMAP_FLAGS with
VMA_REMAP_FLAGS, the vma_flags_t equivalent.
No functional changes intended.
Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
---
drivers/char/mem.c | 6 +++---
drivers/dax/device.c | 10 +++++-----
fs/aio.c | 2 +-
fs/erofs/data.c | 5 +++--
fs/ext4/file.c | 4 ++--
fs/ntfs3/file.c | 2 +-
fs/orangefs/file.c | 4 ++--
fs/ramfs/file-nommu.c | 2 +-
fs/resctrl/pseudo_lock.c | 2 +-
fs/romfs/mmap-nommu.c | 2 +-
fs/xfs/xfs_file.c | 4 ++--
fs/zonefs/file.c | 3 ++-
include/linux/dax.h | 8 ++++----
include/linux/mm.h | 24 +++++++++++++++++++-----
kernel/relay.c | 2 +-
mm/memory.c | 17 ++++++++---------
16 files changed, 56 insertions(+), 41 deletions(-)
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 52039fae1594..cca4529431f8 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -306,7 +306,7 @@ static unsigned zero_mmap_capabilities(struct file *file)
/* can't do an in-place private mapping if there's no MMU */
static inline int private_mapping_ok(struct vm_area_desc *desc)
{
- return is_nommu_shared_mapping(desc->vm_flags);
+ return is_nommu_shared_vma_flags(&desc->vma_flags);
}
#else
@@ -360,7 +360,7 @@ static int mmap_mem_prepare(struct vm_area_desc *desc)
desc->vm_ops = &mmap_mem_ops;
- /* Remap-pfn-range will mark the range VM_IO. */
+ /* Remap-pfn-range will mark the range with the I/O flag. */
mmap_action_remap_full(desc, desc->pgoff);
/* We filter remap errors to -EAGAIN. */
desc->action.error_hook = mmap_filter_error;
@@ -520,7 +520,7 @@ static int mmap_zero_prepare(struct vm_area_desc *desc)
#ifndef CONFIG_MMU
return -ENOSYS;
#endif
- if (desc->vm_flags & VM_SHARED)
+ if (vma_desc_test_flags(desc, VMA_SHARED_BIT))
return shmem_zero_setup_desc(desc);
desc->action.success_hook = mmap_zero_private_success;
diff --git a/drivers/dax/device.c b/drivers/dax/device.c
index 22999a402e02..528e81240c4d 100644
--- a/drivers/dax/device.c
+++ b/drivers/dax/device.c
@@ -13,7 +13,7 @@
#include "dax-private.h"
#include "bus.h"
-static int __check_vma(struct dev_dax *dev_dax, vm_flags_t vm_flags,
+static int __check_vma(struct dev_dax *dev_dax, vma_flags_t flags,
unsigned long start, unsigned long end, struct file *file,
const char *func)
{
@@ -24,7 +24,7 @@ static int __check_vma(struct dev_dax *dev_dax, vm_flags_t vm_flags,
return -ENXIO;
/* prevent private mappings from being established */
- if ((vm_flags & VM_MAYSHARE) != VM_MAYSHARE) {
+ if (!vma_flags_test(&flags, VMA_MAYSHARE_BIT)) {
dev_info_ratelimited(dev,
"%s: %s: fail, attempted private mapping\n",
current->comm, func);
@@ -53,7 +53,7 @@ static int __check_vma(struct dev_dax *dev_dax, vm_flags_t vm_flags,
static int check_vma(struct dev_dax *dev_dax, struct vm_area_struct *vma,
const char *func)
{
- return __check_vma(dev_dax, vma->vm_flags, vma->vm_start, vma->vm_end,
+ return __check_vma(dev_dax, vma->flags, vma->vm_start, vma->vm_end,
vma->vm_file, func);
}
@@ -306,14 +306,14 @@ static int dax_mmap_prepare(struct vm_area_desc *desc)
* fault time.
*/
id = dax_read_lock();
- rc = __check_vma(dev_dax, desc->vm_flags, desc->start, desc->end, filp,
+ rc = __check_vma(dev_dax, desc->vma_flags, desc->start, desc->end, filp,
__func__);
dax_read_unlock(id);
if (rc)
return rc;
desc->vm_ops = &dax_vm_ops;
- desc->vm_flags |= VM_HUGEPAGE;
+ vma_desc_set_flags(desc, VMA_HUGEPAGE_BIT);
return 0;
}
diff --git a/fs/aio.c b/fs/aio.c
index 0a23a8c0717f..59b67b8da1b2 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -394,7 +394,7 @@ static const struct vm_operations_struct aio_ring_vm_ops = {
static int aio_ring_mmap_prepare(struct vm_area_desc *desc)
{
- desc->vm_flags |= VM_DONTEXPAND;
+ vma_desc_set_flags(desc, VMA_DONTEXPAND_BIT);
desc->vm_ops = &aio_ring_vm_ops;
return 0;
}
diff --git a/fs/erofs/data.c b/fs/erofs/data.c
index bb13c4cb8455..e7bc29e764c6 100644
--- a/fs/erofs/data.c
+++ b/fs/erofs/data.c
@@ -438,11 +438,12 @@ static int erofs_file_mmap_prepare(struct vm_area_desc *desc)
if (!IS_DAX(file_inode(desc->file)))
return generic_file_readonly_mmap_prepare(desc);
- if ((desc->vm_flags & VM_SHARED) && (desc->vm_flags & VM_MAYWRITE))
+ if (vma_desc_test_flags(desc, VMA_SHARED_BIT) &&
+ vma_desc_test_flags(desc, VMA_MAYWRITE_BIT))
return -EINVAL;
desc->vm_ops = &erofs_dax_vm_ops;
- desc->vm_flags |= VM_HUGEPAGE;
+ vma_desc_set_flags(desc, VMA_HUGEPAGE_BIT);
return 0;
}
#else
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 7a8b30932189..dfd5f4fe1647 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -822,13 +822,13 @@ static int ext4_file_mmap_prepare(struct vm_area_desc *desc)
* We don't support synchronous mappings for non-DAX files and
* for DAX files if underneath dax_device is not synchronous.
*/
- if (!daxdev_mapping_supported(desc->vm_flags, file_inode(file), dax_dev))
+ if (!daxdev_mapping_supported(desc, file_inode(file), dax_dev))
return -EOPNOTSUPP;
file_accessed(file);
if (IS_DAX(file_inode(file))) {
desc->vm_ops = &ext4_dax_vm_ops;
- desc->vm_flags |= VM_HUGEPAGE;
+ vma_desc_set_flags(desc, VMA_HUGEPAGE_BIT);
} else {
desc->vm_ops = &ext4_file_vm_ops;
}
diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c
index 2e7b2e566ebe..2902fc6d9a85 100644
--- a/fs/ntfs3/file.c
+++ b/fs/ntfs3/file.c
@@ -347,7 +347,7 @@ static int ntfs_file_mmap_prepare(struct vm_area_desc *desc)
struct inode *inode = file_inode(file);
struct ntfs_inode *ni = ntfs_i(inode);
u64 from = ((u64)desc->pgoff << PAGE_SHIFT);
- bool rw = desc->vm_flags & VM_WRITE;
+ const bool rw = vma_desc_test_flags(desc, VMA_WRITE_BIT);
int err;
/* Avoid any operation if inode is bad. */
diff --git a/fs/orangefs/file.c b/fs/orangefs/file.c
index 919f99b16834..c75aa3f419b1 100644
--- a/fs/orangefs/file.c
+++ b/fs/orangefs/file.c
@@ -411,8 +411,8 @@ static int orangefs_file_mmap_prepare(struct vm_area_desc *desc)
"orangefs_file_mmap: called on %pD\n", file);
/* set the sequential readahead hint */
- desc->vm_flags |= VM_SEQ_READ;
- desc->vm_flags &= ~VM_RAND_READ;
+ vma_desc_set_flags(desc, VMA_SEQ_READ_BIT);
+ vma_desc_clear_flags(desc, VMA_RAND_READ_BIT);
file_accessed(file);
desc->vm_ops = &orangefs_file_vm_ops;
diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c
index 77b8ca2757e0..0f8e838ece07 100644
--- a/fs/ramfs/file-nommu.c
+++ b/fs/ramfs/file-nommu.c
@@ -264,7 +264,7 @@ static unsigned long ramfs_nommu_get_unmapped_area(struct file *file,
*/
static int ramfs_nommu_mmap_prepare(struct vm_area_desc *desc)
{
- if (!is_nommu_shared_mapping(desc->vm_flags))
+ if (!is_nommu_shared_vma_flags(&desc->vma_flags))
return -ENOSYS;
file_accessed(desc->file);
diff --git a/fs/resctrl/pseudo_lock.c b/fs/resctrl/pseudo_lock.c
index 0bfc13c5b96d..e81d71abfe54 100644
--- a/fs/resctrl/pseudo_lock.c
+++ b/fs/resctrl/pseudo_lock.c
@@ -1044,7 +1044,7 @@ static int pseudo_lock_dev_mmap_prepare(struct vm_area_desc *desc)
* Ensure changes are carried directly to the memory being mapped,
* do not allow copy-on-write mapping.
*/
- if (!(desc->vm_flags & VM_SHARED)) {
+ if (!vma_desc_test_flags(desc, VMA_SHARED_BIT)) {
mutex_unlock(&rdtgroup_mutex);
return -EINVAL;
}
diff --git a/fs/romfs/mmap-nommu.c b/fs/romfs/mmap-nommu.c
index 4b77c6dc4418..7c3a1a7fecee 100644
--- a/fs/romfs/mmap-nommu.c
+++ b/fs/romfs/mmap-nommu.c
@@ -63,7 +63,7 @@ static unsigned long romfs_get_unmapped_area(struct file *file,
*/
static int romfs_mmap_prepare(struct vm_area_desc *desc)
{
- return is_nommu_shared_mapping(desc->vm_flags) ? 0 : -ENOSYS;
+ return is_nommu_shared_vma_flags(&desc->vma_flags) ? 0 : -ENOSYS;
}
static unsigned romfs_mmap_capabilities(struct file *file)
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index 7874cf745af3..1238ec018bc7 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -1974,14 +1974,14 @@ xfs_file_mmap_prepare(
* We don't support synchronous mappings for non-DAX files and
* for DAX files if underneath dax_device is not synchronous.
*/
- if (!daxdev_mapping_supported(desc->vm_flags, file_inode(file),
+ if (!daxdev_mapping_supported(desc, file_inode(file),
target->bt_daxdev))
return -EOPNOTSUPP;
file_accessed(file);
desc->vm_ops = &xfs_file_vm_ops;
if (IS_DAX(inode))
- desc->vm_flags |= VM_HUGEPAGE;
+ vma_desc_set_flags(desc, VMA_HUGEPAGE_BIT);
return 0;
}
diff --git a/fs/zonefs/file.c b/fs/zonefs/file.c
index c1e5e30e90a0..8a7161fc49e5 100644
--- a/fs/zonefs/file.c
+++ b/fs/zonefs/file.c
@@ -333,7 +333,8 @@ static int zonefs_file_mmap_prepare(struct vm_area_desc *desc)
* ordering between msync() and page cache writeback.
*/
if (zonefs_inode_is_seq(file_inode(file)) &&
- (desc->vm_flags & VM_SHARED) && (desc->vm_flags & VM_MAYWRITE))
+ vma_desc_test_flags(desc, VMA_SHARED_BIT) &&
+ vma_desc_test_flags(desc, VMA_MAYWRITE_BIT))
return -EINVAL;
file_accessed(file);
diff --git a/include/linux/dax.h b/include/linux/dax.h
index 9d624f4d9df6..bf103f317cac 100644
--- a/include/linux/dax.h
+++ b/include/linux/dax.h
@@ -65,11 +65,11 @@ size_t dax_recovery_write(struct dax_device *dax_dev, pgoff_t pgoff,
/*
* Check if given mapping is supported by the file / underlying device.
*/
-static inline bool daxdev_mapping_supported(vm_flags_t vm_flags,
+static inline bool daxdev_mapping_supported(const struct vm_area_desc *desc,
const struct inode *inode,
struct dax_device *dax_dev)
{
- if (!(vm_flags & VM_SYNC))
+ if (!vma_desc_test_flags(desc, VMA_SYNC_BIT))
return true;
if (!IS_DAX(inode))
return false;
@@ -111,11 +111,11 @@ static inline void set_dax_nomc(struct dax_device *dax_dev)
static inline void set_dax_synchronous(struct dax_device *dax_dev)
{
}
-static inline bool daxdev_mapping_supported(vm_flags_t vm_flags,
+static inline bool daxdev_mapping_supported(const struct vm_area_desc *desc,
const struct inode *inode,
struct dax_device *dax_dev)
{
- return !(vm_flags & VM_SYNC);
+ return !vma_desc_test_flags(desc, VMA_SYNC_BIT);
}
static inline size_t dax_recovery_write(struct dax_device *dax_dev,
pgoff_t pgoff, void *addr, size_t bytes, struct iov_iter *i)
diff --git a/include/linux/mm.h b/include/linux/mm.h
index fd93317193e0..e31f72a021ef 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -550,17 +550,18 @@ enum {
/*
* Physically remapped pages are special. Tell the
* rest of the world about it:
- * VM_IO tells people not to look at these pages
+ * IO tells people not to look at these pages
* (accesses can have side effects).
- * VM_PFNMAP tells the core MM that the base pages are just
+ * PFNMAP tells the core MM that the base pages are just
* raw PFN mappings, and do not have a "struct page" associated
* with them.
- * VM_DONTEXPAND
+ * DONTEXPAND
* Disable vma merging and expanding with mremap().
- * VM_DONTDUMP
+ * DONTDUMP
* Omit vma from core dump, even when VM_IO turned off.
*/
-#define VM_REMAP_FLAGS (VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP)
+#define VMA_REMAP_FLAGS mk_vma_flags(VMA_IO_BIT, VMA_PFNMAP_BIT, \
+ VMA_DONTEXPAND_BIT, VMA_DONTDUMP_BIT)
/* This mask prevents VMA from being scanned with khugepaged */
#define VM_NO_KHUGEPAGED (VM_SPECIAL | VM_HUGETLB)
@@ -1925,6 +1926,14 @@ static inline bool is_cow_mapping(vm_flags_t flags)
return (flags & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE;
}
+static inline bool vma_desc_is_cow_mapping(struct vm_area_desc *desc)
+{
+ const vma_flags_t *flags = &desc->vma_flags;
+
+ return vma_flags_test(flags, VMA_MAYWRITE_BIT) &&
+ !vma_flags_test(flags, VMA_SHARED_BIT);
+}
+
#ifndef CONFIG_MMU
static inline bool is_nommu_shared_mapping(vm_flags_t flags)
{
@@ -1938,6 +1947,11 @@ static inline bool is_nommu_shared_mapping(vm_flags_t flags)
*/
return flags & (VM_MAYSHARE | VM_MAYOVERLAY);
}
+
+static inline bool is_nommu_shared_vma_flags(const vma_flags_t *flags)
+{
+ return vma_flags_test(flags, VMA_MAYSHARE_BIT, VMA_MAYOVERLAY_BIT);
+}
#endif
#if defined(CONFIG_SPARSEMEM) && !defined(CONFIG_SPARSEMEM_VMEMMAP)
diff --git a/kernel/relay.c b/kernel/relay.c
index e36f6b926f7f..1c8e88259df0 100644
--- a/kernel/relay.c
+++ b/kernel/relay.c
@@ -92,7 +92,7 @@ static int relay_mmap_prepare_buf(struct rchan_buf *buf,
return -EINVAL;
desc->vm_ops = &relay_file_mmap_ops;
- desc->vm_flags |= VM_DONTEXPAND;
+ vma_desc_set_flags(desc, VMA_DONTEXPAND_BIT);
desc->private_data = buf;
return 0;
diff --git a/mm/memory.c b/mm/memory.c
index 3852075ea62d..ad78cb7e64ec 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -2955,7 +2955,7 @@ static inline int remap_p4d_range(struct mm_struct *mm, pgd_t *pgd,
return 0;
}
-static int get_remap_pgoff(vm_flags_t vm_flags, unsigned long addr,
+static int get_remap_pgoff(bool is_cow, unsigned long addr,
unsigned long end, unsigned long vm_start, unsigned long vm_end,
unsigned long pfn, pgoff_t *vm_pgoff_p)
{
@@ -2965,7 +2965,7 @@ static int get_remap_pgoff(vm_flags_t vm_flags, unsigned long addr,
* un-COW'ed pages by matching them up with "vma->vm_pgoff".
* See vm_normal_page() for details.
*/
- if (is_cow_mapping(vm_flags)) {
+ if (is_cow) {
if (addr != vm_start || end != vm_end)
return -EINVAL;
*vm_pgoff_p = pfn;
@@ -2986,7 +2986,7 @@ static int remap_pfn_range_internal(struct vm_area_struct *vma, unsigned long ad
if (WARN_ON_ONCE(!PAGE_ALIGNED(addr)))
return -EINVAL;
- VM_WARN_ON_ONCE((vma->vm_flags & VM_REMAP_FLAGS) != VM_REMAP_FLAGS);
+ VM_WARN_ON_ONCE(!vma_test_all_flags_mask(vma, VMA_REMAP_FLAGS));
BUG_ON(addr >= end);
pfn -= addr >> PAGE_SHIFT;
@@ -3110,9 +3110,9 @@ void remap_pfn_range_prepare(struct vm_area_desc *desc, unsigned long pfn)
* check it again on complete and will fail there if specified addr is
* invalid.
*/
- get_remap_pgoff(desc->vm_flags, desc->start, desc->end,
+ get_remap_pgoff(vma_desc_is_cow_mapping(desc), desc->start, desc->end,
desc->start, desc->end, pfn, &desc->pgoff);
- desc->vm_flags |= VM_REMAP_FLAGS;
+ vma_desc_set_flags_mask(desc, VMA_REMAP_FLAGS);
}
static int remap_pfn_range_prepare_vma(struct vm_area_struct *vma, unsigned long addr,
@@ -3121,13 +3121,12 @@ static int remap_pfn_range_prepare_vma(struct vm_area_struct *vma, unsigned long
unsigned long end = addr + PAGE_ALIGN(size);
int err;
- err = get_remap_pgoff(vma->vm_flags, addr, end,
- vma->vm_start, vma->vm_end,
- pfn, &vma->vm_pgoff);
+ err = get_remap_pgoff(is_cow_mapping(vma->vm_flags), addr, end,
+ vma->vm_start, vma->vm_end, pfn, &vma->vm_pgoff);
if (err)
return err;
- vm_flags_set(vma, VM_REMAP_FLAGS);
+ vma_set_flags_mask(vma, VMA_REMAP_FLAGS);
return 0;
}
--
2.52.0
^ permalink raw reply [flat|nested] 56+ messages in thread* Re: [PATCH v2 09/13] mm: update all remaining mmap_prepare users to use vma_flags_t
2026-01-22 16:06 ` [PATCH v2 09/13] mm: update all remaining mmap_prepare users " Lorenzo Stoakes
@ 2026-01-22 23:31 ` Damien Le Moal
2026-01-23 7:47 ` Darrick J. Wong
2026-02-06 17:46 ` Pedro Falcato
2 siblings, 0 replies; 56+ messages in thread
From: Damien Le Moal @ 2026-01-22 23:31 UTC (permalink / raw)
To: Lorenzo Stoakes, Andrew Morton; +Cc: linux-fsdevel, linux-mm
On 2026/01/23 3:06, Lorenzo Stoakes wrote:
> We will be shortly removing the vm_flags_t field from vm_area_desc so we
> need to update all mmap_prepare users to only use the dessc->vma_flags
> field.
>
> This patch achieves that and makes all ancillary changes required to make
> this possible.
>
> This lays the groundwork for future work to eliminate the use of vm_flags_t
> in vm_area_desc altogether and more broadly throughout the kernel.
>
> While we're here, we take the opportunity to replace VM_REMAP_FLAGS with
> VMA_REMAP_FLAGS, the vma_flags_t equivalent.
>
> No functional changes intended.
>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
(reduced distribution list)
For zonefs changes:
Acked-by: Damien Le Moal <dlemoal@kernel.org>
--
Damien Le Moal
Western Digital Research
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH v2 09/13] mm: update all remaining mmap_prepare users to use vma_flags_t
2026-01-22 16:06 ` [PATCH v2 09/13] mm: update all remaining mmap_prepare users " Lorenzo Stoakes
2026-01-22 23:31 ` Damien Le Moal
@ 2026-01-23 7:47 ` Darrick J. Wong
2026-02-06 17:46 ` Pedro Falcato
2 siblings, 0 replies; 56+ messages in thread
From: Darrick J. Wong @ 2026-01-23 7:47 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin,
Arnd Bergmann, Greg Kroah-Hartman, Dan Williams, Vishal Verma,
Dave Jiang, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
On Thu, Jan 22, 2026 at 04:06:18PM +0000, Lorenzo Stoakes wrote:
> We will be shortly removing the vm_flags_t field from vm_area_desc so we
> need to update all mmap_prepare users to only use the dessc->vma_flags
> field.
>
> This patch achieves that and makes all ancillary changes required to make
> this possible.
>
> This lays the groundwork for future work to eliminate the use of vm_flags_t
> in vm_area_desc altogether and more broadly throughout the kernel.
>
> While we're here, we take the opportunity to replace VM_REMAP_FLAGS with
> VMA_REMAP_FLAGS, the vma_flags_t equivalent.
>
> No functional changes intended.
>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
> ---
> drivers/char/mem.c | 6 +++---
> drivers/dax/device.c | 10 +++++-----
> fs/aio.c | 2 +-
> fs/erofs/data.c | 5 +++--
> fs/ext4/file.c | 4 ++--
> fs/ntfs3/file.c | 2 +-
> fs/orangefs/file.c | 4 ++--
> fs/ramfs/file-nommu.c | 2 +-
> fs/resctrl/pseudo_lock.c | 2 +-
> fs/romfs/mmap-nommu.c | 2 +-
> fs/xfs/xfs_file.c | 4 ++--
> fs/zonefs/file.c | 3 ++-
> include/linux/dax.h | 8 ++++----
> include/linux/mm.h | 24 +++++++++++++++++++-----
> kernel/relay.c | 2 +-
> mm/memory.c | 17 ++++++++---------
> 16 files changed, 56 insertions(+), 41 deletions(-)
>
<snip to xfs>
> diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
> index 7874cf745af3..1238ec018bc7 100644
> --- a/fs/xfs/xfs_file.c
> +++ b/fs/xfs/xfs_file.c
> @@ -1974,14 +1974,14 @@ xfs_file_mmap_prepare(
> * We don't support synchronous mappings for non-DAX files and
> * for DAX files if underneath dax_device is not synchronous.
> */
> - if (!daxdev_mapping_supported(desc->vm_flags, file_inode(file),
> + if (!daxdev_mapping_supported(desc, file_inode(file),
> target->bt_daxdev))
> return -EOPNOTSUPP;
>
> file_accessed(file);
> desc->vm_ops = &xfs_file_vm_ops;
> if (IS_DAX(inode))
> - desc->vm_flags |= VM_HUGEPAGE;
> + vma_desc_set_flags(desc, VMA_HUGEPAGE_BIT);
Looks good to me,
Acked-by: "Darrick J. Wong" <djwong@kernel.org>
--D
> return 0;
> }
>
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH v2 09/13] mm: update all remaining mmap_prepare users to use vma_flags_t
2026-01-22 16:06 ` [PATCH v2 09/13] mm: update all remaining mmap_prepare users " Lorenzo Stoakes
2026-01-22 23:31 ` Damien Le Moal
2026-01-23 7:47 ` Darrick J. Wong
@ 2026-02-06 17:46 ` Pedro Falcato
2026-02-06 19:31 ` Andrew Morton
2 siblings, 1 reply; 56+ messages in thread
From: Pedro Falcato @ 2026-02-06 17:46 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin,
Arnd Bergmann, Greg Kroah-Hartman, Dan Williams, Vishal Verma,
Dave Jiang, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, David Howells, Paul Moore, James Morris,
Serge E . Hallyn, Yury Norov, Rasmus Villemoes, linux-sgx,
linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
On Thu, Jan 22, 2026 at 04:06:18PM +0000, Lorenzo Stoakes wrote:
> We will be shortly removing the vm_flags_t field from vm_area_desc so we
> need to update all mmap_prepare users to only use the dessc->vma_flags
> field.
>
> This patch achieves that and makes all ancillary changes required to make
> this possible.
>
> This lays the groundwork for future work to eliminate the use of vm_flags_t
> in vm_area_desc altogether and more broadly throughout the kernel.
>
> While we're here, we take the opportunity to replace VM_REMAP_FLAGS with
> VMA_REMAP_FLAGS, the vma_flags_t equivalent.
>
> No functional changes intended.
>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
> ---
> drivers/char/mem.c | 6 +++---
> drivers/dax/device.c | 10 +++++-----
> fs/aio.c | 2 +-
> fs/erofs/data.c | 5 +++--
> fs/ext4/file.c | 4 ++--
> fs/ntfs3/file.c | 2 +-
> fs/orangefs/file.c | 4 ++--
> fs/ramfs/file-nommu.c | 2 +-
> fs/resctrl/pseudo_lock.c | 2 +-
> fs/romfs/mmap-nommu.c | 2 +-
> fs/xfs/xfs_file.c | 4 ++--
> fs/zonefs/file.c | 3 ++-
> include/linux/dax.h | 8 ++++----
> include/linux/mm.h | 24 +++++++++++++++++++-----
> kernel/relay.c | 2 +-
> mm/memory.c | 17 ++++++++---------
> 16 files changed, 56 insertions(+), 41 deletions(-)
>
> diff --git a/drivers/char/mem.c b/drivers/char/mem.c
> index 52039fae1594..cca4529431f8 100644
> --- a/drivers/char/mem.c
> +++ b/drivers/char/mem.c
> @@ -306,7 +306,7 @@ static unsigned zero_mmap_capabilities(struct file *file)
> /* can't do an in-place private mapping if there's no MMU */
> static inline int private_mapping_ok(struct vm_area_desc *desc)
> {
> - return is_nommu_shared_mapping(desc->vm_flags);
> + return is_nommu_shared_vma_flags(&desc->vma_flags);
> }
> #else
>
> @@ -360,7 +360,7 @@ static int mmap_mem_prepare(struct vm_area_desc *desc)
>
> desc->vm_ops = &mmap_mem_ops;
>
> - /* Remap-pfn-range will mark the range VM_IO. */
> + /* Remap-pfn-range will mark the range with the I/O flag. */
> mmap_action_remap_full(desc, desc->pgoff);
> /* We filter remap errors to -EAGAIN. */
> desc->action.error_hook = mmap_filter_error;
> @@ -520,7 +520,7 @@ static int mmap_zero_prepare(struct vm_area_desc *desc)
> #ifndef CONFIG_MMU
> return -ENOSYS;
> #endif
> - if (desc->vm_flags & VM_SHARED)
> + if (vma_desc_test_flags(desc, VMA_SHARED_BIT))
> return shmem_zero_setup_desc(desc);
>
> desc->action.success_hook = mmap_zero_private_success;
> diff --git a/drivers/dax/device.c b/drivers/dax/device.c
> index 22999a402e02..528e81240c4d 100644
> --- a/drivers/dax/device.c
> +++ b/drivers/dax/device.c
> @@ -13,7 +13,7 @@
> #include "dax-private.h"
> #include "bus.h"
>
> -static int __check_vma(struct dev_dax *dev_dax, vm_flags_t vm_flags,
> +static int __check_vma(struct dev_dax *dev_dax, vma_flags_t flags,
> unsigned long start, unsigned long end, struct file *file,
> const char *func)
> {
> @@ -24,7 +24,7 @@ static int __check_vma(struct dev_dax *dev_dax, vm_flags_t vm_flags,
> return -ENXIO;
>
> /* prevent private mappings from being established */
> - if ((vm_flags & VM_MAYSHARE) != VM_MAYSHARE) {
> + if (!vma_flags_test(&flags, VMA_MAYSHARE_BIT)) {
> dev_info_ratelimited(dev,
> "%s: %s: fail, attempted private mapping\n",
> current->comm, func);
> @@ -53,7 +53,7 @@ static int __check_vma(struct dev_dax *dev_dax, vm_flags_t vm_flags,
> static int check_vma(struct dev_dax *dev_dax, struct vm_area_struct *vma,
> const char *func)
> {
> - return __check_vma(dev_dax, vma->vm_flags, vma->vm_start, vma->vm_end,
> + return __check_vma(dev_dax, vma->flags, vma->vm_start, vma->vm_end,
> vma->vm_file, func);
> }
>
> @@ -306,14 +306,14 @@ static int dax_mmap_prepare(struct vm_area_desc *desc)
> * fault time.
> */
> id = dax_read_lock();
> - rc = __check_vma(dev_dax, desc->vm_flags, desc->start, desc->end, filp,
> + rc = __check_vma(dev_dax, desc->vma_flags, desc->start, desc->end, filp,
> __func__);
> dax_read_unlock(id);
> if (rc)
> return rc;
>
> desc->vm_ops = &dax_vm_ops;
> - desc->vm_flags |= VM_HUGEPAGE;
> + vma_desc_set_flags(desc, VMA_HUGEPAGE_BIT);
> return 0;
> }
>
> diff --git a/fs/aio.c b/fs/aio.c
> index 0a23a8c0717f..59b67b8da1b2 100644
> --- a/fs/aio.c
> +++ b/fs/aio.c
> @@ -394,7 +394,7 @@ static const struct vm_operations_struct aio_ring_vm_ops = {
>
> static int aio_ring_mmap_prepare(struct vm_area_desc *desc)
> {
> - desc->vm_flags |= VM_DONTEXPAND;
> + vma_desc_set_flags(desc, VMA_DONTEXPAND_BIT);
> desc->vm_ops = &aio_ring_vm_ops;
> return 0;
> }
> diff --git a/fs/erofs/data.c b/fs/erofs/data.c
> index bb13c4cb8455..e7bc29e764c6 100644
> --- a/fs/erofs/data.c
> +++ b/fs/erofs/data.c
> @@ -438,11 +438,12 @@ static int erofs_file_mmap_prepare(struct vm_area_desc *desc)
> if (!IS_DAX(file_inode(desc->file)))
> return generic_file_readonly_mmap_prepare(desc);
>
> - if ((desc->vm_flags & VM_SHARED) && (desc->vm_flags & VM_MAYWRITE))
> + if (vma_desc_test_flags(desc, VMA_SHARED_BIT) &&
> + vma_desc_test_flags(desc, VMA_MAYWRITE_BIT))
> return -EINVAL;
>
> desc->vm_ops = &erofs_dax_vm_ops;
> - desc->vm_flags |= VM_HUGEPAGE;
> + vma_desc_set_flags(desc, VMA_HUGEPAGE_BIT);
> return 0;
> }
> #else
> diff --git a/fs/ext4/file.c b/fs/ext4/file.c
> index 7a8b30932189..dfd5f4fe1647 100644
> --- a/fs/ext4/file.c
> +++ b/fs/ext4/file.c
> @@ -822,13 +822,13 @@ static int ext4_file_mmap_prepare(struct vm_area_desc *desc)
> * We don't support synchronous mappings for non-DAX files and
> * for DAX files if underneath dax_device is not synchronous.
> */
> - if (!daxdev_mapping_supported(desc->vm_flags, file_inode(file), dax_dev))
> + if (!daxdev_mapping_supported(desc, file_inode(file), dax_dev))
> return -EOPNOTSUPP;
>
> file_accessed(file);
> if (IS_DAX(file_inode(file))) {
> desc->vm_ops = &ext4_dax_vm_ops;
> - desc->vm_flags |= VM_HUGEPAGE;
> + vma_desc_set_flags(desc, VMA_HUGEPAGE_BIT);
> } else {
> desc->vm_ops = &ext4_file_vm_ops;
> }
> diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c
> index 2e7b2e566ebe..2902fc6d9a85 100644
> --- a/fs/ntfs3/file.c
> +++ b/fs/ntfs3/file.c
> @@ -347,7 +347,7 @@ static int ntfs_file_mmap_prepare(struct vm_area_desc *desc)
> struct inode *inode = file_inode(file);
> struct ntfs_inode *ni = ntfs_i(inode);
> u64 from = ((u64)desc->pgoff << PAGE_SHIFT);
> - bool rw = desc->vm_flags & VM_WRITE;
> + const bool rw = vma_desc_test_flags(desc, VMA_WRITE_BIT);
> int err;
>
> /* Avoid any operation if inode is bad. */
> diff --git a/fs/orangefs/file.c b/fs/orangefs/file.c
> index 919f99b16834..c75aa3f419b1 100644
> --- a/fs/orangefs/file.c
> +++ b/fs/orangefs/file.c
> @@ -411,8 +411,8 @@ static int orangefs_file_mmap_prepare(struct vm_area_desc *desc)
> "orangefs_file_mmap: called on %pD\n", file);
>
> /* set the sequential readahead hint */
> - desc->vm_flags |= VM_SEQ_READ;
> - desc->vm_flags &= ~VM_RAND_READ;
> + vma_desc_set_flags(desc, VMA_SEQ_READ_BIT);
> + vma_desc_clear_flags(desc, VMA_RAND_READ_BIT);
>
> file_accessed(file);
> desc->vm_ops = &orangefs_file_vm_ops;
> diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c
> index 77b8ca2757e0..0f8e838ece07 100644
> --- a/fs/ramfs/file-nommu.c
> +++ b/fs/ramfs/file-nommu.c
> @@ -264,7 +264,7 @@ static unsigned long ramfs_nommu_get_unmapped_area(struct file *file,
> */
> static int ramfs_nommu_mmap_prepare(struct vm_area_desc *desc)
> {
> - if (!is_nommu_shared_mapping(desc->vm_flags))
> + if (!is_nommu_shared_vma_flags(&desc->vma_flags))
> return -ENOSYS;
>
> file_accessed(desc->file);
> diff --git a/fs/resctrl/pseudo_lock.c b/fs/resctrl/pseudo_lock.c
> index 0bfc13c5b96d..e81d71abfe54 100644
> --- a/fs/resctrl/pseudo_lock.c
> +++ b/fs/resctrl/pseudo_lock.c
> @@ -1044,7 +1044,7 @@ static int pseudo_lock_dev_mmap_prepare(struct vm_area_desc *desc)
> * Ensure changes are carried directly to the memory being mapped,
> * do not allow copy-on-write mapping.
> */
> - if (!(desc->vm_flags & VM_SHARED)) {
> + if (!vma_desc_test_flags(desc, VMA_SHARED_BIT)) {
> mutex_unlock(&rdtgroup_mutex);
> return -EINVAL;
> }
> diff --git a/fs/romfs/mmap-nommu.c b/fs/romfs/mmap-nommu.c
> index 4b77c6dc4418..7c3a1a7fecee 100644
> --- a/fs/romfs/mmap-nommu.c
> +++ b/fs/romfs/mmap-nommu.c
> @@ -63,7 +63,7 @@ static unsigned long romfs_get_unmapped_area(struct file *file,
> */
> static int romfs_mmap_prepare(struct vm_area_desc *desc)
> {
> - return is_nommu_shared_mapping(desc->vm_flags) ? 0 : -ENOSYS;
> + return is_nommu_shared_vma_flags(&desc->vma_flags) ? 0 : -ENOSYS;
> }
>
> static unsigned romfs_mmap_capabilities(struct file *file)
> diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
> index 7874cf745af3..1238ec018bc7 100644
> --- a/fs/xfs/xfs_file.c
> +++ b/fs/xfs/xfs_file.c
> @@ -1974,14 +1974,14 @@ xfs_file_mmap_prepare(
> * We don't support synchronous mappings for non-DAX files and
> * for DAX files if underneath dax_device is not synchronous.
> */
> - if (!daxdev_mapping_supported(desc->vm_flags, file_inode(file),
> + if (!daxdev_mapping_supported(desc, file_inode(file),
> target->bt_daxdev))
> return -EOPNOTSUPP;
>
> file_accessed(file);
> desc->vm_ops = &xfs_file_vm_ops;
> if (IS_DAX(inode))
> - desc->vm_flags |= VM_HUGEPAGE;
> + vma_desc_set_flags(desc, VMA_HUGEPAGE_BIT);
> return 0;
> }
>
> diff --git a/fs/zonefs/file.c b/fs/zonefs/file.c
> index c1e5e30e90a0..8a7161fc49e5 100644
> --- a/fs/zonefs/file.c
> +++ b/fs/zonefs/file.c
> @@ -333,7 +333,8 @@ static int zonefs_file_mmap_prepare(struct vm_area_desc *desc)
> * ordering between msync() and page cache writeback.
> */
> if (zonefs_inode_is_seq(file_inode(file)) &&
> - (desc->vm_flags & VM_SHARED) && (desc->vm_flags & VM_MAYWRITE))
> + vma_desc_test_flags(desc, VMA_SHARED_BIT) &&
> + vma_desc_test_flags(desc, VMA_MAYWRITE_BIT))
> return -EINVAL;
>
> file_accessed(file);
> diff --git a/include/linux/dax.h b/include/linux/dax.h
> index 9d624f4d9df6..bf103f317cac 100644
> --- a/include/linux/dax.h
> +++ b/include/linux/dax.h
> @@ -65,11 +65,11 @@ size_t dax_recovery_write(struct dax_device *dax_dev, pgoff_t pgoff,
> /*
> * Check if given mapping is supported by the file / underlying device.
> */
> -static inline bool daxdev_mapping_supported(vm_flags_t vm_flags,
> +static inline bool daxdev_mapping_supported(const struct vm_area_desc *desc,
> const struct inode *inode,
> struct dax_device *dax_dev)
> {
> - if (!(vm_flags & VM_SYNC))
> + if (!vma_desc_test_flags(desc, VMA_SYNC_BIT))
> return true;
> if (!IS_DAX(inode))
> return false;
> @@ -111,11 +111,11 @@ static inline void set_dax_nomc(struct dax_device *dax_dev)
> static inline void set_dax_synchronous(struct dax_device *dax_dev)
> {
> }
> -static inline bool daxdev_mapping_supported(vm_flags_t vm_flags,
> +static inline bool daxdev_mapping_supported(const struct vm_area_desc *desc,
> const struct inode *inode,
> struct dax_device *dax_dev)
> {
> - return !(vm_flags & VM_SYNC);
> + return !vma_desc_test_flags(desc, VMA_SYNC_BIT);
> }
> static inline size_t dax_recovery_write(struct dax_device *dax_dev,
> pgoff_t pgoff, void *addr, size_t bytes, struct iov_iter *i)
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index fd93317193e0..e31f72a021ef 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -550,17 +550,18 @@ enum {
> /*
> * Physically remapped pages are special. Tell the
> * rest of the world about it:
> - * VM_IO tells people not to look at these pages
> + * IO tells people not to look at these pages
> * (accesses can have side effects).
> - * VM_PFNMAP tells the core MM that the base pages are just
> + * PFNMAP tells the core MM that the base pages are just
> * raw PFN mappings, and do not have a "struct page" associated
> * with them.
> - * VM_DONTEXPAND
> + * DONTEXPAND
> * Disable vma merging and expanding with mremap().
> - * VM_DONTDUMP
> + * DONTDUMP
> * Omit vma from core dump, even when VM_IO turned off.
> */
I don't think it's useful to erase the VM_ prefix off the flags. These still
exist, so maybe the alternative would be to rename them to e.g VMA_IO in
comments, etc. I think just saying "IO" or "the I/O flag" above is ambiguous.
> -#define VM_REMAP_FLAGS (VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP)
> +#define VMA_REMAP_FLAGS mk_vma_flags(VMA_IO_BIT, VMA_PFNMAP_BIT, \
> + VMA_DONTEXPAND_BIT, VMA_DONTDUMP_BIT)
as a sidenote, these flags are no longer constant expressions and thus
static vma_flags_t flags = VMA_REMAP_FLAGS;
can't compile.
Rest LGTM though.
Acked-by: Pedro Falcato <pfalcato@suse.de>
--
Pedro
^ permalink raw reply [flat|nested] 56+ messages in thread* Re: [PATCH v2 09/13] mm: update all remaining mmap_prepare users to use vma_flags_t
2026-02-06 17:46 ` Pedro Falcato
@ 2026-02-06 19:31 ` Andrew Morton
2026-02-06 20:01 ` Lorenzo Stoakes
0 siblings, 1 reply; 56+ messages in thread
From: Andrew Morton @ 2026-02-06 19:31 UTC (permalink / raw)
To: Pedro Falcato
Cc: Lorenzo Stoakes, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin,
Arnd Bergmann, Greg Kroah-Hartman, Dan Williams, Vishal Verma,
Dave Jiang, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, David Howells, Paul Moore, James Morris,
Serge E . Hallyn, Yury Norov, Rasmus Villemoes, linux-sgx,
linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
On Fri, 6 Feb 2026 17:46:36 +0000 Pedro Falcato <pfalcato@suse.de> wrote:
> > -#define VM_REMAP_FLAGS (VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP)
> > +#define VMA_REMAP_FLAGS mk_vma_flags(VMA_IO_BIT, VMA_PFNMAP_BIT, \
> > + VMA_DONTEXPAND_BIT, VMA_DONTDUMP_BIT)
>
> as a sidenote, these flags are no longer constant expressions and thus
>
> static vma_flags_t flags = VMA_REMAP_FLAGS;
>
> can't compile.
Yup, that isn't nice. An all-caps thing with no () is a compile-time
constant.
It looks like we can make this a nice inlined (commented!) lower-cased
C function as a little low-priority cleanup.
> Rest LGTM though.
>
> Acked-by: Pedro Falcato <pfalcato@suse.de>
Great, thanks.
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH v2 09/13] mm: update all remaining mmap_prepare users to use vma_flags_t
2026-02-06 19:31 ` Andrew Morton
@ 2026-02-06 20:01 ` Lorenzo Stoakes
2026-02-09 19:27 ` Liam R. Howlett
0 siblings, 1 reply; 56+ messages in thread
From: Lorenzo Stoakes @ 2026-02-06 20:01 UTC (permalink / raw)
To: Andrew Morton
Cc: Pedro Falcato, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin,
Arnd Bergmann, Greg Kroah-Hartman, Dan Williams, Vishal Verma,
Dave Jiang, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, David Howells, Paul Moore, James Morris,
Serge E . Hallyn, Yury Norov, Rasmus Villemoes, linux-sgx,
linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
On Fri, Feb 06, 2026 at 11:31:53AM -0800, Andrew Morton wrote:
> On Fri, 6 Feb 2026 17:46:36 +0000 Pedro Falcato <pfalcato@suse.de> wrote:
>
> > > -#define VM_REMAP_FLAGS (VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP)
> > > +#define VMA_REMAP_FLAGS mk_vma_flags(VMA_IO_BIT, VMA_PFNMAP_BIT, \
> > > + VMA_DONTEXPAND_BIT, VMA_DONTDUMP_BIT)
> >
> > as a sidenote, these flags are no longer constant expressions and thus
> >
> > static vma_flags_t flags = VMA_REMAP_FLAGS;
I mean this would be a code smell anyway :) but point taken.
> >
> > can't compile.
>
> Yup, that isn't nice. An all-caps thing with no () is a compile-time
> constant.
There is precedence for this, e.g. TASK_SIZE_MAX and other arch defines like
that:
error: initializer element is not a compile-time constant
3309 | static unsigned long task_max = TASK_SIZE_MAX;
| ^~~~~~~~~~~~~
And this will almost certainly (and certainly in everything I tested) become a
compile-time constant via the optimiser so to all intents and purposes it _is_
essentially compile-time.
But the point of doing it this way is to maintain, as much as possible,
one-to-one translation between the previous approach and the new with as little
noise/friction as possible.
Making this a function makes things really horrible honestly.
Because vma_remap_flags() suddenly because a vague thing - I'd assume this was a
function doing something. So now do we call it get_vma_remap_flags()? Suddenly
something nice-ish like:
if (vma_flags_test(flags, VMA_REMAP_FLAGS)) {
...
}
Become:
if (vma_flags_test(flags, get_vma_remap_flags())) {
...
}
And now it's SUPER ambiguous as to what you're doing there. I'd assume right
away that get_vma_remap_flags() was going off and doing something or referencing
a static variable or something.
Given the compile will treat the former _exactly_ as if it were a compile-time
constant it's just adding unnecessary ambiguity.
So is it something we can live with?
If it looks like a duck, walks like a duck and quacks like a duck, but isn't
there when the pond is first dug out, can we still call it a duck? ;)
>
> It looks like we can make this a nice inlined (commented!) lower-cased
> C function as a little low-priority cleanup.
>
> > Rest LGTM though.
> >
> > Acked-by: Pedro Falcato <pfalcato@suse.de>
>
> Great, thanks.
Cheers, Lorenzo
^ permalink raw reply [flat|nested] 56+ messages in thread* Re: [PATCH v2 09/13] mm: update all remaining mmap_prepare users to use vma_flags_t
2026-02-06 20:01 ` Lorenzo Stoakes
@ 2026-02-09 19:27 ` Liam R. Howlett
0 siblings, 0 replies; 56+ messages in thread
From: Liam R. Howlett @ 2026-02-09 19:27 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Pedro Falcato, Jarkko Sakkinen, Dave Hansen,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, x86,
H . Peter Anvin, Arnd Bergmann, Greg Kroah-Hartman, Dan Williams,
Vishal Verma, Dave Jiang, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jani Nikula,
Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig,
Huang Rui, Matthew Auld, Matthew Brost, Alexander Viro,
Christian Brauner, Jan Kara, Benjamin LaHaise, Gao Xiang,
Chao Yu, Yue Hu, Jeffle Xu, Sandeep Dhavale, Hongbo Li,
Chunhai Guo, Theodore Ts'o, Andreas Dilger, Muchun Song,
Oscar Salvador, David Hildenbrand, Konstantin Komarov,
Mike Marshall, Martin Brandenburg, Tony Luck, Reinette Chatre,
Dave Martin, James Morse, Babu Moger, Carlos Maiolino,
Damien Le Moal, Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Hugh Dickins, Baolin Wang, Zi Yan, Nico Pache, Ryan Roberts,
Dev Jain, Barry Song, Lance Yang, Jann Horn, David Howells,
Paul Moore, James Morris, Serge E . Hallyn, Yury Norov,
Rasmus Villemoes, linux-sgx, linux-kernel, nvdimm, linux-cxl,
dri-devel, intel-gfx, linux-fsdevel, linux-aio, linux-erofs,
linux-ext4, linux-mm, ntfs3, devel, linux-xfs, keyrings,
linux-security-module, Jason Gunthorpe
* Lorenzo Stoakes <lorenzo.stoakes@oracle.com> [260206 20:01]:
> On Fri, Feb 06, 2026 at 11:31:53AM -0800, Andrew Morton wrote:
> > On Fri, 6 Feb 2026 17:46:36 +0000 Pedro Falcato <pfalcato@suse.de> wrote:
> >
> > > > -#define VM_REMAP_FLAGS (VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP)
> > > > +#define VMA_REMAP_FLAGS mk_vma_flags(VMA_IO_BIT, VMA_PFNMAP_BIT, \
> > > > + VMA_DONTEXPAND_BIT, VMA_DONTDUMP_BIT)
> > >
> > > as a sidenote, these flags are no longer constant expressions and thus
> > >
> > > static vma_flags_t flags = VMA_REMAP_FLAGS;
>
> I mean this would be a code smell anyway :) but point taken.
>
> > >
> > > can't compile.
> >
> > Yup, that isn't nice. An all-caps thing with no () is a compile-time
> > constant.
>
> There is precedence for this, e.g. TASK_SIZE_MAX and other arch defines like
> that:
>
> error: initializer element is not a compile-time constant
> 3309 | static unsigned long task_max = TASK_SIZE_MAX;
> | ^~~~~~~~~~~~~
>
> And this will almost certainly (and certainly in everything I tested) become a
> compile-time constant via the optimiser so to all intents and purposes it _is_
> essentially compile-time.
>
> But the point of doing it this way is to maintain, as much as possible,
> one-to-one translation between the previous approach and the new with as little
> noise/friction as possible.
>
> Making this a function makes things really horrible honestly.
>
> Because vma_remap_flags() suddenly because a vague thing - I'd assume this was a
> function doing something. So now do we call it get_vma_remap_flags()? Suddenly
> something nice-ish like:
>
> if (vma_flags_test(flags, VMA_REMAP_FLAGS)) {
> ...
> }
>
> Become:
>
> if (vma_flags_test(flags, get_vma_remap_flags())) {
> ...
> }
>
> And now it's SUPER ambiguous as to what you're doing there. I'd assume right
> away that get_vma_remap_flags() was going off and doing something or referencing
> a static variable or something.
>
> Given the compile will treat the former _exactly_ as if it were a compile-time
> constant it's just adding unnecessary ambiguity.
>
> So is it something we can live with?
How many of these are there going to be? Could we do something like:
static inline remap_vma_flags_test(..) {
return vma_flags_test_all(vma_flags, ...);
}
if (remap_vma_flags_test(vma_flags)) {
...
}
^ permalink raw reply [flat|nested] 56+ messages in thread
* [PATCH v2 10/13] mm: make vm_area_desc utilise vma_flags_t only
2026-01-22 16:06 [PATCH v2 00/13] mm: add bitmap VMA flag helpers and convert all mmap_prepare to use them Lorenzo Stoakes
` (8 preceding siblings ...)
2026-01-22 16:06 ` [PATCH v2 09/13] mm: update all remaining mmap_prepare users " Lorenzo Stoakes
@ 2026-01-22 16:06 ` Lorenzo Stoakes
2026-02-06 17:49 ` Pedro Falcato
2026-02-09 19:32 ` Liam R. Howlett
2026-01-22 16:06 ` [PATCH v2 11/13] tools/testing/vma: separate VMA userland tests into separate files Lorenzo Stoakes
` (4 subsequent siblings)
14 siblings, 2 replies; 56+ messages in thread
From: Lorenzo Stoakes @ 2026-01-22 16:06 UTC (permalink / raw)
To: Andrew Morton
Cc: Jarkko Sakkinen, Dave Hansen, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, x86, H . Peter Anvin, Arnd Bergmann,
Greg Kroah-Hartman, Dan Williams, Vishal Verma, Dave Jiang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
Now we have eliminated all uses of vm_area_desc->vm_flags, eliminate this
field, and have mmap_prepare users utilise the vma_flags_t
vm_area_desc->vma_flags field only.
As part of this change we alter is_shared_maywrite() to accept a
vma_flags_t parameter, and introduce is_shared_maywrite_vm_flags() for use
with legacy vm_flags_t flags.
We also update struct mmap_state to add a union between vma_flags and
vm_flags temporarily until the mmap logic is also converted to using
vma_flags_t.
Also update the VMA userland tests to reflect this change.
Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
---
include/linux/mm.h | 9 +++++++--
include/linux/mm_types.h | 5 +----
mm/filemap.c | 2 +-
mm/util.c | 2 +-
mm/vma.c | 11 +++++++----
mm/vma.h | 3 +--
tools/testing/vma/vma_internal.h | 9 +++++++--
7 files changed, 25 insertions(+), 16 deletions(-)
diff --git a/include/linux/mm.h b/include/linux/mm.h
index e31f72a021ef..37e215de3343 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1290,15 +1290,20 @@ static inline bool vma_is_accessible(const struct vm_area_struct *vma)
return vma->vm_flags & VM_ACCESS_FLAGS;
}
-static inline bool is_shared_maywrite(vm_flags_t vm_flags)
+static inline bool is_shared_maywrite_vm_flags(vm_flags_t vm_flags)
{
return (vm_flags & (VM_SHARED | VM_MAYWRITE)) ==
(VM_SHARED | VM_MAYWRITE);
}
+static inline bool is_shared_maywrite(const vma_flags_t *flags)
+{
+ return vma_flags_test_all(flags, VMA_SHARED_BIT, VMA_MAYWRITE_BIT);
+}
+
static inline bool vma_is_shared_maywrite(const struct vm_area_struct *vma)
{
- return is_shared_maywrite(vma->vm_flags);
+ return is_shared_maywrite(&vma->flags);
}
static inline
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index cdac328b46dc..6d98ff6bc2e5 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -887,10 +887,7 @@ struct vm_area_desc {
/* Mutable fields. Populated with initial state. */
pgoff_t pgoff;
struct file *vm_file;
- union {
- vm_flags_t vm_flags;
- vma_flags_t vma_flags;
- };
+ vma_flags_t vma_flags;
pgprot_t page_prot;
/* Write-only fields. */
diff --git a/mm/filemap.c b/mm/filemap.c
index ebd75684cb0a..6cd7974d4ada 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -4012,7 +4012,7 @@ int generic_file_readonly_mmap(struct file *file, struct vm_area_struct *vma)
int generic_file_readonly_mmap_prepare(struct vm_area_desc *desc)
{
- if (is_shared_maywrite(desc->vm_flags))
+ if (is_shared_maywrite(&desc->vma_flags))
return -EINVAL;
return generic_file_mmap_prepare(desc);
}
diff --git a/mm/util.c b/mm/util.c
index 97cae40c0209..b05ab6f97e11 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -1154,7 +1154,7 @@ int __compat_vma_mmap(const struct file_operations *f_op,
.pgoff = vma->vm_pgoff,
.vm_file = vma->vm_file,
- .vm_flags = vma->vm_flags,
+ .vma_flags = vma->flags,
.page_prot = vma->vm_page_prot,
.action.type = MMAP_NOTHING, /* Default */
diff --git a/mm/vma.c b/mm/vma.c
index 39dcd9ddd4ba..be64f781a3aa 100644
--- a/mm/vma.c
+++ b/mm/vma.c
@@ -15,7 +15,10 @@ struct mmap_state {
unsigned long end;
pgoff_t pgoff;
unsigned long pglen;
- vm_flags_t vm_flags;
+ union {
+ vm_flags_t vm_flags;
+ vma_flags_t vma_flags;
+ };
struct file *file;
pgprot_t page_prot;
@@ -2369,7 +2372,7 @@ static void set_desc_from_map(struct vm_area_desc *desc,
desc->pgoff = map->pgoff;
desc->vm_file = map->file;
- desc->vm_flags = map->vm_flags;
+ desc->vma_flags = map->vma_flags;
desc->page_prot = map->page_prot;
}
@@ -2650,7 +2653,7 @@ static int call_mmap_prepare(struct mmap_state *map,
map->file_doesnt_need_get = true;
map->file = desc->vm_file;
}
- map->vm_flags = desc->vm_flags;
+ map->vma_flags = desc->vma_flags;
map->page_prot = desc->page_prot;
/* User-defined fields. */
map->vm_ops = desc->vm_ops;
@@ -2823,7 +2826,7 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
return -EINVAL;
/* Map writable and ensure this isn't a sealed memfd. */
- if (file && is_shared_maywrite(vm_flags)) {
+ if (file && is_shared_maywrite_vm_flags(vm_flags)) {
int error = mapping_map_writable(file->f_mapping);
if (error)
diff --git a/mm/vma.h b/mm/vma.h
index bb7fa5d2bde2..062672df8a65 100644
--- a/mm/vma.h
+++ b/mm/vma.h
@@ -286,8 +286,7 @@ static inline void set_vma_from_desc(struct vm_area_struct *vma,
vma->vm_pgoff = desc->pgoff;
if (desc->vm_file != vma->vm_file)
vma_set_file(vma, desc->vm_file);
- if (desc->vm_flags != vma->vm_flags)
- vm_flags_set(vma, desc->vm_flags);
+ vma->flags = desc->vma_flags;
vma->vm_page_prot = desc->page_prot;
/* User-defined fields. */
diff --git a/tools/testing/vma/vma_internal.h b/tools/testing/vma/vma_internal.h
index 2b01794cbd61..2743f12ecf32 100644
--- a/tools/testing/vma/vma_internal.h
+++ b/tools/testing/vma/vma_internal.h
@@ -1009,15 +1009,20 @@ static inline void vma_desc_clear_flags_mask(struct vm_area_desc *desc,
#define vma_desc_clear_flags(desc, ...) \
vma_desc_clear_flags_mask(desc, mk_vma_flags(__VA_ARGS__))
-static inline bool is_shared_maywrite(vm_flags_t vm_flags)
+static inline bool is_shared_maywrite_vm_flags(vm_flags_t vm_flags)
{
return (vm_flags & (VM_SHARED | VM_MAYWRITE)) ==
(VM_SHARED | VM_MAYWRITE);
}
+static inline bool is_shared_maywrite(const vma_flags_t *flags)
+{
+ return vma_flags_test_all(flags, VMA_SHARED_BIT, VMA_MAYWRITE_BIT);
+}
+
static inline bool vma_is_shared_maywrite(struct vm_area_struct *vma)
{
- return is_shared_maywrite(vma->vm_flags);
+ return is_shared_maywrite(&vma->flags);
}
static inline struct vm_area_struct *vma_next(struct vma_iterator *vmi)
--
2.52.0
^ permalink raw reply [flat|nested] 56+ messages in thread* Re: [PATCH v2 10/13] mm: make vm_area_desc utilise vma_flags_t only
2026-01-22 16:06 ` [PATCH v2 10/13] mm: make vm_area_desc utilise vma_flags_t only Lorenzo Stoakes
@ 2026-02-06 17:49 ` Pedro Falcato
2026-02-09 19:32 ` Liam R. Howlett
1 sibling, 0 replies; 56+ messages in thread
From: Pedro Falcato @ 2026-02-06 17:49 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin,
Arnd Bergmann, Greg Kroah-Hartman, Dan Williams, Vishal Verma,
Dave Jiang, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, David Howells, Paul Moore, James Morris,
Serge E . Hallyn, Yury Norov, Rasmus Villemoes, linux-sgx,
linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
On Thu, Jan 22, 2026 at 04:06:19PM +0000, Lorenzo Stoakes wrote:
> Now we have eliminated all uses of vm_area_desc->vm_flags, eliminate this
> field, and have mmap_prepare users utilise the vma_flags_t
> vm_area_desc->vma_flags field only.
>
> As part of this change we alter is_shared_maywrite() to accept a
> vma_flags_t parameter, and introduce is_shared_maywrite_vm_flags() for use
> with legacy vm_flags_t flags.
>
> We also update struct mmap_state to add a union between vma_flags and
> vm_flags temporarily until the mmap logic is also converted to using
> vma_flags_t.
>
> Also update the VMA userland tests to reflect this change.
>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Reviewed-by: Pedro Falcato <pfalcato@suse.de>
--
Pedro
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH v2 10/13] mm: make vm_area_desc utilise vma_flags_t only
2026-01-22 16:06 ` [PATCH v2 10/13] mm: make vm_area_desc utilise vma_flags_t only Lorenzo Stoakes
2026-02-06 17:49 ` Pedro Falcato
@ 2026-02-09 19:32 ` Liam R. Howlett
1 sibling, 0 replies; 56+ messages in thread
From: Liam R. Howlett @ 2026-02-09 19:32 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin,
Arnd Bergmann, Greg Kroah-Hartman, Dan Williams, Vishal Verma,
Dave Jiang, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Hugh Dickins, Baolin Wang, Zi Yan, Nico Pache, Ryan Roberts,
Dev Jain, Barry Song, Lance Yang, Jann Horn, Pedro Falcato,
David Howells, Paul Moore, James Morris, Serge E . Hallyn,
Yury Norov, Rasmus Villemoes, linux-sgx, linux-kernel, nvdimm,
linux-cxl, dri-devel, intel-gfx, linux-fsdevel, linux-aio,
linux-erofs, linux-ext4, linux-mm, ntfs3, devel, linux-xfs,
keyrings, linux-security-module, Jason Gunthorpe
* Lorenzo Stoakes <lorenzo.stoakes@oracle.com> [260122 16:06]:
> Now we have eliminated all uses of vm_area_desc->vm_flags, eliminate this
> field, and have mmap_prepare users utilise the vma_flags_t
> vm_area_desc->vma_flags field only.
>
> As part of this change we alter is_shared_maywrite() to accept a
> vma_flags_t parameter, and introduce is_shared_maywrite_vm_flags() for use
> with legacy vm_flags_t flags.
>
> We also update struct mmap_state to add a union between vma_flags and
> vm_flags temporarily until the mmap logic is also converted to using
> vma_flags_t.
>
> Also update the VMA userland tests to reflect this change.
>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Reviewed-by: Liam R. Howlett <Liam.Howlett@oracle.com>
> ---
> include/linux/mm.h | 9 +++++++--
> include/linux/mm_types.h | 5 +----
> mm/filemap.c | 2 +-
> mm/util.c | 2 +-
> mm/vma.c | 11 +++++++----
> mm/vma.h | 3 +--
> tools/testing/vma/vma_internal.h | 9 +++++++--
> 7 files changed, 25 insertions(+), 16 deletions(-)
>
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index e31f72a021ef..37e215de3343 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -1290,15 +1290,20 @@ static inline bool vma_is_accessible(const struct vm_area_struct *vma)
> return vma->vm_flags & VM_ACCESS_FLAGS;
> }
>
> -static inline bool is_shared_maywrite(vm_flags_t vm_flags)
> +static inline bool is_shared_maywrite_vm_flags(vm_flags_t vm_flags)
> {
> return (vm_flags & (VM_SHARED | VM_MAYWRITE)) ==
> (VM_SHARED | VM_MAYWRITE);
> }
>
> +static inline bool is_shared_maywrite(const vma_flags_t *flags)
> +{
> + return vma_flags_test_all(flags, VMA_SHARED_BIT, VMA_MAYWRITE_BIT);
> +}
> +
Confusing git diff here, but looks okay.
> static inline bool vma_is_shared_maywrite(const struct vm_area_struct *vma)
> {
> - return is_shared_maywrite(vma->vm_flags);
> + return is_shared_maywrite(&vma->flags);
> }
>
> static inline
> diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
> index cdac328b46dc..6d98ff6bc2e5 100644
> --- a/include/linux/mm_types.h
> +++ b/include/linux/mm_types.h
> @@ -887,10 +887,7 @@ struct vm_area_desc {
> /* Mutable fields. Populated with initial state. */
> pgoff_t pgoff;
> struct file *vm_file;
> - union {
> - vm_flags_t vm_flags;
> - vma_flags_t vma_flags;
> - };
> + vma_flags_t vma_flags;
> pgprot_t page_prot;
>
> /* Write-only fields. */
> diff --git a/mm/filemap.c b/mm/filemap.c
> index ebd75684cb0a..6cd7974d4ada 100644
> --- a/mm/filemap.c
> +++ b/mm/filemap.c
> @@ -4012,7 +4012,7 @@ int generic_file_readonly_mmap(struct file *file, struct vm_area_struct *vma)
>
> int generic_file_readonly_mmap_prepare(struct vm_area_desc *desc)
> {
> - if (is_shared_maywrite(desc->vm_flags))
> + if (is_shared_maywrite(&desc->vma_flags))
> return -EINVAL;
> return generic_file_mmap_prepare(desc);
> }
> diff --git a/mm/util.c b/mm/util.c
> index 97cae40c0209..b05ab6f97e11 100644
> --- a/mm/util.c
> +++ b/mm/util.c
> @@ -1154,7 +1154,7 @@ int __compat_vma_mmap(const struct file_operations *f_op,
>
> .pgoff = vma->vm_pgoff,
> .vm_file = vma->vm_file,
> - .vm_flags = vma->vm_flags,
> + .vma_flags = vma->flags,
> .page_prot = vma->vm_page_prot,
>
> .action.type = MMAP_NOTHING, /* Default */
> diff --git a/mm/vma.c b/mm/vma.c
> index 39dcd9ddd4ba..be64f781a3aa 100644
> --- a/mm/vma.c
> +++ b/mm/vma.c
> @@ -15,7 +15,10 @@ struct mmap_state {
> unsigned long end;
> pgoff_t pgoff;
> unsigned long pglen;
> - vm_flags_t vm_flags;
> + union {
> + vm_flags_t vm_flags;
> + vma_flags_t vma_flags;
> + };
> struct file *file;
> pgprot_t page_prot;
>
> @@ -2369,7 +2372,7 @@ static void set_desc_from_map(struct vm_area_desc *desc,
>
> desc->pgoff = map->pgoff;
> desc->vm_file = map->file;
> - desc->vm_flags = map->vm_flags;
> + desc->vma_flags = map->vma_flags;
> desc->page_prot = map->page_prot;
> }
>
> @@ -2650,7 +2653,7 @@ static int call_mmap_prepare(struct mmap_state *map,
> map->file_doesnt_need_get = true;
> map->file = desc->vm_file;
> }
> - map->vm_flags = desc->vm_flags;
> + map->vma_flags = desc->vma_flags;
> map->page_prot = desc->page_prot;
> /* User-defined fields. */
> map->vm_ops = desc->vm_ops;
> @@ -2823,7 +2826,7 @@ unsigned long mmap_region(struct file *file, unsigned long addr,
> return -EINVAL;
>
> /* Map writable and ensure this isn't a sealed memfd. */
> - if (file && is_shared_maywrite(vm_flags)) {
> + if (file && is_shared_maywrite_vm_flags(vm_flags)) {
> int error = mapping_map_writable(file->f_mapping);
>
> if (error)
> diff --git a/mm/vma.h b/mm/vma.h
> index bb7fa5d2bde2..062672df8a65 100644
> --- a/mm/vma.h
> +++ b/mm/vma.h
> @@ -286,8 +286,7 @@ static inline void set_vma_from_desc(struct vm_area_struct *vma,
> vma->vm_pgoff = desc->pgoff;
> if (desc->vm_file != vma->vm_file)
> vma_set_file(vma, desc->vm_file);
> - if (desc->vm_flags != vma->vm_flags)
> - vm_flags_set(vma, desc->vm_flags);
> + vma->flags = desc->vma_flags;
> vma->vm_page_prot = desc->page_prot;
>
> /* User-defined fields. */
> diff --git a/tools/testing/vma/vma_internal.h b/tools/testing/vma/vma_internal.h
> index 2b01794cbd61..2743f12ecf32 100644
> --- a/tools/testing/vma/vma_internal.h
> +++ b/tools/testing/vma/vma_internal.h
> @@ -1009,15 +1009,20 @@ static inline void vma_desc_clear_flags_mask(struct vm_area_desc *desc,
> #define vma_desc_clear_flags(desc, ...) \
> vma_desc_clear_flags_mask(desc, mk_vma_flags(__VA_ARGS__))
>
> -static inline bool is_shared_maywrite(vm_flags_t vm_flags)
> +static inline bool is_shared_maywrite_vm_flags(vm_flags_t vm_flags)
> {
> return (vm_flags & (VM_SHARED | VM_MAYWRITE)) ==
> (VM_SHARED | VM_MAYWRITE);
> }
>
> +static inline bool is_shared_maywrite(const vma_flags_t *flags)
> +{
> + return vma_flags_test_all(flags, VMA_SHARED_BIT, VMA_MAYWRITE_BIT);
> +}
> +
> static inline bool vma_is_shared_maywrite(struct vm_area_struct *vma)
> {
> - return is_shared_maywrite(vma->vm_flags);
> + return is_shared_maywrite(&vma->flags);
> }
>
> static inline struct vm_area_struct *vma_next(struct vma_iterator *vmi)
> --
> 2.52.0
>
^ permalink raw reply [flat|nested] 56+ messages in thread
* [PATCH v2 11/13] tools/testing/vma: separate VMA userland tests into separate files
2026-01-22 16:06 [PATCH v2 00/13] mm: add bitmap VMA flag helpers and convert all mmap_prepare to use them Lorenzo Stoakes
` (9 preceding siblings ...)
2026-01-22 16:06 ` [PATCH v2 10/13] mm: make vm_area_desc utilise vma_flags_t only Lorenzo Stoakes
@ 2026-01-22 16:06 ` Lorenzo Stoakes
2026-02-09 19:58 ` Liam R. Howlett
2026-01-22 16:06 ` [PATCH v2 12/13] tools/testing/vma: separate out vma_internal.h into logical headers Lorenzo Stoakes
` (3 subsequent siblings)
14 siblings, 1 reply; 56+ messages in thread
From: Lorenzo Stoakes @ 2026-01-22 16:06 UTC (permalink / raw)
To: Andrew Morton
Cc: Jarkko Sakkinen, Dave Hansen, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, x86, H . Peter Anvin, Arnd Bergmann,
Greg Kroah-Hartman, Dan Williams, Vishal Verma, Dave Jiang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
So far the userland VMA tests have been established as a rough expression
of what's been possible.
qAdapt it into a more usable form by separating out tests and shared helper
functions.
Since we test functions that are declared statically in mm/vma.c, we make
use of the trick of #include'ing kernel C files directly.
In order for the tests to continue to function, we must therefore also
this way into the tests/ directory.
We try to keep as much shared logic actually modularised into a separate
compilation unit in shared.c, however the merge_existing() and attach_vma()
helpers rely on statically declared mm/vma.c functions so these must be
declared in main.c.
Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
---
tools/testing/vma/Makefile | 4 +-
tools/testing/vma/main.c | 55 ++++
tools/testing/vma/shared.c | 131 ++++++++
tools/testing/vma/shared.h | 114 +++++++
tools/testing/vma/{vma.c => tests/merge.c} | 332 +--------------------
tools/testing/vma/tests/mmap.c | 57 ++++
tools/testing/vma/tests/vma.c | 39 +++
tools/testing/vma/vma_internal.h | 9 -
8 files changed, 406 insertions(+), 335 deletions(-)
create mode 100644 tools/testing/vma/main.c
create mode 100644 tools/testing/vma/shared.c
create mode 100644 tools/testing/vma/shared.h
rename tools/testing/vma/{vma.c => tests/merge.c} (82%)
create mode 100644 tools/testing/vma/tests/mmap.c
create mode 100644 tools/testing/vma/tests/vma.c
diff --git a/tools/testing/vma/Makefile b/tools/testing/vma/Makefile
index 66f3831a668f..94133d9d3955 100644
--- a/tools/testing/vma/Makefile
+++ b/tools/testing/vma/Makefile
@@ -6,10 +6,10 @@ default: vma
include ../shared/shared.mk
-OFILES = $(SHARED_OFILES) vma.o maple-shim.o
+OFILES = $(SHARED_OFILES) main.o shared.o maple-shim.o
TARGETS = vma
-vma.o: vma.c vma_internal.h ../../../mm/vma.c ../../../mm/vma_init.c ../../../mm/vma_exec.c ../../../mm/vma.h
+main.o: main.c shared.c shared.h vma_internal.h tests/merge.c tests/mmap.c tests/vma.c ../../../mm/vma.c ../../../mm/vma_init.c ../../../mm/vma_exec.c ../../../mm/vma.h
vma: $(OFILES)
$(CC) $(CFLAGS) -o $@ $(OFILES) $(LDLIBS)
diff --git a/tools/testing/vma/main.c b/tools/testing/vma/main.c
new file mode 100644
index 000000000000..49b09e97a51f
--- /dev/null
+++ b/tools/testing/vma/main.c
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "shared.h"
+/*
+ * Directly import the VMA implementation here. Our vma_internal.h wrapper
+ * provides userland-equivalent functionality for everything vma.c uses.
+ */
+#include "../../../mm/vma_init.c"
+#include "../../../mm/vma_exec.c"
+#include "../../../mm/vma.c"
+
+/* Tests are included directly so they can test static functions in mm/vma.c. */
+#include "tests/merge.c"
+#include "tests/mmap.c"
+#include "tests/vma.c"
+
+/* Helper functions which utilise static kernel functions. */
+
+struct vm_area_struct *merge_existing(struct vma_merge_struct *vmg)
+{
+ struct vm_area_struct *vma;
+
+ vma = vma_merge_existing_range(vmg);
+ if (vma)
+ vma_assert_attached(vma);
+ return vma;
+}
+
+int attach_vma(struct mm_struct *mm, struct vm_area_struct *vma)
+{
+ int res;
+
+ res = vma_link(mm, vma);
+ if (!res)
+ vma_assert_attached(vma);
+ return res;
+}
+
+/* Main test running which invokes tests/ *.c runners. */
+int main(void)
+{
+ int num_tests = 0, num_fail = 0;
+
+ maple_tree_init();
+ vma_state_init();
+
+ run_merge_tests(&num_tests, &num_fail);
+ run_mmap_tests(&num_tests, &num_fail);
+ run_vma_tests(&num_tests, &num_fail);
+
+ printf("%d tests run, %d passed, %d failed.\n",
+ num_tests, num_tests - num_fail, num_fail);
+
+ return num_fail == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/tools/testing/vma/shared.c b/tools/testing/vma/shared.c
new file mode 100644
index 000000000000..bda578cc3304
--- /dev/null
+++ b/tools/testing/vma/shared.c
@@ -0,0 +1,131 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "shared.h"
+
+
+bool fail_prealloc;
+unsigned long mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR;
+unsigned long dac_mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR;
+unsigned long stack_guard_gap = 256UL<<PAGE_SHIFT;
+
+const struct vm_operations_struct vma_dummy_vm_ops;
+struct anon_vma dummy_anon_vma;
+struct task_struct __current;
+
+struct vm_area_struct *alloc_vma(struct mm_struct *mm,
+ unsigned long start, unsigned long end,
+ pgoff_t pgoff, vm_flags_t vm_flags)
+{
+ struct vm_area_struct *vma = vm_area_alloc(mm);
+
+ if (vma == NULL)
+ return NULL;
+
+ vma->vm_start = start;
+ vma->vm_end = end;
+ vma->vm_pgoff = pgoff;
+ vm_flags_reset(vma, vm_flags);
+ vma_assert_detached(vma);
+
+ return vma;
+}
+
+void detach_free_vma(struct vm_area_struct *vma)
+{
+ vma_mark_detached(vma);
+ vm_area_free(vma);
+}
+
+struct vm_area_struct *alloc_and_link_vma(struct mm_struct *mm,
+ unsigned long start, unsigned long end,
+ pgoff_t pgoff, vm_flags_t vm_flags)
+{
+ struct vm_area_struct *vma = alloc_vma(mm, start, end, pgoff, vm_flags);
+
+ if (vma == NULL)
+ return NULL;
+
+ if (attach_vma(mm, vma)) {
+ detach_free_vma(vma);
+ return NULL;
+ }
+
+ /*
+ * Reset this counter which we use to track whether writes have
+ * begun. Linking to the tree will have caused this to be incremented,
+ * which means we will get a false positive otherwise.
+ */
+ vma->vm_lock_seq = UINT_MAX;
+
+ return vma;
+}
+
+void reset_dummy_anon_vma(void)
+{
+ dummy_anon_vma.was_cloned = false;
+ dummy_anon_vma.was_unlinked = false;
+}
+
+int cleanup_mm(struct mm_struct *mm, struct vma_iterator *vmi)
+{
+ struct vm_area_struct *vma;
+ int count = 0;
+
+ fail_prealloc = false;
+ reset_dummy_anon_vma();
+
+ vma_iter_set(vmi, 0);
+ for_each_vma(*vmi, vma) {
+ detach_free_vma(vma);
+ count++;
+ }
+
+ mtree_destroy(&mm->mm_mt);
+ mm->map_count = 0;
+ return count;
+}
+
+bool vma_write_started(struct vm_area_struct *vma)
+{
+ int seq = vma->vm_lock_seq;
+
+ /* We reset after each check. */
+ vma->vm_lock_seq = UINT_MAX;
+
+ /* The vma_start_write() stub simply increments this value. */
+ return seq > -1;
+}
+
+void __vma_set_dummy_anon_vma(struct vm_area_struct *vma,
+ struct anon_vma_chain *avc, struct anon_vma *anon_vma)
+{
+ vma->anon_vma = anon_vma;
+ INIT_LIST_HEAD(&vma->anon_vma_chain);
+ list_add(&avc->same_vma, &vma->anon_vma_chain);
+ avc->anon_vma = vma->anon_vma;
+}
+
+void vma_set_dummy_anon_vma(struct vm_area_struct *vma,
+ struct anon_vma_chain *avc)
+{
+ __vma_set_dummy_anon_vma(vma, avc, &dummy_anon_vma);
+}
+
+struct task_struct *get_current(void)
+{
+ return &__current;
+}
+
+unsigned long rlimit(unsigned int limit)
+{
+ return (unsigned long)-1;
+}
+
+void vma_set_range(struct vm_area_struct *vma,
+ unsigned long start, unsigned long end,
+ pgoff_t pgoff)
+{
+ vma->vm_start = start;
+ vma->vm_end = end;
+ vma->vm_pgoff = pgoff;
+}
diff --git a/tools/testing/vma/shared.h b/tools/testing/vma/shared.h
new file mode 100644
index 000000000000..6c64211cfa22
--- /dev/null
+++ b/tools/testing/vma/shared.h
@@ -0,0 +1,114 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "generated/bit-length.h"
+#include "maple-shared.h"
+#include "vma_internal.h"
+#include "../../../mm/vma.h"
+
+/* Simple test runner. Assumes local num_[fail, tests] counters. */
+#define TEST(name) \
+ do { \
+ (*num_tests)++; \
+ if (!test_##name()) { \
+ (*num_fail)++; \
+ fprintf(stderr, "Test " #name " FAILED\n"); \
+ } \
+ } while (0)
+
+#define ASSERT_TRUE(_expr) \
+ do { \
+ if (!(_expr)) { \
+ fprintf(stderr, \
+ "Assert FAILED at %s:%d:%s(): %s is FALSE.\n", \
+ __FILE__, __LINE__, __FUNCTION__, #_expr); \
+ return false; \
+ } \
+ } while (0)
+
+#define ASSERT_FALSE(_expr) ASSERT_TRUE(!(_expr))
+#define ASSERT_EQ(_val1, _val2) ASSERT_TRUE((_val1) == (_val2))
+#define ASSERT_NE(_val1, _val2) ASSERT_TRUE((_val1) != (_val2))
+
+#define IS_SET(_val, _flags) ((_val & _flags) == _flags)
+
+extern bool fail_prealloc;
+
+/* Override vma_iter_prealloc() so we can choose to fail it. */
+#define vma_iter_prealloc(vmi, vma) \
+ (fail_prealloc ? -ENOMEM : mas_preallocate(&(vmi)->mas, (vma), GFP_KERNEL))
+
+#define CONFIG_DEFAULT_MMAP_MIN_ADDR 65536
+
+extern unsigned long mmap_min_addr;
+extern unsigned long dac_mmap_min_addr;
+extern unsigned long stack_guard_gap;
+
+extern const struct vm_operations_struct vma_dummy_vm_ops;
+extern struct anon_vma dummy_anon_vma;
+extern struct task_struct __current;
+
+/*
+ * Helper function which provides a wrapper around a merge existing VMA
+ * operation.
+ *
+ * Declared in main.c as uses static VMA function.
+ */
+struct vm_area_struct *merge_existing(struct vma_merge_struct *vmg);
+
+/*
+ * Helper function to allocate a VMA and link it to the tree.
+ *
+ * Declared in main.c as uses static VMA function.
+ */
+int attach_vma(struct mm_struct *mm, struct vm_area_struct *vma);
+
+/* Helper function providing a dummy vm_ops->close() method.*/
+static inline void dummy_close(struct vm_area_struct *)
+{
+}
+
+/* Helper function to simply allocate a VMA. */
+struct vm_area_struct *alloc_vma(struct mm_struct *mm,
+ unsigned long start, unsigned long end,
+ pgoff_t pgoff, vm_flags_t vm_flags);
+
+/* Helper function to detach and free a VMA. */
+void detach_free_vma(struct vm_area_struct *vma);
+
+/* Helper function to allocate a VMA and link it to the tree. */
+struct vm_area_struct *alloc_and_link_vma(struct mm_struct *mm,
+ unsigned long start, unsigned long end,
+ pgoff_t pgoff, vm_flags_t vm_flags);
+
+/*
+ * Helper function to reset the dummy anon_vma to indicate it has not been
+ * duplicated.
+ */
+void reset_dummy_anon_vma(void);
+
+/*
+ * Helper function to remove all VMAs and destroy the maple tree associated with
+ * a virtual address space. Returns a count of VMAs in the tree.
+ */
+int cleanup_mm(struct mm_struct *mm, struct vma_iterator *vmi);
+
+/* Helper function to determine if VMA has had vma_start_write() performed. */
+bool vma_write_started(struct vm_area_struct *vma);
+
+void __vma_set_dummy_anon_vma(struct vm_area_struct *vma,
+ struct anon_vma_chain *avc, struct anon_vma *anon_vma);
+
+/* Provide a simple dummy VMA/anon_vma dummy setup for testing. */
+void vma_set_dummy_anon_vma(struct vm_area_struct *vma,
+ struct anon_vma_chain *avc);
+
+/* Helper function to specify a VMA's range. */
+void vma_set_range(struct vm_area_struct *vma,
+ unsigned long start, unsigned long end,
+ pgoff_t pgoff);
diff --git a/tools/testing/vma/vma.c b/tools/testing/vma/tests/merge.c
similarity index 82%
rename from tools/testing/vma/vma.c
rename to tools/testing/vma/tests/merge.c
index 93d21bc7e112..3708dc6945b0 100644
--- a/tools/testing/vma/vma.c
+++ b/tools/testing/vma/tests/merge.c
@@ -1,132 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-or-later
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "generated/bit-length.h"
-
-#include "maple-shared.h"
-#include "vma_internal.h"
-
-/* Include so header guard set. */
-#include "../../../mm/vma.h"
-
-static bool fail_prealloc;
-
-/* Then override vma_iter_prealloc() so we can choose to fail it. */
-#define vma_iter_prealloc(vmi, vma) \
- (fail_prealloc ? -ENOMEM : mas_preallocate(&(vmi)->mas, (vma), GFP_KERNEL))
-
-#define CONFIG_DEFAULT_MMAP_MIN_ADDR 65536
-
-unsigned long mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR;
-unsigned long dac_mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR;
-unsigned long stack_guard_gap = 256UL<<PAGE_SHIFT;
-
-/*
- * Directly import the VMA implementation here. Our vma_internal.h wrapper
- * provides userland-equivalent functionality for everything vma.c uses.
- */
-#include "../../../mm/vma_init.c"
-#include "../../../mm/vma_exec.c"
-#include "../../../mm/vma.c"
-
-const struct vm_operations_struct vma_dummy_vm_ops;
-static struct anon_vma dummy_anon_vma;
-
-#define ASSERT_TRUE(_expr) \
- do { \
- if (!(_expr)) { \
- fprintf(stderr, \
- "Assert FAILED at %s:%d:%s(): %s is FALSE.\n", \
- __FILE__, __LINE__, __FUNCTION__, #_expr); \
- return false; \
- } \
- } while (0)
-#define ASSERT_FALSE(_expr) ASSERT_TRUE(!(_expr))
-#define ASSERT_EQ(_val1, _val2) ASSERT_TRUE((_val1) == (_val2))
-#define ASSERT_NE(_val1, _val2) ASSERT_TRUE((_val1) != (_val2))
-
-#define IS_SET(_val, _flags) ((_val & _flags) == _flags)
-
-static struct task_struct __current;
-
-struct task_struct *get_current(void)
-{
- return &__current;
-}
-
-unsigned long rlimit(unsigned int limit)
-{
- return (unsigned long)-1;
-}
-
-/* Helper function to simply allocate a VMA. */
-static struct vm_area_struct *alloc_vma(struct mm_struct *mm,
- unsigned long start,
- unsigned long end,
- pgoff_t pgoff,
- vm_flags_t vm_flags)
-{
- struct vm_area_struct *vma = vm_area_alloc(mm);
-
- if (vma == NULL)
- return NULL;
-
- vma->vm_start = start;
- vma->vm_end = end;
- vma->vm_pgoff = pgoff;
- vm_flags_reset(vma, vm_flags);
- vma_assert_detached(vma);
-
- return vma;
-}
-
-/* Helper function to allocate a VMA and link it to the tree. */
-static int attach_vma(struct mm_struct *mm, struct vm_area_struct *vma)
-{
- int res;
-
- res = vma_link(mm, vma);
- if (!res)
- vma_assert_attached(vma);
- return res;
-}
-
-static void detach_free_vma(struct vm_area_struct *vma)
-{
- vma_mark_detached(vma);
- vm_area_free(vma);
-}
-
-/* Helper function to allocate a VMA and link it to the tree. */
-static struct vm_area_struct *alloc_and_link_vma(struct mm_struct *mm,
- unsigned long start,
- unsigned long end,
- pgoff_t pgoff,
- vm_flags_t vm_flags)
-{
- struct vm_area_struct *vma = alloc_vma(mm, start, end, pgoff, vm_flags);
-
- if (vma == NULL)
- return NULL;
-
- if (attach_vma(mm, vma)) {
- detach_free_vma(vma);
- return NULL;
- }
-
- /*
- * Reset this counter which we use to track whether writes have
- * begun. Linking to the tree will have caused this to be incremented,
- * which means we will get a false positive otherwise.
- */
- vma->vm_lock_seq = UINT_MAX;
-
- return vma;
-}
-
/* Helper function which provides a wrapper around a merge new VMA operation. */
static struct vm_area_struct *merge_new(struct vma_merge_struct *vmg)
{
@@ -146,20 +19,6 @@ static struct vm_area_struct *merge_new(struct vma_merge_struct *vmg)
return vma;
}
-/*
- * Helper function which provides a wrapper around a merge existing VMA
- * operation.
- */
-static struct vm_area_struct *merge_existing(struct vma_merge_struct *vmg)
-{
- struct vm_area_struct *vma;
-
- vma = vma_merge_existing_range(vmg);
- if (vma)
- vma_assert_attached(vma);
- return vma;
-}
-
/*
* Helper function which provides a wrapper around the expansion of an existing
* VMA.
@@ -173,8 +32,8 @@ static int expand_existing(struct vma_merge_struct *vmg)
* Helper function to reset merge state the associated VMA iterator to a
* specified new range.
*/
-static void vmg_set_range(struct vma_merge_struct *vmg, unsigned long start,
- unsigned long end, pgoff_t pgoff, vm_flags_t vm_flags)
+void vmg_set_range(struct vma_merge_struct *vmg, unsigned long start,
+ unsigned long end, pgoff_t pgoff, vm_flags_t vm_flags)
{
vma_iter_set(vmg->vmi, start);
@@ -197,8 +56,8 @@ static void vmg_set_range(struct vma_merge_struct *vmg, unsigned long start,
/* Helper function to set both the VMG range and its anon_vma. */
static void vmg_set_range_anon_vma(struct vma_merge_struct *vmg, unsigned long start,
- unsigned long end, pgoff_t pgoff, vm_flags_t vm_flags,
- struct anon_vma *anon_vma)
+ unsigned long end, pgoff_t pgoff, vm_flags_t vm_flags,
+ struct anon_vma *anon_vma)
{
vmg_set_range(vmg, start, end, pgoff, vm_flags);
vmg->anon_vma = anon_vma;
@@ -211,10 +70,9 @@ static void vmg_set_range_anon_vma(struct vma_merge_struct *vmg, unsigned long s
* VMA, link it to the maple tree and return it.
*/
static struct vm_area_struct *try_merge_new_vma(struct mm_struct *mm,
- struct vma_merge_struct *vmg,
- unsigned long start, unsigned long end,
- pgoff_t pgoff, vm_flags_t vm_flags,
- bool *was_merged)
+ struct vma_merge_struct *vmg, unsigned long start,
+ unsigned long end, pgoff_t pgoff, vm_flags_t vm_flags,
+ bool *was_merged)
{
struct vm_area_struct *merged;
@@ -234,72 +92,6 @@ static struct vm_area_struct *try_merge_new_vma(struct mm_struct *mm,
return alloc_and_link_vma(mm, start, end, pgoff, vm_flags);
}
-/*
- * Helper function to reset the dummy anon_vma to indicate it has not been
- * duplicated.
- */
-static void reset_dummy_anon_vma(void)
-{
- dummy_anon_vma.was_cloned = false;
- dummy_anon_vma.was_unlinked = false;
-}
-
-/*
- * Helper function to remove all VMAs and destroy the maple tree associated with
- * a virtual address space. Returns a count of VMAs in the tree.
- */
-static int cleanup_mm(struct mm_struct *mm, struct vma_iterator *vmi)
-{
- struct vm_area_struct *vma;
- int count = 0;
-
- fail_prealloc = false;
- reset_dummy_anon_vma();
-
- vma_iter_set(vmi, 0);
- for_each_vma(*vmi, vma) {
- detach_free_vma(vma);
- count++;
- }
-
- mtree_destroy(&mm->mm_mt);
- mm->map_count = 0;
- return count;
-}
-
-/* Helper function to determine if VMA has had vma_start_write() performed. */
-static bool vma_write_started(struct vm_area_struct *vma)
-{
- int seq = vma->vm_lock_seq;
-
- /* We reset after each check. */
- vma->vm_lock_seq = UINT_MAX;
-
- /* The vma_start_write() stub simply increments this value. */
- return seq > -1;
-}
-
-/* Helper function providing a dummy vm_ops->close() method.*/
-static void dummy_close(struct vm_area_struct *)
-{
-}
-
-static void __vma_set_dummy_anon_vma(struct vm_area_struct *vma,
- struct anon_vma_chain *avc,
- struct anon_vma *anon_vma)
-{
- vma->anon_vma = anon_vma;
- INIT_LIST_HEAD(&vma->anon_vma_chain);
- list_add(&avc->same_vma, &vma->anon_vma_chain);
- avc->anon_vma = vma->anon_vma;
-}
-
-static void vma_set_dummy_anon_vma(struct vm_area_struct *vma,
- struct anon_vma_chain *avc)
-{
- __vma_set_dummy_anon_vma(vma, avc, &dummy_anon_vma);
-}
-
static bool test_simple_merge(void)
{
struct vm_area_struct *vma;
@@ -1616,39 +1408,6 @@ static bool test_merge_extend(void)
return true;
}
-static bool test_copy_vma(void)
-{
- vm_flags_t vm_flags = VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE;
- struct mm_struct mm = {};
- bool need_locks = false;
- VMA_ITERATOR(vmi, &mm, 0);
- struct vm_area_struct *vma, *vma_new, *vma_next;
-
- /* Move backwards and do not merge. */
-
- vma = alloc_and_link_vma(&mm, 0x3000, 0x5000, 3, vm_flags);
- vma_new = copy_vma(&vma, 0, 0x2000, 0, &need_locks);
- ASSERT_NE(vma_new, vma);
- ASSERT_EQ(vma_new->vm_start, 0);
- ASSERT_EQ(vma_new->vm_end, 0x2000);
- ASSERT_EQ(vma_new->vm_pgoff, 0);
- vma_assert_attached(vma_new);
-
- cleanup_mm(&mm, &vmi);
-
- /* Move a VMA into position next to another and merge the two. */
-
- vma = alloc_and_link_vma(&mm, 0, 0x2000, 0, vm_flags);
- vma_next = alloc_and_link_vma(&mm, 0x6000, 0x8000, 6, vm_flags);
- vma_new = copy_vma(&vma, 0x4000, 0x2000, 4, &need_locks);
- vma_assert_attached(vma_new);
-
- ASSERT_EQ(vma_new, vma_next);
-
- cleanup_mm(&mm, &vmi);
- return true;
-}
-
static bool test_expand_only_mode(void)
{
vm_flags_t vm_flags = VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE;
@@ -1689,73 +1448,8 @@ static bool test_expand_only_mode(void)
return true;
}
-static bool test_mmap_region_basic(void)
-{
- struct mm_struct mm = {};
- unsigned long addr;
- struct vm_area_struct *vma;
- VMA_ITERATOR(vmi, &mm, 0);
-
- current->mm = &mm;
-
- /* Map at 0x300000, length 0x3000. */
- addr = __mmap_region(NULL, 0x300000, 0x3000,
- VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
- 0x300, NULL);
- ASSERT_EQ(addr, 0x300000);
-
- /* Map at 0x250000, length 0x3000. */
- addr = __mmap_region(NULL, 0x250000, 0x3000,
- VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
- 0x250, NULL);
- ASSERT_EQ(addr, 0x250000);
-
- /* Map at 0x303000, merging to 0x300000 of length 0x6000. */
- addr = __mmap_region(NULL, 0x303000, 0x3000,
- VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
- 0x303, NULL);
- ASSERT_EQ(addr, 0x303000);
-
- /* Map at 0x24d000, merging to 0x250000 of length 0x6000. */
- addr = __mmap_region(NULL, 0x24d000, 0x3000,
- VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
- 0x24d, NULL);
- ASSERT_EQ(addr, 0x24d000);
-
- ASSERT_EQ(mm.map_count, 2);
-
- for_each_vma(vmi, vma) {
- if (vma->vm_start == 0x300000) {
- ASSERT_EQ(vma->vm_end, 0x306000);
- ASSERT_EQ(vma->vm_pgoff, 0x300);
- } else if (vma->vm_start == 0x24d000) {
- ASSERT_EQ(vma->vm_end, 0x253000);
- ASSERT_EQ(vma->vm_pgoff, 0x24d);
- } else {
- ASSERT_FALSE(true);
- }
- }
-
- cleanup_mm(&mm, &vmi);
- return true;
-}
-
-int main(void)
+static void run_merge_tests(int *num_tests, int *num_fail)
{
- int num_tests = 0, num_fail = 0;
-
- maple_tree_init();
- vma_state_init();
-
-#define TEST(name) \
- do { \
- num_tests++; \
- if (!test_##name()) { \
- num_fail++; \
- fprintf(stderr, "Test " #name " FAILED\n"); \
- } \
- } while (0)
-
/* Very simple tests to kick the tyres. */
TEST(simple_merge);
TEST(simple_modify);
@@ -1771,15 +1465,5 @@ int main(void)
TEST(dup_anon_vma);
TEST(vmi_prealloc_fail);
TEST(merge_extend);
- TEST(copy_vma);
TEST(expand_only_mode);
-
- TEST(mmap_region_basic);
-
-#undef TEST
-
- printf("%d tests run, %d passed, %d failed.\n",
- num_tests, num_tests - num_fail, num_fail);
-
- return num_fail == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
diff --git a/tools/testing/vma/tests/mmap.c b/tools/testing/vma/tests/mmap.c
new file mode 100644
index 000000000000..bded4ecbe5db
--- /dev/null
+++ b/tools/testing/vma/tests/mmap.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+static bool test_mmap_region_basic(void)
+{
+ struct mm_struct mm = {};
+ unsigned long addr;
+ struct vm_area_struct *vma;
+ VMA_ITERATOR(vmi, &mm, 0);
+
+ current->mm = &mm;
+
+ /* Map at 0x300000, length 0x3000. */
+ addr = __mmap_region(NULL, 0x300000, 0x3000,
+ VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
+ 0x300, NULL);
+ ASSERT_EQ(addr, 0x300000);
+
+ /* Map at 0x250000, length 0x3000. */
+ addr = __mmap_region(NULL, 0x250000, 0x3000,
+ VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
+ 0x250, NULL);
+ ASSERT_EQ(addr, 0x250000);
+
+ /* Map at 0x303000, merging to 0x300000 of length 0x6000. */
+ addr = __mmap_region(NULL, 0x303000, 0x3000,
+ VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
+ 0x303, NULL);
+ ASSERT_EQ(addr, 0x303000);
+
+ /* Map at 0x24d000, merging to 0x250000 of length 0x6000. */
+ addr = __mmap_region(NULL, 0x24d000, 0x3000,
+ VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
+ 0x24d, NULL);
+ ASSERT_EQ(addr, 0x24d000);
+
+ ASSERT_EQ(mm.map_count, 2);
+
+ for_each_vma(vmi, vma) {
+ if (vma->vm_start == 0x300000) {
+ ASSERT_EQ(vma->vm_end, 0x306000);
+ ASSERT_EQ(vma->vm_pgoff, 0x300);
+ } else if (vma->vm_start == 0x24d000) {
+ ASSERT_EQ(vma->vm_end, 0x253000);
+ ASSERT_EQ(vma->vm_pgoff, 0x24d);
+ } else {
+ ASSERT_FALSE(true);
+ }
+ }
+
+ cleanup_mm(&mm, &vmi);
+ return true;
+}
+
+static void run_mmap_tests(int *num_tests, int *num_fail)
+{
+ TEST(mmap_region_basic);
+}
diff --git a/tools/testing/vma/tests/vma.c b/tools/testing/vma/tests/vma.c
new file mode 100644
index 000000000000..6d9775aee243
--- /dev/null
+++ b/tools/testing/vma/tests/vma.c
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+static bool test_copy_vma(void)
+{
+ vm_flags_t vm_flags = VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE;
+ struct mm_struct mm = {};
+ bool need_locks = false;
+ VMA_ITERATOR(vmi, &mm, 0);
+ struct vm_area_struct *vma, *vma_new, *vma_next;
+
+ /* Move backwards and do not merge. */
+
+ vma = alloc_and_link_vma(&mm, 0x3000, 0x5000, 3, vm_flags);
+ vma_new = copy_vma(&vma, 0, 0x2000, 0, &need_locks);
+ ASSERT_NE(vma_new, vma);
+ ASSERT_EQ(vma_new->vm_start, 0);
+ ASSERT_EQ(vma_new->vm_end, 0x2000);
+ ASSERT_EQ(vma_new->vm_pgoff, 0);
+ vma_assert_attached(vma_new);
+
+ cleanup_mm(&mm, &vmi);
+
+ /* Move a VMA into position next to another and merge the two. */
+
+ vma = alloc_and_link_vma(&mm, 0, 0x2000, 0, vm_flags);
+ vma_next = alloc_and_link_vma(&mm, 0x6000, 0x8000, 6, vm_flags);
+ vma_new = copy_vma(&vma, 0x4000, 0x2000, 4, &need_locks);
+ vma_assert_attached(vma_new);
+
+ ASSERT_EQ(vma_new, vma_next);
+
+ cleanup_mm(&mm, &vmi);
+ return true;
+}
+
+static void run_vma_tests(int *num_tests, int *num_fail)
+{
+ TEST(copy_vma);
+}
diff --git a/tools/testing/vma/vma_internal.h b/tools/testing/vma/vma_internal.h
index 2743f12ecf32..b48ebae3927d 100644
--- a/tools/testing/vma/vma_internal.h
+++ b/tools/testing/vma/vma_internal.h
@@ -1127,15 +1127,6 @@ static inline void mapping_allow_writable(struct address_space *mapping)
atomic_inc(&mapping->i_mmap_writable);
}
-static inline void vma_set_range(struct vm_area_struct *vma,
- unsigned long start, unsigned long end,
- pgoff_t pgoff)
-{
- vma->vm_start = start;
- vma->vm_end = end;
- vma->vm_pgoff = pgoff;
-}
-
static inline
struct vm_area_struct *vma_find(struct vma_iterator *vmi, unsigned long max)
{
--
2.52.0
^ permalink raw reply [flat|nested] 56+ messages in thread* Re: [PATCH v2 11/13] tools/testing/vma: separate VMA userland tests into separate files
2026-01-22 16:06 ` [PATCH v2 11/13] tools/testing/vma: separate VMA userland tests into separate files Lorenzo Stoakes
@ 2026-02-09 19:58 ` Liam R. Howlett
2026-02-10 17:44 ` Lorenzo Stoakes
0 siblings, 1 reply; 56+ messages in thread
From: Liam R. Howlett @ 2026-02-09 19:58 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin,
Arnd Bergmann, Greg Kroah-Hartman, Dan Williams, Vishal Verma,
Dave Jiang, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Hugh Dickins, Baolin Wang, Zi Yan, Nico Pache, Ryan Roberts,
Dev Jain, Barry Song, Lance Yang, Jann Horn, Pedro Falcato,
David Howells, Paul Moore, James Morris, Serge E . Hallyn,
Yury Norov, Rasmus Villemoes, linux-sgx, linux-kernel, nvdimm,
linux-cxl, dri-devel, intel-gfx, linux-fsdevel, linux-aio,
linux-erofs, linux-ext4, linux-mm, ntfs3, devel, linux-xfs,
keyrings, linux-security-module, Jason Gunthorpe
* Lorenzo Stoakes <lorenzo.stoakes@oracle.com> [260122 16:06]:
> So far the userland VMA tests have been established as a rough expression
> of what's been possible.
>
> qAdapt it into a more usable form by separating out tests and shared helper
^^^^ Typo
> functions.
>
> Since we test functions that are declared statically in mm/vma.c, we make
> use of the trick of #include'ing kernel C files directly.
>
> In order for the tests to continue to function, we must therefore also
> this way into the tests/ directory.
>
> We try to keep as much shared logic actually modularised into a separate
> compilation unit in shared.c, however the merge_existing() and attach_vma()
> helpers rely on statically declared mm/vma.c functions so these must be
> declared in main.c.
>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Besides that typo, it looks good.
Reviewed-by: Liam R. Howlett <Liam.Howlett@oracle.com>
> ---
> tools/testing/vma/Makefile | 4 +-
> tools/testing/vma/main.c | 55 ++++
> tools/testing/vma/shared.c | 131 ++++++++
> tools/testing/vma/shared.h | 114 +++++++
> tools/testing/vma/{vma.c => tests/merge.c} | 332 +--------------------
> tools/testing/vma/tests/mmap.c | 57 ++++
> tools/testing/vma/tests/vma.c | 39 +++
> tools/testing/vma/vma_internal.h | 9 -
> 8 files changed, 406 insertions(+), 335 deletions(-)
> create mode 100644 tools/testing/vma/main.c
> create mode 100644 tools/testing/vma/shared.c
> create mode 100644 tools/testing/vma/shared.h
> rename tools/testing/vma/{vma.c => tests/merge.c} (82%)
> create mode 100644 tools/testing/vma/tests/mmap.c
> create mode 100644 tools/testing/vma/tests/vma.c
>
> diff --git a/tools/testing/vma/Makefile b/tools/testing/vma/Makefile
> index 66f3831a668f..94133d9d3955 100644
> --- a/tools/testing/vma/Makefile
> +++ b/tools/testing/vma/Makefile
> @@ -6,10 +6,10 @@ default: vma
>
> include ../shared/shared.mk
>
> -OFILES = $(SHARED_OFILES) vma.o maple-shim.o
> +OFILES = $(SHARED_OFILES) main.o shared.o maple-shim.o
> TARGETS = vma
>
> -vma.o: vma.c vma_internal.h ../../../mm/vma.c ../../../mm/vma_init.c ../../../mm/vma_exec.c ../../../mm/vma.h
> +main.o: main.c shared.c shared.h vma_internal.h tests/merge.c tests/mmap.c tests/vma.c ../../../mm/vma.c ../../../mm/vma_init.c ../../../mm/vma_exec.c ../../../mm/vma.h
>
> vma: $(OFILES)
> $(CC) $(CFLAGS) -o $@ $(OFILES) $(LDLIBS)
> diff --git a/tools/testing/vma/main.c b/tools/testing/vma/main.c
> new file mode 100644
> index 000000000000..49b09e97a51f
> --- /dev/null
> +++ b/tools/testing/vma/main.c
> @@ -0,0 +1,55 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +
> +#include "shared.h"
> +/*
> + * Directly import the VMA implementation here. Our vma_internal.h wrapper
> + * provides userland-equivalent functionality for everything vma.c uses.
> + */
> +#include "../../../mm/vma_init.c"
> +#include "../../../mm/vma_exec.c"
> +#include "../../../mm/vma.c"
> +
> +/* Tests are included directly so they can test static functions in mm/vma.c. */
> +#include "tests/merge.c"
> +#include "tests/mmap.c"
> +#include "tests/vma.c"
> +
> +/* Helper functions which utilise static kernel functions. */
> +
> +struct vm_area_struct *merge_existing(struct vma_merge_struct *vmg)
> +{
> + struct vm_area_struct *vma;
> +
> + vma = vma_merge_existing_range(vmg);
> + if (vma)
> + vma_assert_attached(vma);
> + return vma;
> +}
> +
> +int attach_vma(struct mm_struct *mm, struct vm_area_struct *vma)
> +{
> + int res;
> +
> + res = vma_link(mm, vma);
> + if (!res)
> + vma_assert_attached(vma);
> + return res;
> +}
> +
> +/* Main test running which invokes tests/ *.c runners. */
> +int main(void)
> +{
> + int num_tests = 0, num_fail = 0;
> +
> + maple_tree_init();
> + vma_state_init();
> +
> + run_merge_tests(&num_tests, &num_fail);
> + run_mmap_tests(&num_tests, &num_fail);
> + run_vma_tests(&num_tests, &num_fail);
> +
> + printf("%d tests run, %d passed, %d failed.\n",
> + num_tests, num_tests - num_fail, num_fail);
> +
> + return num_fail == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
> +}
> diff --git a/tools/testing/vma/shared.c b/tools/testing/vma/shared.c
> new file mode 100644
> index 000000000000..bda578cc3304
> --- /dev/null
> +++ b/tools/testing/vma/shared.c
> @@ -0,0 +1,131 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +
> +#include "shared.h"
> +
> +
> +bool fail_prealloc;
> +unsigned long mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR;
> +unsigned long dac_mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR;
> +unsigned long stack_guard_gap = 256UL<<PAGE_SHIFT;
> +
> +const struct vm_operations_struct vma_dummy_vm_ops;
> +struct anon_vma dummy_anon_vma;
> +struct task_struct __current;
> +
> +struct vm_area_struct *alloc_vma(struct mm_struct *mm,
> + unsigned long start, unsigned long end,
> + pgoff_t pgoff, vm_flags_t vm_flags)
> +{
> + struct vm_area_struct *vma = vm_area_alloc(mm);
> +
> + if (vma == NULL)
> + return NULL;
> +
> + vma->vm_start = start;
> + vma->vm_end = end;
> + vma->vm_pgoff = pgoff;
> + vm_flags_reset(vma, vm_flags);
> + vma_assert_detached(vma);
> +
> + return vma;
> +}
> +
> +void detach_free_vma(struct vm_area_struct *vma)
> +{
> + vma_mark_detached(vma);
> + vm_area_free(vma);
> +}
> +
> +struct vm_area_struct *alloc_and_link_vma(struct mm_struct *mm,
> + unsigned long start, unsigned long end,
> + pgoff_t pgoff, vm_flags_t vm_flags)
> +{
> + struct vm_area_struct *vma = alloc_vma(mm, start, end, pgoff, vm_flags);
> +
> + if (vma == NULL)
> + return NULL;
> +
> + if (attach_vma(mm, vma)) {
> + detach_free_vma(vma);
> + return NULL;
> + }
> +
> + /*
> + * Reset this counter which we use to track whether writes have
> + * begun. Linking to the tree will have caused this to be incremented,
> + * which means we will get a false positive otherwise.
> + */
> + vma->vm_lock_seq = UINT_MAX;
> +
> + return vma;
> +}
> +
> +void reset_dummy_anon_vma(void)
> +{
> + dummy_anon_vma.was_cloned = false;
> + dummy_anon_vma.was_unlinked = false;
> +}
> +
> +int cleanup_mm(struct mm_struct *mm, struct vma_iterator *vmi)
> +{
> + struct vm_area_struct *vma;
> + int count = 0;
> +
> + fail_prealloc = false;
> + reset_dummy_anon_vma();
> +
> + vma_iter_set(vmi, 0);
> + for_each_vma(*vmi, vma) {
> + detach_free_vma(vma);
> + count++;
> + }
> +
> + mtree_destroy(&mm->mm_mt);
> + mm->map_count = 0;
> + return count;
> +}
> +
> +bool vma_write_started(struct vm_area_struct *vma)
> +{
> + int seq = vma->vm_lock_seq;
> +
> + /* We reset after each check. */
> + vma->vm_lock_seq = UINT_MAX;
> +
> + /* The vma_start_write() stub simply increments this value. */
> + return seq > -1;
> +}
> +
> +void __vma_set_dummy_anon_vma(struct vm_area_struct *vma,
> + struct anon_vma_chain *avc, struct anon_vma *anon_vma)
> +{
> + vma->anon_vma = anon_vma;
> + INIT_LIST_HEAD(&vma->anon_vma_chain);
> + list_add(&avc->same_vma, &vma->anon_vma_chain);
> + avc->anon_vma = vma->anon_vma;
> +}
> +
> +void vma_set_dummy_anon_vma(struct vm_area_struct *vma,
> + struct anon_vma_chain *avc)
> +{
> + __vma_set_dummy_anon_vma(vma, avc, &dummy_anon_vma);
> +}
> +
> +struct task_struct *get_current(void)
> +{
> + return &__current;
> +}
> +
> +unsigned long rlimit(unsigned int limit)
> +{
> + return (unsigned long)-1;
> +}
> +
> +void vma_set_range(struct vm_area_struct *vma,
> + unsigned long start, unsigned long end,
> + pgoff_t pgoff)
> +{
> + vma->vm_start = start;
> + vma->vm_end = end;
> + vma->vm_pgoff = pgoff;
> +}
> diff --git a/tools/testing/vma/shared.h b/tools/testing/vma/shared.h
> new file mode 100644
> index 000000000000..6c64211cfa22
> --- /dev/null
> +++ b/tools/testing/vma/shared.h
> @@ -0,0 +1,114 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +
> +#pragma once
> +
> +#include <stdbool.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +
> +#include "generated/bit-length.h"
> +#include "maple-shared.h"
> +#include "vma_internal.h"
> +#include "../../../mm/vma.h"
> +
> +/* Simple test runner. Assumes local num_[fail, tests] counters. */
> +#define TEST(name) \
> + do { \
> + (*num_tests)++; \
> + if (!test_##name()) { \
> + (*num_fail)++; \
> + fprintf(stderr, "Test " #name " FAILED\n"); \
> + } \
> + } while (0)
> +
> +#define ASSERT_TRUE(_expr) \
> + do { \
> + if (!(_expr)) { \
> + fprintf(stderr, \
> + "Assert FAILED at %s:%d:%s(): %s is FALSE.\n", \
> + __FILE__, __LINE__, __FUNCTION__, #_expr); \
> + return false; \
> + } \
> + } while (0)
> +
> +#define ASSERT_FALSE(_expr) ASSERT_TRUE(!(_expr))
> +#define ASSERT_EQ(_val1, _val2) ASSERT_TRUE((_val1) == (_val2))
> +#define ASSERT_NE(_val1, _val2) ASSERT_TRUE((_val1) != (_val2))
> +
> +#define IS_SET(_val, _flags) ((_val & _flags) == _flags)
> +
> +extern bool fail_prealloc;
> +
> +/* Override vma_iter_prealloc() so we can choose to fail it. */
> +#define vma_iter_prealloc(vmi, vma) \
> + (fail_prealloc ? -ENOMEM : mas_preallocate(&(vmi)->mas, (vma), GFP_KERNEL))
> +
> +#define CONFIG_DEFAULT_MMAP_MIN_ADDR 65536
> +
> +extern unsigned long mmap_min_addr;
> +extern unsigned long dac_mmap_min_addr;
> +extern unsigned long stack_guard_gap;
> +
> +extern const struct vm_operations_struct vma_dummy_vm_ops;
> +extern struct anon_vma dummy_anon_vma;
> +extern struct task_struct __current;
> +
> +/*
> + * Helper function which provides a wrapper around a merge existing VMA
> + * operation.
> + *
> + * Declared in main.c as uses static VMA function.
> + */
> +struct vm_area_struct *merge_existing(struct vma_merge_struct *vmg);
> +
> +/*
> + * Helper function to allocate a VMA and link it to the tree.
> + *
> + * Declared in main.c as uses static VMA function.
> + */
> +int attach_vma(struct mm_struct *mm, struct vm_area_struct *vma);
> +
> +/* Helper function providing a dummy vm_ops->close() method.*/
> +static inline void dummy_close(struct vm_area_struct *)
> +{
> +}
> +
> +/* Helper function to simply allocate a VMA. */
> +struct vm_area_struct *alloc_vma(struct mm_struct *mm,
> + unsigned long start, unsigned long end,
> + pgoff_t pgoff, vm_flags_t vm_flags);
> +
> +/* Helper function to detach and free a VMA. */
> +void detach_free_vma(struct vm_area_struct *vma);
> +
> +/* Helper function to allocate a VMA and link it to the tree. */
> +struct vm_area_struct *alloc_and_link_vma(struct mm_struct *mm,
> + unsigned long start, unsigned long end,
> + pgoff_t pgoff, vm_flags_t vm_flags);
> +
> +/*
> + * Helper function to reset the dummy anon_vma to indicate it has not been
> + * duplicated.
> + */
> +void reset_dummy_anon_vma(void);
> +
> +/*
> + * Helper function to remove all VMAs and destroy the maple tree associated with
> + * a virtual address space. Returns a count of VMAs in the tree.
> + */
> +int cleanup_mm(struct mm_struct *mm, struct vma_iterator *vmi);
> +
> +/* Helper function to determine if VMA has had vma_start_write() performed. */
> +bool vma_write_started(struct vm_area_struct *vma);
> +
> +void __vma_set_dummy_anon_vma(struct vm_area_struct *vma,
> + struct anon_vma_chain *avc, struct anon_vma *anon_vma);
> +
> +/* Provide a simple dummy VMA/anon_vma dummy setup for testing. */
> +void vma_set_dummy_anon_vma(struct vm_area_struct *vma,
> + struct anon_vma_chain *avc);
> +
> +/* Helper function to specify a VMA's range. */
> +void vma_set_range(struct vm_area_struct *vma,
> + unsigned long start, unsigned long end,
> + pgoff_t pgoff);
> diff --git a/tools/testing/vma/vma.c b/tools/testing/vma/tests/merge.c
> similarity index 82%
> rename from tools/testing/vma/vma.c
> rename to tools/testing/vma/tests/merge.c
> index 93d21bc7e112..3708dc6945b0 100644
> --- a/tools/testing/vma/vma.c
> +++ b/tools/testing/vma/tests/merge.c
> @@ -1,132 +1,5 @@
> // SPDX-License-Identifier: GPL-2.0-or-later
>
> -#include <stdbool.h>
> -#include <stdio.h>
> -#include <stdlib.h>
> -
> -#include "generated/bit-length.h"
> -
> -#include "maple-shared.h"
> -#include "vma_internal.h"
> -
> -/* Include so header guard set. */
> -#include "../../../mm/vma.h"
> -
> -static bool fail_prealloc;
> -
> -/* Then override vma_iter_prealloc() so we can choose to fail it. */
> -#define vma_iter_prealloc(vmi, vma) \
> - (fail_prealloc ? -ENOMEM : mas_preallocate(&(vmi)->mas, (vma), GFP_KERNEL))
> -
> -#define CONFIG_DEFAULT_MMAP_MIN_ADDR 65536
> -
> -unsigned long mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR;
> -unsigned long dac_mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR;
> -unsigned long stack_guard_gap = 256UL<<PAGE_SHIFT;
> -
> -/*
> - * Directly import the VMA implementation here. Our vma_internal.h wrapper
> - * provides userland-equivalent functionality for everything vma.c uses.
> - */
> -#include "../../../mm/vma_init.c"
> -#include "../../../mm/vma_exec.c"
> -#include "../../../mm/vma.c"
> -
> -const struct vm_operations_struct vma_dummy_vm_ops;
> -static struct anon_vma dummy_anon_vma;
> -
> -#define ASSERT_TRUE(_expr) \
> - do { \
> - if (!(_expr)) { \
> - fprintf(stderr, \
> - "Assert FAILED at %s:%d:%s(): %s is FALSE.\n", \
> - __FILE__, __LINE__, __FUNCTION__, #_expr); \
> - return false; \
> - } \
> - } while (0)
> -#define ASSERT_FALSE(_expr) ASSERT_TRUE(!(_expr))
> -#define ASSERT_EQ(_val1, _val2) ASSERT_TRUE((_val1) == (_val2))
> -#define ASSERT_NE(_val1, _val2) ASSERT_TRUE((_val1) != (_val2))
> -
> -#define IS_SET(_val, _flags) ((_val & _flags) == _flags)
> -
> -static struct task_struct __current;
> -
> -struct task_struct *get_current(void)
> -{
> - return &__current;
> -}
> -
> -unsigned long rlimit(unsigned int limit)
> -{
> - return (unsigned long)-1;
> -}
> -
> -/* Helper function to simply allocate a VMA. */
> -static struct vm_area_struct *alloc_vma(struct mm_struct *mm,
> - unsigned long start,
> - unsigned long end,
> - pgoff_t pgoff,
> - vm_flags_t vm_flags)
> -{
> - struct vm_area_struct *vma = vm_area_alloc(mm);
> -
> - if (vma == NULL)
> - return NULL;
> -
> - vma->vm_start = start;
> - vma->vm_end = end;
> - vma->vm_pgoff = pgoff;
> - vm_flags_reset(vma, vm_flags);
> - vma_assert_detached(vma);
> -
> - return vma;
> -}
> -
> -/* Helper function to allocate a VMA and link it to the tree. */
> -static int attach_vma(struct mm_struct *mm, struct vm_area_struct *vma)
> -{
> - int res;
> -
> - res = vma_link(mm, vma);
> - if (!res)
> - vma_assert_attached(vma);
> - return res;
> -}
> -
> -static void detach_free_vma(struct vm_area_struct *vma)
> -{
> - vma_mark_detached(vma);
> - vm_area_free(vma);
> -}
> -
> -/* Helper function to allocate a VMA and link it to the tree. */
> -static struct vm_area_struct *alloc_and_link_vma(struct mm_struct *mm,
> - unsigned long start,
> - unsigned long end,
> - pgoff_t pgoff,
> - vm_flags_t vm_flags)
> -{
> - struct vm_area_struct *vma = alloc_vma(mm, start, end, pgoff, vm_flags);
> -
> - if (vma == NULL)
> - return NULL;
> -
> - if (attach_vma(mm, vma)) {
> - detach_free_vma(vma);
> - return NULL;
> - }
> -
> - /*
> - * Reset this counter which we use to track whether writes have
> - * begun. Linking to the tree will have caused this to be incremented,
> - * which means we will get a false positive otherwise.
> - */
> - vma->vm_lock_seq = UINT_MAX;
> -
> - return vma;
> -}
> -
> /* Helper function which provides a wrapper around a merge new VMA operation. */
> static struct vm_area_struct *merge_new(struct vma_merge_struct *vmg)
> {
> @@ -146,20 +19,6 @@ static struct vm_area_struct *merge_new(struct vma_merge_struct *vmg)
> return vma;
> }
>
> -/*
> - * Helper function which provides a wrapper around a merge existing VMA
> - * operation.
> - */
> -static struct vm_area_struct *merge_existing(struct vma_merge_struct *vmg)
> -{
> - struct vm_area_struct *vma;
> -
> - vma = vma_merge_existing_range(vmg);
> - if (vma)
> - vma_assert_attached(vma);
> - return vma;
> -}
> -
> /*
> * Helper function which provides a wrapper around the expansion of an existing
> * VMA.
> @@ -173,8 +32,8 @@ static int expand_existing(struct vma_merge_struct *vmg)
> * Helper function to reset merge state the associated VMA iterator to a
> * specified new range.
> */
> -static void vmg_set_range(struct vma_merge_struct *vmg, unsigned long start,
> - unsigned long end, pgoff_t pgoff, vm_flags_t vm_flags)
> +void vmg_set_range(struct vma_merge_struct *vmg, unsigned long start,
> + unsigned long end, pgoff_t pgoff, vm_flags_t vm_flags)
> {
> vma_iter_set(vmg->vmi, start);
>
> @@ -197,8 +56,8 @@ static void vmg_set_range(struct vma_merge_struct *vmg, unsigned long start,
>
> /* Helper function to set both the VMG range and its anon_vma. */
> static void vmg_set_range_anon_vma(struct vma_merge_struct *vmg, unsigned long start,
> - unsigned long end, pgoff_t pgoff, vm_flags_t vm_flags,
> - struct anon_vma *anon_vma)
> + unsigned long end, pgoff_t pgoff, vm_flags_t vm_flags,
> + struct anon_vma *anon_vma)
> {
> vmg_set_range(vmg, start, end, pgoff, vm_flags);
> vmg->anon_vma = anon_vma;
> @@ -211,10 +70,9 @@ static void vmg_set_range_anon_vma(struct vma_merge_struct *vmg, unsigned long s
> * VMA, link it to the maple tree and return it.
> */
> static struct vm_area_struct *try_merge_new_vma(struct mm_struct *mm,
> - struct vma_merge_struct *vmg,
> - unsigned long start, unsigned long end,
> - pgoff_t pgoff, vm_flags_t vm_flags,
> - bool *was_merged)
> + struct vma_merge_struct *vmg, unsigned long start,
> + unsigned long end, pgoff_t pgoff, vm_flags_t vm_flags,
> + bool *was_merged)
> {
> struct vm_area_struct *merged;
>
> @@ -234,72 +92,6 @@ static struct vm_area_struct *try_merge_new_vma(struct mm_struct *mm,
> return alloc_and_link_vma(mm, start, end, pgoff, vm_flags);
> }
>
> -/*
> - * Helper function to reset the dummy anon_vma to indicate it has not been
> - * duplicated.
> - */
> -static void reset_dummy_anon_vma(void)
> -{
> - dummy_anon_vma.was_cloned = false;
> - dummy_anon_vma.was_unlinked = false;
> -}
> -
> -/*
> - * Helper function to remove all VMAs and destroy the maple tree associated with
> - * a virtual address space. Returns a count of VMAs in the tree.
> - */
> -static int cleanup_mm(struct mm_struct *mm, struct vma_iterator *vmi)
> -{
> - struct vm_area_struct *vma;
> - int count = 0;
> -
> - fail_prealloc = false;
> - reset_dummy_anon_vma();
> -
> - vma_iter_set(vmi, 0);
> - for_each_vma(*vmi, vma) {
> - detach_free_vma(vma);
> - count++;
> - }
> -
> - mtree_destroy(&mm->mm_mt);
> - mm->map_count = 0;
> - return count;
> -}
> -
> -/* Helper function to determine if VMA has had vma_start_write() performed. */
> -static bool vma_write_started(struct vm_area_struct *vma)
> -{
> - int seq = vma->vm_lock_seq;
> -
> - /* We reset after each check. */
> - vma->vm_lock_seq = UINT_MAX;
> -
> - /* The vma_start_write() stub simply increments this value. */
> - return seq > -1;
> -}
> -
> -/* Helper function providing a dummy vm_ops->close() method.*/
> -static void dummy_close(struct vm_area_struct *)
> -{
> -}
> -
> -static void __vma_set_dummy_anon_vma(struct vm_area_struct *vma,
> - struct anon_vma_chain *avc,
> - struct anon_vma *anon_vma)
> -{
> - vma->anon_vma = anon_vma;
> - INIT_LIST_HEAD(&vma->anon_vma_chain);
> - list_add(&avc->same_vma, &vma->anon_vma_chain);
> - avc->anon_vma = vma->anon_vma;
> -}
> -
> -static void vma_set_dummy_anon_vma(struct vm_area_struct *vma,
> - struct anon_vma_chain *avc)
> -{
> - __vma_set_dummy_anon_vma(vma, avc, &dummy_anon_vma);
> -}
> -
> static bool test_simple_merge(void)
> {
> struct vm_area_struct *vma;
> @@ -1616,39 +1408,6 @@ static bool test_merge_extend(void)
> return true;
> }
>
> -static bool test_copy_vma(void)
> -{
> - vm_flags_t vm_flags = VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE;
> - struct mm_struct mm = {};
> - bool need_locks = false;
> - VMA_ITERATOR(vmi, &mm, 0);
> - struct vm_area_struct *vma, *vma_new, *vma_next;
> -
> - /* Move backwards and do not merge. */
> -
> - vma = alloc_and_link_vma(&mm, 0x3000, 0x5000, 3, vm_flags);
> - vma_new = copy_vma(&vma, 0, 0x2000, 0, &need_locks);
> - ASSERT_NE(vma_new, vma);
> - ASSERT_EQ(vma_new->vm_start, 0);
> - ASSERT_EQ(vma_new->vm_end, 0x2000);
> - ASSERT_EQ(vma_new->vm_pgoff, 0);
> - vma_assert_attached(vma_new);
> -
> - cleanup_mm(&mm, &vmi);
> -
> - /* Move a VMA into position next to another and merge the two. */
> -
> - vma = alloc_and_link_vma(&mm, 0, 0x2000, 0, vm_flags);
> - vma_next = alloc_and_link_vma(&mm, 0x6000, 0x8000, 6, vm_flags);
> - vma_new = copy_vma(&vma, 0x4000, 0x2000, 4, &need_locks);
> - vma_assert_attached(vma_new);
> -
> - ASSERT_EQ(vma_new, vma_next);
> -
> - cleanup_mm(&mm, &vmi);
> - return true;
> -}
> -
> static bool test_expand_only_mode(void)
> {
> vm_flags_t vm_flags = VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE;
> @@ -1689,73 +1448,8 @@ static bool test_expand_only_mode(void)
> return true;
> }
>
> -static bool test_mmap_region_basic(void)
> -{
> - struct mm_struct mm = {};
> - unsigned long addr;
> - struct vm_area_struct *vma;
> - VMA_ITERATOR(vmi, &mm, 0);
> -
> - current->mm = &mm;
> -
> - /* Map at 0x300000, length 0x3000. */
> - addr = __mmap_region(NULL, 0x300000, 0x3000,
> - VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
> - 0x300, NULL);
> - ASSERT_EQ(addr, 0x300000);
> -
> - /* Map at 0x250000, length 0x3000. */
> - addr = __mmap_region(NULL, 0x250000, 0x3000,
> - VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
> - 0x250, NULL);
> - ASSERT_EQ(addr, 0x250000);
> -
> - /* Map at 0x303000, merging to 0x300000 of length 0x6000. */
> - addr = __mmap_region(NULL, 0x303000, 0x3000,
> - VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
> - 0x303, NULL);
> - ASSERT_EQ(addr, 0x303000);
> -
> - /* Map at 0x24d000, merging to 0x250000 of length 0x6000. */
> - addr = __mmap_region(NULL, 0x24d000, 0x3000,
> - VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
> - 0x24d, NULL);
> - ASSERT_EQ(addr, 0x24d000);
> -
> - ASSERT_EQ(mm.map_count, 2);
> -
> - for_each_vma(vmi, vma) {
> - if (vma->vm_start == 0x300000) {
> - ASSERT_EQ(vma->vm_end, 0x306000);
> - ASSERT_EQ(vma->vm_pgoff, 0x300);
> - } else if (vma->vm_start == 0x24d000) {
> - ASSERT_EQ(vma->vm_end, 0x253000);
> - ASSERT_EQ(vma->vm_pgoff, 0x24d);
> - } else {
> - ASSERT_FALSE(true);
> - }
> - }
> -
> - cleanup_mm(&mm, &vmi);
> - return true;
> -}
> -
> -int main(void)
> +static void run_merge_tests(int *num_tests, int *num_fail)
> {
> - int num_tests = 0, num_fail = 0;
> -
> - maple_tree_init();
> - vma_state_init();
> -
> -#define TEST(name) \
> - do { \
> - num_tests++; \
> - if (!test_##name()) { \
> - num_fail++; \
> - fprintf(stderr, "Test " #name " FAILED\n"); \
> - } \
> - } while (0)
> -
> /* Very simple tests to kick the tyres. */
> TEST(simple_merge);
> TEST(simple_modify);
> @@ -1771,15 +1465,5 @@ int main(void)
> TEST(dup_anon_vma);
> TEST(vmi_prealloc_fail);
> TEST(merge_extend);
> - TEST(copy_vma);
> TEST(expand_only_mode);
> -
> - TEST(mmap_region_basic);
> -
> -#undef TEST
> -
> - printf("%d tests run, %d passed, %d failed.\n",
> - num_tests, num_tests - num_fail, num_fail);
> -
> - return num_fail == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
> }
> diff --git a/tools/testing/vma/tests/mmap.c b/tools/testing/vma/tests/mmap.c
> new file mode 100644
> index 000000000000..bded4ecbe5db
> --- /dev/null
> +++ b/tools/testing/vma/tests/mmap.c
> @@ -0,0 +1,57 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +
> +static bool test_mmap_region_basic(void)
> +{
> + struct mm_struct mm = {};
> + unsigned long addr;
> + struct vm_area_struct *vma;
> + VMA_ITERATOR(vmi, &mm, 0);
> +
> + current->mm = &mm;
> +
> + /* Map at 0x300000, length 0x3000. */
> + addr = __mmap_region(NULL, 0x300000, 0x3000,
> + VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
> + 0x300, NULL);
> + ASSERT_EQ(addr, 0x300000);
> +
> + /* Map at 0x250000, length 0x3000. */
> + addr = __mmap_region(NULL, 0x250000, 0x3000,
> + VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
> + 0x250, NULL);
> + ASSERT_EQ(addr, 0x250000);
> +
> + /* Map at 0x303000, merging to 0x300000 of length 0x6000. */
> + addr = __mmap_region(NULL, 0x303000, 0x3000,
> + VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
> + 0x303, NULL);
> + ASSERT_EQ(addr, 0x303000);
> +
> + /* Map at 0x24d000, merging to 0x250000 of length 0x6000. */
> + addr = __mmap_region(NULL, 0x24d000, 0x3000,
> + VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
> + 0x24d, NULL);
> + ASSERT_EQ(addr, 0x24d000);
> +
> + ASSERT_EQ(mm.map_count, 2);
> +
> + for_each_vma(vmi, vma) {
> + if (vma->vm_start == 0x300000) {
> + ASSERT_EQ(vma->vm_end, 0x306000);
> + ASSERT_EQ(vma->vm_pgoff, 0x300);
> + } else if (vma->vm_start == 0x24d000) {
> + ASSERT_EQ(vma->vm_end, 0x253000);
> + ASSERT_EQ(vma->vm_pgoff, 0x24d);
> + } else {
> + ASSERT_FALSE(true);
> + }
> + }
> +
> + cleanup_mm(&mm, &vmi);
> + return true;
> +}
> +
> +static void run_mmap_tests(int *num_tests, int *num_fail)
> +{
> + TEST(mmap_region_basic);
> +}
> diff --git a/tools/testing/vma/tests/vma.c b/tools/testing/vma/tests/vma.c
> new file mode 100644
> index 000000000000..6d9775aee243
> --- /dev/null
> +++ b/tools/testing/vma/tests/vma.c
> @@ -0,0 +1,39 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +
> +static bool test_copy_vma(void)
> +{
> + vm_flags_t vm_flags = VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE;
> + struct mm_struct mm = {};
> + bool need_locks = false;
> + VMA_ITERATOR(vmi, &mm, 0);
> + struct vm_area_struct *vma, *vma_new, *vma_next;
> +
> + /* Move backwards and do not merge. */
> +
> + vma = alloc_and_link_vma(&mm, 0x3000, 0x5000, 3, vm_flags);
> + vma_new = copy_vma(&vma, 0, 0x2000, 0, &need_locks);
> + ASSERT_NE(vma_new, vma);
> + ASSERT_EQ(vma_new->vm_start, 0);
> + ASSERT_EQ(vma_new->vm_end, 0x2000);
> + ASSERT_EQ(vma_new->vm_pgoff, 0);
> + vma_assert_attached(vma_new);
> +
> + cleanup_mm(&mm, &vmi);
> +
> + /* Move a VMA into position next to another and merge the two. */
> +
> + vma = alloc_and_link_vma(&mm, 0, 0x2000, 0, vm_flags);
> + vma_next = alloc_and_link_vma(&mm, 0x6000, 0x8000, 6, vm_flags);
> + vma_new = copy_vma(&vma, 0x4000, 0x2000, 4, &need_locks);
> + vma_assert_attached(vma_new);
> +
> + ASSERT_EQ(vma_new, vma_next);
> +
> + cleanup_mm(&mm, &vmi);
> + return true;
> +}
> +
> +static void run_vma_tests(int *num_tests, int *num_fail)
> +{
> + TEST(copy_vma);
> +}
> diff --git a/tools/testing/vma/vma_internal.h b/tools/testing/vma/vma_internal.h
> index 2743f12ecf32..b48ebae3927d 100644
> --- a/tools/testing/vma/vma_internal.h
> +++ b/tools/testing/vma/vma_internal.h
> @@ -1127,15 +1127,6 @@ static inline void mapping_allow_writable(struct address_space *mapping)
> atomic_inc(&mapping->i_mmap_writable);
> }
>
> -static inline void vma_set_range(struct vm_area_struct *vma,
> - unsigned long start, unsigned long end,
> - pgoff_t pgoff)
> -{
> - vma->vm_start = start;
> - vma->vm_end = end;
> - vma->vm_pgoff = pgoff;
> -}
> -
> static inline
> struct vm_area_struct *vma_find(struct vma_iterator *vmi, unsigned long max)
> {
> --
> 2.52.0
>
^ permalink raw reply [flat|nested] 56+ messages in thread* Re: [PATCH v2 11/13] tools/testing/vma: separate VMA userland tests into separate files
2026-02-09 19:58 ` Liam R. Howlett
@ 2026-02-10 17:44 ` Lorenzo Stoakes
0 siblings, 0 replies; 56+ messages in thread
From: Lorenzo Stoakes @ 2026-02-10 17:44 UTC (permalink / raw)
To: Liam R. Howlett, Andrew Morton, Jarkko Sakkinen, Dave Hansen,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, x86,
H . Peter Anvin, Arnd Bergmann, Greg Kroah-Hartman, Dan Williams,
Vishal Verma, Dave Jiang, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jani Nikula,
Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig,
Huang Rui, Matthew Auld, Matthew Brost, Alexander Viro,
Christian Brauner, Jan Kara, Benjamin LaHaise, Gao Xiang,
Chao Yu, Yue Hu, Jeffle Xu, Sandeep Dhavale, Hongbo Li,
Chunhai Guo, Theodore Ts'o, Andreas Dilger, Muchun Song,
Oscar Salvador, David Hildenbrand, Konstantin Komarov,
Mike Marshall, Martin Brandenburg, Tony Luck, Reinette Chatre,
Dave Martin, James Morse, Babu Moger, Carlos Maiolino,
Damien Le Moal, Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Hugh Dickins, Baolin Wang, Zi Yan, Nico Pache, Ryan Roberts,
Dev Jain, Barry Song, Lance Yang, Jann Horn, Pedro Falcato,
David Howells, Paul Moore, James Morris, Serge E . Hallyn,
Yury Norov, Rasmus Villemoes, linux-sgx, linux-kernel, nvdimm,
linux-cxl, dri-devel, intel-gfx, linux-fsdevel, linux-aio,
linux-erofs, linux-ext4, linux-mm, ntfs3, devel, linux-xfs,
keyrings, linux-security-module, Jason Gunthorpe
On Mon, Feb 09, 2026 at 07:58:22PM +0000, Liam R. Howlett wrote:
> * Lorenzo Stoakes <lorenzo.stoakes@oracle.com> [260122 16:06]:
> > So far the userland VMA tests have been established as a rough expression
> > of what's been possible.
> >
> > qAdapt it into a more usable form by separating out tests and shared helper
> ^^^^ Typo
Oops, Andrew - can you fix that up? Thanks! :)
>
>
> > functions.
> >
> > Since we test functions that are declared statically in mm/vma.c, we make
> > use of the trick of #include'ing kernel C files directly.
> >
> > In order for the tests to continue to function, we must therefore also
> > this way into the tests/ directory.
> >
> > We try to keep as much shared logic actually modularised into a separate
> > compilation unit in shared.c, however the merge_existing() and attach_vma()
> > helpers rely on statically declared mm/vma.c functions so these must be
> > declared in main.c.
> >
> > Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
>
> Besides that typo, it looks good.
>
> Reviewed-by: Liam R. Howlett <Liam.Howlett@oracle.com>
Thanks :)
Cheers, Lorenzo
>
> > ---
> > tools/testing/vma/Makefile | 4 +-
> > tools/testing/vma/main.c | 55 ++++
> > tools/testing/vma/shared.c | 131 ++++++++
> > tools/testing/vma/shared.h | 114 +++++++
> > tools/testing/vma/{vma.c => tests/merge.c} | 332 +--------------------
> > tools/testing/vma/tests/mmap.c | 57 ++++
> > tools/testing/vma/tests/vma.c | 39 +++
> > tools/testing/vma/vma_internal.h | 9 -
> > 8 files changed, 406 insertions(+), 335 deletions(-)
> > create mode 100644 tools/testing/vma/main.c
> > create mode 100644 tools/testing/vma/shared.c
> > create mode 100644 tools/testing/vma/shared.h
> > rename tools/testing/vma/{vma.c => tests/merge.c} (82%)
> > create mode 100644 tools/testing/vma/tests/mmap.c
> > create mode 100644 tools/testing/vma/tests/vma.c
> >
> > diff --git a/tools/testing/vma/Makefile b/tools/testing/vma/Makefile
> > index 66f3831a668f..94133d9d3955 100644
> > --- a/tools/testing/vma/Makefile
> > +++ b/tools/testing/vma/Makefile
> > @@ -6,10 +6,10 @@ default: vma
> >
> > include ../shared/shared.mk
> >
> > -OFILES = $(SHARED_OFILES) vma.o maple-shim.o
> > +OFILES = $(SHARED_OFILES) main.o shared.o maple-shim.o
> > TARGETS = vma
> >
> > -vma.o: vma.c vma_internal.h ../../../mm/vma.c ../../../mm/vma_init.c ../../../mm/vma_exec.c ../../../mm/vma.h
> > +main.o: main.c shared.c shared.h vma_internal.h tests/merge.c tests/mmap.c tests/vma.c ../../../mm/vma.c ../../../mm/vma_init.c ../../../mm/vma_exec.c ../../../mm/vma.h
> >
> > vma: $(OFILES)
> > $(CC) $(CFLAGS) -o $@ $(OFILES) $(LDLIBS)
> > diff --git a/tools/testing/vma/main.c b/tools/testing/vma/main.c
> > new file mode 100644
> > index 000000000000..49b09e97a51f
> > --- /dev/null
> > +++ b/tools/testing/vma/main.c
> > @@ -0,0 +1,55 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +
> > +#include "shared.h"
> > +/*
> > + * Directly import the VMA implementation here. Our vma_internal.h wrapper
> > + * provides userland-equivalent functionality for everything vma.c uses.
> > + */
> > +#include "../../../mm/vma_init.c"
> > +#include "../../../mm/vma_exec.c"
> > +#include "../../../mm/vma.c"
> > +
> > +/* Tests are included directly so they can test static functions in mm/vma.c. */
> > +#include "tests/merge.c"
> > +#include "tests/mmap.c"
> > +#include "tests/vma.c"
> > +
> > +/* Helper functions which utilise static kernel functions. */
> > +
> > +struct vm_area_struct *merge_existing(struct vma_merge_struct *vmg)
> > +{
> > + struct vm_area_struct *vma;
> > +
> > + vma = vma_merge_existing_range(vmg);
> > + if (vma)
> > + vma_assert_attached(vma);
> > + return vma;
> > +}
> > +
> > +int attach_vma(struct mm_struct *mm, struct vm_area_struct *vma)
> > +{
> > + int res;
> > +
> > + res = vma_link(mm, vma);
> > + if (!res)
> > + vma_assert_attached(vma);
> > + return res;
> > +}
> > +
> > +/* Main test running which invokes tests/ *.c runners. */
> > +int main(void)
> > +{
> > + int num_tests = 0, num_fail = 0;
> > +
> > + maple_tree_init();
> > + vma_state_init();
> > +
> > + run_merge_tests(&num_tests, &num_fail);
> > + run_mmap_tests(&num_tests, &num_fail);
> > + run_vma_tests(&num_tests, &num_fail);
> > +
> > + printf("%d tests run, %d passed, %d failed.\n",
> > + num_tests, num_tests - num_fail, num_fail);
> > +
> > + return num_fail == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
> > +}
> > diff --git a/tools/testing/vma/shared.c b/tools/testing/vma/shared.c
> > new file mode 100644
> > index 000000000000..bda578cc3304
> > --- /dev/null
> > +++ b/tools/testing/vma/shared.c
> > @@ -0,0 +1,131 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +
> > +#include "shared.h"
> > +
> > +
> > +bool fail_prealloc;
> > +unsigned long mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR;
> > +unsigned long dac_mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR;
> > +unsigned long stack_guard_gap = 256UL<<PAGE_SHIFT;
> > +
> > +const struct vm_operations_struct vma_dummy_vm_ops;
> > +struct anon_vma dummy_anon_vma;
> > +struct task_struct __current;
> > +
> > +struct vm_area_struct *alloc_vma(struct mm_struct *mm,
> > + unsigned long start, unsigned long end,
> > + pgoff_t pgoff, vm_flags_t vm_flags)
> > +{
> > + struct vm_area_struct *vma = vm_area_alloc(mm);
> > +
> > + if (vma == NULL)
> > + return NULL;
> > +
> > + vma->vm_start = start;
> > + vma->vm_end = end;
> > + vma->vm_pgoff = pgoff;
> > + vm_flags_reset(vma, vm_flags);
> > + vma_assert_detached(vma);
> > +
> > + return vma;
> > +}
> > +
> > +void detach_free_vma(struct vm_area_struct *vma)
> > +{
> > + vma_mark_detached(vma);
> > + vm_area_free(vma);
> > +}
> > +
> > +struct vm_area_struct *alloc_and_link_vma(struct mm_struct *mm,
> > + unsigned long start, unsigned long end,
> > + pgoff_t pgoff, vm_flags_t vm_flags)
> > +{
> > + struct vm_area_struct *vma = alloc_vma(mm, start, end, pgoff, vm_flags);
> > +
> > + if (vma == NULL)
> > + return NULL;
> > +
> > + if (attach_vma(mm, vma)) {
> > + detach_free_vma(vma);
> > + return NULL;
> > + }
> > +
> > + /*
> > + * Reset this counter which we use to track whether writes have
> > + * begun. Linking to the tree will have caused this to be incremented,
> > + * which means we will get a false positive otherwise.
> > + */
> > + vma->vm_lock_seq = UINT_MAX;
> > +
> > + return vma;
> > +}
> > +
> > +void reset_dummy_anon_vma(void)
> > +{
> > + dummy_anon_vma.was_cloned = false;
> > + dummy_anon_vma.was_unlinked = false;
> > +}
> > +
> > +int cleanup_mm(struct mm_struct *mm, struct vma_iterator *vmi)
> > +{
> > + struct vm_area_struct *vma;
> > + int count = 0;
> > +
> > + fail_prealloc = false;
> > + reset_dummy_anon_vma();
> > +
> > + vma_iter_set(vmi, 0);
> > + for_each_vma(*vmi, vma) {
> > + detach_free_vma(vma);
> > + count++;
> > + }
> > +
> > + mtree_destroy(&mm->mm_mt);
> > + mm->map_count = 0;
> > + return count;
> > +}
> > +
> > +bool vma_write_started(struct vm_area_struct *vma)
> > +{
> > + int seq = vma->vm_lock_seq;
> > +
> > + /* We reset after each check. */
> > + vma->vm_lock_seq = UINT_MAX;
> > +
> > + /* The vma_start_write() stub simply increments this value. */
> > + return seq > -1;
> > +}
> > +
> > +void __vma_set_dummy_anon_vma(struct vm_area_struct *vma,
> > + struct anon_vma_chain *avc, struct anon_vma *anon_vma)
> > +{
> > + vma->anon_vma = anon_vma;
> > + INIT_LIST_HEAD(&vma->anon_vma_chain);
> > + list_add(&avc->same_vma, &vma->anon_vma_chain);
> > + avc->anon_vma = vma->anon_vma;
> > +}
> > +
> > +void vma_set_dummy_anon_vma(struct vm_area_struct *vma,
> > + struct anon_vma_chain *avc)
> > +{
> > + __vma_set_dummy_anon_vma(vma, avc, &dummy_anon_vma);
> > +}
> > +
> > +struct task_struct *get_current(void)
> > +{
> > + return &__current;
> > +}
> > +
> > +unsigned long rlimit(unsigned int limit)
> > +{
> > + return (unsigned long)-1;
> > +}
> > +
> > +void vma_set_range(struct vm_area_struct *vma,
> > + unsigned long start, unsigned long end,
> > + pgoff_t pgoff)
> > +{
> > + vma->vm_start = start;
> > + vma->vm_end = end;
> > + vma->vm_pgoff = pgoff;
> > +}
> > diff --git a/tools/testing/vma/shared.h b/tools/testing/vma/shared.h
> > new file mode 100644
> > index 000000000000..6c64211cfa22
> > --- /dev/null
> > +++ b/tools/testing/vma/shared.h
> > @@ -0,0 +1,114 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +
> > +#pragma once
> > +
> > +#include <stdbool.h>
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +
> > +#include "generated/bit-length.h"
> > +#include "maple-shared.h"
> > +#include "vma_internal.h"
> > +#include "../../../mm/vma.h"
> > +
> > +/* Simple test runner. Assumes local num_[fail, tests] counters. */
> > +#define TEST(name) \
> > + do { \
> > + (*num_tests)++; \
> > + if (!test_##name()) { \
> > + (*num_fail)++; \
> > + fprintf(stderr, "Test " #name " FAILED\n"); \
> > + } \
> > + } while (0)
> > +
> > +#define ASSERT_TRUE(_expr) \
> > + do { \
> > + if (!(_expr)) { \
> > + fprintf(stderr, \
> > + "Assert FAILED at %s:%d:%s(): %s is FALSE.\n", \
> > + __FILE__, __LINE__, __FUNCTION__, #_expr); \
> > + return false; \
> > + } \
> > + } while (0)
> > +
> > +#define ASSERT_FALSE(_expr) ASSERT_TRUE(!(_expr))
> > +#define ASSERT_EQ(_val1, _val2) ASSERT_TRUE((_val1) == (_val2))
> > +#define ASSERT_NE(_val1, _val2) ASSERT_TRUE((_val1) != (_val2))
> > +
> > +#define IS_SET(_val, _flags) ((_val & _flags) == _flags)
> > +
> > +extern bool fail_prealloc;
> > +
> > +/* Override vma_iter_prealloc() so we can choose to fail it. */
> > +#define vma_iter_prealloc(vmi, vma) \
> > + (fail_prealloc ? -ENOMEM : mas_preallocate(&(vmi)->mas, (vma), GFP_KERNEL))
> > +
> > +#define CONFIG_DEFAULT_MMAP_MIN_ADDR 65536
> > +
> > +extern unsigned long mmap_min_addr;
> > +extern unsigned long dac_mmap_min_addr;
> > +extern unsigned long stack_guard_gap;
> > +
> > +extern const struct vm_operations_struct vma_dummy_vm_ops;
> > +extern struct anon_vma dummy_anon_vma;
> > +extern struct task_struct __current;
> > +
> > +/*
> > + * Helper function which provides a wrapper around a merge existing VMA
> > + * operation.
> > + *
> > + * Declared in main.c as uses static VMA function.
> > + */
> > +struct vm_area_struct *merge_existing(struct vma_merge_struct *vmg);
> > +
> > +/*
> > + * Helper function to allocate a VMA and link it to the tree.
> > + *
> > + * Declared in main.c as uses static VMA function.
> > + */
> > +int attach_vma(struct mm_struct *mm, struct vm_area_struct *vma);
> > +
> > +/* Helper function providing a dummy vm_ops->close() method.*/
> > +static inline void dummy_close(struct vm_area_struct *)
> > +{
> > +}
> > +
> > +/* Helper function to simply allocate a VMA. */
> > +struct vm_area_struct *alloc_vma(struct mm_struct *mm,
> > + unsigned long start, unsigned long end,
> > + pgoff_t pgoff, vm_flags_t vm_flags);
> > +
> > +/* Helper function to detach and free a VMA. */
> > +void detach_free_vma(struct vm_area_struct *vma);
> > +
> > +/* Helper function to allocate a VMA and link it to the tree. */
> > +struct vm_area_struct *alloc_and_link_vma(struct mm_struct *mm,
> > + unsigned long start, unsigned long end,
> > + pgoff_t pgoff, vm_flags_t vm_flags);
> > +
> > +/*
> > + * Helper function to reset the dummy anon_vma to indicate it has not been
> > + * duplicated.
> > + */
> > +void reset_dummy_anon_vma(void);
> > +
> > +/*
> > + * Helper function to remove all VMAs and destroy the maple tree associated with
> > + * a virtual address space. Returns a count of VMAs in the tree.
> > + */
> > +int cleanup_mm(struct mm_struct *mm, struct vma_iterator *vmi);
> > +
> > +/* Helper function to determine if VMA has had vma_start_write() performed. */
> > +bool vma_write_started(struct vm_area_struct *vma);
> > +
> > +void __vma_set_dummy_anon_vma(struct vm_area_struct *vma,
> > + struct anon_vma_chain *avc, struct anon_vma *anon_vma);
> > +
> > +/* Provide a simple dummy VMA/anon_vma dummy setup for testing. */
> > +void vma_set_dummy_anon_vma(struct vm_area_struct *vma,
> > + struct anon_vma_chain *avc);
> > +
> > +/* Helper function to specify a VMA's range. */
> > +void vma_set_range(struct vm_area_struct *vma,
> > + unsigned long start, unsigned long end,
> > + pgoff_t pgoff);
> > diff --git a/tools/testing/vma/vma.c b/tools/testing/vma/tests/merge.c
> > similarity index 82%
> > rename from tools/testing/vma/vma.c
> > rename to tools/testing/vma/tests/merge.c
> > index 93d21bc7e112..3708dc6945b0 100644
> > --- a/tools/testing/vma/vma.c
> > +++ b/tools/testing/vma/tests/merge.c
> > @@ -1,132 +1,5 @@
> > // SPDX-License-Identifier: GPL-2.0-or-later
> >
> > -#include <stdbool.h>
> > -#include <stdio.h>
> > -#include <stdlib.h>
> > -
> > -#include "generated/bit-length.h"
> > -
> > -#include "maple-shared.h"
> > -#include "vma_internal.h"
> > -
> > -/* Include so header guard set. */
> > -#include "../../../mm/vma.h"
> > -
> > -static bool fail_prealloc;
> > -
> > -/* Then override vma_iter_prealloc() so we can choose to fail it. */
> > -#define vma_iter_prealloc(vmi, vma) \
> > - (fail_prealloc ? -ENOMEM : mas_preallocate(&(vmi)->mas, (vma), GFP_KERNEL))
> > -
> > -#define CONFIG_DEFAULT_MMAP_MIN_ADDR 65536
> > -
> > -unsigned long mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR;
> > -unsigned long dac_mmap_min_addr = CONFIG_DEFAULT_MMAP_MIN_ADDR;
> > -unsigned long stack_guard_gap = 256UL<<PAGE_SHIFT;
> > -
> > -/*
> > - * Directly import the VMA implementation here. Our vma_internal.h wrapper
> > - * provides userland-equivalent functionality for everything vma.c uses.
> > - */
> > -#include "../../../mm/vma_init.c"
> > -#include "../../../mm/vma_exec.c"
> > -#include "../../../mm/vma.c"
> > -
> > -const struct vm_operations_struct vma_dummy_vm_ops;
> > -static struct anon_vma dummy_anon_vma;
> > -
> > -#define ASSERT_TRUE(_expr) \
> > - do { \
> > - if (!(_expr)) { \
> > - fprintf(stderr, \
> > - "Assert FAILED at %s:%d:%s(): %s is FALSE.\n", \
> > - __FILE__, __LINE__, __FUNCTION__, #_expr); \
> > - return false; \
> > - } \
> > - } while (0)
> > -#define ASSERT_FALSE(_expr) ASSERT_TRUE(!(_expr))
> > -#define ASSERT_EQ(_val1, _val2) ASSERT_TRUE((_val1) == (_val2))
> > -#define ASSERT_NE(_val1, _val2) ASSERT_TRUE((_val1) != (_val2))
> > -
> > -#define IS_SET(_val, _flags) ((_val & _flags) == _flags)
> > -
> > -static struct task_struct __current;
> > -
> > -struct task_struct *get_current(void)
> > -{
> > - return &__current;
> > -}
> > -
> > -unsigned long rlimit(unsigned int limit)
> > -{
> > - return (unsigned long)-1;
> > -}
> > -
> > -/* Helper function to simply allocate a VMA. */
> > -static struct vm_area_struct *alloc_vma(struct mm_struct *mm,
> > - unsigned long start,
> > - unsigned long end,
> > - pgoff_t pgoff,
> > - vm_flags_t vm_flags)
> > -{
> > - struct vm_area_struct *vma = vm_area_alloc(mm);
> > -
> > - if (vma == NULL)
> > - return NULL;
> > -
> > - vma->vm_start = start;
> > - vma->vm_end = end;
> > - vma->vm_pgoff = pgoff;
> > - vm_flags_reset(vma, vm_flags);
> > - vma_assert_detached(vma);
> > -
> > - return vma;
> > -}
> > -
> > -/* Helper function to allocate a VMA and link it to the tree. */
> > -static int attach_vma(struct mm_struct *mm, struct vm_area_struct *vma)
> > -{
> > - int res;
> > -
> > - res = vma_link(mm, vma);
> > - if (!res)
> > - vma_assert_attached(vma);
> > - return res;
> > -}
> > -
> > -static void detach_free_vma(struct vm_area_struct *vma)
> > -{
> > - vma_mark_detached(vma);
> > - vm_area_free(vma);
> > -}
> > -
> > -/* Helper function to allocate a VMA and link it to the tree. */
> > -static struct vm_area_struct *alloc_and_link_vma(struct mm_struct *mm,
> > - unsigned long start,
> > - unsigned long end,
> > - pgoff_t pgoff,
> > - vm_flags_t vm_flags)
> > -{
> > - struct vm_area_struct *vma = alloc_vma(mm, start, end, pgoff, vm_flags);
> > -
> > - if (vma == NULL)
> > - return NULL;
> > -
> > - if (attach_vma(mm, vma)) {
> > - detach_free_vma(vma);
> > - return NULL;
> > - }
> > -
> > - /*
> > - * Reset this counter which we use to track whether writes have
> > - * begun. Linking to the tree will have caused this to be incremented,
> > - * which means we will get a false positive otherwise.
> > - */
> > - vma->vm_lock_seq = UINT_MAX;
> > -
> > - return vma;
> > -}
> > -
> > /* Helper function which provides a wrapper around a merge new VMA operation. */
> > static struct vm_area_struct *merge_new(struct vma_merge_struct *vmg)
> > {
> > @@ -146,20 +19,6 @@ static struct vm_area_struct *merge_new(struct vma_merge_struct *vmg)
> > return vma;
> > }
> >
> > -/*
> > - * Helper function which provides a wrapper around a merge existing VMA
> > - * operation.
> > - */
> > -static struct vm_area_struct *merge_existing(struct vma_merge_struct *vmg)
> > -{
> > - struct vm_area_struct *vma;
> > -
> > - vma = vma_merge_existing_range(vmg);
> > - if (vma)
> > - vma_assert_attached(vma);
> > - return vma;
> > -}
> > -
> > /*
> > * Helper function which provides a wrapper around the expansion of an existing
> > * VMA.
> > @@ -173,8 +32,8 @@ static int expand_existing(struct vma_merge_struct *vmg)
> > * Helper function to reset merge state the associated VMA iterator to a
> > * specified new range.
> > */
> > -static void vmg_set_range(struct vma_merge_struct *vmg, unsigned long start,
> > - unsigned long end, pgoff_t pgoff, vm_flags_t vm_flags)
> > +void vmg_set_range(struct vma_merge_struct *vmg, unsigned long start,
> > + unsigned long end, pgoff_t pgoff, vm_flags_t vm_flags)
> > {
> > vma_iter_set(vmg->vmi, start);
> >
> > @@ -197,8 +56,8 @@ static void vmg_set_range(struct vma_merge_struct *vmg, unsigned long start,
> >
> > /* Helper function to set both the VMG range and its anon_vma. */
> > static void vmg_set_range_anon_vma(struct vma_merge_struct *vmg, unsigned long start,
> > - unsigned long end, pgoff_t pgoff, vm_flags_t vm_flags,
> > - struct anon_vma *anon_vma)
> > + unsigned long end, pgoff_t pgoff, vm_flags_t vm_flags,
> > + struct anon_vma *anon_vma)
> > {
> > vmg_set_range(vmg, start, end, pgoff, vm_flags);
> > vmg->anon_vma = anon_vma;
> > @@ -211,10 +70,9 @@ static void vmg_set_range_anon_vma(struct vma_merge_struct *vmg, unsigned long s
> > * VMA, link it to the maple tree and return it.
> > */
> > static struct vm_area_struct *try_merge_new_vma(struct mm_struct *mm,
> > - struct vma_merge_struct *vmg,
> > - unsigned long start, unsigned long end,
> > - pgoff_t pgoff, vm_flags_t vm_flags,
> > - bool *was_merged)
> > + struct vma_merge_struct *vmg, unsigned long start,
> > + unsigned long end, pgoff_t pgoff, vm_flags_t vm_flags,
> > + bool *was_merged)
> > {
> > struct vm_area_struct *merged;
> >
> > @@ -234,72 +92,6 @@ static struct vm_area_struct *try_merge_new_vma(struct mm_struct *mm,
> > return alloc_and_link_vma(mm, start, end, pgoff, vm_flags);
> > }
> >
> > -/*
> > - * Helper function to reset the dummy anon_vma to indicate it has not been
> > - * duplicated.
> > - */
> > -static void reset_dummy_anon_vma(void)
> > -{
> > - dummy_anon_vma.was_cloned = false;
> > - dummy_anon_vma.was_unlinked = false;
> > -}
> > -
> > -/*
> > - * Helper function to remove all VMAs and destroy the maple tree associated with
> > - * a virtual address space. Returns a count of VMAs in the tree.
> > - */
> > -static int cleanup_mm(struct mm_struct *mm, struct vma_iterator *vmi)
> > -{
> > - struct vm_area_struct *vma;
> > - int count = 0;
> > -
> > - fail_prealloc = false;
> > - reset_dummy_anon_vma();
> > -
> > - vma_iter_set(vmi, 0);
> > - for_each_vma(*vmi, vma) {
> > - detach_free_vma(vma);
> > - count++;
> > - }
> > -
> > - mtree_destroy(&mm->mm_mt);
> > - mm->map_count = 0;
> > - return count;
> > -}
> > -
> > -/* Helper function to determine if VMA has had vma_start_write() performed. */
> > -static bool vma_write_started(struct vm_area_struct *vma)
> > -{
> > - int seq = vma->vm_lock_seq;
> > -
> > - /* We reset after each check. */
> > - vma->vm_lock_seq = UINT_MAX;
> > -
> > - /* The vma_start_write() stub simply increments this value. */
> > - return seq > -1;
> > -}
> > -
> > -/* Helper function providing a dummy vm_ops->close() method.*/
> > -static void dummy_close(struct vm_area_struct *)
> > -{
> > -}
> > -
> > -static void __vma_set_dummy_anon_vma(struct vm_area_struct *vma,
> > - struct anon_vma_chain *avc,
> > - struct anon_vma *anon_vma)
> > -{
> > - vma->anon_vma = anon_vma;
> > - INIT_LIST_HEAD(&vma->anon_vma_chain);
> > - list_add(&avc->same_vma, &vma->anon_vma_chain);
> > - avc->anon_vma = vma->anon_vma;
> > -}
> > -
> > -static void vma_set_dummy_anon_vma(struct vm_area_struct *vma,
> > - struct anon_vma_chain *avc)
> > -{
> > - __vma_set_dummy_anon_vma(vma, avc, &dummy_anon_vma);
> > -}
> > -
> > static bool test_simple_merge(void)
> > {
> > struct vm_area_struct *vma;
> > @@ -1616,39 +1408,6 @@ static bool test_merge_extend(void)
> > return true;
> > }
> >
> > -static bool test_copy_vma(void)
> > -{
> > - vm_flags_t vm_flags = VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE;
> > - struct mm_struct mm = {};
> > - bool need_locks = false;
> > - VMA_ITERATOR(vmi, &mm, 0);
> > - struct vm_area_struct *vma, *vma_new, *vma_next;
> > -
> > - /* Move backwards and do not merge. */
> > -
> > - vma = alloc_and_link_vma(&mm, 0x3000, 0x5000, 3, vm_flags);
> > - vma_new = copy_vma(&vma, 0, 0x2000, 0, &need_locks);
> > - ASSERT_NE(vma_new, vma);
> > - ASSERT_EQ(vma_new->vm_start, 0);
> > - ASSERT_EQ(vma_new->vm_end, 0x2000);
> > - ASSERT_EQ(vma_new->vm_pgoff, 0);
> > - vma_assert_attached(vma_new);
> > -
> > - cleanup_mm(&mm, &vmi);
> > -
> > - /* Move a VMA into position next to another and merge the two. */
> > -
> > - vma = alloc_and_link_vma(&mm, 0, 0x2000, 0, vm_flags);
> > - vma_next = alloc_and_link_vma(&mm, 0x6000, 0x8000, 6, vm_flags);
> > - vma_new = copy_vma(&vma, 0x4000, 0x2000, 4, &need_locks);
> > - vma_assert_attached(vma_new);
> > -
> > - ASSERT_EQ(vma_new, vma_next);
> > -
> > - cleanup_mm(&mm, &vmi);
> > - return true;
> > -}
> > -
> > static bool test_expand_only_mode(void)
> > {
> > vm_flags_t vm_flags = VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE;
> > @@ -1689,73 +1448,8 @@ static bool test_expand_only_mode(void)
> > return true;
> > }
> >
> > -static bool test_mmap_region_basic(void)
> > -{
> > - struct mm_struct mm = {};
> > - unsigned long addr;
> > - struct vm_area_struct *vma;
> > - VMA_ITERATOR(vmi, &mm, 0);
> > -
> > - current->mm = &mm;
> > -
> > - /* Map at 0x300000, length 0x3000. */
> > - addr = __mmap_region(NULL, 0x300000, 0x3000,
> > - VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
> > - 0x300, NULL);
> > - ASSERT_EQ(addr, 0x300000);
> > -
> > - /* Map at 0x250000, length 0x3000. */
> > - addr = __mmap_region(NULL, 0x250000, 0x3000,
> > - VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
> > - 0x250, NULL);
> > - ASSERT_EQ(addr, 0x250000);
> > -
> > - /* Map at 0x303000, merging to 0x300000 of length 0x6000. */
> > - addr = __mmap_region(NULL, 0x303000, 0x3000,
> > - VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
> > - 0x303, NULL);
> > - ASSERT_EQ(addr, 0x303000);
> > -
> > - /* Map at 0x24d000, merging to 0x250000 of length 0x6000. */
> > - addr = __mmap_region(NULL, 0x24d000, 0x3000,
> > - VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
> > - 0x24d, NULL);
> > - ASSERT_EQ(addr, 0x24d000);
> > -
> > - ASSERT_EQ(mm.map_count, 2);
> > -
> > - for_each_vma(vmi, vma) {
> > - if (vma->vm_start == 0x300000) {
> > - ASSERT_EQ(vma->vm_end, 0x306000);
> > - ASSERT_EQ(vma->vm_pgoff, 0x300);
> > - } else if (vma->vm_start == 0x24d000) {
> > - ASSERT_EQ(vma->vm_end, 0x253000);
> > - ASSERT_EQ(vma->vm_pgoff, 0x24d);
> > - } else {
> > - ASSERT_FALSE(true);
> > - }
> > - }
> > -
> > - cleanup_mm(&mm, &vmi);
> > - return true;
> > -}
> > -
> > -int main(void)
> > +static void run_merge_tests(int *num_tests, int *num_fail)
> > {
> > - int num_tests = 0, num_fail = 0;
> > -
> > - maple_tree_init();
> > - vma_state_init();
> > -
> > -#define TEST(name) \
> > - do { \
> > - num_tests++; \
> > - if (!test_##name()) { \
> > - num_fail++; \
> > - fprintf(stderr, "Test " #name " FAILED\n"); \
> > - } \
> > - } while (0)
> > -
> > /* Very simple tests to kick the tyres. */
> > TEST(simple_merge);
> > TEST(simple_modify);
> > @@ -1771,15 +1465,5 @@ int main(void)
> > TEST(dup_anon_vma);
> > TEST(vmi_prealloc_fail);
> > TEST(merge_extend);
> > - TEST(copy_vma);
> > TEST(expand_only_mode);
> > -
> > - TEST(mmap_region_basic);
> > -
> > -#undef TEST
> > -
> > - printf("%d tests run, %d passed, %d failed.\n",
> > - num_tests, num_tests - num_fail, num_fail);
> > -
> > - return num_fail == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
> > }
> > diff --git a/tools/testing/vma/tests/mmap.c b/tools/testing/vma/tests/mmap.c
> > new file mode 100644
> > index 000000000000..bded4ecbe5db
> > --- /dev/null
> > +++ b/tools/testing/vma/tests/mmap.c
> > @@ -0,0 +1,57 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +
> > +static bool test_mmap_region_basic(void)
> > +{
> > + struct mm_struct mm = {};
> > + unsigned long addr;
> > + struct vm_area_struct *vma;
> > + VMA_ITERATOR(vmi, &mm, 0);
> > +
> > + current->mm = &mm;
> > +
> > + /* Map at 0x300000, length 0x3000. */
> > + addr = __mmap_region(NULL, 0x300000, 0x3000,
> > + VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
> > + 0x300, NULL);
> > + ASSERT_EQ(addr, 0x300000);
> > +
> > + /* Map at 0x250000, length 0x3000. */
> > + addr = __mmap_region(NULL, 0x250000, 0x3000,
> > + VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
> > + 0x250, NULL);
> > + ASSERT_EQ(addr, 0x250000);
> > +
> > + /* Map at 0x303000, merging to 0x300000 of length 0x6000. */
> > + addr = __mmap_region(NULL, 0x303000, 0x3000,
> > + VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
> > + 0x303, NULL);
> > + ASSERT_EQ(addr, 0x303000);
> > +
> > + /* Map at 0x24d000, merging to 0x250000 of length 0x6000. */
> > + addr = __mmap_region(NULL, 0x24d000, 0x3000,
> > + VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE,
> > + 0x24d, NULL);
> > + ASSERT_EQ(addr, 0x24d000);
> > +
> > + ASSERT_EQ(mm.map_count, 2);
> > +
> > + for_each_vma(vmi, vma) {
> > + if (vma->vm_start == 0x300000) {
> > + ASSERT_EQ(vma->vm_end, 0x306000);
> > + ASSERT_EQ(vma->vm_pgoff, 0x300);
> > + } else if (vma->vm_start == 0x24d000) {
> > + ASSERT_EQ(vma->vm_end, 0x253000);
> > + ASSERT_EQ(vma->vm_pgoff, 0x24d);
> > + } else {
> > + ASSERT_FALSE(true);
> > + }
> > + }
> > +
> > + cleanup_mm(&mm, &vmi);
> > + return true;
> > +}
> > +
> > +static void run_mmap_tests(int *num_tests, int *num_fail)
> > +{
> > + TEST(mmap_region_basic);
> > +}
> > diff --git a/tools/testing/vma/tests/vma.c b/tools/testing/vma/tests/vma.c
> > new file mode 100644
> > index 000000000000..6d9775aee243
> > --- /dev/null
> > +++ b/tools/testing/vma/tests/vma.c
> > @@ -0,0 +1,39 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +
> > +static bool test_copy_vma(void)
> > +{
> > + vm_flags_t vm_flags = VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE;
> > + struct mm_struct mm = {};
> > + bool need_locks = false;
> > + VMA_ITERATOR(vmi, &mm, 0);
> > + struct vm_area_struct *vma, *vma_new, *vma_next;
> > +
> > + /* Move backwards and do not merge. */
> > +
> > + vma = alloc_and_link_vma(&mm, 0x3000, 0x5000, 3, vm_flags);
> > + vma_new = copy_vma(&vma, 0, 0x2000, 0, &need_locks);
> > + ASSERT_NE(vma_new, vma);
> > + ASSERT_EQ(vma_new->vm_start, 0);
> > + ASSERT_EQ(vma_new->vm_end, 0x2000);
> > + ASSERT_EQ(vma_new->vm_pgoff, 0);
> > + vma_assert_attached(vma_new);
> > +
> > + cleanup_mm(&mm, &vmi);
> > +
> > + /* Move a VMA into position next to another and merge the two. */
> > +
> > + vma = alloc_and_link_vma(&mm, 0, 0x2000, 0, vm_flags);
> > + vma_next = alloc_and_link_vma(&mm, 0x6000, 0x8000, 6, vm_flags);
> > + vma_new = copy_vma(&vma, 0x4000, 0x2000, 4, &need_locks);
> > + vma_assert_attached(vma_new);
> > +
> > + ASSERT_EQ(vma_new, vma_next);
> > +
> > + cleanup_mm(&mm, &vmi);
> > + return true;
> > +}
> > +
> > +static void run_vma_tests(int *num_tests, int *num_fail)
> > +{
> > + TEST(copy_vma);
> > +}
> > diff --git a/tools/testing/vma/vma_internal.h b/tools/testing/vma/vma_internal.h
> > index 2743f12ecf32..b48ebae3927d 100644
> > --- a/tools/testing/vma/vma_internal.h
> > +++ b/tools/testing/vma/vma_internal.h
> > @@ -1127,15 +1127,6 @@ static inline void mapping_allow_writable(struct address_space *mapping)
> > atomic_inc(&mapping->i_mmap_writable);
> > }
> >
> > -static inline void vma_set_range(struct vm_area_struct *vma,
> > - unsigned long start, unsigned long end,
> > - pgoff_t pgoff)
> > -{
> > - vma->vm_start = start;
> > - vma->vm_end = end;
> > - vma->vm_pgoff = pgoff;
> > -}
> > -
> > static inline
> > struct vm_area_struct *vma_find(struct vma_iterator *vmi, unsigned long max)
> > {
> > --
> > 2.52.0
> >
^ permalink raw reply [flat|nested] 56+ messages in thread
* [PATCH v2 12/13] tools/testing/vma: separate out vma_internal.h into logical headers
2026-01-22 16:06 [PATCH v2 00/13] mm: add bitmap VMA flag helpers and convert all mmap_prepare to use them Lorenzo Stoakes
` (10 preceding siblings ...)
2026-01-22 16:06 ` [PATCH v2 11/13] tools/testing/vma: separate VMA userland tests into separate files Lorenzo Stoakes
@ 2026-01-22 16:06 ` Lorenzo Stoakes
2026-01-27 10:03 ` Lorenzo Stoakes
2026-02-09 20:18 ` Liam R. Howlett
2026-01-22 16:06 ` [PATCH v2 13/13] tools/testing/vma: add VMA userland tests for VMA flag functions Lorenzo Stoakes
` (2 subsequent siblings)
14 siblings, 2 replies; 56+ messages in thread
From: Lorenzo Stoakes @ 2026-01-22 16:06 UTC (permalink / raw)
To: Andrew Morton
Cc: Jarkko Sakkinen, Dave Hansen, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, x86, H . Peter Anvin, Arnd Bergmann,
Greg Kroah-Hartman, Dan Williams, Vishal Verma, Dave Jiang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
The vma_internal.h file is becoming entirely unmanageable. It combines
duplicated kernel implementation logic that needs to be kept in-sync with
the kernel, stubbed out declarations that we simply ignore for testing
purposes and custom logic added to aid testing.
If we separate each of the three things into separate headers it makes
things far more manageable, so do so:
* include/stubs.h contains the stubbed declarations,
* include/dup.h contains the duplicated kernel declarations, and
* include/custom.h contains declarations customised for testing.
Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
---
tools/testing/vma/Makefile | 2 +-
tools/testing/vma/include/custom.h | 103 ++
tools/testing/vma/include/dup.h | 1341 +++++++++++++++++++
tools/testing/vma/include/stubs.h | 428 ++++++
tools/testing/vma/vma_internal.h | 1936 +---------------------------
5 files changed, 1885 insertions(+), 1925 deletions(-)
create mode 100644 tools/testing/vma/include/custom.h
create mode 100644 tools/testing/vma/include/dup.h
create mode 100644 tools/testing/vma/include/stubs.h
diff --git a/tools/testing/vma/Makefile b/tools/testing/vma/Makefile
index 94133d9d3955..50aa4301b3a6 100644
--- a/tools/testing/vma/Makefile
+++ b/tools/testing/vma/Makefile
@@ -9,7 +9,7 @@ include ../shared/shared.mk
OFILES = $(SHARED_OFILES) main.o shared.o maple-shim.o
TARGETS = vma
-main.o: main.c shared.c shared.h vma_internal.h tests/merge.c tests/mmap.c tests/vma.c ../../../mm/vma.c ../../../mm/vma_init.c ../../../mm/vma_exec.c ../../../mm/vma.h
+main.o: main.c shared.c shared.h vma_internal.h tests/merge.c tests/mmap.c tests/vma.c ../../../mm/vma.c ../../../mm/vma_init.c ../../../mm/vma_exec.c ../../../mm/vma.h include/custom.h include/dup.h include/stubs.h
vma: $(OFILES)
$(CC) $(CFLAGS) -o $@ $(OFILES) $(LDLIBS)
diff --git a/tools/testing/vma/include/custom.h b/tools/testing/vma/include/custom.h
new file mode 100644
index 000000000000..f567127efba9
--- /dev/null
+++ b/tools/testing/vma/include/custom.h
@@ -0,0 +1,103 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#pragma once
+
+/*
+ * Contains declarations that exist in the kernel which have been CUSTOMISED for
+ * testing purposes to faciliate userland VMA testing.
+ */
+
+#ifdef CONFIG_MMU
+extern unsigned long mmap_min_addr;
+extern unsigned long dac_mmap_min_addr;
+#else
+#define mmap_min_addr 0UL
+#define dac_mmap_min_addr 0UL
+#endif
+
+#define VM_WARN_ON(_expr) (WARN_ON(_expr))
+#define VM_WARN_ON_ONCE(_expr) (WARN_ON_ONCE(_expr))
+#define VM_WARN_ON_VMG(_expr, _vmg) (WARN_ON(_expr))
+#define VM_BUG_ON(_expr) (BUG_ON(_expr))
+#define VM_BUG_ON_VMA(_expr, _vma) (BUG_ON(_expr))
+
+/* We hardcode this for now. */
+#define sysctl_max_map_count 0x1000000UL
+
+#define TASK_SIZE ((1ul << 47)-PAGE_SIZE)
+
+/*
+ * The shared stubs do not implement this, it amounts to an fprintf(STDERR,...)
+ * either way :)
+ */
+#define pr_warn_once pr_err
+
+#define pgtable_supports_soft_dirty() 1
+
+struct anon_vma {
+ struct anon_vma *root;
+ struct rb_root_cached rb_root;
+
+ /* Test fields. */
+ bool was_cloned;
+ bool was_unlinked;
+};
+
+static inline void unlink_anon_vmas(struct vm_area_struct *vma)
+{
+ /* For testing purposes, indicate that the anon_vma was unlinked. */
+ vma->anon_vma->was_unlinked = true;
+}
+
+static inline void vma_start_write(struct vm_area_struct *vma)
+{
+ /* Used to indicate to tests that a write operation has begun. */
+ vma->vm_lock_seq++;
+}
+
+static inline __must_check
+int vma_start_write_killable(struct vm_area_struct *vma)
+{
+ /* Used to indicate to tests that a write operation has begun. */
+ vma->vm_lock_seq++;
+ return 0;
+}
+
+static inline int anon_vma_clone(struct vm_area_struct *dst, struct vm_area_struct *src,
+ enum vma_operation operation)
+{
+ /* For testing purposes. We indicate that an anon_vma has been cloned. */
+ if (src->anon_vma != NULL) {
+ dst->anon_vma = src->anon_vma;
+ dst->anon_vma->was_cloned = true;
+ }
+
+ return 0;
+}
+
+static inline int __anon_vma_prepare(struct vm_area_struct *vma)
+{
+ struct anon_vma *anon_vma = calloc(1, sizeof(struct anon_vma));
+
+ if (!anon_vma)
+ return -ENOMEM;
+
+ anon_vma->root = anon_vma;
+ vma->anon_vma = anon_vma;
+
+ return 0;
+}
+
+static inline int anon_vma_prepare(struct vm_area_struct *vma)
+{
+ if (likely(vma->anon_vma))
+ return 0;
+
+ return __anon_vma_prepare(vma);
+}
+
+static inline void vma_lock_init(struct vm_area_struct *vma, bool reset_refcnt)
+{
+ if (reset_refcnt)
+ refcount_set(&vma->vm_refcnt, 0);
+}
diff --git a/tools/testing/vma/include/dup.h b/tools/testing/vma/include/dup.h
new file mode 100644
index 000000000000..ed8708afb7af
--- /dev/null
+++ b/tools/testing/vma/include/dup.h
@@ -0,0 +1,1341 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#pragma once
+
+/* Forward declarations to avoid header cycle. */
+struct vm_area_struct;
+static inline void vma_start_write(struct vm_area_struct *vma);
+
+extern const struct vm_operations_struct vma_dummy_vm_ops;
+extern unsigned long stack_guard_gap;
+extern const struct vm_operations_struct vma_dummy_vm_ops;
+extern unsigned long rlimit(unsigned int limit);
+struct task_struct *get_current(void);
+
+#define MMF_HAS_MDWE 28
+#define current get_current()
+
+/*
+ * Define the task command name length as enum, then it can be visible to
+ * BPF programs.
+ */
+enum {
+ TASK_COMM_LEN = 16,
+};
+
+/* PARTIALLY implemented types. */
+struct mm_struct {
+ struct maple_tree mm_mt;
+ int map_count; /* number of VMAs */
+ unsigned long total_vm; /* Total pages mapped */
+ unsigned long locked_vm; /* Pages that have PG_mlocked set */
+ unsigned long data_vm; /* VM_WRITE & ~VM_SHARED & ~VM_STACK */
+ unsigned long exec_vm; /* VM_EXEC & ~VM_WRITE & ~VM_STACK */
+ unsigned long stack_vm; /* VM_STACK */
+
+ unsigned long def_flags;
+
+ mm_flags_t flags; /* Must use mm_flags_* helpers to access */
+};
+struct address_space {
+ struct rb_root_cached i_mmap;
+ unsigned long flags;
+ atomic_t i_mmap_writable;
+};
+struct file_operations {
+ int (*mmap)(struct file *, struct vm_area_struct *);
+ int (*mmap_prepare)(struct vm_area_desc *);
+};
+struct file {
+ struct address_space *f_mapping;
+ const struct file_operations *f_op;
+};
+struct anon_vma_chain {
+ struct anon_vma *anon_vma;
+ struct list_head same_vma;
+};
+struct task_struct {
+ char comm[TASK_COMM_LEN];
+ pid_t pid;
+ struct mm_struct *mm;
+
+ /* Used for emulating ABI behavior of previous Linux versions: */
+ unsigned int personality;
+};
+
+struct kref {
+ refcount_t refcount;
+};
+
+struct anon_vma_name {
+ struct kref kref;
+ /* The name needs to be at the end because it is dynamically sized. */
+ char name[];
+};
+
+/*
+ * Contains declarations that are DUPLICATED from kernel source in order to
+ * faciliate userland VMA testing.
+ *
+ * These must be kept in sync with kernel source.
+ */
+
+#define VMA_LOCK_OFFSET 0x40000000
+
+typedef struct { unsigned long v; } freeptr_t;
+
+#define VM_NONE 0x00000000
+
+typedef int __bitwise vma_flag_t;
+
+#define ACCESS_PRIVATE(p, member) ((p)->member)
+
+#define DECLARE_VMA_BIT(name, bitnum) \
+ VMA_ ## name ## _BIT = ((__force vma_flag_t)bitnum)
+#define DECLARE_VMA_BIT_ALIAS(name, aliased) \
+ VMA_ ## name ## _BIT = VMA_ ## aliased ## _BIT
+enum {
+ DECLARE_VMA_BIT(READ, 0),
+ DECLARE_VMA_BIT(WRITE, 1),
+ DECLARE_VMA_BIT(EXEC, 2),
+ DECLARE_VMA_BIT(SHARED, 3),
+ /* mprotect() hardcodes VM_MAYREAD >> 4 == VM_READ, and so for r/w/x bits. */
+ DECLARE_VMA_BIT(MAYREAD, 4), /* limits for mprotect() etc. */
+ DECLARE_VMA_BIT(MAYWRITE, 5),
+ DECLARE_VMA_BIT(MAYEXEC, 6),
+ DECLARE_VMA_BIT(MAYSHARE, 7),
+ DECLARE_VMA_BIT(GROWSDOWN, 8), /* general info on the segment */
+#ifdef CONFIG_MMU
+ DECLARE_VMA_BIT(UFFD_MISSING, 9),/* missing pages tracking */
+#else
+ /* nommu: R/O MAP_PRIVATE mapping that might overlay a file mapping */
+ DECLARE_VMA_BIT(MAYOVERLAY, 9),
+#endif /* CONFIG_MMU */
+ /* Page-ranges managed without "struct page", just pure PFN */
+ DECLARE_VMA_BIT(PFNMAP, 10),
+ DECLARE_VMA_BIT(MAYBE_GUARD, 11),
+ DECLARE_VMA_BIT(UFFD_WP, 12), /* wrprotect pages tracking */
+ DECLARE_VMA_BIT(LOCKED, 13),
+ DECLARE_VMA_BIT(IO, 14), /* Memory mapped I/O or similar */
+ DECLARE_VMA_BIT(SEQ_READ, 15), /* App will access data sequentially */
+ DECLARE_VMA_BIT(RAND_READ, 16), /* App will not benefit from clustered reads */
+ DECLARE_VMA_BIT(DONTCOPY, 17), /* Do not copy this vma on fork */
+ DECLARE_VMA_BIT(DONTEXPAND, 18),/* Cannot expand with mremap() */
+ DECLARE_VMA_BIT(LOCKONFAULT, 19),/* Lock pages covered when faulted in */
+ DECLARE_VMA_BIT(ACCOUNT, 20), /* Is a VM accounted object */
+ DECLARE_VMA_BIT(NORESERVE, 21), /* should the VM suppress accounting */
+ DECLARE_VMA_BIT(HUGETLB, 22), /* Huge TLB Page VM */
+ DECLARE_VMA_BIT(SYNC, 23), /* Synchronous page faults */
+ DECLARE_VMA_BIT(ARCH_1, 24), /* Architecture-specific flag */
+ DECLARE_VMA_BIT(WIPEONFORK, 25),/* Wipe VMA contents in child. */
+ DECLARE_VMA_BIT(DONTDUMP, 26), /* Do not include in the core dump */
+ DECLARE_VMA_BIT(SOFTDIRTY, 27), /* NOT soft dirty clean area */
+ DECLARE_VMA_BIT(MIXEDMAP, 28), /* Can contain struct page and pure PFN pages */
+ DECLARE_VMA_BIT(HUGEPAGE, 29), /* MADV_HUGEPAGE marked this vma */
+ DECLARE_VMA_BIT(NOHUGEPAGE, 30),/* MADV_NOHUGEPAGE marked this vma */
+ DECLARE_VMA_BIT(MERGEABLE, 31), /* KSM may merge identical pages */
+ /* These bits are reused, we define specific uses below. */
+ DECLARE_VMA_BIT(HIGH_ARCH_0, 32),
+ DECLARE_VMA_BIT(HIGH_ARCH_1, 33),
+ DECLARE_VMA_BIT(HIGH_ARCH_2, 34),
+ DECLARE_VMA_BIT(HIGH_ARCH_3, 35),
+ DECLARE_VMA_BIT(HIGH_ARCH_4, 36),
+ DECLARE_VMA_BIT(HIGH_ARCH_5, 37),
+ DECLARE_VMA_BIT(HIGH_ARCH_6, 38),
+ /*
+ * This flag is used to connect VFIO to arch specific KVM code. It
+ * indicates that the memory under this VMA is safe for use with any
+ * non-cachable memory type inside KVM. Some VFIO devices, on some
+ * platforms, are thought to be unsafe and can cause machine crashes
+ * if KVM does not lock down the memory type.
+ */
+ DECLARE_VMA_BIT(ALLOW_ANY_UNCACHED, 39),
+#ifdef CONFIG_PPC32
+ DECLARE_VMA_BIT_ALIAS(DROPPABLE, ARCH_1),
+#else
+ DECLARE_VMA_BIT(DROPPABLE, 40),
+#endif
+ DECLARE_VMA_BIT(UFFD_MINOR, 41),
+ DECLARE_VMA_BIT(SEALED, 42),
+ /* Flags that reuse flags above. */
+ DECLARE_VMA_BIT_ALIAS(PKEY_BIT0, HIGH_ARCH_0),
+ DECLARE_VMA_BIT_ALIAS(PKEY_BIT1, HIGH_ARCH_1),
+ DECLARE_VMA_BIT_ALIAS(PKEY_BIT2, HIGH_ARCH_2),
+ DECLARE_VMA_BIT_ALIAS(PKEY_BIT3, HIGH_ARCH_3),
+ DECLARE_VMA_BIT_ALIAS(PKEY_BIT4, HIGH_ARCH_4),
+#if defined(CONFIG_X86_USER_SHADOW_STACK)
+ /*
+ * VM_SHADOW_STACK should not be set with VM_SHARED because of lack of
+ * support core mm.
+ *
+ * These VMAs will get a single end guard page. This helps userspace
+ * protect itself from attacks. A single page is enough for current
+ * shadow stack archs (x86). See the comments near alloc_shstk() in
+ * arch/x86/kernel/shstk.c for more details on the guard size.
+ */
+ DECLARE_VMA_BIT_ALIAS(SHADOW_STACK, HIGH_ARCH_5),
+#elif defined(CONFIG_ARM64_GCS)
+ /*
+ * arm64's Guarded Control Stack implements similar functionality and
+ * has similar constraints to shadow stacks.
+ */
+ DECLARE_VMA_BIT_ALIAS(SHADOW_STACK, HIGH_ARCH_6),
+#endif
+ DECLARE_VMA_BIT_ALIAS(SAO, ARCH_1), /* Strong Access Ordering (powerpc) */
+ DECLARE_VMA_BIT_ALIAS(GROWSUP, ARCH_1), /* parisc */
+ DECLARE_VMA_BIT_ALIAS(SPARC_ADI, ARCH_1), /* sparc64 */
+ DECLARE_VMA_BIT_ALIAS(ARM64_BTI, ARCH_1), /* arm64 */
+ DECLARE_VMA_BIT_ALIAS(ARCH_CLEAR, ARCH_1), /* sparc64, arm64 */
+ DECLARE_VMA_BIT_ALIAS(MAPPED_COPY, ARCH_1), /* !CONFIG_MMU */
+ DECLARE_VMA_BIT_ALIAS(MTE, HIGH_ARCH_4), /* arm64 */
+ DECLARE_VMA_BIT_ALIAS(MTE_ALLOWED, HIGH_ARCH_5),/* arm64 */
+#ifdef CONFIG_STACK_GROWSUP
+ DECLARE_VMA_BIT_ALIAS(STACK, GROWSUP),
+ DECLARE_VMA_BIT_ALIAS(STACK_EARLY, GROWSDOWN),
+#else
+ DECLARE_VMA_BIT_ALIAS(STACK, GROWSDOWN),
+#endif
+};
+
+#define INIT_VM_FLAG(name) BIT((__force int) VMA_ ## name ## _BIT)
+#define VM_READ INIT_VM_FLAG(READ)
+#define VM_WRITE INIT_VM_FLAG(WRITE)
+#define VM_EXEC INIT_VM_FLAG(EXEC)
+#define VM_SHARED INIT_VM_FLAG(SHARED)
+#define VM_MAYREAD INIT_VM_FLAG(MAYREAD)
+#define VM_MAYWRITE INIT_VM_FLAG(MAYWRITE)
+#define VM_MAYEXEC INIT_VM_FLAG(MAYEXEC)
+#define VM_MAYSHARE INIT_VM_FLAG(MAYSHARE)
+#define VM_GROWSDOWN INIT_VM_FLAG(GROWSDOWN)
+#ifdef CONFIG_MMU
+#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)
+#define VM_UFFD_WP INIT_VM_FLAG(UFFD_WP)
+#define VM_LOCKED INIT_VM_FLAG(LOCKED)
+#define VM_IO INIT_VM_FLAG(IO)
+#define VM_SEQ_READ INIT_VM_FLAG(SEQ_READ)
+#define VM_RAND_READ INIT_VM_FLAG(RAND_READ)
+#define VM_DONTCOPY INIT_VM_FLAG(DONTCOPY)
+#define VM_DONTEXPAND INIT_VM_FLAG(DONTEXPAND)
+#define VM_LOCKONFAULT INIT_VM_FLAG(LOCKONFAULT)
+#define VM_ACCOUNT INIT_VM_FLAG(ACCOUNT)
+#define VM_NORESERVE INIT_VM_FLAG(NORESERVE)
+#define VM_HUGETLB INIT_VM_FLAG(HUGETLB)
+#define VM_SYNC INIT_VM_FLAG(SYNC)
+#define VM_ARCH_1 INIT_VM_FLAG(ARCH_1)
+#define VM_WIPEONFORK INIT_VM_FLAG(WIPEONFORK)
+#define VM_DONTDUMP INIT_VM_FLAG(DONTDUMP)
+#ifdef CONFIG_MEM_SOFT_DIRTY
+#define VM_SOFTDIRTY INIT_VM_FLAG(SOFTDIRTY)
+#else
+#define VM_SOFTDIRTY VM_NONE
+#endif
+#define VM_MIXEDMAP INIT_VM_FLAG(MIXEDMAP)
+#define VM_HUGEPAGE INIT_VM_FLAG(HUGEPAGE)
+#define VM_NOHUGEPAGE INIT_VM_FLAG(NOHUGEPAGE)
+#define VM_MERGEABLE INIT_VM_FLAG(MERGEABLE)
+#define VM_STACK INIT_VM_FLAG(STACK)
+#ifdef CONFIG_STACK_GROWS_UP
+#define VM_STACK_EARLY INIT_VM_FLAG(STACK_EARLY)
+#else
+#define VM_STACK_EARLY VM_NONE
+#endif
+#ifdef CONFIG_ARCH_HAS_PKEYS
+#define VM_PKEY_SHIFT ((__force int)VMA_HIGH_ARCH_0_BIT)
+/* Despite the naming, these are FLAGS not bits. */
+#define VM_PKEY_BIT0 INIT_VM_FLAG(PKEY_BIT0)
+#define VM_PKEY_BIT1 INIT_VM_FLAG(PKEY_BIT1)
+#define VM_PKEY_BIT2 INIT_VM_FLAG(PKEY_BIT2)
+#if CONFIG_ARCH_PKEY_BITS > 3
+#define VM_PKEY_BIT3 INIT_VM_FLAG(PKEY_BIT3)
+#else
+#define VM_PKEY_BIT3 VM_NONE
+#endif /* CONFIG_ARCH_PKEY_BITS > 3 */
+#if CONFIG_ARCH_PKEY_BITS > 4
+#define VM_PKEY_BIT4 INIT_VM_FLAG(PKEY_BIT4)
+#else
+#define VM_PKEY_BIT4 VM_NONE
+#endif /* CONFIG_ARCH_PKEY_BITS > 4 */
+#endif /* CONFIG_ARCH_HAS_PKEYS */
+#if defined(CONFIG_X86_USER_SHADOW_STACK) || defined(CONFIG_ARM64_GCS)
+#define VM_SHADOW_STACK INIT_VM_FLAG(SHADOW_STACK)
+#else
+#define VM_SHADOW_STACK VM_NONE
+#endif
+#if defined(CONFIG_PPC64)
+#define VM_SAO INIT_VM_FLAG(SAO)
+#elif defined(CONFIG_PARISC)
+#define VM_GROWSUP INIT_VM_FLAG(GROWSUP)
+#elif defined(CONFIG_SPARC64)
+#define VM_SPARC_ADI INIT_VM_FLAG(SPARC_ADI)
+#define VM_ARCH_CLEAR INIT_VM_FLAG(ARCH_CLEAR)
+#elif defined(CONFIG_ARM64)
+#define VM_ARM64_BTI INIT_VM_FLAG(ARM64_BTI)
+#define VM_ARCH_CLEAR INIT_VM_FLAG(ARCH_CLEAR)
+#elif !defined(CONFIG_MMU)
+#define VM_MAPPED_COPY INIT_VM_FLAG(MAPPED_COPY)
+#endif
+#ifndef VM_GROWSUP
+#define VM_GROWSUP VM_NONE
+#endif
+#ifdef CONFIG_ARM64_MTE
+#define VM_MTE INIT_VM_FLAG(MTE)
+#define VM_MTE_ALLOWED INIT_VM_FLAG(MTE_ALLOWED)
+#else
+#define VM_MTE VM_NONE
+#define VM_MTE_ALLOWED VM_NONE
+#endif
+#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_MINOR
+#define VM_UFFD_MINOR INIT_VM_FLAG(UFFD_MINOR)
+#else
+#define VM_UFFD_MINOR VM_NONE
+#endif
+#ifdef CONFIG_64BIT
+#define VM_ALLOW_ANY_UNCACHED INIT_VM_FLAG(ALLOW_ANY_UNCACHED)
+#define VM_SEALED INIT_VM_FLAG(SEALED)
+#else
+#define VM_ALLOW_ANY_UNCACHED VM_NONE
+#define VM_SEALED VM_NONE
+#endif
+#if defined(CONFIG_64BIT) || defined(CONFIG_PPC32)
+#define VM_DROPPABLE INIT_VM_FLAG(DROPPABLE)
+#else
+#define VM_DROPPABLE VM_NONE
+#endif
+
+/* Bits set in the VMA until the stack is in its final location */
+#define VM_STACK_INCOMPLETE_SETUP (VM_RAND_READ | VM_SEQ_READ | VM_STACK_EARLY)
+
+#define TASK_EXEC ((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0)
+
+/* Common data flag combinations */
+#define VM_DATA_FLAGS_TSK_EXEC (VM_READ | VM_WRITE | TASK_EXEC | \
+ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+#define VM_DATA_FLAGS_NON_EXEC (VM_READ | VM_WRITE | VM_MAYREAD | \
+ VM_MAYWRITE | VM_MAYEXEC)
+#define VM_DATA_FLAGS_EXEC (VM_READ | VM_WRITE | VM_EXEC | \
+ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+
+#ifndef VM_DATA_DEFAULT_FLAGS /* arch can override this */
+#define VM_DATA_DEFAULT_FLAGS VM_DATA_FLAGS_EXEC
+#endif
+
+#ifndef VM_STACK_DEFAULT_FLAGS /* arch can override this */
+#define VM_STACK_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS
+#endif
+
+#define VM_STARTGAP_FLAGS (VM_GROWSDOWN | VM_SHADOW_STACK)
+
+#define VM_STACK_FLAGS (VM_STACK | VM_STACK_DEFAULT_FLAGS | VM_ACCOUNT)
+
+/* VMA basic access permission flags */
+#define VM_ACCESS_FLAGS (VM_READ | VM_WRITE | VM_EXEC)
+
+/*
+ * Special vmas that are non-mergable, non-mlock()able.
+ */
+#define VM_SPECIAL (VM_IO | VM_DONTEXPAND | VM_PFNMAP | VM_MIXEDMAP)
+
+#define DEFAULT_MAP_WINDOW ((1UL << 47) - PAGE_SIZE)
+#define TASK_SIZE_LOW DEFAULT_MAP_WINDOW
+#define TASK_SIZE_MAX DEFAULT_MAP_WINDOW
+#define STACK_TOP TASK_SIZE_LOW
+#define STACK_TOP_MAX TASK_SIZE_MAX
+
+/* This mask represents all the VMA flag bits used by mlock */
+#define VM_LOCKED_MASK (VM_LOCKED | VM_LOCKONFAULT)
+
+#define TASK_EXEC ((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0)
+
+#define VM_DATA_FLAGS_TSK_EXEC (VM_READ | VM_WRITE | TASK_EXEC | \
+ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+
+#define RLIMIT_STACK 3 /* max stack size */
+#define RLIMIT_MEMLOCK 8 /* max locked-in-memory address space */
+
+#define CAP_IPC_LOCK 14
+
+#define VM_STICKY (VM_SOFTDIRTY | VM_MAYBE_GUARD)
+
+#define VM_IGNORE_MERGE VM_STICKY
+
+#define VM_COPY_ON_FORK (VM_PFNMAP | VM_MIXEDMAP | VM_UFFD_WP | VM_MAYBE_GUARD)
+
+#define pgprot_val(x) ((x).pgprot)
+#define __pgprot(x) ((pgprot_t) { (x) } )
+
+#define for_each_vma(__vmi, __vma) \
+ while (((__vma) = vma_next(&(__vmi))) != NULL)
+
+/* The MM code likes to work with exclusive end addresses */
+#define for_each_vma_range(__vmi, __vma, __end) \
+ while (((__vma) = vma_find(&(__vmi), (__end))) != NULL)
+
+#define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK)
+
+#define PHYS_PFN(x) ((unsigned long)((x) >> PAGE_SHIFT))
+
+#define test_and_set_bit(nr, addr) __test_and_set_bit(nr, addr)
+#define test_and_clear_bit(nr, addr) __test_and_clear_bit(nr, addr)
+
+#define AS_MM_ALL_LOCKS 2
+
+#define swap(a, b) \
+ do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0)
+
+/*
+ * Flags for bug emulation.
+ *
+ * These occupy the top three bytes.
+ */
+enum {
+ READ_IMPLIES_EXEC = 0x0400000,
+};
+
+struct vma_iterator {
+ struct ma_state mas;
+};
+
+#define VMA_ITERATOR(name, __mm, __addr) \
+ struct vma_iterator name = { \
+ .mas = { \
+ .tree = &(__mm)->mm_mt, \
+ .index = __addr, \
+ .node = NULL, \
+ .status = ma_start, \
+ }, \
+ }
+
+#define DEFINE_MUTEX(mutexname) \
+ struct mutex mutexname = {}
+
+#define DECLARE_BITMAP(name, bits) \
+ unsigned long name[BITS_TO_LONGS(bits)]
+
+#define EMPTY_VMA_FLAGS ((vma_flags_t){ })
+
+/* What action should be taken after an .mmap_prepare call is complete? */
+enum mmap_action_type {
+ MMAP_NOTHING, /* Mapping is complete, no further action. */
+ MMAP_REMAP_PFN, /* Remap PFN range. */
+ MMAP_IO_REMAP_PFN, /* I/O remap PFN range. */
+};
+
+/*
+ * Describes an action an mmap_prepare hook can instruct to be taken to complete
+ * the mapping of a VMA. Specified in vm_area_desc.
+ */
+struct mmap_action {
+ union {
+ /* Remap range. */
+ struct {
+ unsigned long start;
+ unsigned long start_pfn;
+ unsigned long size;
+ pgprot_t pgprot;
+ } remap;
+ };
+ enum mmap_action_type type;
+
+ /*
+ * If specified, this hook is invoked after the selected action has been
+ * successfully completed. Note that the VMA write lock still held.
+ *
+ * The absolute minimum ought to be done here.
+ *
+ * Returns 0 on success, or an error code.
+ */
+ int (*success_hook)(const struct vm_area_struct *vma);
+
+ /*
+ * If specified, this hook is invoked when an error occurred when
+ * attempting the selection action.
+ *
+ * The hook can return an error code in order to filter the error, but
+ * it is not valid to clear the error here.
+ */
+ int (*error_hook)(int err);
+
+ /*
+ * This should be set in rare instances where the operation required
+ * that the rmap should not be able to access the VMA until
+ * completely set up.
+ */
+ bool hide_from_rmap_until_complete :1;
+};
+
+/* Operations which modify VMAs. */
+enum vma_operation {
+ VMA_OP_SPLIT,
+ VMA_OP_MERGE_UNFAULTED,
+ VMA_OP_REMAP,
+ VMA_OP_FORK,
+};
+
+/*
+ * 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
+ * resultant VMA.
+ *
+ * Helper functions are not required for manipulating any field.
+ */
+struct vm_area_desc {
+ /* Immutable state. */
+ const struct mm_struct *const mm;
+ struct file *const file; /* May vary from vm_file in stacked callers. */
+ unsigned long start;
+ unsigned long end;
+
+ /* Mutable fields. Populated with initial state. */
+ pgoff_t pgoff;
+ struct file *vm_file;
+ union {
+ vm_flags_t vm_flags;
+ vma_flags_t vma_flags;
+ };
+ pgprot_t page_prot;
+
+ /* Write-only fields. */
+ const struct vm_operations_struct *vm_ops;
+ void *private_data;
+
+ /* Take further action? */
+ struct mmap_action action;
+};
+
+struct vm_area_struct {
+ /* The first cache line has the info for VMA tree walking. */
+
+ union {
+ struct {
+ /* VMA covers [vm_start; vm_end) addresses within mm */
+ unsigned long vm_start;
+ unsigned long vm_end;
+ };
+ freeptr_t vm_freeptr; /* Pointer used by SLAB_TYPESAFE_BY_RCU */
+ };
+
+ struct mm_struct *vm_mm; /* The address space we belong to. */
+ pgprot_t vm_page_prot; /* Access permissions of this VMA. */
+
+ /*
+ * Flags, see mm.h.
+ * To modify use vm_flags_{init|reset|set|clear|mod} functions.
+ */
+ union {
+ const vm_flags_t vm_flags;
+ vma_flags_t flags;
+ };
+
+#ifdef CONFIG_PER_VMA_LOCK
+ /*
+ * Can only be written (using WRITE_ONCE()) while holding both:
+ * - mmap_lock (in write mode)
+ * - vm_refcnt bit at VMA_LOCK_OFFSET is set
+ * Can be read reliably while holding one of:
+ * - mmap_lock (in read or write mode)
+ * - vm_refcnt bit at VMA_LOCK_OFFSET is set or vm_refcnt > 1
+ * Can be read unreliably (using READ_ONCE()) for pessimistic bailout
+ * while holding nothing (except RCU to keep the VMA struct allocated).
+ *
+ * This sequence counter is explicitly allowed to overflow; sequence
+ * counter reuse can only lead to occasional unnecessary use of the
+ * slowpath.
+ */
+ unsigned int vm_lock_seq;
+#endif
+
+ /*
+ * A file's MAP_PRIVATE vma can be in both i_mmap tree and anon_vma
+ * list, after a COW of one of the file pages. A MAP_SHARED vma
+ * can only be in the i_mmap tree. An anonymous MAP_PRIVATE, stack
+ * or brk vma (with NULL file) can only be in an anon_vma list.
+ */
+ struct list_head anon_vma_chain; /* Serialized by mmap_lock &
+ * page_table_lock */
+ struct anon_vma *anon_vma; /* Serialized by page_table_lock */
+
+ /* Function pointers to deal with this struct. */
+ const struct vm_operations_struct *vm_ops;
+
+ /* Information about our backing store: */
+ unsigned long vm_pgoff; /* Offset (within vm_file) in PAGE_SIZE
+ units */
+ struct file * vm_file; /* File we map to (can be NULL). */
+ void * vm_private_data; /* was vm_pte (shared mem) */
+
+#ifdef CONFIG_SWAP
+ atomic_long_t swap_readahead_info;
+#endif
+#ifndef CONFIG_MMU
+ struct vm_region *vm_region; /* NOMMU mapping region */
+#endif
+#ifdef CONFIG_NUMA
+ struct mempolicy *vm_policy; /* NUMA policy for the VMA */
+#endif
+#ifdef CONFIG_NUMA_BALANCING
+ struct vma_numab_state *numab_state; /* NUMA Balancing state */
+#endif
+#ifdef CONFIG_PER_VMA_LOCK
+ /* Unstable RCU readers are allowed to read this. */
+ refcount_t vm_refcnt;
+#endif
+ /*
+ * For areas with an address space and backing store,
+ * linkage into the address_space->i_mmap interval tree.
+ *
+ */
+ struct {
+ struct rb_node rb;
+ unsigned long rb_subtree_last;
+ } shared;
+#ifdef CONFIG_ANON_VMA_NAME
+ /*
+ * For private and shared anonymous mappings, a pointer to a null
+ * terminated string containing the name given to the vma, or NULL if
+ * unnamed. Serialized by mmap_lock. Use anon_vma_name to access.
+ */
+ struct anon_vma_name *anon_name;
+#endif
+ struct vm_userfaultfd_ctx vm_userfaultfd_ctx;
+} __randomize_layout;
+
+struct vm_operations_struct {
+ void (*open)(struct vm_area_struct * area);
+ /**
+ * @close: Called when the VMA is being removed from the MM.
+ * Context: User context. May sleep. Caller holds mmap_lock.
+ */
+ void (*close)(struct vm_area_struct * area);
+ /* Called any time before splitting to check if it's allowed */
+ int (*may_split)(struct vm_area_struct *area, unsigned long addr);
+ int (*mremap)(struct vm_area_struct *area);
+ /*
+ * Called by mprotect() to make driver-specific permission
+ * checks before mprotect() is finalised. The VMA must not
+ * be modified. Returns 0 if mprotect() can proceed.
+ */
+ int (*mprotect)(struct vm_area_struct *vma, unsigned long start,
+ unsigned long end, unsigned long newflags);
+ vm_fault_t (*fault)(struct vm_fault *vmf);
+ vm_fault_t (*huge_fault)(struct vm_fault *vmf, unsigned int order);
+ vm_fault_t (*map_pages)(struct vm_fault *vmf,
+ pgoff_t start_pgoff, pgoff_t end_pgoff);
+ unsigned long (*pagesize)(struct vm_area_struct * area);
+
+ /* notification that a previously read-only page is about to become
+ * writable, if an error is returned it will cause a SIGBUS */
+ vm_fault_t (*page_mkwrite)(struct vm_fault *vmf);
+
+ /* same as page_mkwrite when using VM_PFNMAP|VM_MIXEDMAP */
+ vm_fault_t (*pfn_mkwrite)(struct vm_fault *vmf);
+
+ /* called by access_process_vm when get_user_pages() fails, typically
+ * for use by special VMAs. See also generic_access_phys() for a generic
+ * implementation useful for any iomem mapping.
+ */
+ int (*access)(struct vm_area_struct *vma, unsigned long addr,
+ void *buf, int len, int write);
+
+ /* Called by the /proc/PID/maps code to ask the vma whether it
+ * has a special name. Returning non-NULL will also cause this
+ * vma to be dumped unconditionally. */
+ const char *(*name)(struct vm_area_struct *vma);
+
+#ifdef CONFIG_NUMA
+ /*
+ * set_policy() op must add a reference to any non-NULL @new mempolicy
+ * to hold the policy upon return. Caller should pass NULL @new to
+ * remove a policy and fall back to surrounding context--i.e. do not
+ * install a MPOL_DEFAULT policy, nor the task or system default
+ * mempolicy.
+ */
+ int (*set_policy)(struct vm_area_struct *vma, struct mempolicy *new);
+
+ /*
+ * get_policy() op must add reference [mpol_get()] to any policy at
+ * (vma,addr) marked as MPOL_SHARED. The shared policy infrastructure
+ * in mm/mempolicy.c will do this automatically.
+ * get_policy() must NOT add a ref if the policy at (vma,addr) is not
+ * marked as MPOL_SHARED. vma policies are protected by the mmap_lock.
+ * If no [shared/vma] mempolicy exists at the addr, get_policy() op
+ * must return NULL--i.e., do not "fallback" to task or system default
+ * policy.
+ */
+ struct mempolicy *(*get_policy)(struct vm_area_struct *vma,
+ unsigned long addr, pgoff_t *ilx);
+#endif
+#ifdef CONFIG_FIND_NORMAL_PAGE
+ /*
+ * Called by vm_normal_page() for special PTEs in @vma at @addr. This
+ * allows for returning a "normal" page from vm_normal_page() even
+ * though the PTE indicates that the "struct page" either does not exist
+ * or should not be touched: "special".
+ *
+ * Do not add new users: this really only works when a "normal" page
+ * was mapped, but then the PTE got changed to something weird (+
+ * marked special) that would not make pte_pfn() identify the originally
+ * inserted page.
+ */
+ struct page *(*find_normal_page)(struct vm_area_struct *vma,
+ unsigned long addr);
+#endif /* CONFIG_FIND_NORMAL_PAGE */
+};
+
+struct vm_unmapped_area_info {
+#define VM_UNMAPPED_AREA_TOPDOWN 1
+ unsigned long flags;
+ unsigned long length;
+ unsigned long low_limit;
+ unsigned long high_limit;
+ unsigned long align_mask;
+ unsigned long align_offset;
+ unsigned long start_gap;
+};
+
+struct pagetable_move_control {
+ struct vm_area_struct *old; /* Source VMA. */
+ struct vm_area_struct *new; /* Destination VMA. */
+ unsigned long old_addr; /* Address from which the move begins. */
+ unsigned long old_end; /* Exclusive address at which old range ends. */
+ unsigned long new_addr; /* Address to move page tables to. */
+ unsigned long len_in; /* Bytes to remap specified by user. */
+
+ bool need_rmap_locks; /* Do rmap locks need to be taken? */
+ bool for_stack; /* Is this an early temp stack being moved? */
+};
+
+#define PAGETABLE_MOVE(name, old_, new_, old_addr_, new_addr_, len_) \
+ struct pagetable_move_control name = { \
+ .old = old_, \
+ .new = new_, \
+ .old_addr = old_addr_, \
+ .old_end = (old_addr_) + (len_), \
+ .new_addr = new_addr_, \
+ .len_in = len_, \
+ }
+
+static inline void vma_iter_invalidate(struct vma_iterator *vmi)
+{
+ mas_pause(&vmi->mas);
+}
+
+static inline pgprot_t pgprot_modify(pgprot_t oldprot, pgprot_t newprot)
+{
+ return __pgprot(pgprot_val(oldprot) | pgprot_val(newprot));
+}
+
+static inline pgprot_t vm_get_page_prot(vm_flags_t vm_flags)
+{
+ return __pgprot(vm_flags);
+}
+
+static inline bool mm_flags_test(int flag, const struct mm_struct *mm)
+{
+ return test_bit(flag, ACCESS_PRIVATE(&mm->flags, __mm_flags));
+}
+
+/*
+ * 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;
+}
+
+static inline void vma_flags_clear_all(vma_flags_t *flags)
+{
+ bitmap_zero(ACCESS_PRIVATE(flags, __vma_flags), NUM_VMA_FLAG_BITS);
+}
+
+static inline void vma_flag_set(vma_flags_t *flags, vma_flag_t bit)
+{
+ unsigned long *bitmap = ACCESS_PRIVATE(flags, __vma_flags);
+
+ __set_bit((__force int)bit, bitmap);
+}
+
+/* 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);
+}
+
+static inline vma_flags_t __mk_vma_flags(size_t count, const vma_flag_t *bits)
+{
+ vma_flags_t flags;
+ int i;
+
+ vma_flags_clear_all(&flags);
+ for (i = 0; i < count; i++)
+ vma_flag_set(&flags, bits[i]);
+ return flags;
+}
+
+#define mk_vma_flags(...) __mk_vma_flags(COUNT_ARGS(__VA_ARGS__), \
+ (const vma_flag_t []){__VA_ARGS__})
+
+static __always_inline bool vma_flags_test_mask(const vma_flags_t *flags,
+ vma_flags_t to_test)
+{
+ const unsigned long *bitmap = flags->__vma_flags;
+ const unsigned long *bitmap_to_test = to_test.__vma_flags;
+
+ return bitmap_intersects(bitmap_to_test, bitmap, NUM_VMA_FLAG_BITS);
+}
+
+#define vma_flags_test(flags, ...) \
+ vma_flags_test_mask(flags, mk_vma_flags(__VA_ARGS__))
+
+static __always_inline bool vma_flags_test_all_mask(const vma_flags_t *flags,
+ vma_flags_t to_test)
+{
+ const unsigned long *bitmap = flags->__vma_flags;
+ const unsigned long *bitmap_to_test = to_test.__vma_flags;
+
+ return bitmap_subset(bitmap_to_test, bitmap, NUM_VMA_FLAG_BITS);
+}
+
+#define vma_flags_test_all(flags, ...) \
+ vma_flags_test_all_mask(flags, mk_vma_flags(__VA_ARGS__))
+
+static __always_inline void vma_flags_set_mask(vma_flags_t *flags, vma_flags_t to_set)
+{
+ unsigned long *bitmap = flags->__vma_flags;
+ const unsigned long *bitmap_to_set = to_set.__vma_flags;
+
+ bitmap_or(bitmap, bitmap, bitmap_to_set, NUM_VMA_FLAG_BITS);
+}
+
+#define vma_flags_set(flags, ...) \
+ vma_flags_set_mask(flags, mk_vma_flags(__VA_ARGS__))
+
+static __always_inline void vma_flags_clear_mask(vma_flags_t *flags, vma_flags_t to_clear)
+{
+ unsigned long *bitmap = flags->__vma_flags;
+ const unsigned long *bitmap_to_clear = to_clear.__vma_flags;
+
+ bitmap_andnot(bitmap, bitmap, bitmap_to_clear, NUM_VMA_FLAG_BITS);
+}
+
+#define vma_flags_clear(flags, ...) \
+ vma_flags_clear_mask(flags, mk_vma_flags(__VA_ARGS__))
+
+static inline bool vma_test_all_flags_mask(const struct vm_area_struct *vma,
+ vma_flags_t flags)
+{
+ return vma_flags_test_all_mask(&vma->flags, flags);
+}
+
+#define vma_test_all_flags(vma, ...) \
+ vma_test_all_flags_mask(vma, mk_vma_flags(__VA_ARGS__))
+
+static inline bool is_shared_maywrite_vm_flags(vm_flags_t vm_flags)
+{
+ return (vm_flags & (VM_SHARED | VM_MAYWRITE)) ==
+ (VM_SHARED | VM_MAYWRITE);
+}
+
+static inline void vma_set_flags_mask(struct vm_area_struct *vma,
+ vma_flags_t flags)
+{
+ vma_flags_set_mask(&vma->flags, flags);
+}
+
+#define vma_set_flags(vma, ...) \
+ vma_set_flags_mask(vma, mk_vma_flags(__VA_ARGS__))
+
+static inline bool vma_desc_test_flags_mask(const struct vm_area_desc *desc,
+ vma_flags_t flags)
+{
+ return vma_flags_test_mask(&desc->vma_flags, flags);
+}
+
+#define vma_desc_test_flags(desc, ...) \
+ vma_desc_test_flags_mask(desc, mk_vma_flags(__VA_ARGS__))
+
+static inline void vma_desc_set_flags_mask(struct vm_area_desc *desc,
+ vma_flags_t flags)
+{
+ vma_flags_set_mask(&desc->vma_flags, flags);
+}
+
+#define vma_desc_set_flags(desc, ...) \
+ vma_desc_set_flags_mask(desc, mk_vma_flags(__VA_ARGS__))
+
+static inline void vma_desc_clear_flags_mask(struct vm_area_desc *desc,
+ vma_flags_t flags)
+{
+ vma_flags_clear_mask(&desc->vma_flags, flags);
+}
+
+#define vma_desc_clear_flags(desc, ...) \
+ vma_desc_clear_flags_mask(desc, mk_vma_flags(__VA_ARGS__))
+
+static inline bool is_shared_maywrite(const vma_flags_t *flags)
+{
+ return vma_flags_test_all(flags, VMA_SHARED_BIT, VMA_MAYWRITE_BIT);
+}
+
+static inline bool vma_is_shared_maywrite(struct vm_area_struct *vma)
+{
+ return is_shared_maywrite(&vma->flags);
+}
+
+static inline struct vm_area_struct *vma_next(struct vma_iterator *vmi)
+{
+ /*
+ * Uses mas_find() to get the first VMA when the iterator starts.
+ * Calling mas_next() could skip the first entry.
+ */
+ return mas_find(&vmi->mas, ULONG_MAX);
+}
+
+/*
+ * WARNING: to avoid racing with vma_mark_attached()/vma_mark_detached(), these
+ * assertions should be made either under mmap_write_lock or when the object
+ * has been isolated under mmap_write_lock, ensuring no competing writers.
+ */
+static inline void vma_assert_attached(struct vm_area_struct *vma)
+{
+ WARN_ON_ONCE(!refcount_read(&vma->vm_refcnt));
+}
+
+static inline void vma_assert_detached(struct vm_area_struct *vma)
+{
+ WARN_ON_ONCE(refcount_read(&vma->vm_refcnt));
+}
+
+static inline void vma_assert_write_locked(struct vm_area_struct *);
+static inline void vma_mark_attached(struct vm_area_struct *vma)
+{
+ vma_assert_write_locked(vma);
+ vma_assert_detached(vma);
+ refcount_set_release(&vma->vm_refcnt, 1);
+}
+
+static inline void vma_mark_detached(struct vm_area_struct *vma)
+{
+ vma_assert_write_locked(vma);
+ vma_assert_attached(vma);
+ /* We are the only writer, so no need to use vma_refcount_put(). */
+ if (unlikely(!refcount_dec_and_test(&vma->vm_refcnt))) {
+ /*
+ * Reader must have temporarily raised vm_refcnt but it will
+ * drop it without using the vma since vma is write-locked.
+ */
+ }
+}
+
+static inline void vma_init(struct vm_area_struct *vma, struct mm_struct *mm)
+{
+ memset(vma, 0, sizeof(*vma));
+ vma->vm_mm = mm;
+ vma->vm_ops = &vma_dummy_vm_ops;
+ INIT_LIST_HEAD(&vma->anon_vma_chain);
+ vma->vm_lock_seq = UINT_MAX;
+}
+
+/*
+ * These are defined in vma.h, but sadly vm_stat_account() is referenced by
+ * kernel/fork.c, so we have to these broadly available there, and temporarily
+ * define them here to resolve the dependency cycle.
+ */
+#define is_exec_mapping(flags) \
+ ((flags & (VM_EXEC | VM_WRITE | VM_STACK)) == VM_EXEC)
+
+#define is_stack_mapping(flags) \
+ (((flags & VM_STACK) == VM_STACK) || (flags & VM_SHADOW_STACK))
+
+#define is_data_mapping(flags) \
+ ((flags & (VM_WRITE | VM_SHARED | VM_STACK)) == VM_WRITE)
+
+static inline void vm_stat_account(struct mm_struct *mm, vm_flags_t flags,
+ long npages)
+{
+ WRITE_ONCE(mm->total_vm, READ_ONCE(mm->total_vm)+npages);
+
+ if (is_exec_mapping(flags))
+ mm->exec_vm += npages;
+ else if (is_stack_mapping(flags))
+ mm->stack_vm += npages;
+ else if (is_data_mapping(flags))
+ mm->data_vm += npages;
+}
+
+#undef is_exec_mapping
+#undef is_stack_mapping
+#undef is_data_mapping
+
+static inline void vm_unacct_memory(long pages)
+{
+ vm_acct_memory(-pages);
+}
+
+static inline void mapping_allow_writable(struct address_space *mapping)
+{
+ atomic_inc(&mapping->i_mmap_writable);
+}
+
+static inline
+struct vm_area_struct *vma_find(struct vma_iterator *vmi, unsigned long max)
+{
+ return mas_find(&vmi->mas, max - 1);
+}
+
+static inline int vma_iter_clear_gfp(struct vma_iterator *vmi,
+ unsigned long start, unsigned long end, gfp_t gfp)
+{
+ __mas_set_range(&vmi->mas, start, end - 1);
+ mas_store_gfp(&vmi->mas, NULL, gfp);
+ if (unlikely(mas_is_err(&vmi->mas)))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static inline void vma_set_anonymous(struct vm_area_struct *vma)
+{
+ vma->vm_ops = NULL;
+}
+
+/* Declared in vma.h. */
+static inline void set_vma_from_desc(struct vm_area_struct *vma,
+ struct vm_area_desc *desc);
+
+static inline int __compat_vma_mmap(const struct file_operations *f_op,
+ struct file *file, struct vm_area_struct *vma)
+{
+ struct vm_area_desc desc = {
+ .mm = vma->vm_mm,
+ .file = file,
+ .start = vma->vm_start,
+ .end = vma->vm_end,
+
+ .pgoff = vma->vm_pgoff,
+ .vm_file = vma->vm_file,
+ .vm_flags = vma->vm_flags,
+ .page_prot = vma->vm_page_prot,
+
+ .action.type = MMAP_NOTHING, /* Default */
+ };
+ int err;
+
+ err = f_op->mmap_prepare(&desc);
+ if (err)
+ return err;
+
+ mmap_action_prepare(&desc.action, &desc);
+ set_vma_from_desc(vma, &desc);
+ return mmap_action_complete(&desc.action, vma);
+}
+
+static inline int compat_vma_mmap(struct file *file,
+ struct vm_area_struct *vma)
+{
+ return __compat_vma_mmap(file->f_op, file, vma);
+}
+
+
+static inline void vma_iter_init(struct vma_iterator *vmi,
+ struct mm_struct *mm, unsigned long addr)
+{
+ mas_init(&vmi->mas, &mm->mm_mt, addr);
+}
+
+static inline unsigned long vma_pages(struct vm_area_struct *vma)
+{
+ return (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+}
+
+static inline void mmap_assert_locked(struct mm_struct *);
+static inline struct vm_area_struct *find_vma_intersection(struct mm_struct *mm,
+ unsigned long start_addr,
+ unsigned long end_addr)
+{
+ unsigned long index = start_addr;
+
+ mmap_assert_locked(mm);
+ return mt_find(&mm->mm_mt, &index, end_addr - 1);
+}
+
+static inline
+struct vm_area_struct *vma_lookup(struct mm_struct *mm, unsigned long addr)
+{
+ return mtree_load(&mm->mm_mt, addr);
+}
+
+static inline struct vm_area_struct *vma_prev(struct vma_iterator *vmi)
+{
+ return mas_prev(&vmi->mas, 0);
+}
+
+static inline void vma_iter_set(struct vma_iterator *vmi, unsigned long addr)
+{
+ mas_set(&vmi->mas, addr);
+}
+
+static inline bool vma_is_anonymous(struct vm_area_struct *vma)
+{
+ return !vma->vm_ops;
+}
+
+/* Defined in vma.h, so temporarily define here to avoid circular dependency. */
+#define vma_iter_load(vmi) \
+ mas_walk(&(vmi)->mas)
+
+static inline struct vm_area_struct *
+find_vma_prev(struct mm_struct *mm, unsigned long addr,
+ struct vm_area_struct **pprev)
+{
+ struct vm_area_struct *vma;
+ VMA_ITERATOR(vmi, mm, addr);
+
+ vma = vma_iter_load(&vmi);
+ *pprev = vma_prev(&vmi);
+ if (!vma)
+ vma = vma_next(&vmi);
+ return vma;
+}
+
+#undef vma_iter_load
+
+static inline void vma_iter_free(struct vma_iterator *vmi)
+{
+ mas_destroy(&vmi->mas);
+}
+
+static inline
+struct vm_area_struct *vma_iter_next_range(struct vma_iterator *vmi)
+{
+ return mas_next_range(&vmi->mas, ULONG_MAX);
+}
+
+bool vma_wants_writenotify(struct vm_area_struct *vma, pgprot_t vm_page_prot);
+
+/* Update vma->vm_page_prot to reflect vma->vm_flags. */
+static inline void vma_set_page_prot(struct vm_area_struct *vma)
+{
+ vm_flags_t vm_flags = vma->vm_flags;
+ pgprot_t vm_page_prot;
+
+ /* testing: we inline vm_pgprot_modify() to avoid clash with vma.h. */
+ vm_page_prot = pgprot_modify(vma->vm_page_prot, vm_get_page_prot(vm_flags));
+
+ if (vma_wants_writenotify(vma, vm_page_prot)) {
+ vm_flags &= ~VM_SHARED;
+ /* testing: we inline vm_pgprot_modify() to avoid clash with vma.h. */
+ vm_page_prot = pgprot_modify(vm_page_prot, vm_get_page_prot(vm_flags));
+ }
+ /* remove_protection_ptes reads vma->vm_page_prot without mmap_lock */
+ WRITE_ONCE(vma->vm_page_prot, vm_page_prot);
+}
+
+static inline unsigned long stack_guard_start_gap(struct vm_area_struct *vma)
+{
+ if (vma->vm_flags & VM_GROWSDOWN)
+ return stack_guard_gap;
+
+ /* See reasoning around the VM_SHADOW_STACK definition */
+ if (vma->vm_flags & VM_SHADOW_STACK)
+ return PAGE_SIZE;
+
+ return 0;
+}
+
+static inline unsigned long vm_start_gap(struct vm_area_struct *vma)
+{
+ unsigned long gap = stack_guard_start_gap(vma);
+ unsigned long vm_start = vma->vm_start;
+
+ vm_start -= gap;
+ if (vm_start > vma->vm_start)
+ vm_start = 0;
+ return vm_start;
+}
+
+static inline unsigned long vm_end_gap(struct vm_area_struct *vma)
+{
+ unsigned long vm_end = vma->vm_end;
+
+ if (vma->vm_flags & VM_GROWSUP) {
+ vm_end += stack_guard_gap;
+ if (vm_end < vma->vm_end)
+ vm_end = -PAGE_SIZE;
+ }
+ return vm_end;
+}
+
+static inline bool vma_is_accessible(struct vm_area_struct *vma)
+{
+ return vma->vm_flags & VM_ACCESS_FLAGS;
+}
+
+static inline bool mlock_future_ok(const struct mm_struct *mm,
+ vm_flags_t vm_flags, unsigned long bytes)
+{
+ unsigned long locked_pages, limit_pages;
+
+ if (!(vm_flags & VM_LOCKED) || capable(CAP_IPC_LOCK))
+ return true;
+
+ locked_pages = bytes >> PAGE_SHIFT;
+ locked_pages += mm->locked_vm;
+
+ limit_pages = rlimit(RLIMIT_MEMLOCK);
+ limit_pages >>= PAGE_SHIFT;
+
+ return locked_pages <= limit_pages;
+}
+
+static inline bool map_deny_write_exec(unsigned long old, unsigned long new)
+{
+ /* If MDWE is disabled, we have nothing to deny. */
+ if (mm_flags_test(MMF_HAS_MDWE, current->mm))
+ return false;
+
+ /* If the new VMA is not executable, we have nothing to deny. */
+ if (!(new & VM_EXEC))
+ return false;
+
+ /* Under MDWE we do not accept newly writably executable VMAs... */
+ if (new & VM_WRITE)
+ return true;
+
+ /* ...nor previously non-executable VMAs becoming executable. */
+ if (!(old & VM_EXEC))
+ return true;
+
+ return false;
+}
+
+static inline int mapping_map_writable(struct address_space *mapping)
+{
+ return atomic_inc_unless_negative(&mapping->i_mmap_writable) ?
+ 0 : -EPERM;
+}
+
+/* Did the driver provide valid mmap hook configuration? */
+static inline bool can_mmap_file(struct file *file)
+{
+ bool has_mmap = file->f_op->mmap;
+ bool has_mmap_prepare = file->f_op->mmap_prepare;
+
+ /* Hooks are mutually exclusive. */
+ if (WARN_ON_ONCE(has_mmap && has_mmap_prepare))
+ return false;
+ if (!has_mmap && !has_mmap_prepare)
+ return false;
+
+ return true;
+}
+
+static inline int vfs_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ if (file->f_op->mmap_prepare)
+ return compat_vma_mmap(file, vma);
+
+ return file->f_op->mmap(file, vma);
+}
+
+static inline int vfs_mmap_prepare(struct file *file, struct vm_area_desc *desc)
+{
+ return file->f_op->mmap_prepare(desc);
+}
+
+static inline void vma_set_file(struct vm_area_struct *vma, struct file *file)
+{
+ /* Changing an anonymous vma with this is illegal */
+ get_file(file);
+ swap(vma->vm_file, file);
+ fput(file);
+}
+
+struct unmap_desc {
+ struct ma_state *mas; /* the maple state point to the first vma */
+ struct vm_area_struct *first; /* The first vma */
+ unsigned long pg_start; /* The first pagetable address to free (floor) */
+ unsigned long pg_end; /* The last pagetable address to free (ceiling) */
+ unsigned long vma_start; /* The min vma address */
+ unsigned long vma_end; /* The max vma address */
+ unsigned long tree_end; /* Maximum for the vma tree search */
+ unsigned long tree_reset; /* Where to reset the vma tree walk */
+ bool mm_wr_locked; /* If the mmap write lock is held */
+};
diff --git a/tools/testing/vma/include/stubs.h b/tools/testing/vma/include/stubs.h
new file mode 100644
index 000000000000..947a3a0c2566
--- /dev/null
+++ b/tools/testing/vma/include/stubs.h
@@ -0,0 +1,428 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#pragma once
+
+/*
+ * Contains declarations that are STUBBED, that is that are rendered no-ops, in
+ * order to faciliate userland VMA testing.
+ */
+
+/* Forward declarations. */
+struct mm_struct;
+struct vm_area_struct;
+struct vm_area_desc;
+struct pagetable_move_control;
+struct mmap_action;
+struct file;
+struct anon_vma;
+struct anon_vma_chain;
+struct address_space;
+struct unmap_desc;
+
+#define __bitwise
+#define __randomize_layout
+
+#define FIRST_USER_ADDRESS 0UL
+#define USER_PGTABLES_CEILING 0UL
+
+#define vma_policy(vma) NULL
+
+#define down_write_nest_lock(sem, nest_lock)
+
+#define data_race(expr) expr
+
+#define ASSERT_EXCLUSIVE_WRITER(x)
+
+struct vm_userfaultfd_ctx {};
+struct mempolicy {};
+struct mmu_gather {};
+struct mutex {};
+struct vm_fault {};
+
+static inline void userfaultfd_unmap_complete(struct mm_struct *mm,
+ struct list_head *uf)
+{
+}
+
+static inline unsigned long move_page_tables(struct pagetable_move_control *pmc)
+{
+ return 0;
+}
+
+static inline void free_pgd_range(struct mmu_gather *tlb,
+ unsigned long addr, unsigned long end,
+ unsigned long floor, unsigned long ceiling)
+{
+}
+
+static inline int ksm_execve(struct mm_struct *mm)
+{
+ return 0;
+}
+
+static inline void ksm_exit(struct mm_struct *mm)
+{
+}
+
+static inline void vma_numab_state_init(struct vm_area_struct *vma)
+{
+}
+
+static inline void vma_numab_state_free(struct vm_area_struct *vma)
+{
+}
+
+static inline void dup_anon_vma_name(struct vm_area_struct *orig_vma,
+ struct vm_area_struct *new_vma)
+{
+}
+
+static inline void free_anon_vma_name(struct vm_area_struct *vma)
+{
+}
+
+static inline void mmap_action_prepare(struct mmap_action *action,
+ struct vm_area_desc *desc)
+{
+}
+
+static inline int mmap_action_complete(struct mmap_action *action,
+ struct vm_area_struct *vma)
+{
+ return 0;
+}
+
+static inline void fixup_hugetlb_reservations(struct vm_area_struct *vma)
+{
+}
+
+static inline bool shmem_file(struct file *file)
+{
+ return false;
+}
+
+static inline vm_flags_t ksm_vma_flags(const struct mm_struct *mm,
+ const struct file *file, vm_flags_t vm_flags)
+{
+ return vm_flags;
+}
+
+static inline void remap_pfn_range_prepare(struct vm_area_desc *desc, unsigned long pfn)
+{
+}
+
+static inline int remap_pfn_range_complete(struct vm_area_struct *vma, unsigned long addr,
+ unsigned long pfn, unsigned long size, pgprot_t pgprot)
+{
+ return 0;
+}
+
+static inline int do_munmap(struct mm_struct *, unsigned long, size_t,
+ struct list_head *uf)
+{
+ return 0;
+}
+
+/* Currently stubbed but we may later wish to un-stub. */
+static inline void vm_acct_memory(long pages);
+
+static inline void mmap_assert_locked(struct mm_struct *mm)
+{
+}
+
+
+static inline void anon_vma_unlock_write(struct anon_vma *anon_vma)
+{
+}
+
+static inline void i_mmap_unlock_write(struct address_space *mapping)
+{
+}
+
+static inline int userfaultfd_unmap_prep(struct vm_area_struct *vma,
+ unsigned long start,
+ unsigned long end,
+ struct list_head *unmaps)
+{
+ return 0;
+}
+
+static inline void mmap_write_downgrade(struct mm_struct *mm)
+{
+}
+
+static inline void mmap_read_unlock(struct mm_struct *mm)
+{
+}
+
+static inline void mmap_write_unlock(struct mm_struct *mm)
+{
+}
+
+static inline int mmap_write_lock_killable(struct mm_struct *mm)
+{
+ return 0;
+}
+
+static inline bool can_modify_mm(struct mm_struct *mm,
+ unsigned long start,
+ unsigned long end)
+{
+ return true;
+}
+
+static inline void arch_unmap(struct mm_struct *mm,
+ unsigned long start,
+ unsigned long end)
+{
+}
+
+static inline bool mpol_equal(struct mempolicy *a, struct mempolicy *b)
+{
+ return true;
+}
+
+static inline void khugepaged_enter_vma(struct vm_area_struct *vma,
+ vm_flags_t vm_flags)
+{
+}
+
+static inline bool mapping_can_writeback(struct address_space *mapping)
+{
+ return true;
+}
+
+static inline bool is_vm_hugetlb_page(struct vm_area_struct *vma)
+{
+ return false;
+}
+
+static inline bool vma_soft_dirty_enabled(struct vm_area_struct *vma)
+{
+ return false;
+}
+
+static inline bool userfaultfd_wp(struct vm_area_struct *vma)
+{
+ return false;
+}
+
+static inline void mmap_assert_write_locked(struct mm_struct *mm)
+{
+}
+
+static inline void mutex_lock(struct mutex *lock)
+{
+}
+
+static inline void mutex_unlock(struct mutex *lock)
+{
+}
+
+static inline bool mutex_is_locked(struct mutex *lock)
+{
+ return true;
+}
+
+static inline bool signal_pending(void *p)
+{
+ return false;
+}
+
+static inline bool is_file_hugepages(struct file *file)
+{
+ return false;
+}
+
+static inline int security_vm_enough_memory_mm(struct mm_struct *mm, long pages)
+{
+ return 0;
+}
+
+static inline bool may_expand_vm(struct mm_struct *mm, vm_flags_t flags,
+ unsigned long npages)
+{
+ return true;
+}
+
+static inline int shmem_zero_setup(struct vm_area_struct *vma)
+{
+ return 0;
+}
+
+
+static inline void vm_acct_memory(long pages)
+{
+}
+
+static inline void vma_interval_tree_insert(struct vm_area_struct *vma,
+ struct rb_root_cached *rb)
+{
+}
+
+static inline void vma_interval_tree_remove(struct vm_area_struct *vma,
+ struct rb_root_cached *rb)
+{
+}
+
+static inline void flush_dcache_mmap_unlock(struct address_space *mapping)
+{
+}
+
+static inline void anon_vma_interval_tree_insert(struct anon_vma_chain *avc,
+ struct rb_root_cached *rb)
+{
+}
+
+static inline void anon_vma_interval_tree_remove(struct anon_vma_chain *avc,
+ struct rb_root_cached *rb)
+{
+}
+
+static inline void uprobe_mmap(struct vm_area_struct *vma)
+{
+}
+
+static inline void uprobe_munmap(struct vm_area_struct *vma,
+ unsigned long start, unsigned long end)
+{
+}
+
+static inline void i_mmap_lock_write(struct address_space *mapping)
+{
+}
+
+static inline void anon_vma_lock_write(struct anon_vma *anon_vma)
+{
+}
+
+static inline void vma_assert_write_locked(struct vm_area_struct *vma)
+{
+}
+
+static inline void ksm_add_vma(struct vm_area_struct *vma)
+{
+}
+
+static inline void perf_event_mmap(struct vm_area_struct *vma)
+{
+}
+
+static inline bool vma_is_dax(struct vm_area_struct *vma)
+{
+ return false;
+}
+
+static inline struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
+{
+ return NULL;
+}
+
+static inline bool arch_validate_flags(vm_flags_t flags)
+{
+ return true;
+}
+
+static inline void vma_close(struct vm_area_struct *vma)
+{
+}
+
+static inline int mmap_file(struct file *file, struct vm_area_struct *vma)
+{
+ return 0;
+}
+
+static inline int is_hugepage_only_range(struct mm_struct *mm,
+ unsigned long addr, unsigned long len)
+{
+ return 0;
+}
+
+static inline bool capable(int cap)
+{
+ return true;
+}
+
+static inline struct anon_vma_name *anon_vma_name(struct vm_area_struct *vma)
+{
+ return NULL;
+}
+
+static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma,
+ struct vm_userfaultfd_ctx vm_ctx)
+{
+ return true;
+}
+
+static inline bool anon_vma_name_eq(struct anon_vma_name *anon_name1,
+ struct anon_vma_name *anon_name2)
+{
+ return true;
+}
+
+static inline void might_sleep(void)
+{
+}
+
+static inline void fput(struct file *file)
+{
+}
+
+static inline void mpol_put(struct mempolicy *pol)
+{
+}
+
+static inline void lru_add_drain(void)
+{
+}
+
+static inline void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm)
+{
+}
+
+static inline void update_hiwater_rss(struct mm_struct *mm)
+{
+}
+
+static inline void update_hiwater_vm(struct mm_struct *mm)
+{
+}
+
+static inline void unmap_vmas(struct mmu_gather *tlb, struct unmap_desc *unmap)
+{
+}
+
+static inline void free_pgtables(struct mmu_gather *tlb, struct unmap_desc *unmap)
+{
+}
+
+static inline void mapping_unmap_writable(struct address_space *mapping)
+{
+}
+
+static inline void flush_dcache_mmap_lock(struct address_space *mapping)
+{
+}
+
+static inline void tlb_finish_mmu(struct mmu_gather *tlb)
+{
+}
+
+static inline struct file *get_file(struct file *f)
+{
+ return f;
+}
+
+static inline int vma_dup_policy(struct vm_area_struct *src, struct vm_area_struct *dst)
+{
+ return 0;
+}
+
+static inline void vma_adjust_trans_huge(struct vm_area_struct *vma,
+ unsigned long start,
+ unsigned long end,
+ struct vm_area_struct *next)
+{
+}
+
+static inline void hugetlb_split(struct vm_area_struct *, unsigned long) {}
diff --git a/tools/testing/vma/vma_internal.h b/tools/testing/vma/vma_internal.h
index b48ebae3927d..e3ed05b57819 100644
--- a/tools/testing/vma/vma_internal.h
+++ b/tools/testing/vma/vma_internal.h
@@ -12,15 +12,11 @@
#ifndef __MM_VMA_INTERNAL_H
#define __MM_VMA_INTERNAL_H
-#define __private
-#define __bitwise
-#define __randomize_layout
+#include <stdlib.h>
#define CONFIG_MMU
#define CONFIG_PER_VMA_LOCK
-#include <stdlib.h>
-
#ifdef __CONCAT
#undef __CONCAT
#endif
@@ -35,1936 +31,28 @@
#include <linux/refcount.h>
#include <linux/slab.h>
-extern unsigned long stack_guard_gap;
-#ifdef CONFIG_MMU
-extern unsigned long mmap_min_addr;
-extern unsigned long dac_mmap_min_addr;
-#else
-#define mmap_min_addr 0UL
-#define dac_mmap_min_addr 0UL
-#endif
-
-#define ACCESS_PRIVATE(p, member) ((p)->member)
-
-#define VM_WARN_ON(_expr) (WARN_ON(_expr))
-#define VM_WARN_ON_ONCE(_expr) (WARN_ON_ONCE(_expr))
-#define VM_WARN_ON_VMG(_expr, _vmg) (WARN_ON(_expr))
-#define VM_BUG_ON(_expr) (BUG_ON(_expr))
-#define VM_BUG_ON_VMA(_expr, _vma) (BUG_ON(_expr))
-
-#define MMF_HAS_MDWE 28
-
-/*
- * vm_flags in vm_area_struct, see mm_types.h.
- * When changing, update also include/trace/events/mmflags.h
- */
-
-#define VM_NONE 0x00000000
-
-/**
- * typedef vma_flag_t - specifies an individual VMA flag by bit number.
- *
- * This value is made type safe by sparse to avoid passing invalid flag values
- * around.
- */
-typedef int __bitwise vma_flag_t;
-
-#define DECLARE_VMA_BIT(name, bitnum) \
- VMA_ ## name ## _BIT = ((__force vma_flag_t)bitnum)
-#define DECLARE_VMA_BIT_ALIAS(name, aliased) \
- VMA_ ## name ## _BIT = VMA_ ## aliased ## _BIT
-enum {
- DECLARE_VMA_BIT(READ, 0),
- DECLARE_VMA_BIT(WRITE, 1),
- DECLARE_VMA_BIT(EXEC, 2),
- DECLARE_VMA_BIT(SHARED, 3),
- /* mprotect() hardcodes VM_MAYREAD >> 4 == VM_READ, and so for r/w/x bits. */
- DECLARE_VMA_BIT(MAYREAD, 4), /* limits for mprotect() etc. */
- DECLARE_VMA_BIT(MAYWRITE, 5),
- DECLARE_VMA_BIT(MAYEXEC, 6),
- DECLARE_VMA_BIT(MAYSHARE, 7),
- DECLARE_VMA_BIT(GROWSDOWN, 8), /* general info on the segment */
-#ifdef CONFIG_MMU
- DECLARE_VMA_BIT(UFFD_MISSING, 9),/* missing pages tracking */
-#else
- /* nommu: R/O MAP_PRIVATE mapping that might overlay a file mapping */
- DECLARE_VMA_BIT(MAYOVERLAY, 9),
-#endif /* CONFIG_MMU */
- /* Page-ranges managed without "struct page", just pure PFN */
- DECLARE_VMA_BIT(PFNMAP, 10),
- DECLARE_VMA_BIT(MAYBE_GUARD, 11),
- DECLARE_VMA_BIT(UFFD_WP, 12), /* wrprotect pages tracking */
- DECLARE_VMA_BIT(LOCKED, 13),
- DECLARE_VMA_BIT(IO, 14), /* Memory mapped I/O or similar */
- DECLARE_VMA_BIT(SEQ_READ, 15), /* App will access data sequentially */
- DECLARE_VMA_BIT(RAND_READ, 16), /* App will not benefit from clustered reads */
- DECLARE_VMA_BIT(DONTCOPY, 17), /* Do not copy this vma on fork */
- DECLARE_VMA_BIT(DONTEXPAND, 18),/* Cannot expand with mremap() */
- DECLARE_VMA_BIT(LOCKONFAULT, 19),/* Lock pages covered when faulted in */
- DECLARE_VMA_BIT(ACCOUNT, 20), /* Is a VM accounted object */
- DECLARE_VMA_BIT(NORESERVE, 21), /* should the VM suppress accounting */
- DECLARE_VMA_BIT(HUGETLB, 22), /* Huge TLB Page VM */
- DECLARE_VMA_BIT(SYNC, 23), /* Synchronous page faults */
- DECLARE_VMA_BIT(ARCH_1, 24), /* Architecture-specific flag */
- DECLARE_VMA_BIT(WIPEONFORK, 25),/* Wipe VMA contents in child. */
- DECLARE_VMA_BIT(DONTDUMP, 26), /* Do not include in the core dump */
- DECLARE_VMA_BIT(SOFTDIRTY, 27), /* NOT soft dirty clean area */
- DECLARE_VMA_BIT(MIXEDMAP, 28), /* Can contain struct page and pure PFN pages */
- DECLARE_VMA_BIT(HUGEPAGE, 29), /* MADV_HUGEPAGE marked this vma */
- DECLARE_VMA_BIT(NOHUGEPAGE, 30),/* MADV_NOHUGEPAGE marked this vma */
- DECLARE_VMA_BIT(MERGEABLE, 31), /* KSM may merge identical pages */
- /* These bits are reused, we define specific uses below. */
- DECLARE_VMA_BIT(HIGH_ARCH_0, 32),
- DECLARE_VMA_BIT(HIGH_ARCH_1, 33),
- DECLARE_VMA_BIT(HIGH_ARCH_2, 34),
- DECLARE_VMA_BIT(HIGH_ARCH_3, 35),
- DECLARE_VMA_BIT(HIGH_ARCH_4, 36),
- DECLARE_VMA_BIT(HIGH_ARCH_5, 37),
- DECLARE_VMA_BIT(HIGH_ARCH_6, 38),
- /*
- * This flag is used to connect VFIO to arch specific KVM code. It
- * indicates that the memory under this VMA is safe for use with any
- * non-cachable memory type inside KVM. Some VFIO devices, on some
- * platforms, are thought to be unsafe and can cause machine crashes
- * if KVM does not lock down the memory type.
- */
- DECLARE_VMA_BIT(ALLOW_ANY_UNCACHED, 39),
-#ifdef CONFIG_PPC32
- DECLARE_VMA_BIT_ALIAS(DROPPABLE, ARCH_1),
-#else
- DECLARE_VMA_BIT(DROPPABLE, 40),
-#endif
- DECLARE_VMA_BIT(UFFD_MINOR, 41),
- DECLARE_VMA_BIT(SEALED, 42),
- /* Flags that reuse flags above. */
- DECLARE_VMA_BIT_ALIAS(PKEY_BIT0, HIGH_ARCH_0),
- DECLARE_VMA_BIT_ALIAS(PKEY_BIT1, HIGH_ARCH_1),
- DECLARE_VMA_BIT_ALIAS(PKEY_BIT2, HIGH_ARCH_2),
- DECLARE_VMA_BIT_ALIAS(PKEY_BIT3, HIGH_ARCH_3),
- DECLARE_VMA_BIT_ALIAS(PKEY_BIT4, HIGH_ARCH_4),
-#if defined(CONFIG_X86_USER_SHADOW_STACK)
- /*
- * VM_SHADOW_STACK should not be set with VM_SHARED because of lack of
- * support core mm.
- *
- * These VMAs will get a single end guard page. This helps userspace
- * protect itself from attacks. A single page is enough for current
- * shadow stack archs (x86). See the comments near alloc_shstk() in
- * arch/x86/kernel/shstk.c for more details on the guard size.
- */
- DECLARE_VMA_BIT_ALIAS(SHADOW_STACK, HIGH_ARCH_5),
-#elif defined(CONFIG_ARM64_GCS)
- /*
- * arm64's Guarded Control Stack implements similar functionality and
- * has similar constraints to shadow stacks.
- */
- DECLARE_VMA_BIT_ALIAS(SHADOW_STACK, HIGH_ARCH_6),
-#endif
- DECLARE_VMA_BIT_ALIAS(SAO, ARCH_1), /* Strong Access Ordering (powerpc) */
- DECLARE_VMA_BIT_ALIAS(GROWSUP, ARCH_1), /* parisc */
- DECLARE_VMA_BIT_ALIAS(SPARC_ADI, ARCH_1), /* sparc64 */
- DECLARE_VMA_BIT_ALIAS(ARM64_BTI, ARCH_1), /* arm64 */
- DECLARE_VMA_BIT_ALIAS(ARCH_CLEAR, ARCH_1), /* sparc64, arm64 */
- DECLARE_VMA_BIT_ALIAS(MAPPED_COPY, ARCH_1), /* !CONFIG_MMU */
- DECLARE_VMA_BIT_ALIAS(MTE, HIGH_ARCH_4), /* arm64 */
- DECLARE_VMA_BIT_ALIAS(MTE_ALLOWED, HIGH_ARCH_5),/* arm64 */
-#ifdef CONFIG_STACK_GROWSUP
- DECLARE_VMA_BIT_ALIAS(STACK, GROWSUP),
- DECLARE_VMA_BIT_ALIAS(STACK_EARLY, GROWSDOWN),
-#else
- DECLARE_VMA_BIT_ALIAS(STACK, GROWSDOWN),
-#endif
-};
-
-#define INIT_VM_FLAG(name) BIT((__force int) VMA_ ## name ## _BIT)
-#define VM_READ INIT_VM_FLAG(READ)
-#define VM_WRITE INIT_VM_FLAG(WRITE)
-#define VM_EXEC INIT_VM_FLAG(EXEC)
-#define VM_SHARED INIT_VM_FLAG(SHARED)
-#define VM_MAYREAD INIT_VM_FLAG(MAYREAD)
-#define VM_MAYWRITE INIT_VM_FLAG(MAYWRITE)
-#define VM_MAYEXEC INIT_VM_FLAG(MAYEXEC)
-#define VM_MAYSHARE INIT_VM_FLAG(MAYSHARE)
-#define VM_GROWSDOWN INIT_VM_FLAG(GROWSDOWN)
-#ifdef CONFIG_MMU
-#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)
-#define VM_UFFD_WP INIT_VM_FLAG(UFFD_WP)
-#define VM_LOCKED INIT_VM_FLAG(LOCKED)
-#define VM_IO INIT_VM_FLAG(IO)
-#define VM_SEQ_READ INIT_VM_FLAG(SEQ_READ)
-#define VM_RAND_READ INIT_VM_FLAG(RAND_READ)
-#define VM_DONTCOPY INIT_VM_FLAG(DONTCOPY)
-#define VM_DONTEXPAND INIT_VM_FLAG(DONTEXPAND)
-#define VM_LOCKONFAULT INIT_VM_FLAG(LOCKONFAULT)
-#define VM_ACCOUNT INIT_VM_FLAG(ACCOUNT)
-#define VM_NORESERVE INIT_VM_FLAG(NORESERVE)
-#define VM_HUGETLB INIT_VM_FLAG(HUGETLB)
-#define VM_SYNC INIT_VM_FLAG(SYNC)
-#define VM_ARCH_1 INIT_VM_FLAG(ARCH_1)
-#define VM_WIPEONFORK INIT_VM_FLAG(WIPEONFORK)
-#define VM_DONTDUMP INIT_VM_FLAG(DONTDUMP)
-#ifdef CONFIG_MEM_SOFT_DIRTY
-#define VM_SOFTDIRTY INIT_VM_FLAG(SOFTDIRTY)
-#else
-#define VM_SOFTDIRTY VM_NONE
-#endif
-#define VM_MIXEDMAP INIT_VM_FLAG(MIXEDMAP)
-#define VM_HUGEPAGE INIT_VM_FLAG(HUGEPAGE)
-#define VM_NOHUGEPAGE INIT_VM_FLAG(NOHUGEPAGE)
-#define VM_MERGEABLE INIT_VM_FLAG(MERGEABLE)
-#define VM_STACK INIT_VM_FLAG(STACK)
-#ifdef CONFIG_STACK_GROWS_UP
-#define VM_STACK_EARLY INIT_VM_FLAG(STACK_EARLY)
-#else
-#define VM_STACK_EARLY VM_NONE
-#endif
-#ifdef CONFIG_ARCH_HAS_PKEYS
-#define VM_PKEY_SHIFT ((__force int)VMA_HIGH_ARCH_0_BIT)
-/* Despite the naming, these are FLAGS not bits. */
-#define VM_PKEY_BIT0 INIT_VM_FLAG(PKEY_BIT0)
-#define VM_PKEY_BIT1 INIT_VM_FLAG(PKEY_BIT1)
-#define VM_PKEY_BIT2 INIT_VM_FLAG(PKEY_BIT2)
-#if CONFIG_ARCH_PKEY_BITS > 3
-#define VM_PKEY_BIT3 INIT_VM_FLAG(PKEY_BIT3)
-#else
-#define VM_PKEY_BIT3 VM_NONE
-#endif /* CONFIG_ARCH_PKEY_BITS > 3 */
-#if CONFIG_ARCH_PKEY_BITS > 4
-#define VM_PKEY_BIT4 INIT_VM_FLAG(PKEY_BIT4)
-#else
-#define VM_PKEY_BIT4 VM_NONE
-#endif /* CONFIG_ARCH_PKEY_BITS > 4 */
-#endif /* CONFIG_ARCH_HAS_PKEYS */
-#if defined(CONFIG_X86_USER_SHADOW_STACK) || defined(CONFIG_ARM64_GCS)
-#define VM_SHADOW_STACK INIT_VM_FLAG(SHADOW_STACK)
-#else
-#define VM_SHADOW_STACK VM_NONE
-#endif
-#if defined(CONFIG_PPC64)
-#define VM_SAO INIT_VM_FLAG(SAO)
-#elif defined(CONFIG_PARISC)
-#define VM_GROWSUP INIT_VM_FLAG(GROWSUP)
-#elif defined(CONFIG_SPARC64)
-#define VM_SPARC_ADI INIT_VM_FLAG(SPARC_ADI)
-#define VM_ARCH_CLEAR INIT_VM_FLAG(ARCH_CLEAR)
-#elif defined(CONFIG_ARM64)
-#define VM_ARM64_BTI INIT_VM_FLAG(ARM64_BTI)
-#define VM_ARCH_CLEAR INIT_VM_FLAG(ARCH_CLEAR)
-#elif !defined(CONFIG_MMU)
-#define VM_MAPPED_COPY INIT_VM_FLAG(MAPPED_COPY)
-#endif
-#ifndef VM_GROWSUP
-#define VM_GROWSUP VM_NONE
-#endif
-#ifdef CONFIG_ARM64_MTE
-#define VM_MTE INIT_VM_FLAG(MTE)
-#define VM_MTE_ALLOWED INIT_VM_FLAG(MTE_ALLOWED)
-#else
-#define VM_MTE VM_NONE
-#define VM_MTE_ALLOWED VM_NONE
-#endif
-#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_MINOR
-#define VM_UFFD_MINOR INIT_VM_FLAG(UFFD_MINOR)
-#else
-#define VM_UFFD_MINOR VM_NONE
-#endif
-#ifdef CONFIG_64BIT
-#define VM_ALLOW_ANY_UNCACHED INIT_VM_FLAG(ALLOW_ANY_UNCACHED)
-#define VM_SEALED INIT_VM_FLAG(SEALED)
-#else
-#define VM_ALLOW_ANY_UNCACHED VM_NONE
-#define VM_SEALED VM_NONE
-#endif
-#if defined(CONFIG_64BIT) || defined(CONFIG_PPC32)
-#define VM_DROPPABLE INIT_VM_FLAG(DROPPABLE)
-#else
-#define VM_DROPPABLE VM_NONE
-#endif
-
-/* Bits set in the VMA until the stack is in its final location */
-#define VM_STACK_INCOMPLETE_SETUP (VM_RAND_READ | VM_SEQ_READ | VM_STACK_EARLY)
-
-#define TASK_EXEC ((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0)
-
-/* Common data flag combinations */
-#define VM_DATA_FLAGS_TSK_EXEC (VM_READ | VM_WRITE | TASK_EXEC | \
- VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
-#define VM_DATA_FLAGS_NON_EXEC (VM_READ | VM_WRITE | VM_MAYREAD | \
- VM_MAYWRITE | VM_MAYEXEC)
-#define VM_DATA_FLAGS_EXEC (VM_READ | VM_WRITE | VM_EXEC | \
- VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
-
-#ifndef VM_DATA_DEFAULT_FLAGS /* arch can override this */
-#define VM_DATA_DEFAULT_FLAGS VM_DATA_FLAGS_EXEC
-#endif
-
-#ifndef VM_STACK_DEFAULT_FLAGS /* arch can override this */
-#define VM_STACK_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS
-#endif
-
-#define VM_STARTGAP_FLAGS (VM_GROWSDOWN | VM_SHADOW_STACK)
-
-#define VM_STACK_FLAGS (VM_STACK | VM_STACK_DEFAULT_FLAGS | VM_ACCOUNT)
-
-/* VMA basic access permission flags */
-#define VM_ACCESS_FLAGS (VM_READ | VM_WRITE | VM_EXEC)
-
-/*
- * Special vmas that are non-mergable, non-mlock()able.
- */
-#define VM_SPECIAL (VM_IO | VM_DONTEXPAND | VM_PFNMAP | VM_MIXEDMAP)
-
-#define DEFAULT_MAP_WINDOW ((1UL << 47) - PAGE_SIZE)
-#define TASK_SIZE_LOW DEFAULT_MAP_WINDOW
-#define TASK_SIZE_MAX DEFAULT_MAP_WINDOW
-#define STACK_TOP TASK_SIZE_LOW
-#define STACK_TOP_MAX TASK_SIZE_MAX
-
-/* This mask represents all the VMA flag bits used by mlock */
-#define VM_LOCKED_MASK (VM_LOCKED | VM_LOCKONFAULT)
-
-#define TASK_EXEC ((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0)
-
-#define VM_DATA_FLAGS_TSK_EXEC (VM_READ | VM_WRITE | TASK_EXEC | \
- VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
-
-#define RLIMIT_STACK 3 /* max stack size */
-#define RLIMIT_MEMLOCK 8 /* max locked-in-memory address space */
-
-#define CAP_IPC_LOCK 14
-
-/*
- * Flags which should be 'sticky' on merge - that is, flags which, when one VMA
- * possesses it but the other does not, the merged VMA should nonetheless have
- * applied to it:
- *
- * VM_SOFTDIRTY - if a VMA is marked soft-dirty, that is has not had its
- * references cleared via /proc/$pid/clear_refs, any merged VMA
- * should be considered soft-dirty also as it operates at a VMA
- * granularity.
- */
-#define VM_STICKY (VM_SOFTDIRTY | VM_MAYBE_GUARD)
-
/*
- * VMA flags we ignore for the purposes of merge, i.e. one VMA possessing one
- * of these flags and the other not does not preclude a merge.
- *
- * VM_STICKY - When merging VMAs, VMA flags must match, unless they are
- * 'sticky'. If any sticky flags exist in either VMA, we simply
- * set all of them on the merged VMA.
+ * DUPLICATE typedef definitions from kernel source that have to be declared
+ * ahead of all other headers.
*/
-#define VM_IGNORE_MERGE VM_STICKY
-
-/*
- * Flags which should result in page tables being copied on fork. These are
- * flags which indicate that the VMA maps page tables which cannot be
- * reconsistuted upon page fault, so necessitate page table copying upon
- *
- * VM_PFNMAP / VM_MIXEDMAP - These contain kernel-mapped data which cannot be
- * reasonably reconstructed on page fault.
- *
- * VM_UFFD_WP - Encodes metadata about an installed uffd
- * write protect handler, which cannot be
- * reconstructed on page fault.
- *
- * We always copy pgtables when dst_vma has uffd-wp
- * enabled even if it's file-backed
- * (e.g. shmem). Because when uffd-wp is enabled,
- * pgtable contains uffd-wp protection information,
- * that's something we can't retrieve from page cache,
- * and skip copying will lose those info.
- *
- * VM_MAYBE_GUARD - Could contain page guard region markers which
- * by design are a property of the page tables
- * only and thus cannot be reconstructed on page
- * fault.
- */
-#define VM_COPY_ON_FORK (VM_PFNMAP | VM_MIXEDMAP | VM_UFFD_WP | VM_MAYBE_GUARD)
-
-#define FIRST_USER_ADDRESS 0UL
-#define USER_PGTABLES_CEILING 0UL
-
-#define vma_policy(vma) NULL
-
-#define down_write_nest_lock(sem, nest_lock)
-
-#define pgprot_val(x) ((x).pgprot)
-#define __pgprot(x) ((pgprot_t) { (x) } )
-
-#define for_each_vma(__vmi, __vma) \
- while (((__vma) = vma_next(&(__vmi))) != NULL)
-
-/* The MM code likes to work with exclusive end addresses */
-#define for_each_vma_range(__vmi, __vma, __end) \
- while (((__vma) = vma_find(&(__vmi), (__end))) != NULL)
-
-#define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK)
-
-#define PHYS_PFN(x) ((unsigned long)((x) >> PAGE_SHIFT))
-
-#define test_and_set_bit(nr, addr) __test_and_set_bit(nr, addr)
-#define test_and_clear_bit(nr, addr) __test_and_clear_bit(nr, addr)
-
-#define TASK_SIZE ((1ul << 47)-PAGE_SIZE)
-
-#define AS_MM_ALL_LOCKS 2
-
-/* We hardcode this for now. */
-#define sysctl_max_map_count 0x1000000UL
-
-#define pgoff_t unsigned long
-typedef unsigned long pgprotval_t;
-typedef struct pgprot { pgprotval_t pgprot; } pgprot_t;
-typedef unsigned long vm_flags_t;
-typedef __bitwise unsigned int vm_fault_t;
-
-/*
- * The shared stubs do not implement this, it amounts to an fprintf(STDERR,...)
- * either way :)
- */
-#define pr_warn_once pr_err
-
-#define data_race(expr) expr
-
-#define ASSERT_EXCLUSIVE_WRITER(x)
-
-#define pgtable_supports_soft_dirty() 1
-
-/**
- * swap - swap values of @a and @b
- * @a: first value
- * @b: second value
- */
-#define swap(a, b) \
- do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0)
-
-struct kref {
- refcount_t refcount;
-};
-
-/*
- * Define the task command name length as enum, then it can be visible to
- * BPF programs.
- */
-enum {
- TASK_COMM_LEN = 16,
-};
-
-/*
- * Flags for bug emulation.
- *
- * These occupy the top three bytes.
- */
-enum {
- READ_IMPLIES_EXEC = 0x0400000,
-};
-
-struct task_struct {
- char comm[TASK_COMM_LEN];
- pid_t pid;
- struct mm_struct *mm;
-
- /* Used for emulating ABI behavior of previous Linux versions: */
- unsigned int personality;
-};
-
-struct task_struct *get_current(void);
-#define current get_current()
-
-struct anon_vma {
- struct anon_vma *root;
- struct rb_root_cached rb_root;
-
- /* Test fields. */
- bool was_cloned;
- bool was_unlinked;
-};
-
-struct anon_vma_chain {
- struct anon_vma *anon_vma;
- struct list_head same_vma;
-};
-
-struct anon_vma_name {
- struct kref kref;
- /* The name needs to be at the end because it is dynamically sized. */
- char name[];
-};
-
-struct vma_iterator {
- struct ma_state mas;
-};
-
-#define VMA_ITERATOR(name, __mm, __addr) \
- struct vma_iterator name = { \
- .mas = { \
- .tree = &(__mm)->mm_mt, \
- .index = __addr, \
- .node = NULL, \
- .status = ma_start, \
- }, \
- }
-
-struct address_space {
- struct rb_root_cached i_mmap;
- unsigned long flags;
- atomic_t i_mmap_writable;
-};
-
-struct vm_userfaultfd_ctx {};
-struct mempolicy {};
-struct mmu_gather {};
-struct mutex {};
-#define DEFINE_MUTEX(mutexname) \
- struct mutex mutexname = {}
-
-#define DECLARE_BITMAP(name, bits) \
- unsigned long name[BITS_TO_LONGS(bits)]
-
+#define __private
#define NUM_MM_FLAG_BITS (64)
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;
-#define EMPTY_VMA_FLAGS ((vma_flags_t){ })
-
-struct mm_struct {
- struct maple_tree mm_mt;
- int map_count; /* number of VMAs */
- unsigned long total_vm; /* Total pages mapped */
- unsigned long locked_vm; /* Pages that have PG_mlocked set */
- unsigned long data_vm; /* VM_WRITE & ~VM_SHARED & ~VM_STACK */
- unsigned long exec_vm; /* VM_EXEC & ~VM_WRITE & ~VM_STACK */
- unsigned long stack_vm; /* VM_STACK */
-
- unsigned long def_flags;
-
- mm_flags_t flags; /* Must use mm_flags_* helpers to access */
-};
-
-struct vm_area_struct;
-
-
-/* What action should be taken after an .mmap_prepare call is complete? */
-enum mmap_action_type {
- MMAP_NOTHING, /* Mapping is complete, no further action. */
- MMAP_REMAP_PFN, /* Remap PFN range. */
- MMAP_IO_REMAP_PFN, /* I/O remap PFN range. */
-};
-
-/*
- * Describes an action an mmap_prepare hook can instruct to be taken to complete
- * the mapping of a VMA. Specified in vm_area_desc.
- */
-struct mmap_action {
- union {
- /* Remap range. */
- struct {
- unsigned long start;
- unsigned long start_pfn;
- unsigned long size;
- pgprot_t pgprot;
- } remap;
- };
- enum mmap_action_type type;
-
- /*
- * If specified, this hook is invoked after the selected action has been
- * successfully completed. Note that the VMA write lock still held.
- *
- * The absolute minimum ought to be done here.
- *
- * Returns 0 on success, or an error code.
- */
- int (*success_hook)(const struct vm_area_struct *vma);
-
- /*
- * If specified, this hook is invoked when an error occurred when
- * attempting the selection action.
- *
- * The hook can return an error code in order to filter the error, but
- * it is not valid to clear the error here.
- */
- int (*error_hook)(int err);
-
- /*
- * This should be set in rare instances where the operation required
- * that the rmap should not be able to access the VMA until
- * completely set up.
- */
- bool hide_from_rmap_until_complete :1;
-};
-
-/* Operations which modify VMAs. */
-enum vma_operation {
- VMA_OP_SPLIT,
- VMA_OP_MERGE_UNFAULTED,
- VMA_OP_REMAP,
- VMA_OP_FORK,
-};
-
-/*
- * 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
- * resultant VMA.
- *
- * Helper functions are not required for manipulating any field.
- */
-struct vm_area_desc {
- /* Immutable state. */
- const struct mm_struct *const mm;
- struct file *const file; /* May vary from vm_file in stacked callers. */
- unsigned long start;
- unsigned long end;
-
- /* Mutable fields. Populated with initial state. */
- pgoff_t pgoff;
- struct file *vm_file;
- union {
- vm_flags_t vm_flags;
- vma_flags_t vma_flags;
- };
- pgprot_t page_prot;
-
- /* Write-only fields. */
- const struct vm_operations_struct *vm_ops;
- void *private_data;
-
- /* Take further action? */
- struct mmap_action action;
-};
-
-struct file_operations {
- int (*mmap)(struct file *, struct vm_area_struct *);
- int (*mmap_prepare)(struct vm_area_desc *);
-};
-
-struct file {
- struct address_space *f_mapping;
- const struct file_operations *f_op;
-};
-
-#define VMA_LOCK_OFFSET 0x40000000
-
-typedef struct { unsigned long v; } freeptr_t;
-
-struct vm_area_struct {
- /* The first cache line has the info for VMA tree walking. */
-
- union {
- struct {
- /* VMA covers [vm_start; vm_end) addresses within mm */
- unsigned long vm_start;
- unsigned long vm_end;
- };
- freeptr_t vm_freeptr; /* Pointer used by SLAB_TYPESAFE_BY_RCU */
- };
-
- struct mm_struct *vm_mm; /* The address space we belong to. */
- pgprot_t vm_page_prot; /* Access permissions of this VMA. */
-
- /*
- * Flags, see mm.h.
- * To modify use vm_flags_{init|reset|set|clear|mod} functions.
- */
- union {
- const vm_flags_t vm_flags;
- vma_flags_t flags;
- };
-
-#ifdef CONFIG_PER_VMA_LOCK
- /*
- * Can only be written (using WRITE_ONCE()) while holding both:
- * - mmap_lock (in write mode)
- * - vm_refcnt bit at VMA_LOCK_OFFSET is set
- * Can be read reliably while holding one of:
- * - mmap_lock (in read or write mode)
- * - vm_refcnt bit at VMA_LOCK_OFFSET is set or vm_refcnt > 1
- * Can be read unreliably (using READ_ONCE()) for pessimistic bailout
- * while holding nothing (except RCU to keep the VMA struct allocated).
- *
- * This sequence counter is explicitly allowed to overflow; sequence
- * counter reuse can only lead to occasional unnecessary use of the
- * slowpath.
- */
- unsigned int vm_lock_seq;
-#endif
-
- /*
- * A file's MAP_PRIVATE vma can be in both i_mmap tree and anon_vma
- * list, after a COW of one of the file pages. A MAP_SHARED vma
- * can only be in the i_mmap tree. An anonymous MAP_PRIVATE, stack
- * or brk vma (with NULL file) can only be in an anon_vma list.
- */
- struct list_head anon_vma_chain; /* Serialized by mmap_lock &
- * page_table_lock */
- struct anon_vma *anon_vma; /* Serialized by page_table_lock */
-
- /* Function pointers to deal with this struct. */
- const struct vm_operations_struct *vm_ops;
-
- /* Information about our backing store: */
- unsigned long vm_pgoff; /* Offset (within vm_file) in PAGE_SIZE
- units */
- struct file * vm_file; /* File we map to (can be NULL). */
- void * vm_private_data; /* was vm_pte (shared mem) */
-
-#ifdef CONFIG_SWAP
- atomic_long_t swap_readahead_info;
-#endif
-#ifndef CONFIG_MMU
- struct vm_region *vm_region; /* NOMMU mapping region */
-#endif
-#ifdef CONFIG_NUMA
- struct mempolicy *vm_policy; /* NUMA policy for the VMA */
-#endif
-#ifdef CONFIG_NUMA_BALANCING
- struct vma_numab_state *numab_state; /* NUMA Balancing state */
-#endif
-#ifdef CONFIG_PER_VMA_LOCK
- /* Unstable RCU readers are allowed to read this. */
- refcount_t vm_refcnt;
-#endif
- /*
- * For areas with an address space and backing store,
- * linkage into the address_space->i_mmap interval tree.
- *
- */
- struct {
- struct rb_node rb;
- unsigned long rb_subtree_last;
- } shared;
-#ifdef CONFIG_ANON_VMA_NAME
- /*
- * For private and shared anonymous mappings, a pointer to a null
- * terminated string containing the name given to the vma, or NULL if
- * unnamed. Serialized by mmap_lock. Use anon_vma_name to access.
- */
- struct anon_vma_name *anon_name;
-#endif
- struct vm_userfaultfd_ctx vm_userfaultfd_ctx;
-} __randomize_layout;
-
-struct vm_fault {};
-
-struct vm_operations_struct {
- void (*open)(struct vm_area_struct * area);
- /**
- * @close: Called when the VMA is being removed from the MM.
- * Context: User context. May sleep. Caller holds mmap_lock.
- */
- void (*close)(struct vm_area_struct * area);
- /* Called any time before splitting to check if it's allowed */
- int (*may_split)(struct vm_area_struct *area, unsigned long addr);
- int (*mremap)(struct vm_area_struct *area);
- /*
- * Called by mprotect() to make driver-specific permission
- * checks before mprotect() is finalised. The VMA must not
- * be modified. Returns 0 if mprotect() can proceed.
- */
- int (*mprotect)(struct vm_area_struct *vma, unsigned long start,
- unsigned long end, unsigned long newflags);
- vm_fault_t (*fault)(struct vm_fault *vmf);
- vm_fault_t (*huge_fault)(struct vm_fault *vmf, unsigned int order);
- vm_fault_t (*map_pages)(struct vm_fault *vmf,
- pgoff_t start_pgoff, pgoff_t end_pgoff);
- unsigned long (*pagesize)(struct vm_area_struct * area);
-
- /* notification that a previously read-only page is about to become
- * writable, if an error is returned it will cause a SIGBUS */
- vm_fault_t (*page_mkwrite)(struct vm_fault *vmf);
-
- /* same as page_mkwrite when using VM_PFNMAP|VM_MIXEDMAP */
- vm_fault_t (*pfn_mkwrite)(struct vm_fault *vmf);
-
- /* called by access_process_vm when get_user_pages() fails, typically
- * for use by special VMAs. See also generic_access_phys() for a generic
- * implementation useful for any iomem mapping.
- */
- int (*access)(struct vm_area_struct *vma, unsigned long addr,
- void *buf, int len, int write);
-
- /* Called by the /proc/PID/maps code to ask the vma whether it
- * has a special name. Returning non-NULL will also cause this
- * vma to be dumped unconditionally. */
- const char *(*name)(struct vm_area_struct *vma);
-
-#ifdef CONFIG_NUMA
- /*
- * set_policy() op must add a reference to any non-NULL @new mempolicy
- * to hold the policy upon return. Caller should pass NULL @new to
- * remove a policy and fall back to surrounding context--i.e. do not
- * install a MPOL_DEFAULT policy, nor the task or system default
- * mempolicy.
- */
- int (*set_policy)(struct vm_area_struct *vma, struct mempolicy *new);
-
- /*
- * get_policy() op must add reference [mpol_get()] to any policy at
- * (vma,addr) marked as MPOL_SHARED. The shared policy infrastructure
- * in mm/mempolicy.c will do this automatically.
- * get_policy() must NOT add a ref if the policy at (vma,addr) is not
- * marked as MPOL_SHARED. vma policies are protected by the mmap_lock.
- * If no [shared/vma] mempolicy exists at the addr, get_policy() op
- * must return NULL--i.e., do not "fallback" to task or system default
- * policy.
- */
- struct mempolicy *(*get_policy)(struct vm_area_struct *vma,
- unsigned long addr, pgoff_t *ilx);
-#endif
-#ifdef CONFIG_FIND_NORMAL_PAGE
- /*
- * Called by vm_normal_page() for special PTEs in @vma at @addr. This
- * allows for returning a "normal" page from vm_normal_page() even
- * though the PTE indicates that the "struct page" either does not exist
- * or should not be touched: "special".
- *
- * Do not add new users: this really only works when a "normal" page
- * was mapped, but then the PTE got changed to something weird (+
- * marked special) that would not make pte_pfn() identify the originally
- * inserted page.
- */
- struct page *(*find_normal_page)(struct vm_area_struct *vma,
- unsigned long addr);
-#endif /* CONFIG_FIND_NORMAL_PAGE */
-};
-
-struct vm_unmapped_area_info {
-#define VM_UNMAPPED_AREA_TOPDOWN 1
- unsigned long flags;
- unsigned long length;
- unsigned long low_limit;
- unsigned long high_limit;
- unsigned long align_mask;
- unsigned long align_offset;
- unsigned long start_gap;
-};
-
-struct pagetable_move_control {
- struct vm_area_struct *old; /* Source VMA. */
- struct vm_area_struct *new; /* Destination VMA. */
- unsigned long old_addr; /* Address from which the move begins. */
- unsigned long old_end; /* Exclusive address at which old range ends. */
- unsigned long new_addr; /* Address to move page tables to. */
- unsigned long len_in; /* Bytes to remap specified by user. */
-
- bool need_rmap_locks; /* Do rmap locks need to be taken? */
- bool for_stack; /* Is this an early temp stack being moved? */
-};
-
-#define PAGETABLE_MOVE(name, old_, new_, old_addr_, new_addr_, len_) \
- struct pagetable_move_control name = { \
- .old = old_, \
- .new = new_, \
- .old_addr = old_addr_, \
- .old_end = (old_addr_) + (len_), \
- .new_addr = new_addr_, \
- .len_in = len_, \
- }
-
-static inline void vma_iter_invalidate(struct vma_iterator *vmi)
-{
- mas_pause(&vmi->mas);
-}
-
-static inline pgprot_t pgprot_modify(pgprot_t oldprot, pgprot_t newprot)
-{
- return __pgprot(pgprot_val(oldprot) | pgprot_val(newprot));
-}
-
-static inline pgprot_t vm_get_page_prot(vm_flags_t vm_flags)
-{
- return __pgprot(vm_flags);
-}
-
-static inline void vma_flags_clear_all(vma_flags_t *flags)
-{
- bitmap_zero(flags->__vma_flags, NUM_VMA_FLAG_BITS);
-}
-
-static inline void vma_flag_set(vma_flags_t *flags, vma_flag_t bit)
-{
- unsigned long *bitmap = flags->__vma_flags;
-
- __set_bit((__force int)bit, bitmap);
-}
-
-static inline vma_flags_t __mk_vma_flags(size_t count, const vma_flag_t *bits)
-{
- vma_flags_t flags;
- int i;
-
- vma_flags_clear_all(&flags);
- for (i = 0; i < count; i++)
- vma_flag_set(&flags, bits[i]);
- return flags;
-}
-
-#define mk_vma_flags(...) __mk_vma_flags(COUNT_ARGS(__VA_ARGS__), \
- (const vma_flag_t []){__VA_ARGS__})
-
-static __always_inline bool vma_flags_test_mask(const vma_flags_t *flags,
- vma_flags_t to_test)
-{
- const unsigned long *bitmap = flags->__vma_flags;
- const unsigned long *bitmap_to_test = to_test.__vma_flags;
-
- return bitmap_intersects(bitmap_to_test, bitmap, NUM_VMA_FLAG_BITS);
-}
-
-#define vma_flags_test(flags, ...) \
- vma_flags_test_mask(flags, mk_vma_flags(__VA_ARGS__))
-
-static __always_inline bool vma_flags_test_all_mask(const vma_flags_t *flags,
- vma_flags_t to_test)
-{
- const unsigned long *bitmap = flags->__vma_flags;
- const unsigned long *bitmap_to_test = to_test.__vma_flags;
-
- return bitmap_subset(bitmap_to_test, bitmap, NUM_VMA_FLAG_BITS);
-}
-
-#define vma_flags_test_all(flags, ...) \
- vma_flags_test_all_mask(flags, mk_vma_flags(__VA_ARGS__))
-
-static __always_inline void vma_flags_set_mask(vma_flags_t *flags, vma_flags_t to_set)
-{
- unsigned long *bitmap = flags->__vma_flags;
- const unsigned long *bitmap_to_set = to_set.__vma_flags;
-
- bitmap_or(bitmap, bitmap, bitmap_to_set, NUM_VMA_FLAG_BITS);
-}
-
-#define vma_flags_set(flags, ...) \
- vma_flags_set_mask(flags, mk_vma_flags(__VA_ARGS__))
-
-static __always_inline void vma_flags_clear_mask(vma_flags_t *flags, vma_flags_t to_clear)
-{
- unsigned long *bitmap = flags->__vma_flags;
- const unsigned long *bitmap_to_clear = to_clear.__vma_flags;
-
- bitmap_andnot(bitmap, bitmap, bitmap_to_clear, NUM_VMA_FLAG_BITS);
-}
-
-#define vma_flags_clear(flags, ...) \
- vma_flags_clear_mask(flags, mk_vma_flags(__VA_ARGS__))
-
-static inline bool vma_test_all_flags_mask(const struct vm_area_struct *vma,
- vma_flags_t flags)
-{
- return vma_flags_test_all_mask(&vma->flags, flags);
-}
-
-#define vma_test_all_flags(vma, ...) \
- vma_test_all_flags_mask(vma, mk_vma_flags(__VA_ARGS__))
-
-static inline void vma_set_flags_mask(struct vm_area_struct *vma,
- vma_flags_t flags)
-{
- vma_flags_set_mask(&vma->flags, flags);
-}
-
-#define vma_set_flags(vma, ...) \
- vma_set_flags_mask(vma, mk_vma_flags(__VA_ARGS__))
-
-static inline bool vma_desc_test_flags_mask(const struct vm_area_desc *desc,
- vma_flags_t flags)
-{
- return vma_flags_test_mask(&desc->vma_flags, flags);
-}
-
-#define vma_desc_test_flags(desc, ...) \
- vma_desc_test_flags_mask(desc, mk_vma_flags(__VA_ARGS__))
-
-static inline void vma_desc_set_flags_mask(struct vm_area_desc *desc,
- vma_flags_t flags)
-{
- vma_flags_set_mask(&desc->vma_flags, flags);
-}
-
-#define vma_desc_set_flags(desc, ...) \
- vma_desc_set_flags_mask(desc, mk_vma_flags(__VA_ARGS__))
-
-static inline void vma_desc_clear_flags_mask(struct vm_area_desc *desc,
- vma_flags_t flags)
-{
- vma_flags_clear_mask(&desc->vma_flags, flags);
-}
-
-#define vma_desc_clear_flags(desc, ...) \
- vma_desc_clear_flags_mask(desc, mk_vma_flags(__VA_ARGS__))
-
-static inline bool is_shared_maywrite_vm_flags(vm_flags_t vm_flags)
-{
- return (vm_flags & (VM_SHARED | VM_MAYWRITE)) ==
- (VM_SHARED | VM_MAYWRITE);
-}
-
-static inline bool is_shared_maywrite(const vma_flags_t *flags)
-{
- return vma_flags_test_all(flags, VMA_SHARED_BIT, VMA_MAYWRITE_BIT);
-}
-
-static inline bool vma_is_shared_maywrite(struct vm_area_struct *vma)
-{
- return is_shared_maywrite(&vma->flags);
-}
-
-static inline struct vm_area_struct *vma_next(struct vma_iterator *vmi)
-{
- /*
- * Uses mas_find() to get the first VMA when the iterator starts.
- * Calling mas_next() could skip the first entry.
- */
- return mas_find(&vmi->mas, ULONG_MAX);
-}
-
-/*
- * WARNING: to avoid racing with vma_mark_attached()/vma_mark_detached(), these
- * assertions should be made either under mmap_write_lock or when the object
- * has been isolated under mmap_write_lock, ensuring no competing writers.
- */
-static inline void vma_assert_attached(struct vm_area_struct *vma)
-{
- WARN_ON_ONCE(!refcount_read(&vma->vm_refcnt));
-}
-
-static inline void vma_assert_detached(struct vm_area_struct *vma)
-{
- WARN_ON_ONCE(refcount_read(&vma->vm_refcnt));
-}
-
-static inline void vma_assert_write_locked(struct vm_area_struct *);
-static inline void vma_mark_attached(struct vm_area_struct *vma)
-{
- vma_assert_write_locked(vma);
- vma_assert_detached(vma);
- refcount_set_release(&vma->vm_refcnt, 1);
-}
-
-static inline void vma_mark_detached(struct vm_area_struct *vma)
-{
- vma_assert_write_locked(vma);
- vma_assert_attached(vma);
- /* We are the only writer, so no need to use vma_refcount_put(). */
- if (unlikely(!refcount_dec_and_test(&vma->vm_refcnt))) {
- /*
- * Reader must have temporarily raised vm_refcnt but it will
- * drop it without using the vma since vma is write-locked.
- */
- }
-}
-
-extern const struct vm_operations_struct vma_dummy_vm_ops;
-
-extern unsigned long rlimit(unsigned int limit);
-
-static inline void vma_init(struct vm_area_struct *vma, struct mm_struct *mm)
-{
- memset(vma, 0, sizeof(*vma));
- vma->vm_mm = mm;
- vma->vm_ops = &vma_dummy_vm_ops;
- INIT_LIST_HEAD(&vma->anon_vma_chain);
- vma->vm_lock_seq = UINT_MAX;
-}
-
-/*
- * These are defined in vma.h, but sadly vm_stat_account() is referenced by
- * kernel/fork.c, so we have to these broadly available there, and temporarily
- * define them here to resolve the dependency cycle.
- */
-
-#define is_exec_mapping(flags) \
- ((flags & (VM_EXEC | VM_WRITE | VM_STACK)) == VM_EXEC)
-
-#define is_stack_mapping(flags) \
- (((flags & VM_STACK) == VM_STACK) || (flags & VM_SHADOW_STACK))
-
-#define is_data_mapping(flags) \
- ((flags & (VM_WRITE | VM_SHARED | VM_STACK)) == VM_WRITE)
-
-static inline void vm_stat_account(struct mm_struct *mm, vm_flags_t flags,
- long npages)
-{
- WRITE_ONCE(mm->total_vm, READ_ONCE(mm->total_vm)+npages);
-
- if (is_exec_mapping(flags))
- mm->exec_vm += npages;
- else if (is_stack_mapping(flags))
- mm->stack_vm += npages;
- else if (is_data_mapping(flags))
- mm->data_vm += npages;
-}
-
-#undef is_exec_mapping
-#undef is_stack_mapping
-#undef is_data_mapping
-
-/* Currently stubbed but we may later wish to un-stub. */
-static inline void vm_acct_memory(long pages);
-static inline void vm_unacct_memory(long pages)
-{
- vm_acct_memory(-pages);
-}
-
-static inline void mapping_allow_writable(struct address_space *mapping)
-{
- atomic_inc(&mapping->i_mmap_writable);
-}
-
-static inline
-struct vm_area_struct *vma_find(struct vma_iterator *vmi, unsigned long max)
-{
- return mas_find(&vmi->mas, max - 1);
-}
-
-static inline int vma_iter_clear_gfp(struct vma_iterator *vmi,
- unsigned long start, unsigned long end, gfp_t gfp)
-{
- __mas_set_range(&vmi->mas, start, end - 1);
- mas_store_gfp(&vmi->mas, NULL, gfp);
- if (unlikely(mas_is_err(&vmi->mas)))
- return -ENOMEM;
-
- return 0;
-}
-
-static inline void mmap_assert_locked(struct mm_struct *);
-static inline struct vm_area_struct *find_vma_intersection(struct mm_struct *mm,
- unsigned long start_addr,
- unsigned long end_addr)
-{
- unsigned long index = start_addr;
-
- mmap_assert_locked(mm);
- return mt_find(&mm->mm_mt, &index, end_addr - 1);
-}
-
-static inline
-struct vm_area_struct *vma_lookup(struct mm_struct *mm, unsigned long addr)
-{
- return mtree_load(&mm->mm_mt, addr);
-}
-
-static inline struct vm_area_struct *vma_prev(struct vma_iterator *vmi)
-{
- return mas_prev(&vmi->mas, 0);
-}
-
-static inline void vma_iter_set(struct vma_iterator *vmi, unsigned long addr)
-{
- mas_set(&vmi->mas, addr);
-}
-
-static inline bool vma_is_anonymous(struct vm_area_struct *vma)
-{
- return !vma->vm_ops;
-}
-
-/* Defined in vma.h, so temporarily define here to avoid circular dependency. */
-#define vma_iter_load(vmi) \
- mas_walk(&(vmi)->mas)
-
-static inline struct vm_area_struct *
-find_vma_prev(struct mm_struct *mm, unsigned long addr,
- struct vm_area_struct **pprev)
-{
- struct vm_area_struct *vma;
- VMA_ITERATOR(vmi, mm, addr);
-
- vma = vma_iter_load(&vmi);
- *pprev = vma_prev(&vmi);
- if (!vma)
- vma = vma_next(&vmi);
- return vma;
-}
-
-#undef vma_iter_load
-
-static inline void vma_iter_init(struct vma_iterator *vmi,
- struct mm_struct *mm, unsigned long addr)
-{
- mas_init(&vmi->mas, &mm->mm_mt, addr);
-}
-
-/* Stubbed functions. */
-
-static inline struct anon_vma_name *anon_vma_name(struct vm_area_struct *vma)
-{
- return NULL;
-}
-
-static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma,
- struct vm_userfaultfd_ctx vm_ctx)
-{
- return true;
-}
-
-static inline bool anon_vma_name_eq(struct anon_vma_name *anon_name1,
- struct anon_vma_name *anon_name2)
-{
- return true;
-}
-
-static inline void might_sleep(void)
-{
-}
-
-static inline unsigned long vma_pages(struct vm_area_struct *vma)
-{
- return (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
-}
-
-static inline void fput(struct file *file)
-{
-}
-
-static inline void mpol_put(struct mempolicy *pol)
-{
-}
-
-static inline void lru_add_drain(void)
-{
-}
-
-static inline void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm)
-{
-}
-
-static inline void update_hiwater_rss(struct mm_struct *mm)
-{
-}
-
-static inline void update_hiwater_vm(struct mm_struct *mm)
-{
-}
-
-struct unmap_desc;
-
-static inline void unmap_vmas(struct mmu_gather *tlb, struct unmap_desc *unmap)
-{
-}
-
-static inline void free_pgtables(struct mmu_gather *tlb, struct unmap_desc *desc)
-{
- (void)tlb;
- (void)desc;
-}
-
-static inline void mapping_unmap_writable(struct address_space *mapping)
-{
-}
-
-static inline void flush_dcache_mmap_lock(struct address_space *mapping)
-{
-}
-
-static inline void tlb_finish_mmu(struct mmu_gather *tlb)
-{
-}
-
-static inline struct file *get_file(struct file *f)
-{
- return f;
-}
-
-static inline int vma_dup_policy(struct vm_area_struct *src, struct vm_area_struct *dst)
-{
- return 0;
-}
-
-static inline int anon_vma_clone(struct vm_area_struct *dst, struct vm_area_struct *src,
- enum vma_operation operation)
-{
- /* For testing purposes. We indicate that an anon_vma has been cloned. */
- if (src->anon_vma != NULL) {
- dst->anon_vma = src->anon_vma;
- dst->anon_vma->was_cloned = true;
- }
-
- return 0;
-}
-
-static inline void vma_start_write(struct vm_area_struct *vma)
-{
- /* Used to indicate to tests that a write operation has begun. */
- vma->vm_lock_seq++;
-}
-
-static inline __must_check
-int vma_start_write_killable(struct vm_area_struct *vma)
-{
- /* Used to indicate to tests that a write operation has begun. */
- vma->vm_lock_seq++;
- return 0;
-}
-
-static inline void vma_adjust_trans_huge(struct vm_area_struct *vma,
- unsigned long start,
- unsigned long end,
- struct vm_area_struct *next)
-{
-}
-
-static inline void hugetlb_split(struct vm_area_struct *, unsigned long) {}
-
-static inline void vma_iter_free(struct vma_iterator *vmi)
-{
- mas_destroy(&vmi->mas);
-}
-
-static inline
-struct vm_area_struct *vma_iter_next_range(struct vma_iterator *vmi)
-{
- return mas_next_range(&vmi->mas, ULONG_MAX);
-}
-
-static inline void vm_acct_memory(long pages)
-{
-}
-
-static inline void vma_interval_tree_insert(struct vm_area_struct *vma,
- struct rb_root_cached *rb)
-{
-}
-
-static inline void vma_interval_tree_remove(struct vm_area_struct *vma,
- struct rb_root_cached *rb)
-{
-}
-
-static inline void flush_dcache_mmap_unlock(struct address_space *mapping)
-{
-}
-
-static inline void anon_vma_interval_tree_insert(struct anon_vma_chain *avc,
- struct rb_root_cached *rb)
-{
-}
-
-static inline void anon_vma_interval_tree_remove(struct anon_vma_chain *avc,
- struct rb_root_cached *rb)
-{
-}
-
-static inline void uprobe_mmap(struct vm_area_struct *vma)
-{
-}
-
-static inline void uprobe_munmap(struct vm_area_struct *vma,
- unsigned long start, unsigned long end)
-{
-}
-
-static inline void i_mmap_lock_write(struct address_space *mapping)
-{
-}
-
-static inline void anon_vma_lock_write(struct anon_vma *anon_vma)
-{
-}
-
-static inline void vma_assert_write_locked(struct vm_area_struct *vma)
-{
-}
-
-static inline void unlink_anon_vmas(struct vm_area_struct *vma)
-{
- /* For testing purposes, indicate that the anon_vma was unlinked. */
- vma->anon_vma->was_unlinked = true;
-}
-
-static inline void anon_vma_unlock_write(struct anon_vma *anon_vma)
-{
-}
-
-static inline void i_mmap_unlock_write(struct address_space *mapping)
-{
-}
-
-static inline int userfaultfd_unmap_prep(struct vm_area_struct *vma,
- unsigned long start,
- unsigned long end,
- struct list_head *unmaps)
-{
- return 0;
-}
-
-static inline void mmap_write_downgrade(struct mm_struct *mm)
-{
-}
-
-static inline void mmap_read_unlock(struct mm_struct *mm)
-{
-}
-
-static inline void mmap_write_unlock(struct mm_struct *mm)
-{
-}
-
-static inline int mmap_write_lock_killable(struct mm_struct *mm)
-{
- return 0;
-}
-
-static inline bool can_modify_mm(struct mm_struct *mm,
- unsigned long start,
- unsigned long end)
-{
- return true;
-}
-
-static inline void arch_unmap(struct mm_struct *mm,
- unsigned long start,
- unsigned long end)
-{
-}
-
-static inline void mmap_assert_locked(struct mm_struct *mm)
-{
-}
-
-static inline bool mpol_equal(struct mempolicy *a, struct mempolicy *b)
-{
- return true;
-}
-
-static inline void khugepaged_enter_vma(struct vm_area_struct *vma,
- vm_flags_t vm_flags)
-{
-}
-
-static inline bool mapping_can_writeback(struct address_space *mapping)
-{
- return true;
-}
-
-static inline bool is_vm_hugetlb_page(struct vm_area_struct *vma)
-{
- return false;
-}
-
-static inline bool vma_soft_dirty_enabled(struct vm_area_struct *vma)
-{
- return false;
-}
-
-static inline bool userfaultfd_wp(struct vm_area_struct *vma)
-{
- return false;
-}
-
-static inline void mmap_assert_write_locked(struct mm_struct *mm)
-{
-}
-
-static inline void mutex_lock(struct mutex *lock)
-{
-}
-
-static inline void mutex_unlock(struct mutex *lock)
-{
-}
-
-static inline bool mutex_is_locked(struct mutex *lock)
-{
- return true;
-}
-
-static inline bool signal_pending(void *p)
-{
- return false;
-}
-
-static inline bool is_file_hugepages(struct file *file)
-{
- return false;
-}
-
-static inline int security_vm_enough_memory_mm(struct mm_struct *mm, long pages)
-{
- return 0;
-}
-
-static inline bool may_expand_vm(struct mm_struct *mm, vm_flags_t flags,
- unsigned long npages)
-{
- return true;
-}
-
-static inline int shmem_zero_setup(struct vm_area_struct *vma)
-{
- return 0;
-}
-
-static inline void vma_set_anonymous(struct vm_area_struct *vma)
-{
- vma->vm_ops = NULL;
-}
-
-static inline void ksm_add_vma(struct vm_area_struct *vma)
-{
-}
-
-static inline void perf_event_mmap(struct vm_area_struct *vma)
-{
-}
-
-static inline bool vma_is_dax(struct vm_area_struct *vma)
-{
- return false;
-}
-
-static inline struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
-{
- return NULL;
-}
-
-bool vma_wants_writenotify(struct vm_area_struct *vma, pgprot_t vm_page_prot);
-
-/* Update vma->vm_page_prot to reflect vma->vm_flags. */
-static inline void vma_set_page_prot(struct vm_area_struct *vma)
-{
- vm_flags_t vm_flags = vma->vm_flags;
- pgprot_t vm_page_prot;
-
- /* testing: we inline vm_pgprot_modify() to avoid clash with vma.h. */
- vm_page_prot = pgprot_modify(vma->vm_page_prot, vm_get_page_prot(vm_flags));
-
- if (vma_wants_writenotify(vma, vm_page_prot)) {
- vm_flags &= ~VM_SHARED;
- /* testing: we inline vm_pgprot_modify() to avoid clash with vma.h. */
- vm_page_prot = pgprot_modify(vm_page_prot, vm_get_page_prot(vm_flags));
- }
- /* remove_protection_ptes reads vma->vm_page_prot without mmap_lock */
- WRITE_ONCE(vma->vm_page_prot, vm_page_prot);
-}
-
-static inline bool arch_validate_flags(vm_flags_t flags)
-{
- return true;
-}
-
-static inline void vma_close(struct vm_area_struct *vma)
-{
-}
-
-static inline int mmap_file(struct file *file, struct vm_area_struct *vma)
-{
- return 0;
-}
-
-static inline unsigned long stack_guard_start_gap(struct vm_area_struct *vma)
-{
- if (vma->vm_flags & VM_GROWSDOWN)
- return stack_guard_gap;
-
- /* See reasoning around the VM_SHADOW_STACK definition */
- if (vma->vm_flags & VM_SHADOW_STACK)
- return PAGE_SIZE;
-
- return 0;
-}
-
-static inline unsigned long vm_start_gap(struct vm_area_struct *vma)
-{
- unsigned long gap = stack_guard_start_gap(vma);
- unsigned long vm_start = vma->vm_start;
-
- vm_start -= gap;
- if (vm_start > vma->vm_start)
- vm_start = 0;
- return vm_start;
-}
-
-static inline unsigned long vm_end_gap(struct vm_area_struct *vma)
-{
- unsigned long vm_end = vma->vm_end;
-
- if (vma->vm_flags & VM_GROWSUP) {
- vm_end += stack_guard_gap;
- if (vm_end < vma->vm_end)
- vm_end = -PAGE_SIZE;
- }
- return vm_end;
-}
-
-static inline int is_hugepage_only_range(struct mm_struct *mm,
- unsigned long addr, unsigned long len)
-{
- return 0;
-}
-
-static inline bool vma_is_accessible(struct vm_area_struct *vma)
-{
- return vma->vm_flags & VM_ACCESS_FLAGS;
-}
-
-static inline bool capable(int cap)
-{
- return true;
-}
-
-static inline bool mlock_future_ok(const struct mm_struct *mm,
- vm_flags_t vm_flags, unsigned long bytes)
-{
- unsigned long locked_pages, limit_pages;
-
- if (!(vm_flags & VM_LOCKED) || capable(CAP_IPC_LOCK))
- return true;
-
- locked_pages = bytes >> PAGE_SHIFT;
- locked_pages += mm->locked_vm;
-
- limit_pages = rlimit(RLIMIT_MEMLOCK);
- limit_pages >>= PAGE_SHIFT;
-
- return locked_pages <= limit_pages;
-}
-
-static inline int __anon_vma_prepare(struct vm_area_struct *vma)
-{
- struct anon_vma *anon_vma = calloc(1, sizeof(struct anon_vma));
-
- if (!anon_vma)
- return -ENOMEM;
-
- anon_vma->root = anon_vma;
- vma->anon_vma = anon_vma;
-
- return 0;
-}
-
-static inline int anon_vma_prepare(struct vm_area_struct *vma)
-{
- if (likely(vma->anon_vma))
- return 0;
-
- return __anon_vma_prepare(vma);
-}
-
-static inline void userfaultfd_unmap_complete(struct mm_struct *mm,
- struct list_head *uf)
-{
-}
-
-static inline bool mm_flags_test(int flag, const struct mm_struct *mm)
-{
- return test_bit(flag, ACCESS_PRIVATE(&mm->flags, __mm_flags));
-}
-
-/*
- * 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.
- *
- * This denies the following:
- *
- * a) mmap(PROT_WRITE | PROT_EXEC)
- *
- * b) mmap(PROT_WRITE)
- * mprotect(PROT_EXEC)
- *
- * c) mmap(PROT_WRITE)
- * mprotect(PROT_READ)
- * mprotect(PROT_EXEC)
- *
- * But allows the following:
- *
- * d) mmap(PROT_READ | PROT_EXEC)
- * mmap(PROT_READ | PROT_EXEC | PROT_BTI)
- *
- * This is only applicable if the user has set the Memory-Deny-Write-Execute
- * (MDWE) protection mask for the current process.
- *
- * @old specifies the VMA flags the VMA originally possessed, and @new the ones
- * we propose to set.
- *
- * Return: false if proposed change is OK, true if not ok and should be denied.
- */
-static inline bool map_deny_write_exec(unsigned long old, unsigned long new)
-{
- /* If MDWE is disabled, we have nothing to deny. */
- if (mm_flags_test(MMF_HAS_MDWE, current->mm))
- return false;
-
- /* If the new VMA is not executable, we have nothing to deny. */
- if (!(new & VM_EXEC))
- return false;
-
- /* Under MDWE we do not accept newly writably executable VMAs... */
- if (new & VM_WRITE)
- return true;
-
- /* ...nor previously non-executable VMAs becoming executable. */
- if (!(old & VM_EXEC))
- return true;
-
- return false;
-}
-
-static inline int mapping_map_writable(struct address_space *mapping)
-{
- return atomic_inc_unless_negative(&mapping->i_mmap_writable) ?
- 0 : -EPERM;
-}
-
-static inline unsigned long move_page_tables(struct pagetable_move_control *pmc)
-{
- return 0;
-}
-
-static inline void free_pgd_range(struct mmu_gather *tlb,
- unsigned long addr, unsigned long end,
- unsigned long floor, unsigned long ceiling)
-{
-}
-
-static inline int ksm_execve(struct mm_struct *mm)
-{
- return 0;
-}
-
-static inline void ksm_exit(struct mm_struct *mm)
-{
-}
-
-static inline void vma_lock_init(struct vm_area_struct *vma, bool reset_refcnt)
-{
- if (reset_refcnt)
- refcount_set(&vma->vm_refcnt, 0);
-}
-
-static inline void vma_numab_state_init(struct vm_area_struct *vma)
-{
-}
-
-static inline void vma_numab_state_free(struct vm_area_struct *vma)
-{
-}
-
-static inline void dup_anon_vma_name(struct vm_area_struct *orig_vma,
- struct vm_area_struct *new_vma)
-{
-}
-
-static inline void free_anon_vma_name(struct vm_area_struct *vma)
-{
-}
-
-/* Declared in vma.h. */
-static inline void set_vma_from_desc(struct vm_area_struct *vma,
- struct vm_area_desc *desc);
-
-static inline void mmap_action_prepare(struct mmap_action *action,
- struct vm_area_desc *desc)
-{
-}
-
-static inline int mmap_action_complete(struct mmap_action *action,
- struct vm_area_struct *vma)
-{
- return 0;
-}
-
-static inline int __compat_vma_mmap(const struct file_operations *f_op,
- struct file *file, struct vm_area_struct *vma)
-{
- struct vm_area_desc desc = {
- .mm = vma->vm_mm,
- .file = file,
- .start = vma->vm_start,
- .end = vma->vm_end,
-
- .pgoff = vma->vm_pgoff,
- .vm_file = vma->vm_file,
- .vm_flags = vma->vm_flags,
- .page_prot = vma->vm_page_prot,
-
- .action.type = MMAP_NOTHING, /* Default */
- };
- int err;
-
- err = f_op->mmap_prepare(&desc);
- if (err)
- return err;
-
- mmap_action_prepare(&desc.action, &desc);
- set_vma_from_desc(vma, &desc);
- return mmap_action_complete(&desc.action, vma);
-}
-
-static inline int compat_vma_mmap(struct file *file,
- struct vm_area_struct *vma)
-{
- return __compat_vma_mmap(file->f_op, file, vma);
-}
-
-/* Did the driver provide valid mmap hook configuration? */
-static inline bool can_mmap_file(struct file *file)
-{
- bool has_mmap = file->f_op->mmap;
- bool has_mmap_prepare = file->f_op->mmap_prepare;
-
- /* Hooks are mutually exclusive. */
- if (WARN_ON_ONCE(has_mmap && has_mmap_prepare))
- return false;
- if (!has_mmap && !has_mmap_prepare)
- return false;
-
- return true;
-}
-
-static inline int vfs_mmap(struct file *file, struct vm_area_struct *vma)
-{
- if (file->f_op->mmap_prepare)
- return compat_vma_mmap(file, vma);
-
- return file->f_op->mmap(file, vma);
-}
-
-static inline int vfs_mmap_prepare(struct file *file, struct vm_area_desc *desc)
-{
- return file->f_op->mmap_prepare(desc);
-}
-
-static inline void fixup_hugetlb_reservations(struct vm_area_struct *vma)
-{
-}
-
-static inline void vma_set_file(struct vm_area_struct *vma, struct file *file)
-{
- /* Changing an anonymous vma with this is illegal */
- get_file(file);
- swap(vma->vm_file, file);
- fput(file);
-}
-
-static inline bool shmem_file(struct file *file)
-{
- return false;
-}
-
-static inline vm_flags_t ksm_vma_flags(const struct mm_struct *mm,
- const struct file *file, vm_flags_t vm_flags)
-{
- return vm_flags;
-}
-
-static inline void remap_pfn_range_prepare(struct vm_area_desc *desc, unsigned long pfn)
-{
-}
-
-static inline int remap_pfn_range_complete(struct vm_area_struct *vma, unsigned long addr,
- unsigned long pfn, unsigned long size, pgprot_t pgprot)
-{
- return 0;
-}
+typedef unsigned long vm_flags_t;
+#define pgoff_t unsigned long
+typedef unsigned long pgprotval_t;
+typedef struct pgprot { pgprotval_t pgprot; } pgprot_t;
+typedef __bitwise unsigned int vm_fault_t;
-static inline int do_munmap(struct mm_struct *, unsigned long, size_t,
- struct list_head *uf)
-{
- return 0;
-}
+#include "include/stubs.h"
+#include "include/dup.h"
+#include "include/custom.h"
#endif /* __MM_VMA_INTERNAL_H */
--
2.52.0
^ permalink raw reply [flat|nested] 56+ messages in thread* Re: [PATCH v2 12/13] tools/testing/vma: separate out vma_internal.h into logical headers
2026-01-22 16:06 ` [PATCH v2 12/13] tools/testing/vma: separate out vma_internal.h into logical headers Lorenzo Stoakes
@ 2026-01-27 10:03 ` Lorenzo Stoakes
2026-02-09 20:18 ` Liam R. Howlett
1 sibling, 0 replies; 56+ messages in thread
From: Lorenzo Stoakes @ 2026-01-27 10:03 UTC (permalink / raw)
To: Andrew Morton
Cc: Jarkko Sakkinen, Dave Hansen, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, x86, H . Peter Anvin, Arnd Bergmann,
Greg Kroah-Hartman, Dan Williams, Vishal Verma, Dave Jiang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
Hi Andrew,
Could you apply the attached fix-patch to avoid a duplicate struct define as
reported by https://lore.kernel.org/all/202601271308.b8d3fcb6-lkp@intel.com/ ?
Thanks, Lorenzo
----8<----
From d19e621020697b25d70f13ffeb2b0eb46682a60d Mon Sep 17 00:00:00 2001
From: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Date: Tue, 27 Jan 2026 10:02:00 +0000
Subject: [PATCH] fix
Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
---
tools/testing/vma/include/dup.h | 12 ------------
1 file changed, 12 deletions(-)
diff --git a/tools/testing/vma/include/dup.h b/tools/testing/vma/include/dup.h
index ed8708afb7af..0accfc296615 100644
--- a/tools/testing/vma/include/dup.h
+++ b/tools/testing/vma/include/dup.h
@@ -1327,15 +1327,3 @@ static inline void vma_set_file(struct vm_area_struct *vma, struct file *file)
swap(vma->vm_file, file);
fput(file);
}
-
-struct unmap_desc {
- struct ma_state *mas; /* the maple state point to the first vma */
- struct vm_area_struct *first; /* The first vma */
- unsigned long pg_start; /* The first pagetable address to free (floor) */
- unsigned long pg_end; /* The last pagetable address to free (ceiling) */
- unsigned long vma_start; /* The min vma address */
- unsigned long vma_end; /* The max vma address */
- unsigned long tree_end; /* Maximum for the vma tree search */
- unsigned long tree_reset; /* Where to reset the vma tree walk */
- bool mm_wr_locked; /* If the mmap write lock is held */
-};
--
2.52.0
^ permalink raw reply [flat|nested] 56+ messages in thread* Re: [PATCH v2 12/13] tools/testing/vma: separate out vma_internal.h into logical headers
2026-01-22 16:06 ` [PATCH v2 12/13] tools/testing/vma: separate out vma_internal.h into logical headers Lorenzo Stoakes
2026-01-27 10:03 ` Lorenzo Stoakes
@ 2026-02-09 20:18 ` Liam R. Howlett
1 sibling, 0 replies; 56+ messages in thread
From: Liam R. Howlett @ 2026-02-09 20:18 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin,
Arnd Bergmann, Greg Kroah-Hartman, Dan Williams, Vishal Verma,
Dave Jiang, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Hugh Dickins, Baolin Wang, Zi Yan, Nico Pache, Ryan Roberts,
Dev Jain, Barry Song, Lance Yang, Jann Horn, Pedro Falcato,
David Howells, Paul Moore, James Morris, Serge E . Hallyn,
Yury Norov, Rasmus Villemoes, linux-sgx, linux-kernel, nvdimm,
linux-cxl, dri-devel, intel-gfx, linux-fsdevel, linux-aio,
linux-erofs, linux-ext4, linux-mm, ntfs3, devel, linux-xfs,
keyrings, linux-security-module, Jason Gunthorpe
* Lorenzo Stoakes <lorenzo.stoakes@oracle.com> [260122 16:06]:
> The vma_internal.h file is becoming entirely unmanageable. It combines
> duplicated kernel implementation logic that needs to be kept in-sync with
> the kernel, stubbed out declarations that we simply ignore for testing
> purposes and custom logic added to aid testing.
>
> If we separate each of the three things into separate headers it makes
> things far more manageable, so do so:
>
> * include/stubs.h contains the stubbed declarations,
> * include/dup.h contains the duplicated kernel declarations, and
> * include/custom.h contains declarations customised for testing.
>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
With the follow-up added on,
Reviewed-by: Liam R. Howlett <Liam.Howlett@oracle.com>
> ---
> tools/testing/vma/Makefile | 2 +-
> tools/testing/vma/include/custom.h | 103 ++
> tools/testing/vma/include/dup.h | 1341 +++++++++++++++++++
> tools/testing/vma/include/stubs.h | 428 ++++++
> tools/testing/vma/vma_internal.h | 1936 +---------------------------
> 5 files changed, 1885 insertions(+), 1925 deletions(-)
> create mode 100644 tools/testing/vma/include/custom.h
> create mode 100644 tools/testing/vma/include/dup.h
> create mode 100644 tools/testing/vma/include/stubs.h
>
> diff --git a/tools/testing/vma/Makefile b/tools/testing/vma/Makefile
> index 94133d9d3955..50aa4301b3a6 100644
> --- a/tools/testing/vma/Makefile
> +++ b/tools/testing/vma/Makefile
> @@ -9,7 +9,7 @@ include ../shared/shared.mk
> OFILES = $(SHARED_OFILES) main.o shared.o maple-shim.o
> TARGETS = vma
>
> -main.o: main.c shared.c shared.h vma_internal.h tests/merge.c tests/mmap.c tests/vma.c ../../../mm/vma.c ../../../mm/vma_init.c ../../../mm/vma_exec.c ../../../mm/vma.h
> +main.o: main.c shared.c shared.h vma_internal.h tests/merge.c tests/mmap.c tests/vma.c ../../../mm/vma.c ../../../mm/vma_init.c ../../../mm/vma_exec.c ../../../mm/vma.h include/custom.h include/dup.h include/stubs.h
>
> vma: $(OFILES)
> $(CC) $(CFLAGS) -o $@ $(OFILES) $(LDLIBS)
> diff --git a/tools/testing/vma/include/custom.h b/tools/testing/vma/include/custom.h
> new file mode 100644
> index 000000000000..f567127efba9
> --- /dev/null
> +++ b/tools/testing/vma/include/custom.h
> @@ -0,0 +1,103 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +
> +#pragma once
> +
> +/*
> + * Contains declarations that exist in the kernel which have been CUSTOMISED for
> + * testing purposes to faciliate userland VMA testing.
> + */
> +
> +#ifdef CONFIG_MMU
> +extern unsigned long mmap_min_addr;
> +extern unsigned long dac_mmap_min_addr;
> +#else
> +#define mmap_min_addr 0UL
> +#define dac_mmap_min_addr 0UL
> +#endif
> +
> +#define VM_WARN_ON(_expr) (WARN_ON(_expr))
> +#define VM_WARN_ON_ONCE(_expr) (WARN_ON_ONCE(_expr))
> +#define VM_WARN_ON_VMG(_expr, _vmg) (WARN_ON(_expr))
> +#define VM_BUG_ON(_expr) (BUG_ON(_expr))
> +#define VM_BUG_ON_VMA(_expr, _vma) (BUG_ON(_expr))
> +
> +/* We hardcode this for now. */
> +#define sysctl_max_map_count 0x1000000UL
> +
> +#define TASK_SIZE ((1ul << 47)-PAGE_SIZE)
> +
> +/*
> + * The shared stubs do not implement this, it amounts to an fprintf(STDERR,...)
> + * either way :)
> + */
> +#define pr_warn_once pr_err
> +
> +#define pgtable_supports_soft_dirty() 1
> +
> +struct anon_vma {
> + struct anon_vma *root;
> + struct rb_root_cached rb_root;
> +
> + /* Test fields. */
> + bool was_cloned;
> + bool was_unlinked;
> +};
> +
> +static inline void unlink_anon_vmas(struct vm_area_struct *vma)
> +{
> + /* For testing purposes, indicate that the anon_vma was unlinked. */
> + vma->anon_vma->was_unlinked = true;
> +}
> +
> +static inline void vma_start_write(struct vm_area_struct *vma)
> +{
> + /* Used to indicate to tests that a write operation has begun. */
> + vma->vm_lock_seq++;
> +}
> +
> +static inline __must_check
> +int vma_start_write_killable(struct vm_area_struct *vma)
> +{
> + /* Used to indicate to tests that a write operation has begun. */
> + vma->vm_lock_seq++;
> + return 0;
> +}
> +
> +static inline int anon_vma_clone(struct vm_area_struct *dst, struct vm_area_struct *src,
> + enum vma_operation operation)
> +{
> + /* For testing purposes. We indicate that an anon_vma has been cloned. */
> + if (src->anon_vma != NULL) {
> + dst->anon_vma = src->anon_vma;
> + dst->anon_vma->was_cloned = true;
> + }
> +
> + return 0;
> +}
> +
> +static inline int __anon_vma_prepare(struct vm_area_struct *vma)
> +{
> + struct anon_vma *anon_vma = calloc(1, sizeof(struct anon_vma));
> +
> + if (!anon_vma)
> + return -ENOMEM;
> +
> + anon_vma->root = anon_vma;
> + vma->anon_vma = anon_vma;
> +
> + return 0;
> +}
> +
> +static inline int anon_vma_prepare(struct vm_area_struct *vma)
> +{
> + if (likely(vma->anon_vma))
> + return 0;
> +
> + return __anon_vma_prepare(vma);
> +}
> +
> +static inline void vma_lock_init(struct vm_area_struct *vma, bool reset_refcnt)
> +{
> + if (reset_refcnt)
> + refcount_set(&vma->vm_refcnt, 0);
> +}
> diff --git a/tools/testing/vma/include/dup.h b/tools/testing/vma/include/dup.h
> new file mode 100644
> index 000000000000..ed8708afb7af
> --- /dev/null
> +++ b/tools/testing/vma/include/dup.h
> @@ -0,0 +1,1341 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +
> +#pragma once
> +
> +/* Forward declarations to avoid header cycle. */
> +struct vm_area_struct;
> +static inline void vma_start_write(struct vm_area_struct *vma);
> +
> +extern const struct vm_operations_struct vma_dummy_vm_ops;
> +extern unsigned long stack_guard_gap;
> +extern const struct vm_operations_struct vma_dummy_vm_ops;
> +extern unsigned long rlimit(unsigned int limit);
> +struct task_struct *get_current(void);
> +
> +#define MMF_HAS_MDWE 28
> +#define current get_current()
> +
> +/*
> + * Define the task command name length as enum, then it can be visible to
> + * BPF programs.
> + */
> +enum {
> + TASK_COMM_LEN = 16,
> +};
> +
> +/* PARTIALLY implemented types. */
> +struct mm_struct {
> + struct maple_tree mm_mt;
> + int map_count; /* number of VMAs */
> + unsigned long total_vm; /* Total pages mapped */
> + unsigned long locked_vm; /* Pages that have PG_mlocked set */
> + unsigned long data_vm; /* VM_WRITE & ~VM_SHARED & ~VM_STACK */
> + unsigned long exec_vm; /* VM_EXEC & ~VM_WRITE & ~VM_STACK */
> + unsigned long stack_vm; /* VM_STACK */
> +
> + unsigned long def_flags;
> +
> + mm_flags_t flags; /* Must use mm_flags_* helpers to access */
> +};
> +struct address_space {
> + struct rb_root_cached i_mmap;
> + unsigned long flags;
> + atomic_t i_mmap_writable;
> +};
> +struct file_operations {
> + int (*mmap)(struct file *, struct vm_area_struct *);
> + int (*mmap_prepare)(struct vm_area_desc *);
> +};
> +struct file {
> + struct address_space *f_mapping;
> + const struct file_operations *f_op;
> +};
> +struct anon_vma_chain {
> + struct anon_vma *anon_vma;
> + struct list_head same_vma;
> +};
> +struct task_struct {
> + char comm[TASK_COMM_LEN];
> + pid_t pid;
> + struct mm_struct *mm;
> +
> + /* Used for emulating ABI behavior of previous Linux versions: */
> + unsigned int personality;
> +};
> +
> +struct kref {
> + refcount_t refcount;
> +};
> +
> +struct anon_vma_name {
> + struct kref kref;
> + /* The name needs to be at the end because it is dynamically sized. */
> + char name[];
> +};
> +
> +/*
> + * Contains declarations that are DUPLICATED from kernel source in order to
> + * faciliate userland VMA testing.
> + *
> + * These must be kept in sync with kernel source.
> + */
> +
> +#define VMA_LOCK_OFFSET 0x40000000
> +
> +typedef struct { unsigned long v; } freeptr_t;
> +
> +#define VM_NONE 0x00000000
> +
> +typedef int __bitwise vma_flag_t;
> +
> +#define ACCESS_PRIVATE(p, member) ((p)->member)
> +
> +#define DECLARE_VMA_BIT(name, bitnum) \
> + VMA_ ## name ## _BIT = ((__force vma_flag_t)bitnum)
> +#define DECLARE_VMA_BIT_ALIAS(name, aliased) \
> + VMA_ ## name ## _BIT = VMA_ ## aliased ## _BIT
> +enum {
> + DECLARE_VMA_BIT(READ, 0),
> + DECLARE_VMA_BIT(WRITE, 1),
> + DECLARE_VMA_BIT(EXEC, 2),
> + DECLARE_VMA_BIT(SHARED, 3),
> + /* mprotect() hardcodes VM_MAYREAD >> 4 == VM_READ, and so for r/w/x bits. */
> + DECLARE_VMA_BIT(MAYREAD, 4), /* limits for mprotect() etc. */
> + DECLARE_VMA_BIT(MAYWRITE, 5),
> + DECLARE_VMA_BIT(MAYEXEC, 6),
> + DECLARE_VMA_BIT(MAYSHARE, 7),
> + DECLARE_VMA_BIT(GROWSDOWN, 8), /* general info on the segment */
> +#ifdef CONFIG_MMU
> + DECLARE_VMA_BIT(UFFD_MISSING, 9),/* missing pages tracking */
> +#else
> + /* nommu: R/O MAP_PRIVATE mapping that might overlay a file mapping */
> + DECLARE_VMA_BIT(MAYOVERLAY, 9),
> +#endif /* CONFIG_MMU */
> + /* Page-ranges managed without "struct page", just pure PFN */
> + DECLARE_VMA_BIT(PFNMAP, 10),
> + DECLARE_VMA_BIT(MAYBE_GUARD, 11),
> + DECLARE_VMA_BIT(UFFD_WP, 12), /* wrprotect pages tracking */
> + DECLARE_VMA_BIT(LOCKED, 13),
> + DECLARE_VMA_BIT(IO, 14), /* Memory mapped I/O or similar */
> + DECLARE_VMA_BIT(SEQ_READ, 15), /* App will access data sequentially */
> + DECLARE_VMA_BIT(RAND_READ, 16), /* App will not benefit from clustered reads */
> + DECLARE_VMA_BIT(DONTCOPY, 17), /* Do not copy this vma on fork */
> + DECLARE_VMA_BIT(DONTEXPAND, 18),/* Cannot expand with mremap() */
> + DECLARE_VMA_BIT(LOCKONFAULT, 19),/* Lock pages covered when faulted in */
> + DECLARE_VMA_BIT(ACCOUNT, 20), /* Is a VM accounted object */
> + DECLARE_VMA_BIT(NORESERVE, 21), /* should the VM suppress accounting */
> + DECLARE_VMA_BIT(HUGETLB, 22), /* Huge TLB Page VM */
> + DECLARE_VMA_BIT(SYNC, 23), /* Synchronous page faults */
> + DECLARE_VMA_BIT(ARCH_1, 24), /* Architecture-specific flag */
> + DECLARE_VMA_BIT(WIPEONFORK, 25),/* Wipe VMA contents in child. */
> + DECLARE_VMA_BIT(DONTDUMP, 26), /* Do not include in the core dump */
> + DECLARE_VMA_BIT(SOFTDIRTY, 27), /* NOT soft dirty clean area */
> + DECLARE_VMA_BIT(MIXEDMAP, 28), /* Can contain struct page and pure PFN pages */
> + DECLARE_VMA_BIT(HUGEPAGE, 29), /* MADV_HUGEPAGE marked this vma */
> + DECLARE_VMA_BIT(NOHUGEPAGE, 30),/* MADV_NOHUGEPAGE marked this vma */
> + DECLARE_VMA_BIT(MERGEABLE, 31), /* KSM may merge identical pages */
> + /* These bits are reused, we define specific uses below. */
> + DECLARE_VMA_BIT(HIGH_ARCH_0, 32),
> + DECLARE_VMA_BIT(HIGH_ARCH_1, 33),
> + DECLARE_VMA_BIT(HIGH_ARCH_2, 34),
> + DECLARE_VMA_BIT(HIGH_ARCH_3, 35),
> + DECLARE_VMA_BIT(HIGH_ARCH_4, 36),
> + DECLARE_VMA_BIT(HIGH_ARCH_5, 37),
> + DECLARE_VMA_BIT(HIGH_ARCH_6, 38),
> + /*
> + * This flag is used to connect VFIO to arch specific KVM code. It
> + * indicates that the memory under this VMA is safe for use with any
> + * non-cachable memory type inside KVM. Some VFIO devices, on some
> + * platforms, are thought to be unsafe and can cause machine crashes
> + * if KVM does not lock down the memory type.
> + */
> + DECLARE_VMA_BIT(ALLOW_ANY_UNCACHED, 39),
> +#ifdef CONFIG_PPC32
> + DECLARE_VMA_BIT_ALIAS(DROPPABLE, ARCH_1),
> +#else
> + DECLARE_VMA_BIT(DROPPABLE, 40),
> +#endif
> + DECLARE_VMA_BIT(UFFD_MINOR, 41),
> + DECLARE_VMA_BIT(SEALED, 42),
> + /* Flags that reuse flags above. */
> + DECLARE_VMA_BIT_ALIAS(PKEY_BIT0, HIGH_ARCH_0),
> + DECLARE_VMA_BIT_ALIAS(PKEY_BIT1, HIGH_ARCH_1),
> + DECLARE_VMA_BIT_ALIAS(PKEY_BIT2, HIGH_ARCH_2),
> + DECLARE_VMA_BIT_ALIAS(PKEY_BIT3, HIGH_ARCH_3),
> + DECLARE_VMA_BIT_ALIAS(PKEY_BIT4, HIGH_ARCH_4),
> +#if defined(CONFIG_X86_USER_SHADOW_STACK)
> + /*
> + * VM_SHADOW_STACK should not be set with VM_SHARED because of lack of
> + * support core mm.
> + *
> + * These VMAs will get a single end guard page. This helps userspace
> + * protect itself from attacks. A single page is enough for current
> + * shadow stack archs (x86). See the comments near alloc_shstk() in
> + * arch/x86/kernel/shstk.c for more details on the guard size.
> + */
> + DECLARE_VMA_BIT_ALIAS(SHADOW_STACK, HIGH_ARCH_5),
> +#elif defined(CONFIG_ARM64_GCS)
> + /*
> + * arm64's Guarded Control Stack implements similar functionality and
> + * has similar constraints to shadow stacks.
> + */
> + DECLARE_VMA_BIT_ALIAS(SHADOW_STACK, HIGH_ARCH_6),
> +#endif
> + DECLARE_VMA_BIT_ALIAS(SAO, ARCH_1), /* Strong Access Ordering (powerpc) */
> + DECLARE_VMA_BIT_ALIAS(GROWSUP, ARCH_1), /* parisc */
> + DECLARE_VMA_BIT_ALIAS(SPARC_ADI, ARCH_1), /* sparc64 */
> + DECLARE_VMA_BIT_ALIAS(ARM64_BTI, ARCH_1), /* arm64 */
> + DECLARE_VMA_BIT_ALIAS(ARCH_CLEAR, ARCH_1), /* sparc64, arm64 */
> + DECLARE_VMA_BIT_ALIAS(MAPPED_COPY, ARCH_1), /* !CONFIG_MMU */
> + DECLARE_VMA_BIT_ALIAS(MTE, HIGH_ARCH_4), /* arm64 */
> + DECLARE_VMA_BIT_ALIAS(MTE_ALLOWED, HIGH_ARCH_5),/* arm64 */
> +#ifdef CONFIG_STACK_GROWSUP
> + DECLARE_VMA_BIT_ALIAS(STACK, GROWSUP),
> + DECLARE_VMA_BIT_ALIAS(STACK_EARLY, GROWSDOWN),
> +#else
> + DECLARE_VMA_BIT_ALIAS(STACK, GROWSDOWN),
> +#endif
> +};
> +
> +#define INIT_VM_FLAG(name) BIT((__force int) VMA_ ## name ## _BIT)
> +#define VM_READ INIT_VM_FLAG(READ)
> +#define VM_WRITE INIT_VM_FLAG(WRITE)
> +#define VM_EXEC INIT_VM_FLAG(EXEC)
> +#define VM_SHARED INIT_VM_FLAG(SHARED)
> +#define VM_MAYREAD INIT_VM_FLAG(MAYREAD)
> +#define VM_MAYWRITE INIT_VM_FLAG(MAYWRITE)
> +#define VM_MAYEXEC INIT_VM_FLAG(MAYEXEC)
> +#define VM_MAYSHARE INIT_VM_FLAG(MAYSHARE)
> +#define VM_GROWSDOWN INIT_VM_FLAG(GROWSDOWN)
> +#ifdef CONFIG_MMU
> +#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)
> +#define VM_UFFD_WP INIT_VM_FLAG(UFFD_WP)
> +#define VM_LOCKED INIT_VM_FLAG(LOCKED)
> +#define VM_IO INIT_VM_FLAG(IO)
> +#define VM_SEQ_READ INIT_VM_FLAG(SEQ_READ)
> +#define VM_RAND_READ INIT_VM_FLAG(RAND_READ)
> +#define VM_DONTCOPY INIT_VM_FLAG(DONTCOPY)
> +#define VM_DONTEXPAND INIT_VM_FLAG(DONTEXPAND)
> +#define VM_LOCKONFAULT INIT_VM_FLAG(LOCKONFAULT)
> +#define VM_ACCOUNT INIT_VM_FLAG(ACCOUNT)
> +#define VM_NORESERVE INIT_VM_FLAG(NORESERVE)
> +#define VM_HUGETLB INIT_VM_FLAG(HUGETLB)
> +#define VM_SYNC INIT_VM_FLAG(SYNC)
> +#define VM_ARCH_1 INIT_VM_FLAG(ARCH_1)
> +#define VM_WIPEONFORK INIT_VM_FLAG(WIPEONFORK)
> +#define VM_DONTDUMP INIT_VM_FLAG(DONTDUMP)
> +#ifdef CONFIG_MEM_SOFT_DIRTY
> +#define VM_SOFTDIRTY INIT_VM_FLAG(SOFTDIRTY)
> +#else
> +#define VM_SOFTDIRTY VM_NONE
> +#endif
> +#define VM_MIXEDMAP INIT_VM_FLAG(MIXEDMAP)
> +#define VM_HUGEPAGE INIT_VM_FLAG(HUGEPAGE)
> +#define VM_NOHUGEPAGE INIT_VM_FLAG(NOHUGEPAGE)
> +#define VM_MERGEABLE INIT_VM_FLAG(MERGEABLE)
> +#define VM_STACK INIT_VM_FLAG(STACK)
> +#ifdef CONFIG_STACK_GROWS_UP
> +#define VM_STACK_EARLY INIT_VM_FLAG(STACK_EARLY)
> +#else
> +#define VM_STACK_EARLY VM_NONE
> +#endif
> +#ifdef CONFIG_ARCH_HAS_PKEYS
> +#define VM_PKEY_SHIFT ((__force int)VMA_HIGH_ARCH_0_BIT)
> +/* Despite the naming, these are FLAGS not bits. */
> +#define VM_PKEY_BIT0 INIT_VM_FLAG(PKEY_BIT0)
> +#define VM_PKEY_BIT1 INIT_VM_FLAG(PKEY_BIT1)
> +#define VM_PKEY_BIT2 INIT_VM_FLAG(PKEY_BIT2)
> +#if CONFIG_ARCH_PKEY_BITS > 3
> +#define VM_PKEY_BIT3 INIT_VM_FLAG(PKEY_BIT3)
> +#else
> +#define VM_PKEY_BIT3 VM_NONE
> +#endif /* CONFIG_ARCH_PKEY_BITS > 3 */
> +#if CONFIG_ARCH_PKEY_BITS > 4
> +#define VM_PKEY_BIT4 INIT_VM_FLAG(PKEY_BIT4)
> +#else
> +#define VM_PKEY_BIT4 VM_NONE
> +#endif /* CONFIG_ARCH_PKEY_BITS > 4 */
> +#endif /* CONFIG_ARCH_HAS_PKEYS */
> +#if defined(CONFIG_X86_USER_SHADOW_STACK) || defined(CONFIG_ARM64_GCS)
> +#define VM_SHADOW_STACK INIT_VM_FLAG(SHADOW_STACK)
> +#else
> +#define VM_SHADOW_STACK VM_NONE
> +#endif
> +#if defined(CONFIG_PPC64)
> +#define VM_SAO INIT_VM_FLAG(SAO)
> +#elif defined(CONFIG_PARISC)
> +#define VM_GROWSUP INIT_VM_FLAG(GROWSUP)
> +#elif defined(CONFIG_SPARC64)
> +#define VM_SPARC_ADI INIT_VM_FLAG(SPARC_ADI)
> +#define VM_ARCH_CLEAR INIT_VM_FLAG(ARCH_CLEAR)
> +#elif defined(CONFIG_ARM64)
> +#define VM_ARM64_BTI INIT_VM_FLAG(ARM64_BTI)
> +#define VM_ARCH_CLEAR INIT_VM_FLAG(ARCH_CLEAR)
> +#elif !defined(CONFIG_MMU)
> +#define VM_MAPPED_COPY INIT_VM_FLAG(MAPPED_COPY)
> +#endif
> +#ifndef VM_GROWSUP
> +#define VM_GROWSUP VM_NONE
> +#endif
> +#ifdef CONFIG_ARM64_MTE
> +#define VM_MTE INIT_VM_FLAG(MTE)
> +#define VM_MTE_ALLOWED INIT_VM_FLAG(MTE_ALLOWED)
> +#else
> +#define VM_MTE VM_NONE
> +#define VM_MTE_ALLOWED VM_NONE
> +#endif
> +#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_MINOR
> +#define VM_UFFD_MINOR INIT_VM_FLAG(UFFD_MINOR)
> +#else
> +#define VM_UFFD_MINOR VM_NONE
> +#endif
> +#ifdef CONFIG_64BIT
> +#define VM_ALLOW_ANY_UNCACHED INIT_VM_FLAG(ALLOW_ANY_UNCACHED)
> +#define VM_SEALED INIT_VM_FLAG(SEALED)
> +#else
> +#define VM_ALLOW_ANY_UNCACHED VM_NONE
> +#define VM_SEALED VM_NONE
> +#endif
> +#if defined(CONFIG_64BIT) || defined(CONFIG_PPC32)
> +#define VM_DROPPABLE INIT_VM_FLAG(DROPPABLE)
> +#else
> +#define VM_DROPPABLE VM_NONE
> +#endif
> +
> +/* Bits set in the VMA until the stack is in its final location */
> +#define VM_STACK_INCOMPLETE_SETUP (VM_RAND_READ | VM_SEQ_READ | VM_STACK_EARLY)
> +
> +#define TASK_EXEC ((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0)
> +
> +/* Common data flag combinations */
> +#define VM_DATA_FLAGS_TSK_EXEC (VM_READ | VM_WRITE | TASK_EXEC | \
> + VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
> +#define VM_DATA_FLAGS_NON_EXEC (VM_READ | VM_WRITE | VM_MAYREAD | \
> + VM_MAYWRITE | VM_MAYEXEC)
> +#define VM_DATA_FLAGS_EXEC (VM_READ | VM_WRITE | VM_EXEC | \
> + VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
> +
> +#ifndef VM_DATA_DEFAULT_FLAGS /* arch can override this */
> +#define VM_DATA_DEFAULT_FLAGS VM_DATA_FLAGS_EXEC
> +#endif
> +
> +#ifndef VM_STACK_DEFAULT_FLAGS /* arch can override this */
> +#define VM_STACK_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS
> +#endif
> +
> +#define VM_STARTGAP_FLAGS (VM_GROWSDOWN | VM_SHADOW_STACK)
> +
> +#define VM_STACK_FLAGS (VM_STACK | VM_STACK_DEFAULT_FLAGS | VM_ACCOUNT)
> +
> +/* VMA basic access permission flags */
> +#define VM_ACCESS_FLAGS (VM_READ | VM_WRITE | VM_EXEC)
> +
> +/*
> + * Special vmas that are non-mergable, non-mlock()able.
> + */
> +#define VM_SPECIAL (VM_IO | VM_DONTEXPAND | VM_PFNMAP | VM_MIXEDMAP)
> +
> +#define DEFAULT_MAP_WINDOW ((1UL << 47) - PAGE_SIZE)
> +#define TASK_SIZE_LOW DEFAULT_MAP_WINDOW
> +#define TASK_SIZE_MAX DEFAULT_MAP_WINDOW
> +#define STACK_TOP TASK_SIZE_LOW
> +#define STACK_TOP_MAX TASK_SIZE_MAX
> +
> +/* This mask represents all the VMA flag bits used by mlock */
> +#define VM_LOCKED_MASK (VM_LOCKED | VM_LOCKONFAULT)
> +
> +#define TASK_EXEC ((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0)
> +
> +#define VM_DATA_FLAGS_TSK_EXEC (VM_READ | VM_WRITE | TASK_EXEC | \
> + VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
> +
> +#define RLIMIT_STACK 3 /* max stack size */
> +#define RLIMIT_MEMLOCK 8 /* max locked-in-memory address space */
> +
> +#define CAP_IPC_LOCK 14
> +
> +#define VM_STICKY (VM_SOFTDIRTY | VM_MAYBE_GUARD)
> +
> +#define VM_IGNORE_MERGE VM_STICKY
> +
> +#define VM_COPY_ON_FORK (VM_PFNMAP | VM_MIXEDMAP | VM_UFFD_WP | VM_MAYBE_GUARD)
> +
> +#define pgprot_val(x) ((x).pgprot)
> +#define __pgprot(x) ((pgprot_t) { (x) } )
> +
> +#define for_each_vma(__vmi, __vma) \
> + while (((__vma) = vma_next(&(__vmi))) != NULL)
> +
> +/* The MM code likes to work with exclusive end addresses */
> +#define for_each_vma_range(__vmi, __vma, __end) \
> + while (((__vma) = vma_find(&(__vmi), (__end))) != NULL)
> +
> +#define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK)
> +
> +#define PHYS_PFN(x) ((unsigned long)((x) >> PAGE_SHIFT))
> +
> +#define test_and_set_bit(nr, addr) __test_and_set_bit(nr, addr)
> +#define test_and_clear_bit(nr, addr) __test_and_clear_bit(nr, addr)
> +
> +#define AS_MM_ALL_LOCKS 2
> +
> +#define swap(a, b) \
> + do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0)
> +
> +/*
> + * Flags for bug emulation.
> + *
> + * These occupy the top three bytes.
> + */
> +enum {
> + READ_IMPLIES_EXEC = 0x0400000,
> +};
> +
> +struct vma_iterator {
> + struct ma_state mas;
> +};
> +
> +#define VMA_ITERATOR(name, __mm, __addr) \
> + struct vma_iterator name = { \
> + .mas = { \
> + .tree = &(__mm)->mm_mt, \
> + .index = __addr, \
> + .node = NULL, \
> + .status = ma_start, \
> + }, \
> + }
> +
> +#define DEFINE_MUTEX(mutexname) \
> + struct mutex mutexname = {}
> +
> +#define DECLARE_BITMAP(name, bits) \
> + unsigned long name[BITS_TO_LONGS(bits)]
> +
> +#define EMPTY_VMA_FLAGS ((vma_flags_t){ })
> +
> +/* What action should be taken after an .mmap_prepare call is complete? */
> +enum mmap_action_type {
> + MMAP_NOTHING, /* Mapping is complete, no further action. */
> + MMAP_REMAP_PFN, /* Remap PFN range. */
> + MMAP_IO_REMAP_PFN, /* I/O remap PFN range. */
> +};
> +
> +/*
> + * Describes an action an mmap_prepare hook can instruct to be taken to complete
> + * the mapping of a VMA. Specified in vm_area_desc.
> + */
> +struct mmap_action {
> + union {
> + /* Remap range. */
> + struct {
> + unsigned long start;
> + unsigned long start_pfn;
> + unsigned long size;
> + pgprot_t pgprot;
> + } remap;
> + };
> + enum mmap_action_type type;
> +
> + /*
> + * If specified, this hook is invoked after the selected action has been
> + * successfully completed. Note that the VMA write lock still held.
> + *
> + * The absolute minimum ought to be done here.
> + *
> + * Returns 0 on success, or an error code.
> + */
> + int (*success_hook)(const struct vm_area_struct *vma);
> +
> + /*
> + * If specified, this hook is invoked when an error occurred when
> + * attempting the selection action.
> + *
> + * The hook can return an error code in order to filter the error, but
> + * it is not valid to clear the error here.
> + */
> + int (*error_hook)(int err);
> +
> + /*
> + * This should be set in rare instances where the operation required
> + * that the rmap should not be able to access the VMA until
> + * completely set up.
> + */
> + bool hide_from_rmap_until_complete :1;
> +};
> +
> +/* Operations which modify VMAs. */
> +enum vma_operation {
> + VMA_OP_SPLIT,
> + VMA_OP_MERGE_UNFAULTED,
> + VMA_OP_REMAP,
> + VMA_OP_FORK,
> +};
> +
> +/*
> + * 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
> + * resultant VMA.
> + *
> + * Helper functions are not required for manipulating any field.
> + */
> +struct vm_area_desc {
> + /* Immutable state. */
> + const struct mm_struct *const mm;
> + struct file *const file; /* May vary from vm_file in stacked callers. */
> + unsigned long start;
> + unsigned long end;
> +
> + /* Mutable fields. Populated with initial state. */
> + pgoff_t pgoff;
> + struct file *vm_file;
> + union {
> + vm_flags_t vm_flags;
> + vma_flags_t vma_flags;
> + };
> + pgprot_t page_prot;
> +
> + /* Write-only fields. */
> + const struct vm_operations_struct *vm_ops;
> + void *private_data;
> +
> + /* Take further action? */
> + struct mmap_action action;
> +};
> +
> +struct vm_area_struct {
> + /* The first cache line has the info for VMA tree walking. */
> +
> + union {
> + struct {
> + /* VMA covers [vm_start; vm_end) addresses within mm */
> + unsigned long vm_start;
> + unsigned long vm_end;
> + };
> + freeptr_t vm_freeptr; /* Pointer used by SLAB_TYPESAFE_BY_RCU */
> + };
> +
> + struct mm_struct *vm_mm; /* The address space we belong to. */
> + pgprot_t vm_page_prot; /* Access permissions of this VMA. */
> +
> + /*
> + * Flags, see mm.h.
> + * To modify use vm_flags_{init|reset|set|clear|mod} functions.
> + */
> + union {
> + const vm_flags_t vm_flags;
> + vma_flags_t flags;
> + };
> +
> +#ifdef CONFIG_PER_VMA_LOCK
> + /*
> + * Can only be written (using WRITE_ONCE()) while holding both:
> + * - mmap_lock (in write mode)
> + * - vm_refcnt bit at VMA_LOCK_OFFSET is set
> + * Can be read reliably while holding one of:
> + * - mmap_lock (in read or write mode)
> + * - vm_refcnt bit at VMA_LOCK_OFFSET is set or vm_refcnt > 1
> + * Can be read unreliably (using READ_ONCE()) for pessimistic bailout
> + * while holding nothing (except RCU to keep the VMA struct allocated).
> + *
> + * This sequence counter is explicitly allowed to overflow; sequence
> + * counter reuse can only lead to occasional unnecessary use of the
> + * slowpath.
> + */
> + unsigned int vm_lock_seq;
> +#endif
> +
> + /*
> + * A file's MAP_PRIVATE vma can be in both i_mmap tree and anon_vma
> + * list, after a COW of one of the file pages. A MAP_SHARED vma
> + * can only be in the i_mmap tree. An anonymous MAP_PRIVATE, stack
> + * or brk vma (with NULL file) can only be in an anon_vma list.
> + */
> + struct list_head anon_vma_chain; /* Serialized by mmap_lock &
> + * page_table_lock */
> + struct anon_vma *anon_vma; /* Serialized by page_table_lock */
> +
> + /* Function pointers to deal with this struct. */
> + const struct vm_operations_struct *vm_ops;
> +
> + /* Information about our backing store: */
> + unsigned long vm_pgoff; /* Offset (within vm_file) in PAGE_SIZE
> + units */
> + struct file * vm_file; /* File we map to (can be NULL). */
> + void * vm_private_data; /* was vm_pte (shared mem) */
> +
> +#ifdef CONFIG_SWAP
> + atomic_long_t swap_readahead_info;
> +#endif
> +#ifndef CONFIG_MMU
> + struct vm_region *vm_region; /* NOMMU mapping region */
> +#endif
> +#ifdef CONFIG_NUMA
> + struct mempolicy *vm_policy; /* NUMA policy for the VMA */
> +#endif
> +#ifdef CONFIG_NUMA_BALANCING
> + struct vma_numab_state *numab_state; /* NUMA Balancing state */
> +#endif
> +#ifdef CONFIG_PER_VMA_LOCK
> + /* Unstable RCU readers are allowed to read this. */
> + refcount_t vm_refcnt;
> +#endif
> + /*
> + * For areas with an address space and backing store,
> + * linkage into the address_space->i_mmap interval tree.
> + *
> + */
> + struct {
> + struct rb_node rb;
> + unsigned long rb_subtree_last;
> + } shared;
> +#ifdef CONFIG_ANON_VMA_NAME
> + /*
> + * For private and shared anonymous mappings, a pointer to a null
> + * terminated string containing the name given to the vma, or NULL if
> + * unnamed. Serialized by mmap_lock. Use anon_vma_name to access.
> + */
> + struct anon_vma_name *anon_name;
> +#endif
> + struct vm_userfaultfd_ctx vm_userfaultfd_ctx;
> +} __randomize_layout;
> +
> +struct vm_operations_struct {
> + void (*open)(struct vm_area_struct * area);
> + /**
> + * @close: Called when the VMA is being removed from the MM.
> + * Context: User context. May sleep. Caller holds mmap_lock.
> + */
> + void (*close)(struct vm_area_struct * area);
> + /* Called any time before splitting to check if it's allowed */
> + int (*may_split)(struct vm_area_struct *area, unsigned long addr);
> + int (*mremap)(struct vm_area_struct *area);
> + /*
> + * Called by mprotect() to make driver-specific permission
> + * checks before mprotect() is finalised. The VMA must not
> + * be modified. Returns 0 if mprotect() can proceed.
> + */
> + int (*mprotect)(struct vm_area_struct *vma, unsigned long start,
> + unsigned long end, unsigned long newflags);
> + vm_fault_t (*fault)(struct vm_fault *vmf);
> + vm_fault_t (*huge_fault)(struct vm_fault *vmf, unsigned int order);
> + vm_fault_t (*map_pages)(struct vm_fault *vmf,
> + pgoff_t start_pgoff, pgoff_t end_pgoff);
> + unsigned long (*pagesize)(struct vm_area_struct * area);
> +
> + /* notification that a previously read-only page is about to become
> + * writable, if an error is returned it will cause a SIGBUS */
> + vm_fault_t (*page_mkwrite)(struct vm_fault *vmf);
> +
> + /* same as page_mkwrite when using VM_PFNMAP|VM_MIXEDMAP */
> + vm_fault_t (*pfn_mkwrite)(struct vm_fault *vmf);
> +
> + /* called by access_process_vm when get_user_pages() fails, typically
> + * for use by special VMAs. See also generic_access_phys() for a generic
> + * implementation useful for any iomem mapping.
> + */
> + int (*access)(struct vm_area_struct *vma, unsigned long addr,
> + void *buf, int len, int write);
> +
> + /* Called by the /proc/PID/maps code to ask the vma whether it
> + * has a special name. Returning non-NULL will also cause this
> + * vma to be dumped unconditionally. */
> + const char *(*name)(struct vm_area_struct *vma);
> +
> +#ifdef CONFIG_NUMA
> + /*
> + * set_policy() op must add a reference to any non-NULL @new mempolicy
> + * to hold the policy upon return. Caller should pass NULL @new to
> + * remove a policy and fall back to surrounding context--i.e. do not
> + * install a MPOL_DEFAULT policy, nor the task or system default
> + * mempolicy.
> + */
> + int (*set_policy)(struct vm_area_struct *vma, struct mempolicy *new);
> +
> + /*
> + * get_policy() op must add reference [mpol_get()] to any policy at
> + * (vma,addr) marked as MPOL_SHARED. The shared policy infrastructure
> + * in mm/mempolicy.c will do this automatically.
> + * get_policy() must NOT add a ref if the policy at (vma,addr) is not
> + * marked as MPOL_SHARED. vma policies are protected by the mmap_lock.
> + * If no [shared/vma] mempolicy exists at the addr, get_policy() op
> + * must return NULL--i.e., do not "fallback" to task or system default
> + * policy.
> + */
> + struct mempolicy *(*get_policy)(struct vm_area_struct *vma,
> + unsigned long addr, pgoff_t *ilx);
> +#endif
> +#ifdef CONFIG_FIND_NORMAL_PAGE
> + /*
> + * Called by vm_normal_page() for special PTEs in @vma at @addr. This
> + * allows for returning a "normal" page from vm_normal_page() even
> + * though the PTE indicates that the "struct page" either does not exist
> + * or should not be touched: "special".
> + *
> + * Do not add new users: this really only works when a "normal" page
> + * was mapped, but then the PTE got changed to something weird (+
> + * marked special) that would not make pte_pfn() identify the originally
> + * inserted page.
> + */
> + struct page *(*find_normal_page)(struct vm_area_struct *vma,
> + unsigned long addr);
> +#endif /* CONFIG_FIND_NORMAL_PAGE */
> +};
> +
> +struct vm_unmapped_area_info {
> +#define VM_UNMAPPED_AREA_TOPDOWN 1
> + unsigned long flags;
> + unsigned long length;
> + unsigned long low_limit;
> + unsigned long high_limit;
> + unsigned long align_mask;
> + unsigned long align_offset;
> + unsigned long start_gap;
> +};
> +
> +struct pagetable_move_control {
> + struct vm_area_struct *old; /* Source VMA. */
> + struct vm_area_struct *new; /* Destination VMA. */
> + unsigned long old_addr; /* Address from which the move begins. */
> + unsigned long old_end; /* Exclusive address at which old range ends. */
> + unsigned long new_addr; /* Address to move page tables to. */
> + unsigned long len_in; /* Bytes to remap specified by user. */
> +
> + bool need_rmap_locks; /* Do rmap locks need to be taken? */
> + bool for_stack; /* Is this an early temp stack being moved? */
> +};
> +
> +#define PAGETABLE_MOVE(name, old_, new_, old_addr_, new_addr_, len_) \
> + struct pagetable_move_control name = { \
> + .old = old_, \
> + .new = new_, \
> + .old_addr = old_addr_, \
> + .old_end = (old_addr_) + (len_), \
> + .new_addr = new_addr_, \
> + .len_in = len_, \
> + }
> +
> +static inline void vma_iter_invalidate(struct vma_iterator *vmi)
> +{
> + mas_pause(&vmi->mas);
> +}
> +
> +static inline pgprot_t pgprot_modify(pgprot_t oldprot, pgprot_t newprot)
> +{
> + return __pgprot(pgprot_val(oldprot) | pgprot_val(newprot));
> +}
> +
> +static inline pgprot_t vm_get_page_prot(vm_flags_t vm_flags)
> +{
> + return __pgprot(vm_flags);
> +}
> +
> +static inline bool mm_flags_test(int flag, const struct mm_struct *mm)
> +{
> + return test_bit(flag, ACCESS_PRIVATE(&mm->flags, __mm_flags));
> +}
> +
> +/*
> + * 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;
> +}
> +
> +static inline void vma_flags_clear_all(vma_flags_t *flags)
> +{
> + bitmap_zero(ACCESS_PRIVATE(flags, __vma_flags), NUM_VMA_FLAG_BITS);
> +}
> +
> +static inline void vma_flag_set(vma_flags_t *flags, vma_flag_t bit)
> +{
> + unsigned long *bitmap = ACCESS_PRIVATE(flags, __vma_flags);
> +
> + __set_bit((__force int)bit, bitmap);
> +}
> +
> +/* 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);
> +}
> +
> +static inline vma_flags_t __mk_vma_flags(size_t count, const vma_flag_t *bits)
> +{
> + vma_flags_t flags;
> + int i;
> +
> + vma_flags_clear_all(&flags);
> + for (i = 0; i < count; i++)
> + vma_flag_set(&flags, bits[i]);
> + return flags;
> +}
> +
> +#define mk_vma_flags(...) __mk_vma_flags(COUNT_ARGS(__VA_ARGS__), \
> + (const vma_flag_t []){__VA_ARGS__})
> +
> +static __always_inline bool vma_flags_test_mask(const vma_flags_t *flags,
> + vma_flags_t to_test)
> +{
> + const unsigned long *bitmap = flags->__vma_flags;
> + const unsigned long *bitmap_to_test = to_test.__vma_flags;
> +
> + return bitmap_intersects(bitmap_to_test, bitmap, NUM_VMA_FLAG_BITS);
> +}
> +
> +#define vma_flags_test(flags, ...) \
> + vma_flags_test_mask(flags, mk_vma_flags(__VA_ARGS__))
> +
> +static __always_inline bool vma_flags_test_all_mask(const vma_flags_t *flags,
> + vma_flags_t to_test)
> +{
> + const unsigned long *bitmap = flags->__vma_flags;
> + const unsigned long *bitmap_to_test = to_test.__vma_flags;
> +
> + return bitmap_subset(bitmap_to_test, bitmap, NUM_VMA_FLAG_BITS);
> +}
> +
> +#define vma_flags_test_all(flags, ...) \
> + vma_flags_test_all_mask(flags, mk_vma_flags(__VA_ARGS__))
> +
> +static __always_inline void vma_flags_set_mask(vma_flags_t *flags, vma_flags_t to_set)
> +{
> + unsigned long *bitmap = flags->__vma_flags;
> + const unsigned long *bitmap_to_set = to_set.__vma_flags;
> +
> + bitmap_or(bitmap, bitmap, bitmap_to_set, NUM_VMA_FLAG_BITS);
> +}
> +
> +#define vma_flags_set(flags, ...) \
> + vma_flags_set_mask(flags, mk_vma_flags(__VA_ARGS__))
> +
> +static __always_inline void vma_flags_clear_mask(vma_flags_t *flags, vma_flags_t to_clear)
> +{
> + unsigned long *bitmap = flags->__vma_flags;
> + const unsigned long *bitmap_to_clear = to_clear.__vma_flags;
> +
> + bitmap_andnot(bitmap, bitmap, bitmap_to_clear, NUM_VMA_FLAG_BITS);
> +}
> +
> +#define vma_flags_clear(flags, ...) \
> + vma_flags_clear_mask(flags, mk_vma_flags(__VA_ARGS__))
> +
> +static inline bool vma_test_all_flags_mask(const struct vm_area_struct *vma,
> + vma_flags_t flags)
> +{
> + return vma_flags_test_all_mask(&vma->flags, flags);
> +}
> +
> +#define vma_test_all_flags(vma, ...) \
> + vma_test_all_flags_mask(vma, mk_vma_flags(__VA_ARGS__))
> +
> +static inline bool is_shared_maywrite_vm_flags(vm_flags_t vm_flags)
> +{
> + return (vm_flags & (VM_SHARED | VM_MAYWRITE)) ==
> + (VM_SHARED | VM_MAYWRITE);
> +}
> +
> +static inline void vma_set_flags_mask(struct vm_area_struct *vma,
> + vma_flags_t flags)
> +{
> + vma_flags_set_mask(&vma->flags, flags);
> +}
> +
> +#define vma_set_flags(vma, ...) \
> + vma_set_flags_mask(vma, mk_vma_flags(__VA_ARGS__))
> +
> +static inline bool vma_desc_test_flags_mask(const struct vm_area_desc *desc,
> + vma_flags_t flags)
> +{
> + return vma_flags_test_mask(&desc->vma_flags, flags);
> +}
> +
> +#define vma_desc_test_flags(desc, ...) \
> + vma_desc_test_flags_mask(desc, mk_vma_flags(__VA_ARGS__))
> +
> +static inline void vma_desc_set_flags_mask(struct vm_area_desc *desc,
> + vma_flags_t flags)
> +{
> + vma_flags_set_mask(&desc->vma_flags, flags);
> +}
> +
> +#define vma_desc_set_flags(desc, ...) \
> + vma_desc_set_flags_mask(desc, mk_vma_flags(__VA_ARGS__))
> +
> +static inline void vma_desc_clear_flags_mask(struct vm_area_desc *desc,
> + vma_flags_t flags)
> +{
> + vma_flags_clear_mask(&desc->vma_flags, flags);
> +}
> +
> +#define vma_desc_clear_flags(desc, ...) \
> + vma_desc_clear_flags_mask(desc, mk_vma_flags(__VA_ARGS__))
> +
> +static inline bool is_shared_maywrite(const vma_flags_t *flags)
> +{
> + return vma_flags_test_all(flags, VMA_SHARED_BIT, VMA_MAYWRITE_BIT);
> +}
> +
> +static inline bool vma_is_shared_maywrite(struct vm_area_struct *vma)
> +{
> + return is_shared_maywrite(&vma->flags);
> +}
> +
> +static inline struct vm_area_struct *vma_next(struct vma_iterator *vmi)
> +{
> + /*
> + * Uses mas_find() to get the first VMA when the iterator starts.
> + * Calling mas_next() could skip the first entry.
> + */
> + return mas_find(&vmi->mas, ULONG_MAX);
> +}
> +
> +/*
> + * WARNING: to avoid racing with vma_mark_attached()/vma_mark_detached(), these
> + * assertions should be made either under mmap_write_lock or when the object
> + * has been isolated under mmap_write_lock, ensuring no competing writers.
> + */
> +static inline void vma_assert_attached(struct vm_area_struct *vma)
> +{
> + WARN_ON_ONCE(!refcount_read(&vma->vm_refcnt));
> +}
> +
> +static inline void vma_assert_detached(struct vm_area_struct *vma)
> +{
> + WARN_ON_ONCE(refcount_read(&vma->vm_refcnt));
> +}
> +
> +static inline void vma_assert_write_locked(struct vm_area_struct *);
> +static inline void vma_mark_attached(struct vm_area_struct *vma)
> +{
> + vma_assert_write_locked(vma);
> + vma_assert_detached(vma);
> + refcount_set_release(&vma->vm_refcnt, 1);
> +}
> +
> +static inline void vma_mark_detached(struct vm_area_struct *vma)
> +{
> + vma_assert_write_locked(vma);
> + vma_assert_attached(vma);
> + /* We are the only writer, so no need to use vma_refcount_put(). */
> + if (unlikely(!refcount_dec_and_test(&vma->vm_refcnt))) {
> + /*
> + * Reader must have temporarily raised vm_refcnt but it will
> + * drop it without using the vma since vma is write-locked.
> + */
> + }
> +}
> +
> +static inline void vma_init(struct vm_area_struct *vma, struct mm_struct *mm)
> +{
> + memset(vma, 0, sizeof(*vma));
> + vma->vm_mm = mm;
> + vma->vm_ops = &vma_dummy_vm_ops;
> + INIT_LIST_HEAD(&vma->anon_vma_chain);
> + vma->vm_lock_seq = UINT_MAX;
> +}
> +
> +/*
> + * These are defined in vma.h, but sadly vm_stat_account() is referenced by
> + * kernel/fork.c, so we have to these broadly available there, and temporarily
> + * define them here to resolve the dependency cycle.
> + */
> +#define is_exec_mapping(flags) \
> + ((flags & (VM_EXEC | VM_WRITE | VM_STACK)) == VM_EXEC)
> +
> +#define is_stack_mapping(flags) \
> + (((flags & VM_STACK) == VM_STACK) || (flags & VM_SHADOW_STACK))
> +
> +#define is_data_mapping(flags) \
> + ((flags & (VM_WRITE | VM_SHARED | VM_STACK)) == VM_WRITE)
> +
> +static inline void vm_stat_account(struct mm_struct *mm, vm_flags_t flags,
> + long npages)
> +{
> + WRITE_ONCE(mm->total_vm, READ_ONCE(mm->total_vm)+npages);
> +
> + if (is_exec_mapping(flags))
> + mm->exec_vm += npages;
> + else if (is_stack_mapping(flags))
> + mm->stack_vm += npages;
> + else if (is_data_mapping(flags))
> + mm->data_vm += npages;
> +}
> +
> +#undef is_exec_mapping
> +#undef is_stack_mapping
> +#undef is_data_mapping
> +
> +static inline void vm_unacct_memory(long pages)
> +{
> + vm_acct_memory(-pages);
> +}
> +
> +static inline void mapping_allow_writable(struct address_space *mapping)
> +{
> + atomic_inc(&mapping->i_mmap_writable);
> +}
> +
> +static inline
> +struct vm_area_struct *vma_find(struct vma_iterator *vmi, unsigned long max)
> +{
> + return mas_find(&vmi->mas, max - 1);
> +}
> +
> +static inline int vma_iter_clear_gfp(struct vma_iterator *vmi,
> + unsigned long start, unsigned long end, gfp_t gfp)
> +{
> + __mas_set_range(&vmi->mas, start, end - 1);
> + mas_store_gfp(&vmi->mas, NULL, gfp);
> + if (unlikely(mas_is_err(&vmi->mas)))
> + return -ENOMEM;
> +
> + return 0;
> +}
> +
> +static inline void vma_set_anonymous(struct vm_area_struct *vma)
> +{
> + vma->vm_ops = NULL;
> +}
> +
> +/* Declared in vma.h. */
> +static inline void set_vma_from_desc(struct vm_area_struct *vma,
> + struct vm_area_desc *desc);
> +
> +static inline int __compat_vma_mmap(const struct file_operations *f_op,
> + struct file *file, struct vm_area_struct *vma)
> +{
> + struct vm_area_desc desc = {
> + .mm = vma->vm_mm,
> + .file = file,
> + .start = vma->vm_start,
> + .end = vma->vm_end,
> +
> + .pgoff = vma->vm_pgoff,
> + .vm_file = vma->vm_file,
> + .vm_flags = vma->vm_flags,
> + .page_prot = vma->vm_page_prot,
> +
> + .action.type = MMAP_NOTHING, /* Default */
> + };
> + int err;
> +
> + err = f_op->mmap_prepare(&desc);
> + if (err)
> + return err;
> +
> + mmap_action_prepare(&desc.action, &desc);
> + set_vma_from_desc(vma, &desc);
> + return mmap_action_complete(&desc.action, vma);
> +}
> +
> +static inline int compat_vma_mmap(struct file *file,
> + struct vm_area_struct *vma)
> +{
> + return __compat_vma_mmap(file->f_op, file, vma);
> +}
> +
> +
> +static inline void vma_iter_init(struct vma_iterator *vmi,
> + struct mm_struct *mm, unsigned long addr)
> +{
> + mas_init(&vmi->mas, &mm->mm_mt, addr);
> +}
> +
> +static inline unsigned long vma_pages(struct vm_area_struct *vma)
> +{
> + return (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
> +}
> +
> +static inline void mmap_assert_locked(struct mm_struct *);
> +static inline struct vm_area_struct *find_vma_intersection(struct mm_struct *mm,
> + unsigned long start_addr,
> + unsigned long end_addr)
> +{
> + unsigned long index = start_addr;
> +
> + mmap_assert_locked(mm);
> + return mt_find(&mm->mm_mt, &index, end_addr - 1);
> +}
> +
> +static inline
> +struct vm_area_struct *vma_lookup(struct mm_struct *mm, unsigned long addr)
> +{
> + return mtree_load(&mm->mm_mt, addr);
> +}
> +
> +static inline struct vm_area_struct *vma_prev(struct vma_iterator *vmi)
> +{
> + return mas_prev(&vmi->mas, 0);
> +}
> +
> +static inline void vma_iter_set(struct vma_iterator *vmi, unsigned long addr)
> +{
> + mas_set(&vmi->mas, addr);
> +}
> +
> +static inline bool vma_is_anonymous(struct vm_area_struct *vma)
> +{
> + return !vma->vm_ops;
> +}
> +
> +/* Defined in vma.h, so temporarily define here to avoid circular dependency. */
> +#define vma_iter_load(vmi) \
> + mas_walk(&(vmi)->mas)
> +
> +static inline struct vm_area_struct *
> +find_vma_prev(struct mm_struct *mm, unsigned long addr,
> + struct vm_area_struct **pprev)
> +{
> + struct vm_area_struct *vma;
> + VMA_ITERATOR(vmi, mm, addr);
> +
> + vma = vma_iter_load(&vmi);
> + *pprev = vma_prev(&vmi);
> + if (!vma)
> + vma = vma_next(&vmi);
> + return vma;
> +}
> +
> +#undef vma_iter_load
> +
> +static inline void vma_iter_free(struct vma_iterator *vmi)
> +{
> + mas_destroy(&vmi->mas);
> +}
> +
> +static inline
> +struct vm_area_struct *vma_iter_next_range(struct vma_iterator *vmi)
> +{
> + return mas_next_range(&vmi->mas, ULONG_MAX);
> +}
> +
> +bool vma_wants_writenotify(struct vm_area_struct *vma, pgprot_t vm_page_prot);
> +
> +/* Update vma->vm_page_prot to reflect vma->vm_flags. */
> +static inline void vma_set_page_prot(struct vm_area_struct *vma)
> +{
> + vm_flags_t vm_flags = vma->vm_flags;
> + pgprot_t vm_page_prot;
> +
> + /* testing: we inline vm_pgprot_modify() to avoid clash with vma.h. */
> + vm_page_prot = pgprot_modify(vma->vm_page_prot, vm_get_page_prot(vm_flags));
> +
> + if (vma_wants_writenotify(vma, vm_page_prot)) {
> + vm_flags &= ~VM_SHARED;
> + /* testing: we inline vm_pgprot_modify() to avoid clash with vma.h. */
> + vm_page_prot = pgprot_modify(vm_page_prot, vm_get_page_prot(vm_flags));
> + }
> + /* remove_protection_ptes reads vma->vm_page_prot without mmap_lock */
> + WRITE_ONCE(vma->vm_page_prot, vm_page_prot);
> +}
> +
> +static inline unsigned long stack_guard_start_gap(struct vm_area_struct *vma)
> +{
> + if (vma->vm_flags & VM_GROWSDOWN)
> + return stack_guard_gap;
> +
> + /* See reasoning around the VM_SHADOW_STACK definition */
> + if (vma->vm_flags & VM_SHADOW_STACK)
> + return PAGE_SIZE;
> +
> + return 0;
> +}
> +
> +static inline unsigned long vm_start_gap(struct vm_area_struct *vma)
> +{
> + unsigned long gap = stack_guard_start_gap(vma);
> + unsigned long vm_start = vma->vm_start;
> +
> + vm_start -= gap;
> + if (vm_start > vma->vm_start)
> + vm_start = 0;
> + return vm_start;
> +}
> +
> +static inline unsigned long vm_end_gap(struct vm_area_struct *vma)
> +{
> + unsigned long vm_end = vma->vm_end;
> +
> + if (vma->vm_flags & VM_GROWSUP) {
> + vm_end += stack_guard_gap;
> + if (vm_end < vma->vm_end)
> + vm_end = -PAGE_SIZE;
> + }
> + return vm_end;
> +}
> +
> +static inline bool vma_is_accessible(struct vm_area_struct *vma)
> +{
> + return vma->vm_flags & VM_ACCESS_FLAGS;
> +}
> +
> +static inline bool mlock_future_ok(const struct mm_struct *mm,
> + vm_flags_t vm_flags, unsigned long bytes)
> +{
> + unsigned long locked_pages, limit_pages;
> +
> + if (!(vm_flags & VM_LOCKED) || capable(CAP_IPC_LOCK))
> + return true;
> +
> + locked_pages = bytes >> PAGE_SHIFT;
> + locked_pages += mm->locked_vm;
> +
> + limit_pages = rlimit(RLIMIT_MEMLOCK);
> + limit_pages >>= PAGE_SHIFT;
> +
> + return locked_pages <= limit_pages;
> +}
> +
> +static inline bool map_deny_write_exec(unsigned long old, unsigned long new)
> +{
> + /* If MDWE is disabled, we have nothing to deny. */
> + if (mm_flags_test(MMF_HAS_MDWE, current->mm))
> + return false;
> +
> + /* If the new VMA is not executable, we have nothing to deny. */
> + if (!(new & VM_EXEC))
> + return false;
> +
> + /* Under MDWE we do not accept newly writably executable VMAs... */
> + if (new & VM_WRITE)
> + return true;
> +
> + /* ...nor previously non-executable VMAs becoming executable. */
> + if (!(old & VM_EXEC))
> + return true;
> +
> + return false;
> +}
> +
> +static inline int mapping_map_writable(struct address_space *mapping)
> +{
> + return atomic_inc_unless_negative(&mapping->i_mmap_writable) ?
> + 0 : -EPERM;
> +}
> +
> +/* Did the driver provide valid mmap hook configuration? */
> +static inline bool can_mmap_file(struct file *file)
> +{
> + bool has_mmap = file->f_op->mmap;
> + bool has_mmap_prepare = file->f_op->mmap_prepare;
> +
> + /* Hooks are mutually exclusive. */
> + if (WARN_ON_ONCE(has_mmap && has_mmap_prepare))
> + return false;
> + if (!has_mmap && !has_mmap_prepare)
> + return false;
> +
> + return true;
> +}
> +
> +static inline int vfs_mmap(struct file *file, struct vm_area_struct *vma)
> +{
> + if (file->f_op->mmap_prepare)
> + return compat_vma_mmap(file, vma);
> +
> + return file->f_op->mmap(file, vma);
> +}
> +
> +static inline int vfs_mmap_prepare(struct file *file, struct vm_area_desc *desc)
> +{
> + return file->f_op->mmap_prepare(desc);
> +}
> +
> +static inline void vma_set_file(struct vm_area_struct *vma, struct file *file)
> +{
> + /* Changing an anonymous vma with this is illegal */
> + get_file(file);
> + swap(vma->vm_file, file);
> + fput(file);
> +}
> +
> +struct unmap_desc {
> + struct ma_state *mas; /* the maple state point to the first vma */
> + struct vm_area_struct *first; /* The first vma */
> + unsigned long pg_start; /* The first pagetable address to free (floor) */
> + unsigned long pg_end; /* The last pagetable address to free (ceiling) */
> + unsigned long vma_start; /* The min vma address */
> + unsigned long vma_end; /* The max vma address */
> + unsigned long tree_end; /* Maximum for the vma tree search */
> + unsigned long tree_reset; /* Where to reset the vma tree walk */
> + bool mm_wr_locked; /* If the mmap write lock is held */
> +};
> diff --git a/tools/testing/vma/include/stubs.h b/tools/testing/vma/include/stubs.h
> new file mode 100644
> index 000000000000..947a3a0c2566
> --- /dev/null
> +++ b/tools/testing/vma/include/stubs.h
> @@ -0,0 +1,428 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +
> +#pragma once
> +
> +/*
> + * Contains declarations that are STUBBED, that is that are rendered no-ops, in
> + * order to faciliate userland VMA testing.
> + */
> +
> +/* Forward declarations. */
> +struct mm_struct;
> +struct vm_area_struct;
> +struct vm_area_desc;
> +struct pagetable_move_control;
> +struct mmap_action;
> +struct file;
> +struct anon_vma;
> +struct anon_vma_chain;
> +struct address_space;
> +struct unmap_desc;
> +
> +#define __bitwise
> +#define __randomize_layout
> +
> +#define FIRST_USER_ADDRESS 0UL
> +#define USER_PGTABLES_CEILING 0UL
> +
> +#define vma_policy(vma) NULL
> +
> +#define down_write_nest_lock(sem, nest_lock)
> +
> +#define data_race(expr) expr
> +
> +#define ASSERT_EXCLUSIVE_WRITER(x)
> +
> +struct vm_userfaultfd_ctx {};
> +struct mempolicy {};
> +struct mmu_gather {};
> +struct mutex {};
> +struct vm_fault {};
> +
> +static inline void userfaultfd_unmap_complete(struct mm_struct *mm,
> + struct list_head *uf)
> +{
> +}
> +
> +static inline unsigned long move_page_tables(struct pagetable_move_control *pmc)
> +{
> + return 0;
> +}
> +
> +static inline void free_pgd_range(struct mmu_gather *tlb,
> + unsigned long addr, unsigned long end,
> + unsigned long floor, unsigned long ceiling)
> +{
> +}
> +
> +static inline int ksm_execve(struct mm_struct *mm)
> +{
> + return 0;
> +}
> +
> +static inline void ksm_exit(struct mm_struct *mm)
> +{
> +}
> +
> +static inline void vma_numab_state_init(struct vm_area_struct *vma)
> +{
> +}
> +
> +static inline void vma_numab_state_free(struct vm_area_struct *vma)
> +{
> +}
> +
> +static inline void dup_anon_vma_name(struct vm_area_struct *orig_vma,
> + struct vm_area_struct *new_vma)
> +{
> +}
> +
> +static inline void free_anon_vma_name(struct vm_area_struct *vma)
> +{
> +}
> +
> +static inline void mmap_action_prepare(struct mmap_action *action,
> + struct vm_area_desc *desc)
> +{
> +}
> +
> +static inline int mmap_action_complete(struct mmap_action *action,
> + struct vm_area_struct *vma)
> +{
> + return 0;
> +}
> +
> +static inline void fixup_hugetlb_reservations(struct vm_area_struct *vma)
> +{
> +}
> +
> +static inline bool shmem_file(struct file *file)
> +{
> + return false;
> +}
> +
> +static inline vm_flags_t ksm_vma_flags(const struct mm_struct *mm,
> + const struct file *file, vm_flags_t vm_flags)
> +{
> + return vm_flags;
> +}
> +
> +static inline void remap_pfn_range_prepare(struct vm_area_desc *desc, unsigned long pfn)
> +{
> +}
> +
> +static inline int remap_pfn_range_complete(struct vm_area_struct *vma, unsigned long addr,
> + unsigned long pfn, unsigned long size, pgprot_t pgprot)
> +{
> + return 0;
> +}
> +
> +static inline int do_munmap(struct mm_struct *, unsigned long, size_t,
> + struct list_head *uf)
> +{
> + return 0;
> +}
> +
> +/* Currently stubbed but we may later wish to un-stub. */
> +static inline void vm_acct_memory(long pages);
> +
> +static inline void mmap_assert_locked(struct mm_struct *mm)
> +{
> +}
> +
> +
> +static inline void anon_vma_unlock_write(struct anon_vma *anon_vma)
> +{
> +}
> +
> +static inline void i_mmap_unlock_write(struct address_space *mapping)
> +{
> +}
> +
> +static inline int userfaultfd_unmap_prep(struct vm_area_struct *vma,
> + unsigned long start,
> + unsigned long end,
> + struct list_head *unmaps)
> +{
> + return 0;
> +}
> +
> +static inline void mmap_write_downgrade(struct mm_struct *mm)
> +{
> +}
> +
> +static inline void mmap_read_unlock(struct mm_struct *mm)
> +{
> +}
> +
> +static inline void mmap_write_unlock(struct mm_struct *mm)
> +{
> +}
> +
> +static inline int mmap_write_lock_killable(struct mm_struct *mm)
> +{
> + return 0;
> +}
> +
> +static inline bool can_modify_mm(struct mm_struct *mm,
> + unsigned long start,
> + unsigned long end)
> +{
> + return true;
> +}
> +
> +static inline void arch_unmap(struct mm_struct *mm,
> + unsigned long start,
> + unsigned long end)
> +{
> +}
> +
> +static inline bool mpol_equal(struct mempolicy *a, struct mempolicy *b)
> +{
> + return true;
> +}
> +
> +static inline void khugepaged_enter_vma(struct vm_area_struct *vma,
> + vm_flags_t vm_flags)
> +{
> +}
> +
> +static inline bool mapping_can_writeback(struct address_space *mapping)
> +{
> + return true;
> +}
> +
> +static inline bool is_vm_hugetlb_page(struct vm_area_struct *vma)
> +{
> + return false;
> +}
> +
> +static inline bool vma_soft_dirty_enabled(struct vm_area_struct *vma)
> +{
> + return false;
> +}
> +
> +static inline bool userfaultfd_wp(struct vm_area_struct *vma)
> +{
> + return false;
> +}
> +
> +static inline void mmap_assert_write_locked(struct mm_struct *mm)
> +{
> +}
> +
> +static inline void mutex_lock(struct mutex *lock)
> +{
> +}
> +
> +static inline void mutex_unlock(struct mutex *lock)
> +{
> +}
> +
> +static inline bool mutex_is_locked(struct mutex *lock)
> +{
> + return true;
> +}
> +
> +static inline bool signal_pending(void *p)
> +{
> + return false;
> +}
> +
> +static inline bool is_file_hugepages(struct file *file)
> +{
> + return false;
> +}
> +
> +static inline int security_vm_enough_memory_mm(struct mm_struct *mm, long pages)
> +{
> + return 0;
> +}
> +
> +static inline bool may_expand_vm(struct mm_struct *mm, vm_flags_t flags,
> + unsigned long npages)
> +{
> + return true;
> +}
> +
> +static inline int shmem_zero_setup(struct vm_area_struct *vma)
> +{
> + return 0;
> +}
> +
> +
> +static inline void vm_acct_memory(long pages)
> +{
> +}
> +
> +static inline void vma_interval_tree_insert(struct vm_area_struct *vma,
> + struct rb_root_cached *rb)
> +{
> +}
> +
> +static inline void vma_interval_tree_remove(struct vm_area_struct *vma,
> + struct rb_root_cached *rb)
> +{
> +}
> +
> +static inline void flush_dcache_mmap_unlock(struct address_space *mapping)
> +{
> +}
> +
> +static inline void anon_vma_interval_tree_insert(struct anon_vma_chain *avc,
> + struct rb_root_cached *rb)
> +{
> +}
> +
> +static inline void anon_vma_interval_tree_remove(struct anon_vma_chain *avc,
> + struct rb_root_cached *rb)
> +{
> +}
> +
> +static inline void uprobe_mmap(struct vm_area_struct *vma)
> +{
> +}
> +
> +static inline void uprobe_munmap(struct vm_area_struct *vma,
> + unsigned long start, unsigned long end)
> +{
> +}
> +
> +static inline void i_mmap_lock_write(struct address_space *mapping)
> +{
> +}
> +
> +static inline void anon_vma_lock_write(struct anon_vma *anon_vma)
> +{
> +}
> +
> +static inline void vma_assert_write_locked(struct vm_area_struct *vma)
> +{
> +}
> +
> +static inline void ksm_add_vma(struct vm_area_struct *vma)
> +{
> +}
> +
> +static inline void perf_event_mmap(struct vm_area_struct *vma)
> +{
> +}
> +
> +static inline bool vma_is_dax(struct vm_area_struct *vma)
> +{
> + return false;
> +}
> +
> +static inline struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
> +{
> + return NULL;
> +}
> +
> +static inline bool arch_validate_flags(vm_flags_t flags)
> +{
> + return true;
> +}
> +
> +static inline void vma_close(struct vm_area_struct *vma)
> +{
> +}
> +
> +static inline int mmap_file(struct file *file, struct vm_area_struct *vma)
> +{
> + return 0;
> +}
> +
> +static inline int is_hugepage_only_range(struct mm_struct *mm,
> + unsigned long addr, unsigned long len)
> +{
> + return 0;
> +}
> +
> +static inline bool capable(int cap)
> +{
> + return true;
> +}
> +
> +static inline struct anon_vma_name *anon_vma_name(struct vm_area_struct *vma)
> +{
> + return NULL;
> +}
> +
> +static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma,
> + struct vm_userfaultfd_ctx vm_ctx)
> +{
> + return true;
> +}
> +
> +static inline bool anon_vma_name_eq(struct anon_vma_name *anon_name1,
> + struct anon_vma_name *anon_name2)
> +{
> + return true;
> +}
> +
> +static inline void might_sleep(void)
> +{
> +}
> +
> +static inline void fput(struct file *file)
> +{
> +}
> +
> +static inline void mpol_put(struct mempolicy *pol)
> +{
> +}
> +
> +static inline void lru_add_drain(void)
> +{
> +}
> +
> +static inline void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm)
> +{
> +}
> +
> +static inline void update_hiwater_rss(struct mm_struct *mm)
> +{
> +}
> +
> +static inline void update_hiwater_vm(struct mm_struct *mm)
> +{
> +}
> +
> +static inline void unmap_vmas(struct mmu_gather *tlb, struct unmap_desc *unmap)
> +{
> +}
> +
> +static inline void free_pgtables(struct mmu_gather *tlb, struct unmap_desc *unmap)
> +{
> +}
> +
> +static inline void mapping_unmap_writable(struct address_space *mapping)
> +{
> +}
> +
> +static inline void flush_dcache_mmap_lock(struct address_space *mapping)
> +{
> +}
> +
> +static inline void tlb_finish_mmu(struct mmu_gather *tlb)
> +{
> +}
> +
> +static inline struct file *get_file(struct file *f)
> +{
> + return f;
> +}
> +
> +static inline int vma_dup_policy(struct vm_area_struct *src, struct vm_area_struct *dst)
> +{
> + return 0;
> +}
> +
> +static inline void vma_adjust_trans_huge(struct vm_area_struct *vma,
> + unsigned long start,
> + unsigned long end,
> + struct vm_area_struct *next)
> +{
> +}
> +
> +static inline void hugetlb_split(struct vm_area_struct *, unsigned long) {}
> diff --git a/tools/testing/vma/vma_internal.h b/tools/testing/vma/vma_internal.h
> index b48ebae3927d..e3ed05b57819 100644
> --- a/tools/testing/vma/vma_internal.h
> +++ b/tools/testing/vma/vma_internal.h
> @@ -12,15 +12,11 @@
> #ifndef __MM_VMA_INTERNAL_H
> #define __MM_VMA_INTERNAL_H
>
> -#define __private
> -#define __bitwise
> -#define __randomize_layout
> +#include <stdlib.h>
>
> #define CONFIG_MMU
> #define CONFIG_PER_VMA_LOCK
>
> -#include <stdlib.h>
> -
> #ifdef __CONCAT
> #undef __CONCAT
> #endif
> @@ -35,1936 +31,28 @@
> #include <linux/refcount.h>
> #include <linux/slab.h>
>
> -extern unsigned long stack_guard_gap;
> -#ifdef CONFIG_MMU
> -extern unsigned long mmap_min_addr;
> -extern unsigned long dac_mmap_min_addr;
> -#else
> -#define mmap_min_addr 0UL
> -#define dac_mmap_min_addr 0UL
> -#endif
> -
> -#define ACCESS_PRIVATE(p, member) ((p)->member)
> -
> -#define VM_WARN_ON(_expr) (WARN_ON(_expr))
> -#define VM_WARN_ON_ONCE(_expr) (WARN_ON_ONCE(_expr))
> -#define VM_WARN_ON_VMG(_expr, _vmg) (WARN_ON(_expr))
> -#define VM_BUG_ON(_expr) (BUG_ON(_expr))
> -#define VM_BUG_ON_VMA(_expr, _vma) (BUG_ON(_expr))
> -
> -#define MMF_HAS_MDWE 28
> -
> -/*
> - * vm_flags in vm_area_struct, see mm_types.h.
> - * When changing, update also include/trace/events/mmflags.h
> - */
> -
> -#define VM_NONE 0x00000000
> -
> -/**
> - * typedef vma_flag_t - specifies an individual VMA flag by bit number.
> - *
> - * This value is made type safe by sparse to avoid passing invalid flag values
> - * around.
> - */
> -typedef int __bitwise vma_flag_t;
> -
> -#define DECLARE_VMA_BIT(name, bitnum) \
> - VMA_ ## name ## _BIT = ((__force vma_flag_t)bitnum)
> -#define DECLARE_VMA_BIT_ALIAS(name, aliased) \
> - VMA_ ## name ## _BIT = VMA_ ## aliased ## _BIT
> -enum {
> - DECLARE_VMA_BIT(READ, 0),
> - DECLARE_VMA_BIT(WRITE, 1),
> - DECLARE_VMA_BIT(EXEC, 2),
> - DECLARE_VMA_BIT(SHARED, 3),
> - /* mprotect() hardcodes VM_MAYREAD >> 4 == VM_READ, and so for r/w/x bits. */
> - DECLARE_VMA_BIT(MAYREAD, 4), /* limits for mprotect() etc. */
> - DECLARE_VMA_BIT(MAYWRITE, 5),
> - DECLARE_VMA_BIT(MAYEXEC, 6),
> - DECLARE_VMA_BIT(MAYSHARE, 7),
> - DECLARE_VMA_BIT(GROWSDOWN, 8), /* general info on the segment */
> -#ifdef CONFIG_MMU
> - DECLARE_VMA_BIT(UFFD_MISSING, 9),/* missing pages tracking */
> -#else
> - /* nommu: R/O MAP_PRIVATE mapping that might overlay a file mapping */
> - DECLARE_VMA_BIT(MAYOVERLAY, 9),
> -#endif /* CONFIG_MMU */
> - /* Page-ranges managed without "struct page", just pure PFN */
> - DECLARE_VMA_BIT(PFNMAP, 10),
> - DECLARE_VMA_BIT(MAYBE_GUARD, 11),
> - DECLARE_VMA_BIT(UFFD_WP, 12), /* wrprotect pages tracking */
> - DECLARE_VMA_BIT(LOCKED, 13),
> - DECLARE_VMA_BIT(IO, 14), /* Memory mapped I/O or similar */
> - DECLARE_VMA_BIT(SEQ_READ, 15), /* App will access data sequentially */
> - DECLARE_VMA_BIT(RAND_READ, 16), /* App will not benefit from clustered reads */
> - DECLARE_VMA_BIT(DONTCOPY, 17), /* Do not copy this vma on fork */
> - DECLARE_VMA_BIT(DONTEXPAND, 18),/* Cannot expand with mremap() */
> - DECLARE_VMA_BIT(LOCKONFAULT, 19),/* Lock pages covered when faulted in */
> - DECLARE_VMA_BIT(ACCOUNT, 20), /* Is a VM accounted object */
> - DECLARE_VMA_BIT(NORESERVE, 21), /* should the VM suppress accounting */
> - DECLARE_VMA_BIT(HUGETLB, 22), /* Huge TLB Page VM */
> - DECLARE_VMA_BIT(SYNC, 23), /* Synchronous page faults */
> - DECLARE_VMA_BIT(ARCH_1, 24), /* Architecture-specific flag */
> - DECLARE_VMA_BIT(WIPEONFORK, 25),/* Wipe VMA contents in child. */
> - DECLARE_VMA_BIT(DONTDUMP, 26), /* Do not include in the core dump */
> - DECLARE_VMA_BIT(SOFTDIRTY, 27), /* NOT soft dirty clean area */
> - DECLARE_VMA_BIT(MIXEDMAP, 28), /* Can contain struct page and pure PFN pages */
> - DECLARE_VMA_BIT(HUGEPAGE, 29), /* MADV_HUGEPAGE marked this vma */
> - DECLARE_VMA_BIT(NOHUGEPAGE, 30),/* MADV_NOHUGEPAGE marked this vma */
> - DECLARE_VMA_BIT(MERGEABLE, 31), /* KSM may merge identical pages */
> - /* These bits are reused, we define specific uses below. */
> - DECLARE_VMA_BIT(HIGH_ARCH_0, 32),
> - DECLARE_VMA_BIT(HIGH_ARCH_1, 33),
> - DECLARE_VMA_BIT(HIGH_ARCH_2, 34),
> - DECLARE_VMA_BIT(HIGH_ARCH_3, 35),
> - DECLARE_VMA_BIT(HIGH_ARCH_4, 36),
> - DECLARE_VMA_BIT(HIGH_ARCH_5, 37),
> - DECLARE_VMA_BIT(HIGH_ARCH_6, 38),
> - /*
> - * This flag is used to connect VFIO to arch specific KVM code. It
> - * indicates that the memory under this VMA is safe for use with any
> - * non-cachable memory type inside KVM. Some VFIO devices, on some
> - * platforms, are thought to be unsafe and can cause machine crashes
> - * if KVM does not lock down the memory type.
> - */
> - DECLARE_VMA_BIT(ALLOW_ANY_UNCACHED, 39),
> -#ifdef CONFIG_PPC32
> - DECLARE_VMA_BIT_ALIAS(DROPPABLE, ARCH_1),
> -#else
> - DECLARE_VMA_BIT(DROPPABLE, 40),
> -#endif
> - DECLARE_VMA_BIT(UFFD_MINOR, 41),
> - DECLARE_VMA_BIT(SEALED, 42),
> - /* Flags that reuse flags above. */
> - DECLARE_VMA_BIT_ALIAS(PKEY_BIT0, HIGH_ARCH_0),
> - DECLARE_VMA_BIT_ALIAS(PKEY_BIT1, HIGH_ARCH_1),
> - DECLARE_VMA_BIT_ALIAS(PKEY_BIT2, HIGH_ARCH_2),
> - DECLARE_VMA_BIT_ALIAS(PKEY_BIT3, HIGH_ARCH_3),
> - DECLARE_VMA_BIT_ALIAS(PKEY_BIT4, HIGH_ARCH_4),
> -#if defined(CONFIG_X86_USER_SHADOW_STACK)
> - /*
> - * VM_SHADOW_STACK should not be set with VM_SHARED because of lack of
> - * support core mm.
> - *
> - * These VMAs will get a single end guard page. This helps userspace
> - * protect itself from attacks. A single page is enough for current
> - * shadow stack archs (x86). See the comments near alloc_shstk() in
> - * arch/x86/kernel/shstk.c for more details on the guard size.
> - */
> - DECLARE_VMA_BIT_ALIAS(SHADOW_STACK, HIGH_ARCH_5),
> -#elif defined(CONFIG_ARM64_GCS)
> - /*
> - * arm64's Guarded Control Stack implements similar functionality and
> - * has similar constraints to shadow stacks.
> - */
> - DECLARE_VMA_BIT_ALIAS(SHADOW_STACK, HIGH_ARCH_6),
> -#endif
> - DECLARE_VMA_BIT_ALIAS(SAO, ARCH_1), /* Strong Access Ordering (powerpc) */
> - DECLARE_VMA_BIT_ALIAS(GROWSUP, ARCH_1), /* parisc */
> - DECLARE_VMA_BIT_ALIAS(SPARC_ADI, ARCH_1), /* sparc64 */
> - DECLARE_VMA_BIT_ALIAS(ARM64_BTI, ARCH_1), /* arm64 */
> - DECLARE_VMA_BIT_ALIAS(ARCH_CLEAR, ARCH_1), /* sparc64, arm64 */
> - DECLARE_VMA_BIT_ALIAS(MAPPED_COPY, ARCH_1), /* !CONFIG_MMU */
> - DECLARE_VMA_BIT_ALIAS(MTE, HIGH_ARCH_4), /* arm64 */
> - DECLARE_VMA_BIT_ALIAS(MTE_ALLOWED, HIGH_ARCH_5),/* arm64 */
> -#ifdef CONFIG_STACK_GROWSUP
> - DECLARE_VMA_BIT_ALIAS(STACK, GROWSUP),
> - DECLARE_VMA_BIT_ALIAS(STACK_EARLY, GROWSDOWN),
> -#else
> - DECLARE_VMA_BIT_ALIAS(STACK, GROWSDOWN),
> -#endif
> -};
> -
> -#define INIT_VM_FLAG(name) BIT((__force int) VMA_ ## name ## _BIT)
> -#define VM_READ INIT_VM_FLAG(READ)
> -#define VM_WRITE INIT_VM_FLAG(WRITE)
> -#define VM_EXEC INIT_VM_FLAG(EXEC)
> -#define VM_SHARED INIT_VM_FLAG(SHARED)
> -#define VM_MAYREAD INIT_VM_FLAG(MAYREAD)
> -#define VM_MAYWRITE INIT_VM_FLAG(MAYWRITE)
> -#define VM_MAYEXEC INIT_VM_FLAG(MAYEXEC)
> -#define VM_MAYSHARE INIT_VM_FLAG(MAYSHARE)
> -#define VM_GROWSDOWN INIT_VM_FLAG(GROWSDOWN)
> -#ifdef CONFIG_MMU
> -#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)
> -#define VM_UFFD_WP INIT_VM_FLAG(UFFD_WP)
> -#define VM_LOCKED INIT_VM_FLAG(LOCKED)
> -#define VM_IO INIT_VM_FLAG(IO)
> -#define VM_SEQ_READ INIT_VM_FLAG(SEQ_READ)
> -#define VM_RAND_READ INIT_VM_FLAG(RAND_READ)
> -#define VM_DONTCOPY INIT_VM_FLAG(DONTCOPY)
> -#define VM_DONTEXPAND INIT_VM_FLAG(DONTEXPAND)
> -#define VM_LOCKONFAULT INIT_VM_FLAG(LOCKONFAULT)
> -#define VM_ACCOUNT INIT_VM_FLAG(ACCOUNT)
> -#define VM_NORESERVE INIT_VM_FLAG(NORESERVE)
> -#define VM_HUGETLB INIT_VM_FLAG(HUGETLB)
> -#define VM_SYNC INIT_VM_FLAG(SYNC)
> -#define VM_ARCH_1 INIT_VM_FLAG(ARCH_1)
> -#define VM_WIPEONFORK INIT_VM_FLAG(WIPEONFORK)
> -#define VM_DONTDUMP INIT_VM_FLAG(DONTDUMP)
> -#ifdef CONFIG_MEM_SOFT_DIRTY
> -#define VM_SOFTDIRTY INIT_VM_FLAG(SOFTDIRTY)
> -#else
> -#define VM_SOFTDIRTY VM_NONE
> -#endif
> -#define VM_MIXEDMAP INIT_VM_FLAG(MIXEDMAP)
> -#define VM_HUGEPAGE INIT_VM_FLAG(HUGEPAGE)
> -#define VM_NOHUGEPAGE INIT_VM_FLAG(NOHUGEPAGE)
> -#define VM_MERGEABLE INIT_VM_FLAG(MERGEABLE)
> -#define VM_STACK INIT_VM_FLAG(STACK)
> -#ifdef CONFIG_STACK_GROWS_UP
> -#define VM_STACK_EARLY INIT_VM_FLAG(STACK_EARLY)
> -#else
> -#define VM_STACK_EARLY VM_NONE
> -#endif
> -#ifdef CONFIG_ARCH_HAS_PKEYS
> -#define VM_PKEY_SHIFT ((__force int)VMA_HIGH_ARCH_0_BIT)
> -/* Despite the naming, these are FLAGS not bits. */
> -#define VM_PKEY_BIT0 INIT_VM_FLAG(PKEY_BIT0)
> -#define VM_PKEY_BIT1 INIT_VM_FLAG(PKEY_BIT1)
> -#define VM_PKEY_BIT2 INIT_VM_FLAG(PKEY_BIT2)
> -#if CONFIG_ARCH_PKEY_BITS > 3
> -#define VM_PKEY_BIT3 INIT_VM_FLAG(PKEY_BIT3)
> -#else
> -#define VM_PKEY_BIT3 VM_NONE
> -#endif /* CONFIG_ARCH_PKEY_BITS > 3 */
> -#if CONFIG_ARCH_PKEY_BITS > 4
> -#define VM_PKEY_BIT4 INIT_VM_FLAG(PKEY_BIT4)
> -#else
> -#define VM_PKEY_BIT4 VM_NONE
> -#endif /* CONFIG_ARCH_PKEY_BITS > 4 */
> -#endif /* CONFIG_ARCH_HAS_PKEYS */
> -#if defined(CONFIG_X86_USER_SHADOW_STACK) || defined(CONFIG_ARM64_GCS)
> -#define VM_SHADOW_STACK INIT_VM_FLAG(SHADOW_STACK)
> -#else
> -#define VM_SHADOW_STACK VM_NONE
> -#endif
> -#if defined(CONFIG_PPC64)
> -#define VM_SAO INIT_VM_FLAG(SAO)
> -#elif defined(CONFIG_PARISC)
> -#define VM_GROWSUP INIT_VM_FLAG(GROWSUP)
> -#elif defined(CONFIG_SPARC64)
> -#define VM_SPARC_ADI INIT_VM_FLAG(SPARC_ADI)
> -#define VM_ARCH_CLEAR INIT_VM_FLAG(ARCH_CLEAR)
> -#elif defined(CONFIG_ARM64)
> -#define VM_ARM64_BTI INIT_VM_FLAG(ARM64_BTI)
> -#define VM_ARCH_CLEAR INIT_VM_FLAG(ARCH_CLEAR)
> -#elif !defined(CONFIG_MMU)
> -#define VM_MAPPED_COPY INIT_VM_FLAG(MAPPED_COPY)
> -#endif
> -#ifndef VM_GROWSUP
> -#define VM_GROWSUP VM_NONE
> -#endif
> -#ifdef CONFIG_ARM64_MTE
> -#define VM_MTE INIT_VM_FLAG(MTE)
> -#define VM_MTE_ALLOWED INIT_VM_FLAG(MTE_ALLOWED)
> -#else
> -#define VM_MTE VM_NONE
> -#define VM_MTE_ALLOWED VM_NONE
> -#endif
> -#ifdef CONFIG_HAVE_ARCH_USERFAULTFD_MINOR
> -#define VM_UFFD_MINOR INIT_VM_FLAG(UFFD_MINOR)
> -#else
> -#define VM_UFFD_MINOR VM_NONE
> -#endif
> -#ifdef CONFIG_64BIT
> -#define VM_ALLOW_ANY_UNCACHED INIT_VM_FLAG(ALLOW_ANY_UNCACHED)
> -#define VM_SEALED INIT_VM_FLAG(SEALED)
> -#else
> -#define VM_ALLOW_ANY_UNCACHED VM_NONE
> -#define VM_SEALED VM_NONE
> -#endif
> -#if defined(CONFIG_64BIT) || defined(CONFIG_PPC32)
> -#define VM_DROPPABLE INIT_VM_FLAG(DROPPABLE)
> -#else
> -#define VM_DROPPABLE VM_NONE
> -#endif
> -
> -/* Bits set in the VMA until the stack is in its final location */
> -#define VM_STACK_INCOMPLETE_SETUP (VM_RAND_READ | VM_SEQ_READ | VM_STACK_EARLY)
> -
> -#define TASK_EXEC ((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0)
> -
> -/* Common data flag combinations */
> -#define VM_DATA_FLAGS_TSK_EXEC (VM_READ | VM_WRITE | TASK_EXEC | \
> - VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
> -#define VM_DATA_FLAGS_NON_EXEC (VM_READ | VM_WRITE | VM_MAYREAD | \
> - VM_MAYWRITE | VM_MAYEXEC)
> -#define VM_DATA_FLAGS_EXEC (VM_READ | VM_WRITE | VM_EXEC | \
> - VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
> -
> -#ifndef VM_DATA_DEFAULT_FLAGS /* arch can override this */
> -#define VM_DATA_DEFAULT_FLAGS VM_DATA_FLAGS_EXEC
> -#endif
> -
> -#ifndef VM_STACK_DEFAULT_FLAGS /* arch can override this */
> -#define VM_STACK_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS
> -#endif
> -
> -#define VM_STARTGAP_FLAGS (VM_GROWSDOWN | VM_SHADOW_STACK)
> -
> -#define VM_STACK_FLAGS (VM_STACK | VM_STACK_DEFAULT_FLAGS | VM_ACCOUNT)
> -
> -/* VMA basic access permission flags */
> -#define VM_ACCESS_FLAGS (VM_READ | VM_WRITE | VM_EXEC)
> -
> -/*
> - * Special vmas that are non-mergable, non-mlock()able.
> - */
> -#define VM_SPECIAL (VM_IO | VM_DONTEXPAND | VM_PFNMAP | VM_MIXEDMAP)
> -
> -#define DEFAULT_MAP_WINDOW ((1UL << 47) - PAGE_SIZE)
> -#define TASK_SIZE_LOW DEFAULT_MAP_WINDOW
> -#define TASK_SIZE_MAX DEFAULT_MAP_WINDOW
> -#define STACK_TOP TASK_SIZE_LOW
> -#define STACK_TOP_MAX TASK_SIZE_MAX
> -
> -/* This mask represents all the VMA flag bits used by mlock */
> -#define VM_LOCKED_MASK (VM_LOCKED | VM_LOCKONFAULT)
> -
> -#define TASK_EXEC ((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0)
> -
> -#define VM_DATA_FLAGS_TSK_EXEC (VM_READ | VM_WRITE | TASK_EXEC | \
> - VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
> -
> -#define RLIMIT_STACK 3 /* max stack size */
> -#define RLIMIT_MEMLOCK 8 /* max locked-in-memory address space */
> -
> -#define CAP_IPC_LOCK 14
> -
> -/*
> - * Flags which should be 'sticky' on merge - that is, flags which, when one VMA
> - * possesses it but the other does not, the merged VMA should nonetheless have
> - * applied to it:
> - *
> - * VM_SOFTDIRTY - if a VMA is marked soft-dirty, that is has not had its
> - * references cleared via /proc/$pid/clear_refs, any merged VMA
> - * should be considered soft-dirty also as it operates at a VMA
> - * granularity.
> - */
> -#define VM_STICKY (VM_SOFTDIRTY | VM_MAYBE_GUARD)
> -
> /*
> - * VMA flags we ignore for the purposes of merge, i.e. one VMA possessing one
> - * of these flags and the other not does not preclude a merge.
> - *
> - * VM_STICKY - When merging VMAs, VMA flags must match, unless they are
> - * 'sticky'. If any sticky flags exist in either VMA, we simply
> - * set all of them on the merged VMA.
> + * DUPLICATE typedef definitions from kernel source that have to be declared
> + * ahead of all other headers.
> */
> -#define VM_IGNORE_MERGE VM_STICKY
> -
> -/*
> - * Flags which should result in page tables being copied on fork. These are
> - * flags which indicate that the VMA maps page tables which cannot be
> - * reconsistuted upon page fault, so necessitate page table copying upon
> - *
> - * VM_PFNMAP / VM_MIXEDMAP - These contain kernel-mapped data which cannot be
> - * reasonably reconstructed on page fault.
> - *
> - * VM_UFFD_WP - Encodes metadata about an installed uffd
> - * write protect handler, which cannot be
> - * reconstructed on page fault.
> - *
> - * We always copy pgtables when dst_vma has uffd-wp
> - * enabled even if it's file-backed
> - * (e.g. shmem). Because when uffd-wp is enabled,
> - * pgtable contains uffd-wp protection information,
> - * that's something we can't retrieve from page cache,
> - * and skip copying will lose those info.
> - *
> - * VM_MAYBE_GUARD - Could contain page guard region markers which
> - * by design are a property of the page tables
> - * only and thus cannot be reconstructed on page
> - * fault.
> - */
> -#define VM_COPY_ON_FORK (VM_PFNMAP | VM_MIXEDMAP | VM_UFFD_WP | VM_MAYBE_GUARD)
> -
> -#define FIRST_USER_ADDRESS 0UL
> -#define USER_PGTABLES_CEILING 0UL
> -
> -#define vma_policy(vma) NULL
> -
> -#define down_write_nest_lock(sem, nest_lock)
> -
> -#define pgprot_val(x) ((x).pgprot)
> -#define __pgprot(x) ((pgprot_t) { (x) } )
> -
> -#define for_each_vma(__vmi, __vma) \
> - while (((__vma) = vma_next(&(__vmi))) != NULL)
> -
> -/* The MM code likes to work with exclusive end addresses */
> -#define for_each_vma_range(__vmi, __vma, __end) \
> - while (((__vma) = vma_find(&(__vmi), (__end))) != NULL)
> -
> -#define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK)
> -
> -#define PHYS_PFN(x) ((unsigned long)((x) >> PAGE_SHIFT))
> -
> -#define test_and_set_bit(nr, addr) __test_and_set_bit(nr, addr)
> -#define test_and_clear_bit(nr, addr) __test_and_clear_bit(nr, addr)
> -
> -#define TASK_SIZE ((1ul << 47)-PAGE_SIZE)
> -
> -#define AS_MM_ALL_LOCKS 2
> -
> -/* We hardcode this for now. */
> -#define sysctl_max_map_count 0x1000000UL
> -
> -#define pgoff_t unsigned long
> -typedef unsigned long pgprotval_t;
> -typedef struct pgprot { pgprotval_t pgprot; } pgprot_t;
> -typedef unsigned long vm_flags_t;
> -typedef __bitwise unsigned int vm_fault_t;
> -
> -/*
> - * The shared stubs do not implement this, it amounts to an fprintf(STDERR,...)
> - * either way :)
> - */
> -#define pr_warn_once pr_err
> -
> -#define data_race(expr) expr
> -
> -#define ASSERT_EXCLUSIVE_WRITER(x)
> -
> -#define pgtable_supports_soft_dirty() 1
> -
> -/**
> - * swap - swap values of @a and @b
> - * @a: first value
> - * @b: second value
> - */
> -#define swap(a, b) \
> - do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0)
> -
> -struct kref {
> - refcount_t refcount;
> -};
> -
> -/*
> - * Define the task command name length as enum, then it can be visible to
> - * BPF programs.
> - */
> -enum {
> - TASK_COMM_LEN = 16,
> -};
> -
> -/*
> - * Flags for bug emulation.
> - *
> - * These occupy the top three bytes.
> - */
> -enum {
> - READ_IMPLIES_EXEC = 0x0400000,
> -};
> -
> -struct task_struct {
> - char comm[TASK_COMM_LEN];
> - pid_t pid;
> - struct mm_struct *mm;
> -
> - /* Used for emulating ABI behavior of previous Linux versions: */
> - unsigned int personality;
> -};
> -
> -struct task_struct *get_current(void);
> -#define current get_current()
> -
> -struct anon_vma {
> - struct anon_vma *root;
> - struct rb_root_cached rb_root;
> -
> - /* Test fields. */
> - bool was_cloned;
> - bool was_unlinked;
> -};
> -
> -struct anon_vma_chain {
> - struct anon_vma *anon_vma;
> - struct list_head same_vma;
> -};
> -
> -struct anon_vma_name {
> - struct kref kref;
> - /* The name needs to be at the end because it is dynamically sized. */
> - char name[];
> -};
> -
> -struct vma_iterator {
> - struct ma_state mas;
> -};
> -
> -#define VMA_ITERATOR(name, __mm, __addr) \
> - struct vma_iterator name = { \
> - .mas = { \
> - .tree = &(__mm)->mm_mt, \
> - .index = __addr, \
> - .node = NULL, \
> - .status = ma_start, \
> - }, \
> - }
> -
> -struct address_space {
> - struct rb_root_cached i_mmap;
> - unsigned long flags;
> - atomic_t i_mmap_writable;
> -};
> -
> -struct vm_userfaultfd_ctx {};
> -struct mempolicy {};
> -struct mmu_gather {};
> -struct mutex {};
> -#define DEFINE_MUTEX(mutexname) \
> - struct mutex mutexname = {}
> -
> -#define DECLARE_BITMAP(name, bits) \
> - unsigned long name[BITS_TO_LONGS(bits)]
> -
> +#define __private
> #define NUM_MM_FLAG_BITS (64)
> 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;
>
> -#define EMPTY_VMA_FLAGS ((vma_flags_t){ })
> -
> -struct mm_struct {
> - struct maple_tree mm_mt;
> - int map_count; /* number of VMAs */
> - unsigned long total_vm; /* Total pages mapped */
> - unsigned long locked_vm; /* Pages that have PG_mlocked set */
> - unsigned long data_vm; /* VM_WRITE & ~VM_SHARED & ~VM_STACK */
> - unsigned long exec_vm; /* VM_EXEC & ~VM_WRITE & ~VM_STACK */
> - unsigned long stack_vm; /* VM_STACK */
> -
> - unsigned long def_flags;
> -
> - mm_flags_t flags; /* Must use mm_flags_* helpers to access */
> -};
> -
> -struct vm_area_struct;
> -
> -
> -/* What action should be taken after an .mmap_prepare call is complete? */
> -enum mmap_action_type {
> - MMAP_NOTHING, /* Mapping is complete, no further action. */
> - MMAP_REMAP_PFN, /* Remap PFN range. */
> - MMAP_IO_REMAP_PFN, /* I/O remap PFN range. */
> -};
> -
> -/*
> - * Describes an action an mmap_prepare hook can instruct to be taken to complete
> - * the mapping of a VMA. Specified in vm_area_desc.
> - */
> -struct mmap_action {
> - union {
> - /* Remap range. */
> - struct {
> - unsigned long start;
> - unsigned long start_pfn;
> - unsigned long size;
> - pgprot_t pgprot;
> - } remap;
> - };
> - enum mmap_action_type type;
> -
> - /*
> - * If specified, this hook is invoked after the selected action has been
> - * successfully completed. Note that the VMA write lock still held.
> - *
> - * The absolute minimum ought to be done here.
> - *
> - * Returns 0 on success, or an error code.
> - */
> - int (*success_hook)(const struct vm_area_struct *vma);
> -
> - /*
> - * If specified, this hook is invoked when an error occurred when
> - * attempting the selection action.
> - *
> - * The hook can return an error code in order to filter the error, but
> - * it is not valid to clear the error here.
> - */
> - int (*error_hook)(int err);
> -
> - /*
> - * This should be set in rare instances where the operation required
> - * that the rmap should not be able to access the VMA until
> - * completely set up.
> - */
> - bool hide_from_rmap_until_complete :1;
> -};
> -
> -/* Operations which modify VMAs. */
> -enum vma_operation {
> - VMA_OP_SPLIT,
> - VMA_OP_MERGE_UNFAULTED,
> - VMA_OP_REMAP,
> - VMA_OP_FORK,
> -};
> -
> -/*
> - * 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
> - * resultant VMA.
> - *
> - * Helper functions are not required for manipulating any field.
> - */
> -struct vm_area_desc {
> - /* Immutable state. */
> - const struct mm_struct *const mm;
> - struct file *const file; /* May vary from vm_file in stacked callers. */
> - unsigned long start;
> - unsigned long end;
> -
> - /* Mutable fields. Populated with initial state. */
> - pgoff_t pgoff;
> - struct file *vm_file;
> - union {
> - vm_flags_t vm_flags;
> - vma_flags_t vma_flags;
> - };
> - pgprot_t page_prot;
> -
> - /* Write-only fields. */
> - const struct vm_operations_struct *vm_ops;
> - void *private_data;
> -
> - /* Take further action? */
> - struct mmap_action action;
> -};
> -
> -struct file_operations {
> - int (*mmap)(struct file *, struct vm_area_struct *);
> - int (*mmap_prepare)(struct vm_area_desc *);
> -};
> -
> -struct file {
> - struct address_space *f_mapping;
> - const struct file_operations *f_op;
> -};
> -
> -#define VMA_LOCK_OFFSET 0x40000000
> -
> -typedef struct { unsigned long v; } freeptr_t;
> -
> -struct vm_area_struct {
> - /* The first cache line has the info for VMA tree walking. */
> -
> - union {
> - struct {
> - /* VMA covers [vm_start; vm_end) addresses within mm */
> - unsigned long vm_start;
> - unsigned long vm_end;
> - };
> - freeptr_t vm_freeptr; /* Pointer used by SLAB_TYPESAFE_BY_RCU */
> - };
> -
> - struct mm_struct *vm_mm; /* The address space we belong to. */
> - pgprot_t vm_page_prot; /* Access permissions of this VMA. */
> -
> - /*
> - * Flags, see mm.h.
> - * To modify use vm_flags_{init|reset|set|clear|mod} functions.
> - */
> - union {
> - const vm_flags_t vm_flags;
> - vma_flags_t flags;
> - };
> -
> -#ifdef CONFIG_PER_VMA_LOCK
> - /*
> - * Can only be written (using WRITE_ONCE()) while holding both:
> - * - mmap_lock (in write mode)
> - * - vm_refcnt bit at VMA_LOCK_OFFSET is set
> - * Can be read reliably while holding one of:
> - * - mmap_lock (in read or write mode)
> - * - vm_refcnt bit at VMA_LOCK_OFFSET is set or vm_refcnt > 1
> - * Can be read unreliably (using READ_ONCE()) for pessimistic bailout
> - * while holding nothing (except RCU to keep the VMA struct allocated).
> - *
> - * This sequence counter is explicitly allowed to overflow; sequence
> - * counter reuse can only lead to occasional unnecessary use of the
> - * slowpath.
> - */
> - unsigned int vm_lock_seq;
> -#endif
> -
> - /*
> - * A file's MAP_PRIVATE vma can be in both i_mmap tree and anon_vma
> - * list, after a COW of one of the file pages. A MAP_SHARED vma
> - * can only be in the i_mmap tree. An anonymous MAP_PRIVATE, stack
> - * or brk vma (with NULL file) can only be in an anon_vma list.
> - */
> - struct list_head anon_vma_chain; /* Serialized by mmap_lock &
> - * page_table_lock */
> - struct anon_vma *anon_vma; /* Serialized by page_table_lock */
> -
> - /* Function pointers to deal with this struct. */
> - const struct vm_operations_struct *vm_ops;
> -
> - /* Information about our backing store: */
> - unsigned long vm_pgoff; /* Offset (within vm_file) in PAGE_SIZE
> - units */
> - struct file * vm_file; /* File we map to (can be NULL). */
> - void * vm_private_data; /* was vm_pte (shared mem) */
> -
> -#ifdef CONFIG_SWAP
> - atomic_long_t swap_readahead_info;
> -#endif
> -#ifndef CONFIG_MMU
> - struct vm_region *vm_region; /* NOMMU mapping region */
> -#endif
> -#ifdef CONFIG_NUMA
> - struct mempolicy *vm_policy; /* NUMA policy for the VMA */
> -#endif
> -#ifdef CONFIG_NUMA_BALANCING
> - struct vma_numab_state *numab_state; /* NUMA Balancing state */
> -#endif
> -#ifdef CONFIG_PER_VMA_LOCK
> - /* Unstable RCU readers are allowed to read this. */
> - refcount_t vm_refcnt;
> -#endif
> - /*
> - * For areas with an address space and backing store,
> - * linkage into the address_space->i_mmap interval tree.
> - *
> - */
> - struct {
> - struct rb_node rb;
> - unsigned long rb_subtree_last;
> - } shared;
> -#ifdef CONFIG_ANON_VMA_NAME
> - /*
> - * For private and shared anonymous mappings, a pointer to a null
> - * terminated string containing the name given to the vma, or NULL if
> - * unnamed. Serialized by mmap_lock. Use anon_vma_name to access.
> - */
> - struct anon_vma_name *anon_name;
> -#endif
> - struct vm_userfaultfd_ctx vm_userfaultfd_ctx;
> -} __randomize_layout;
> -
> -struct vm_fault {};
> -
> -struct vm_operations_struct {
> - void (*open)(struct vm_area_struct * area);
> - /**
> - * @close: Called when the VMA is being removed from the MM.
> - * Context: User context. May sleep. Caller holds mmap_lock.
> - */
> - void (*close)(struct vm_area_struct * area);
> - /* Called any time before splitting to check if it's allowed */
> - int (*may_split)(struct vm_area_struct *area, unsigned long addr);
> - int (*mremap)(struct vm_area_struct *area);
> - /*
> - * Called by mprotect() to make driver-specific permission
> - * checks before mprotect() is finalised. The VMA must not
> - * be modified. Returns 0 if mprotect() can proceed.
> - */
> - int (*mprotect)(struct vm_area_struct *vma, unsigned long start,
> - unsigned long end, unsigned long newflags);
> - vm_fault_t (*fault)(struct vm_fault *vmf);
> - vm_fault_t (*huge_fault)(struct vm_fault *vmf, unsigned int order);
> - vm_fault_t (*map_pages)(struct vm_fault *vmf,
> - pgoff_t start_pgoff, pgoff_t end_pgoff);
> - unsigned long (*pagesize)(struct vm_area_struct * area);
> -
> - /* notification that a previously read-only page is about to become
> - * writable, if an error is returned it will cause a SIGBUS */
> - vm_fault_t (*page_mkwrite)(struct vm_fault *vmf);
> -
> - /* same as page_mkwrite when using VM_PFNMAP|VM_MIXEDMAP */
> - vm_fault_t (*pfn_mkwrite)(struct vm_fault *vmf);
> -
> - /* called by access_process_vm when get_user_pages() fails, typically
> - * for use by special VMAs. See also generic_access_phys() for a generic
> - * implementation useful for any iomem mapping.
> - */
> - int (*access)(struct vm_area_struct *vma, unsigned long addr,
> - void *buf, int len, int write);
> -
> - /* Called by the /proc/PID/maps code to ask the vma whether it
> - * has a special name. Returning non-NULL will also cause this
> - * vma to be dumped unconditionally. */
> - const char *(*name)(struct vm_area_struct *vma);
> -
> -#ifdef CONFIG_NUMA
> - /*
> - * set_policy() op must add a reference to any non-NULL @new mempolicy
> - * to hold the policy upon return. Caller should pass NULL @new to
> - * remove a policy and fall back to surrounding context--i.e. do not
> - * install a MPOL_DEFAULT policy, nor the task or system default
> - * mempolicy.
> - */
> - int (*set_policy)(struct vm_area_struct *vma, struct mempolicy *new);
> -
> - /*
> - * get_policy() op must add reference [mpol_get()] to any policy at
> - * (vma,addr) marked as MPOL_SHARED. The shared policy infrastructure
> - * in mm/mempolicy.c will do this automatically.
> - * get_policy() must NOT add a ref if the policy at (vma,addr) is not
> - * marked as MPOL_SHARED. vma policies are protected by the mmap_lock.
> - * If no [shared/vma] mempolicy exists at the addr, get_policy() op
> - * must return NULL--i.e., do not "fallback" to task or system default
> - * policy.
> - */
> - struct mempolicy *(*get_policy)(struct vm_area_struct *vma,
> - unsigned long addr, pgoff_t *ilx);
> -#endif
> -#ifdef CONFIG_FIND_NORMAL_PAGE
> - /*
> - * Called by vm_normal_page() for special PTEs in @vma at @addr. This
> - * allows for returning a "normal" page from vm_normal_page() even
> - * though the PTE indicates that the "struct page" either does not exist
> - * or should not be touched: "special".
> - *
> - * Do not add new users: this really only works when a "normal" page
> - * was mapped, but then the PTE got changed to something weird (+
> - * marked special) that would not make pte_pfn() identify the originally
> - * inserted page.
> - */
> - struct page *(*find_normal_page)(struct vm_area_struct *vma,
> - unsigned long addr);
> -#endif /* CONFIG_FIND_NORMAL_PAGE */
> -};
> -
> -struct vm_unmapped_area_info {
> -#define VM_UNMAPPED_AREA_TOPDOWN 1
> - unsigned long flags;
> - unsigned long length;
> - unsigned long low_limit;
> - unsigned long high_limit;
> - unsigned long align_mask;
> - unsigned long align_offset;
> - unsigned long start_gap;
> -};
> -
> -struct pagetable_move_control {
> - struct vm_area_struct *old; /* Source VMA. */
> - struct vm_area_struct *new; /* Destination VMA. */
> - unsigned long old_addr; /* Address from which the move begins. */
> - unsigned long old_end; /* Exclusive address at which old range ends. */
> - unsigned long new_addr; /* Address to move page tables to. */
> - unsigned long len_in; /* Bytes to remap specified by user. */
> -
> - bool need_rmap_locks; /* Do rmap locks need to be taken? */
> - bool for_stack; /* Is this an early temp stack being moved? */
> -};
> -
> -#define PAGETABLE_MOVE(name, old_, new_, old_addr_, new_addr_, len_) \
> - struct pagetable_move_control name = { \
> - .old = old_, \
> - .new = new_, \
> - .old_addr = old_addr_, \
> - .old_end = (old_addr_) + (len_), \
> - .new_addr = new_addr_, \
> - .len_in = len_, \
> - }
> -
> -static inline void vma_iter_invalidate(struct vma_iterator *vmi)
> -{
> - mas_pause(&vmi->mas);
> -}
> -
> -static inline pgprot_t pgprot_modify(pgprot_t oldprot, pgprot_t newprot)
> -{
> - return __pgprot(pgprot_val(oldprot) | pgprot_val(newprot));
> -}
> -
> -static inline pgprot_t vm_get_page_prot(vm_flags_t vm_flags)
> -{
> - return __pgprot(vm_flags);
> -}
> -
> -static inline void vma_flags_clear_all(vma_flags_t *flags)
> -{
> - bitmap_zero(flags->__vma_flags, NUM_VMA_FLAG_BITS);
> -}
> -
> -static inline void vma_flag_set(vma_flags_t *flags, vma_flag_t bit)
> -{
> - unsigned long *bitmap = flags->__vma_flags;
> -
> - __set_bit((__force int)bit, bitmap);
> -}
> -
> -static inline vma_flags_t __mk_vma_flags(size_t count, const vma_flag_t *bits)
> -{
> - vma_flags_t flags;
> - int i;
> -
> - vma_flags_clear_all(&flags);
> - for (i = 0; i < count; i++)
> - vma_flag_set(&flags, bits[i]);
> - return flags;
> -}
> -
> -#define mk_vma_flags(...) __mk_vma_flags(COUNT_ARGS(__VA_ARGS__), \
> - (const vma_flag_t []){__VA_ARGS__})
> -
> -static __always_inline bool vma_flags_test_mask(const vma_flags_t *flags,
> - vma_flags_t to_test)
> -{
> - const unsigned long *bitmap = flags->__vma_flags;
> - const unsigned long *bitmap_to_test = to_test.__vma_flags;
> -
> - return bitmap_intersects(bitmap_to_test, bitmap, NUM_VMA_FLAG_BITS);
> -}
> -
> -#define vma_flags_test(flags, ...) \
> - vma_flags_test_mask(flags, mk_vma_flags(__VA_ARGS__))
> -
> -static __always_inline bool vma_flags_test_all_mask(const vma_flags_t *flags,
> - vma_flags_t to_test)
> -{
> - const unsigned long *bitmap = flags->__vma_flags;
> - const unsigned long *bitmap_to_test = to_test.__vma_flags;
> -
> - return bitmap_subset(bitmap_to_test, bitmap, NUM_VMA_FLAG_BITS);
> -}
> -
> -#define vma_flags_test_all(flags, ...) \
> - vma_flags_test_all_mask(flags, mk_vma_flags(__VA_ARGS__))
> -
> -static __always_inline void vma_flags_set_mask(vma_flags_t *flags, vma_flags_t to_set)
> -{
> - unsigned long *bitmap = flags->__vma_flags;
> - const unsigned long *bitmap_to_set = to_set.__vma_flags;
> -
> - bitmap_or(bitmap, bitmap, bitmap_to_set, NUM_VMA_FLAG_BITS);
> -}
> -
> -#define vma_flags_set(flags, ...) \
> - vma_flags_set_mask(flags, mk_vma_flags(__VA_ARGS__))
> -
> -static __always_inline void vma_flags_clear_mask(vma_flags_t *flags, vma_flags_t to_clear)
> -{
> - unsigned long *bitmap = flags->__vma_flags;
> - const unsigned long *bitmap_to_clear = to_clear.__vma_flags;
> -
> - bitmap_andnot(bitmap, bitmap, bitmap_to_clear, NUM_VMA_FLAG_BITS);
> -}
> -
> -#define vma_flags_clear(flags, ...) \
> - vma_flags_clear_mask(flags, mk_vma_flags(__VA_ARGS__))
> -
> -static inline bool vma_test_all_flags_mask(const struct vm_area_struct *vma,
> - vma_flags_t flags)
> -{
> - return vma_flags_test_all_mask(&vma->flags, flags);
> -}
> -
> -#define vma_test_all_flags(vma, ...) \
> - vma_test_all_flags_mask(vma, mk_vma_flags(__VA_ARGS__))
> -
> -static inline void vma_set_flags_mask(struct vm_area_struct *vma,
> - vma_flags_t flags)
> -{
> - vma_flags_set_mask(&vma->flags, flags);
> -}
> -
> -#define vma_set_flags(vma, ...) \
> - vma_set_flags_mask(vma, mk_vma_flags(__VA_ARGS__))
> -
> -static inline bool vma_desc_test_flags_mask(const struct vm_area_desc *desc,
> - vma_flags_t flags)
> -{
> - return vma_flags_test_mask(&desc->vma_flags, flags);
> -}
> -
> -#define vma_desc_test_flags(desc, ...) \
> - vma_desc_test_flags_mask(desc, mk_vma_flags(__VA_ARGS__))
> -
> -static inline void vma_desc_set_flags_mask(struct vm_area_desc *desc,
> - vma_flags_t flags)
> -{
> - vma_flags_set_mask(&desc->vma_flags, flags);
> -}
> -
> -#define vma_desc_set_flags(desc, ...) \
> - vma_desc_set_flags_mask(desc, mk_vma_flags(__VA_ARGS__))
> -
> -static inline void vma_desc_clear_flags_mask(struct vm_area_desc *desc,
> - vma_flags_t flags)
> -{
> - vma_flags_clear_mask(&desc->vma_flags, flags);
> -}
> -
> -#define vma_desc_clear_flags(desc, ...) \
> - vma_desc_clear_flags_mask(desc, mk_vma_flags(__VA_ARGS__))
> -
> -static inline bool is_shared_maywrite_vm_flags(vm_flags_t vm_flags)
> -{
> - return (vm_flags & (VM_SHARED | VM_MAYWRITE)) ==
> - (VM_SHARED | VM_MAYWRITE);
> -}
> -
> -static inline bool is_shared_maywrite(const vma_flags_t *flags)
> -{
> - return vma_flags_test_all(flags, VMA_SHARED_BIT, VMA_MAYWRITE_BIT);
> -}
> -
> -static inline bool vma_is_shared_maywrite(struct vm_area_struct *vma)
> -{
> - return is_shared_maywrite(&vma->flags);
> -}
> -
> -static inline struct vm_area_struct *vma_next(struct vma_iterator *vmi)
> -{
> - /*
> - * Uses mas_find() to get the first VMA when the iterator starts.
> - * Calling mas_next() could skip the first entry.
> - */
> - return mas_find(&vmi->mas, ULONG_MAX);
> -}
> -
> -/*
> - * WARNING: to avoid racing with vma_mark_attached()/vma_mark_detached(), these
> - * assertions should be made either under mmap_write_lock or when the object
> - * has been isolated under mmap_write_lock, ensuring no competing writers.
> - */
> -static inline void vma_assert_attached(struct vm_area_struct *vma)
> -{
> - WARN_ON_ONCE(!refcount_read(&vma->vm_refcnt));
> -}
> -
> -static inline void vma_assert_detached(struct vm_area_struct *vma)
> -{
> - WARN_ON_ONCE(refcount_read(&vma->vm_refcnt));
> -}
> -
> -static inline void vma_assert_write_locked(struct vm_area_struct *);
> -static inline void vma_mark_attached(struct vm_area_struct *vma)
> -{
> - vma_assert_write_locked(vma);
> - vma_assert_detached(vma);
> - refcount_set_release(&vma->vm_refcnt, 1);
> -}
> -
> -static inline void vma_mark_detached(struct vm_area_struct *vma)
> -{
> - vma_assert_write_locked(vma);
> - vma_assert_attached(vma);
> - /* We are the only writer, so no need to use vma_refcount_put(). */
> - if (unlikely(!refcount_dec_and_test(&vma->vm_refcnt))) {
> - /*
> - * Reader must have temporarily raised vm_refcnt but it will
> - * drop it without using the vma since vma is write-locked.
> - */
> - }
> -}
> -
> -extern const struct vm_operations_struct vma_dummy_vm_ops;
> -
> -extern unsigned long rlimit(unsigned int limit);
> -
> -static inline void vma_init(struct vm_area_struct *vma, struct mm_struct *mm)
> -{
> - memset(vma, 0, sizeof(*vma));
> - vma->vm_mm = mm;
> - vma->vm_ops = &vma_dummy_vm_ops;
> - INIT_LIST_HEAD(&vma->anon_vma_chain);
> - vma->vm_lock_seq = UINT_MAX;
> -}
> -
> -/*
> - * These are defined in vma.h, but sadly vm_stat_account() is referenced by
> - * kernel/fork.c, so we have to these broadly available there, and temporarily
> - * define them here to resolve the dependency cycle.
> - */
> -
> -#define is_exec_mapping(flags) \
> - ((flags & (VM_EXEC | VM_WRITE | VM_STACK)) == VM_EXEC)
> -
> -#define is_stack_mapping(flags) \
> - (((flags & VM_STACK) == VM_STACK) || (flags & VM_SHADOW_STACK))
> -
> -#define is_data_mapping(flags) \
> - ((flags & (VM_WRITE | VM_SHARED | VM_STACK)) == VM_WRITE)
> -
> -static inline void vm_stat_account(struct mm_struct *mm, vm_flags_t flags,
> - long npages)
> -{
> - WRITE_ONCE(mm->total_vm, READ_ONCE(mm->total_vm)+npages);
> -
> - if (is_exec_mapping(flags))
> - mm->exec_vm += npages;
> - else if (is_stack_mapping(flags))
> - mm->stack_vm += npages;
> - else if (is_data_mapping(flags))
> - mm->data_vm += npages;
> -}
> -
> -#undef is_exec_mapping
> -#undef is_stack_mapping
> -#undef is_data_mapping
> -
> -/* Currently stubbed but we may later wish to un-stub. */
> -static inline void vm_acct_memory(long pages);
> -static inline void vm_unacct_memory(long pages)
> -{
> - vm_acct_memory(-pages);
> -}
> -
> -static inline void mapping_allow_writable(struct address_space *mapping)
> -{
> - atomic_inc(&mapping->i_mmap_writable);
> -}
> -
> -static inline
> -struct vm_area_struct *vma_find(struct vma_iterator *vmi, unsigned long max)
> -{
> - return mas_find(&vmi->mas, max - 1);
> -}
> -
> -static inline int vma_iter_clear_gfp(struct vma_iterator *vmi,
> - unsigned long start, unsigned long end, gfp_t gfp)
> -{
> - __mas_set_range(&vmi->mas, start, end - 1);
> - mas_store_gfp(&vmi->mas, NULL, gfp);
> - if (unlikely(mas_is_err(&vmi->mas)))
> - return -ENOMEM;
> -
> - return 0;
> -}
> -
> -static inline void mmap_assert_locked(struct mm_struct *);
> -static inline struct vm_area_struct *find_vma_intersection(struct mm_struct *mm,
> - unsigned long start_addr,
> - unsigned long end_addr)
> -{
> - unsigned long index = start_addr;
> -
> - mmap_assert_locked(mm);
> - return mt_find(&mm->mm_mt, &index, end_addr - 1);
> -}
> -
> -static inline
> -struct vm_area_struct *vma_lookup(struct mm_struct *mm, unsigned long addr)
> -{
> - return mtree_load(&mm->mm_mt, addr);
> -}
> -
> -static inline struct vm_area_struct *vma_prev(struct vma_iterator *vmi)
> -{
> - return mas_prev(&vmi->mas, 0);
> -}
> -
> -static inline void vma_iter_set(struct vma_iterator *vmi, unsigned long addr)
> -{
> - mas_set(&vmi->mas, addr);
> -}
> -
> -static inline bool vma_is_anonymous(struct vm_area_struct *vma)
> -{
> - return !vma->vm_ops;
> -}
> -
> -/* Defined in vma.h, so temporarily define here to avoid circular dependency. */
> -#define vma_iter_load(vmi) \
> - mas_walk(&(vmi)->mas)
> -
> -static inline struct vm_area_struct *
> -find_vma_prev(struct mm_struct *mm, unsigned long addr,
> - struct vm_area_struct **pprev)
> -{
> - struct vm_area_struct *vma;
> - VMA_ITERATOR(vmi, mm, addr);
> -
> - vma = vma_iter_load(&vmi);
> - *pprev = vma_prev(&vmi);
> - if (!vma)
> - vma = vma_next(&vmi);
> - return vma;
> -}
> -
> -#undef vma_iter_load
> -
> -static inline void vma_iter_init(struct vma_iterator *vmi,
> - struct mm_struct *mm, unsigned long addr)
> -{
> - mas_init(&vmi->mas, &mm->mm_mt, addr);
> -}
> -
> -/* Stubbed functions. */
> -
> -static inline struct anon_vma_name *anon_vma_name(struct vm_area_struct *vma)
> -{
> - return NULL;
> -}
> -
> -static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma,
> - struct vm_userfaultfd_ctx vm_ctx)
> -{
> - return true;
> -}
> -
> -static inline bool anon_vma_name_eq(struct anon_vma_name *anon_name1,
> - struct anon_vma_name *anon_name2)
> -{
> - return true;
> -}
> -
> -static inline void might_sleep(void)
> -{
> -}
> -
> -static inline unsigned long vma_pages(struct vm_area_struct *vma)
> -{
> - return (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
> -}
> -
> -static inline void fput(struct file *file)
> -{
> -}
> -
> -static inline void mpol_put(struct mempolicy *pol)
> -{
> -}
> -
> -static inline void lru_add_drain(void)
> -{
> -}
> -
> -static inline void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm)
> -{
> -}
> -
> -static inline void update_hiwater_rss(struct mm_struct *mm)
> -{
> -}
> -
> -static inline void update_hiwater_vm(struct mm_struct *mm)
> -{
> -}
> -
> -struct unmap_desc;
> -
> -static inline void unmap_vmas(struct mmu_gather *tlb, struct unmap_desc *unmap)
> -{
> -}
> -
> -static inline void free_pgtables(struct mmu_gather *tlb, struct unmap_desc *desc)
> -{
> - (void)tlb;
> - (void)desc;
> -}
> -
> -static inline void mapping_unmap_writable(struct address_space *mapping)
> -{
> -}
> -
> -static inline void flush_dcache_mmap_lock(struct address_space *mapping)
> -{
> -}
> -
> -static inline void tlb_finish_mmu(struct mmu_gather *tlb)
> -{
> -}
> -
> -static inline struct file *get_file(struct file *f)
> -{
> - return f;
> -}
> -
> -static inline int vma_dup_policy(struct vm_area_struct *src, struct vm_area_struct *dst)
> -{
> - return 0;
> -}
> -
> -static inline int anon_vma_clone(struct vm_area_struct *dst, struct vm_area_struct *src,
> - enum vma_operation operation)
> -{
> - /* For testing purposes. We indicate that an anon_vma has been cloned. */
> - if (src->anon_vma != NULL) {
> - dst->anon_vma = src->anon_vma;
> - dst->anon_vma->was_cloned = true;
> - }
> -
> - return 0;
> -}
> -
> -static inline void vma_start_write(struct vm_area_struct *vma)
> -{
> - /* Used to indicate to tests that a write operation has begun. */
> - vma->vm_lock_seq++;
> -}
> -
> -static inline __must_check
> -int vma_start_write_killable(struct vm_area_struct *vma)
> -{
> - /* Used to indicate to tests that a write operation has begun. */
> - vma->vm_lock_seq++;
> - return 0;
> -}
> -
> -static inline void vma_adjust_trans_huge(struct vm_area_struct *vma,
> - unsigned long start,
> - unsigned long end,
> - struct vm_area_struct *next)
> -{
> -}
> -
> -static inline void hugetlb_split(struct vm_area_struct *, unsigned long) {}
> -
> -static inline void vma_iter_free(struct vma_iterator *vmi)
> -{
> - mas_destroy(&vmi->mas);
> -}
> -
> -static inline
> -struct vm_area_struct *vma_iter_next_range(struct vma_iterator *vmi)
> -{
> - return mas_next_range(&vmi->mas, ULONG_MAX);
> -}
> -
> -static inline void vm_acct_memory(long pages)
> -{
> -}
> -
> -static inline void vma_interval_tree_insert(struct vm_area_struct *vma,
> - struct rb_root_cached *rb)
> -{
> -}
> -
> -static inline void vma_interval_tree_remove(struct vm_area_struct *vma,
> - struct rb_root_cached *rb)
> -{
> -}
> -
> -static inline void flush_dcache_mmap_unlock(struct address_space *mapping)
> -{
> -}
> -
> -static inline void anon_vma_interval_tree_insert(struct anon_vma_chain *avc,
> - struct rb_root_cached *rb)
> -{
> -}
> -
> -static inline void anon_vma_interval_tree_remove(struct anon_vma_chain *avc,
> - struct rb_root_cached *rb)
> -{
> -}
> -
> -static inline void uprobe_mmap(struct vm_area_struct *vma)
> -{
> -}
> -
> -static inline void uprobe_munmap(struct vm_area_struct *vma,
> - unsigned long start, unsigned long end)
> -{
> -}
> -
> -static inline void i_mmap_lock_write(struct address_space *mapping)
> -{
> -}
> -
> -static inline void anon_vma_lock_write(struct anon_vma *anon_vma)
> -{
> -}
> -
> -static inline void vma_assert_write_locked(struct vm_area_struct *vma)
> -{
> -}
> -
> -static inline void unlink_anon_vmas(struct vm_area_struct *vma)
> -{
> - /* For testing purposes, indicate that the anon_vma was unlinked. */
> - vma->anon_vma->was_unlinked = true;
> -}
> -
> -static inline void anon_vma_unlock_write(struct anon_vma *anon_vma)
> -{
> -}
> -
> -static inline void i_mmap_unlock_write(struct address_space *mapping)
> -{
> -}
> -
> -static inline int userfaultfd_unmap_prep(struct vm_area_struct *vma,
> - unsigned long start,
> - unsigned long end,
> - struct list_head *unmaps)
> -{
> - return 0;
> -}
> -
> -static inline void mmap_write_downgrade(struct mm_struct *mm)
> -{
> -}
> -
> -static inline void mmap_read_unlock(struct mm_struct *mm)
> -{
> -}
> -
> -static inline void mmap_write_unlock(struct mm_struct *mm)
> -{
> -}
> -
> -static inline int mmap_write_lock_killable(struct mm_struct *mm)
> -{
> - return 0;
> -}
> -
> -static inline bool can_modify_mm(struct mm_struct *mm,
> - unsigned long start,
> - unsigned long end)
> -{
> - return true;
> -}
> -
> -static inline void arch_unmap(struct mm_struct *mm,
> - unsigned long start,
> - unsigned long end)
> -{
> -}
> -
> -static inline void mmap_assert_locked(struct mm_struct *mm)
> -{
> -}
> -
> -static inline bool mpol_equal(struct mempolicy *a, struct mempolicy *b)
> -{
> - return true;
> -}
> -
> -static inline void khugepaged_enter_vma(struct vm_area_struct *vma,
> - vm_flags_t vm_flags)
> -{
> -}
> -
> -static inline bool mapping_can_writeback(struct address_space *mapping)
> -{
> - return true;
> -}
> -
> -static inline bool is_vm_hugetlb_page(struct vm_area_struct *vma)
> -{
> - return false;
> -}
> -
> -static inline bool vma_soft_dirty_enabled(struct vm_area_struct *vma)
> -{
> - return false;
> -}
> -
> -static inline bool userfaultfd_wp(struct vm_area_struct *vma)
> -{
> - return false;
> -}
> -
> -static inline void mmap_assert_write_locked(struct mm_struct *mm)
> -{
> -}
> -
> -static inline void mutex_lock(struct mutex *lock)
> -{
> -}
> -
> -static inline void mutex_unlock(struct mutex *lock)
> -{
> -}
> -
> -static inline bool mutex_is_locked(struct mutex *lock)
> -{
> - return true;
> -}
> -
> -static inline bool signal_pending(void *p)
> -{
> - return false;
> -}
> -
> -static inline bool is_file_hugepages(struct file *file)
> -{
> - return false;
> -}
> -
> -static inline int security_vm_enough_memory_mm(struct mm_struct *mm, long pages)
> -{
> - return 0;
> -}
> -
> -static inline bool may_expand_vm(struct mm_struct *mm, vm_flags_t flags,
> - unsigned long npages)
> -{
> - return true;
> -}
> -
> -static inline int shmem_zero_setup(struct vm_area_struct *vma)
> -{
> - return 0;
> -}
> -
> -static inline void vma_set_anonymous(struct vm_area_struct *vma)
> -{
> - vma->vm_ops = NULL;
> -}
> -
> -static inline void ksm_add_vma(struct vm_area_struct *vma)
> -{
> -}
> -
> -static inline void perf_event_mmap(struct vm_area_struct *vma)
> -{
> -}
> -
> -static inline bool vma_is_dax(struct vm_area_struct *vma)
> -{
> - return false;
> -}
> -
> -static inline struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
> -{
> - return NULL;
> -}
> -
> -bool vma_wants_writenotify(struct vm_area_struct *vma, pgprot_t vm_page_prot);
> -
> -/* Update vma->vm_page_prot to reflect vma->vm_flags. */
> -static inline void vma_set_page_prot(struct vm_area_struct *vma)
> -{
> - vm_flags_t vm_flags = vma->vm_flags;
> - pgprot_t vm_page_prot;
> -
> - /* testing: we inline vm_pgprot_modify() to avoid clash with vma.h. */
> - vm_page_prot = pgprot_modify(vma->vm_page_prot, vm_get_page_prot(vm_flags));
> -
> - if (vma_wants_writenotify(vma, vm_page_prot)) {
> - vm_flags &= ~VM_SHARED;
> - /* testing: we inline vm_pgprot_modify() to avoid clash with vma.h. */
> - vm_page_prot = pgprot_modify(vm_page_prot, vm_get_page_prot(vm_flags));
> - }
> - /* remove_protection_ptes reads vma->vm_page_prot without mmap_lock */
> - WRITE_ONCE(vma->vm_page_prot, vm_page_prot);
> -}
> -
> -static inline bool arch_validate_flags(vm_flags_t flags)
> -{
> - return true;
> -}
> -
> -static inline void vma_close(struct vm_area_struct *vma)
> -{
> -}
> -
> -static inline int mmap_file(struct file *file, struct vm_area_struct *vma)
> -{
> - return 0;
> -}
> -
> -static inline unsigned long stack_guard_start_gap(struct vm_area_struct *vma)
> -{
> - if (vma->vm_flags & VM_GROWSDOWN)
> - return stack_guard_gap;
> -
> - /* See reasoning around the VM_SHADOW_STACK definition */
> - if (vma->vm_flags & VM_SHADOW_STACK)
> - return PAGE_SIZE;
> -
> - return 0;
> -}
> -
> -static inline unsigned long vm_start_gap(struct vm_area_struct *vma)
> -{
> - unsigned long gap = stack_guard_start_gap(vma);
> - unsigned long vm_start = vma->vm_start;
> -
> - vm_start -= gap;
> - if (vm_start > vma->vm_start)
> - vm_start = 0;
> - return vm_start;
> -}
> -
> -static inline unsigned long vm_end_gap(struct vm_area_struct *vma)
> -{
> - unsigned long vm_end = vma->vm_end;
> -
> - if (vma->vm_flags & VM_GROWSUP) {
> - vm_end += stack_guard_gap;
> - if (vm_end < vma->vm_end)
> - vm_end = -PAGE_SIZE;
> - }
> - return vm_end;
> -}
> -
> -static inline int is_hugepage_only_range(struct mm_struct *mm,
> - unsigned long addr, unsigned long len)
> -{
> - return 0;
> -}
> -
> -static inline bool vma_is_accessible(struct vm_area_struct *vma)
> -{
> - return vma->vm_flags & VM_ACCESS_FLAGS;
> -}
> -
> -static inline bool capable(int cap)
> -{
> - return true;
> -}
> -
> -static inline bool mlock_future_ok(const struct mm_struct *mm,
> - vm_flags_t vm_flags, unsigned long bytes)
> -{
> - unsigned long locked_pages, limit_pages;
> -
> - if (!(vm_flags & VM_LOCKED) || capable(CAP_IPC_LOCK))
> - return true;
> -
> - locked_pages = bytes >> PAGE_SHIFT;
> - locked_pages += mm->locked_vm;
> -
> - limit_pages = rlimit(RLIMIT_MEMLOCK);
> - limit_pages >>= PAGE_SHIFT;
> -
> - return locked_pages <= limit_pages;
> -}
> -
> -static inline int __anon_vma_prepare(struct vm_area_struct *vma)
> -{
> - struct anon_vma *anon_vma = calloc(1, sizeof(struct anon_vma));
> -
> - if (!anon_vma)
> - return -ENOMEM;
> -
> - anon_vma->root = anon_vma;
> - vma->anon_vma = anon_vma;
> -
> - return 0;
> -}
> -
> -static inline int anon_vma_prepare(struct vm_area_struct *vma)
> -{
> - if (likely(vma->anon_vma))
> - return 0;
> -
> - return __anon_vma_prepare(vma);
> -}
> -
> -static inline void userfaultfd_unmap_complete(struct mm_struct *mm,
> - struct list_head *uf)
> -{
> -}
> -
> -static inline bool mm_flags_test(int flag, const struct mm_struct *mm)
> -{
> - return test_bit(flag, ACCESS_PRIVATE(&mm->flags, __mm_flags));
> -}
> -
> -/*
> - * 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.
> - *
> - * This denies the following:
> - *
> - * a) mmap(PROT_WRITE | PROT_EXEC)
> - *
> - * b) mmap(PROT_WRITE)
> - * mprotect(PROT_EXEC)
> - *
> - * c) mmap(PROT_WRITE)
> - * mprotect(PROT_READ)
> - * mprotect(PROT_EXEC)
> - *
> - * But allows the following:
> - *
> - * d) mmap(PROT_READ | PROT_EXEC)
> - * mmap(PROT_READ | PROT_EXEC | PROT_BTI)
> - *
> - * This is only applicable if the user has set the Memory-Deny-Write-Execute
> - * (MDWE) protection mask for the current process.
> - *
> - * @old specifies the VMA flags the VMA originally possessed, and @new the ones
> - * we propose to set.
> - *
> - * Return: false if proposed change is OK, true if not ok and should be denied.
> - */
> -static inline bool map_deny_write_exec(unsigned long old, unsigned long new)
> -{
> - /* If MDWE is disabled, we have nothing to deny. */
> - if (mm_flags_test(MMF_HAS_MDWE, current->mm))
> - return false;
> -
> - /* If the new VMA is not executable, we have nothing to deny. */
> - if (!(new & VM_EXEC))
> - return false;
> -
> - /* Under MDWE we do not accept newly writably executable VMAs... */
> - if (new & VM_WRITE)
> - return true;
> -
> - /* ...nor previously non-executable VMAs becoming executable. */
> - if (!(old & VM_EXEC))
> - return true;
> -
> - return false;
> -}
> -
> -static inline int mapping_map_writable(struct address_space *mapping)
> -{
> - return atomic_inc_unless_negative(&mapping->i_mmap_writable) ?
> - 0 : -EPERM;
> -}
> -
> -static inline unsigned long move_page_tables(struct pagetable_move_control *pmc)
> -{
> - return 0;
> -}
> -
> -static inline void free_pgd_range(struct mmu_gather *tlb,
> - unsigned long addr, unsigned long end,
> - unsigned long floor, unsigned long ceiling)
> -{
> -}
> -
> -static inline int ksm_execve(struct mm_struct *mm)
> -{
> - return 0;
> -}
> -
> -static inline void ksm_exit(struct mm_struct *mm)
> -{
> -}
> -
> -static inline void vma_lock_init(struct vm_area_struct *vma, bool reset_refcnt)
> -{
> - if (reset_refcnt)
> - refcount_set(&vma->vm_refcnt, 0);
> -}
> -
> -static inline void vma_numab_state_init(struct vm_area_struct *vma)
> -{
> -}
> -
> -static inline void vma_numab_state_free(struct vm_area_struct *vma)
> -{
> -}
> -
> -static inline void dup_anon_vma_name(struct vm_area_struct *orig_vma,
> - struct vm_area_struct *new_vma)
> -{
> -}
> -
> -static inline void free_anon_vma_name(struct vm_area_struct *vma)
> -{
> -}
> -
> -/* Declared in vma.h. */
> -static inline void set_vma_from_desc(struct vm_area_struct *vma,
> - struct vm_area_desc *desc);
> -
> -static inline void mmap_action_prepare(struct mmap_action *action,
> - struct vm_area_desc *desc)
> -{
> -}
> -
> -static inline int mmap_action_complete(struct mmap_action *action,
> - struct vm_area_struct *vma)
> -{
> - return 0;
> -}
> -
> -static inline int __compat_vma_mmap(const struct file_operations *f_op,
> - struct file *file, struct vm_area_struct *vma)
> -{
> - struct vm_area_desc desc = {
> - .mm = vma->vm_mm,
> - .file = file,
> - .start = vma->vm_start,
> - .end = vma->vm_end,
> -
> - .pgoff = vma->vm_pgoff,
> - .vm_file = vma->vm_file,
> - .vm_flags = vma->vm_flags,
> - .page_prot = vma->vm_page_prot,
> -
> - .action.type = MMAP_NOTHING, /* Default */
> - };
> - int err;
> -
> - err = f_op->mmap_prepare(&desc);
> - if (err)
> - return err;
> -
> - mmap_action_prepare(&desc.action, &desc);
> - set_vma_from_desc(vma, &desc);
> - return mmap_action_complete(&desc.action, vma);
> -}
> -
> -static inline int compat_vma_mmap(struct file *file,
> - struct vm_area_struct *vma)
> -{
> - return __compat_vma_mmap(file->f_op, file, vma);
> -}
> -
> -/* Did the driver provide valid mmap hook configuration? */
> -static inline bool can_mmap_file(struct file *file)
> -{
> - bool has_mmap = file->f_op->mmap;
> - bool has_mmap_prepare = file->f_op->mmap_prepare;
> -
> - /* Hooks are mutually exclusive. */
> - if (WARN_ON_ONCE(has_mmap && has_mmap_prepare))
> - return false;
> - if (!has_mmap && !has_mmap_prepare)
> - return false;
> -
> - return true;
> -}
> -
> -static inline int vfs_mmap(struct file *file, struct vm_area_struct *vma)
> -{
> - if (file->f_op->mmap_prepare)
> - return compat_vma_mmap(file, vma);
> -
> - return file->f_op->mmap(file, vma);
> -}
> -
> -static inline int vfs_mmap_prepare(struct file *file, struct vm_area_desc *desc)
> -{
> - return file->f_op->mmap_prepare(desc);
> -}
> -
> -static inline void fixup_hugetlb_reservations(struct vm_area_struct *vma)
> -{
> -}
> -
> -static inline void vma_set_file(struct vm_area_struct *vma, struct file *file)
> -{
> - /* Changing an anonymous vma with this is illegal */
> - get_file(file);
> - swap(vma->vm_file, file);
> - fput(file);
> -}
> -
> -static inline bool shmem_file(struct file *file)
> -{
> - return false;
> -}
> -
> -static inline vm_flags_t ksm_vma_flags(const struct mm_struct *mm,
> - const struct file *file, vm_flags_t vm_flags)
> -{
> - return vm_flags;
> -}
> -
> -static inline void remap_pfn_range_prepare(struct vm_area_desc *desc, unsigned long pfn)
> -{
> -}
> -
> -static inline int remap_pfn_range_complete(struct vm_area_struct *vma, unsigned long addr,
> - unsigned long pfn, unsigned long size, pgprot_t pgprot)
> -{
> - return 0;
> -}
> +typedef unsigned long vm_flags_t;
> +#define pgoff_t unsigned long
> +typedef unsigned long pgprotval_t;
> +typedef struct pgprot { pgprotval_t pgprot; } pgprot_t;
> +typedef __bitwise unsigned int vm_fault_t;
>
> -static inline int do_munmap(struct mm_struct *, unsigned long, size_t,
> - struct list_head *uf)
> -{
> - return 0;
> -}
> +#include "include/stubs.h"
> +#include "include/dup.h"
> +#include "include/custom.h"
>
> #endif /* __MM_VMA_INTERNAL_H */
> --
> 2.52.0
>
^ permalink raw reply [flat|nested] 56+ messages in thread
* [PATCH v2 13/13] tools/testing/vma: add VMA userland tests for VMA flag functions
2026-01-22 16:06 [PATCH v2 00/13] mm: add bitmap VMA flag helpers and convert all mmap_prepare to use them Lorenzo Stoakes
` (11 preceding siblings ...)
2026-01-22 16:06 ` [PATCH v2 12/13] tools/testing/vma: separate out vma_internal.h into logical headers Lorenzo Stoakes
@ 2026-01-22 16:06 ` Lorenzo Stoakes
2026-02-09 20:23 ` Liam R. Howlett
2026-01-22 16:56 ` [PATCH v2 00/13] mm: add bitmap VMA flag helpers and convert all mmap_prepare to use them Andrew Morton
2026-01-27 13:53 ` Yury Norov
14 siblings, 1 reply; 56+ messages in thread
From: Lorenzo Stoakes @ 2026-01-22 16:06 UTC (permalink / raw)
To: Andrew Morton
Cc: Jarkko Sakkinen, Dave Hansen, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, x86, H . Peter Anvin, Arnd Bergmann,
Greg Kroah-Hartman, Dan Williams, Vishal Verma, Dave Jiang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
Now we have the capability to test the new helpers for the bitmap VMA flags
in userland, do so.
We also update the Makefile such that both VMA (and while we're here)
mm_struct flag sizes can be customised on build. We default to 128-bit to
enable testing of flags above word size even on 64-bit systems.
We add userland tests to ensure that we do not regress VMA flag behaviour
with the introduction when using bitmap VMA flags, nor accidentally
introduce unexpected results due to for instance higher bit values not
being correctly cleared/set.
As part of this change, make __mk_vma_flags() a custom function so we can
handle specifying invalid VMA bits. This is purposeful so we can have the
VMA tests work at lower and higher number of VMA flags without having to
duplicate code too much.
Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
---
tools/testing/vma/Makefile | 3 +
tools/testing/vma/include/custom.h | 16 ++
tools/testing/vma/include/dup.h | 11 +-
tools/testing/vma/tests/vma.c | 300 +++++++++++++++++++++++++++++
tools/testing/vma/vma_internal.h | 4 +-
5 files changed, 322 insertions(+), 12 deletions(-)
diff --git a/tools/testing/vma/Makefile b/tools/testing/vma/Makefile
index 50aa4301b3a6..e72b45dedda5 100644
--- a/tools/testing/vma/Makefile
+++ b/tools/testing/vma/Makefile
@@ -9,6 +9,9 @@ include ../shared/shared.mk
OFILES = $(SHARED_OFILES) main.o shared.o maple-shim.o
TARGETS = vma
+# These can be varied to test different sizes.
+CFLAGS += -DNUM_VMA_FLAG_BITS=128 -DNUM_MM_FLAG_BITS=128
+
main.o: main.c shared.c shared.h vma_internal.h tests/merge.c tests/mmap.c tests/vma.c ../../../mm/vma.c ../../../mm/vma_init.c ../../../mm/vma_exec.c ../../../mm/vma.h include/custom.h include/dup.h include/stubs.h
vma: $(OFILES)
diff --git a/tools/testing/vma/include/custom.h b/tools/testing/vma/include/custom.h
index f567127efba9..802a76317245 100644
--- a/tools/testing/vma/include/custom.h
+++ b/tools/testing/vma/include/custom.h
@@ -101,3 +101,19 @@ static inline void vma_lock_init(struct vm_area_struct *vma, bool reset_refcnt)
if (reset_refcnt)
refcount_set(&vma->vm_refcnt, 0);
}
+
+static inline vma_flags_t __mk_vma_flags(size_t count, const vma_flag_t *bits)
+{
+ vma_flags_t flags;
+ int i;
+
+ /*
+ * For testing purposes: allow invalid bit specification so we can
+ * easily test.
+ */
+ vma_flags_clear_all(&flags);
+ for (i = 0; i < count; i++)
+ if (bits[i] < NUM_VMA_FLAG_BITS)
+ vma_flag_set(&flags, bits[i]);
+ return flags;
+}
diff --git a/tools/testing/vma/include/dup.h b/tools/testing/vma/include/dup.h
index ed8708afb7af..31ee02f709b2 100644
--- a/tools/testing/vma/include/dup.h
+++ b/tools/testing/vma/include/dup.h
@@ -838,16 +838,7 @@ static inline void vm_flags_clear(struct vm_area_struct *vma,
vma_flags_clear_word(&vma->flags, flags);
}
-static inline vma_flags_t __mk_vma_flags(size_t count, const vma_flag_t *bits)
-{
- vma_flags_t flags;
- int i;
-
- vma_flags_clear_all(&flags);
- for (i = 0; i < count; i++)
- vma_flag_set(&flags, bits[i]);
- return flags;
-}
+static inline vma_flags_t __mk_vma_flags(size_t count, const vma_flag_t *bits);
#define mk_vma_flags(...) __mk_vma_flags(COUNT_ARGS(__VA_ARGS__), \
(const vma_flag_t []){__VA_ARGS__})
diff --git a/tools/testing/vma/tests/vma.c b/tools/testing/vma/tests/vma.c
index 6d9775aee243..c54ffc954f11 100644
--- a/tools/testing/vma/tests/vma.c
+++ b/tools/testing/vma/tests/vma.c
@@ -1,5 +1,25 @@
// SPDX-License-Identifier: GPL-2.0-or-later
+static bool compare_legacy_flags(vm_flags_t legacy_flags, vma_flags_t flags)
+{
+ const unsigned long legacy_val = legacy_flags;
+ /* The lower word should contain the precise same value. */
+ const unsigned long flags_lower = flags.__vma_flags[0];
+#if NUM_VMA_FLAGS > BITS_PER_LONG
+ int i;
+
+ /* All bits in higher flag values should be zero. */
+ for (i = 1; i < NUM_VMA_FLAGS / BITS_PER_LONG; i++) {
+ if (flags.__vma_flags[i] != 0)
+ return false;
+ }
+#endif
+
+ static_assert(sizeof(legacy_flags) == sizeof(unsigned long));
+
+ return legacy_val == flags_lower;
+}
+
static bool test_copy_vma(void)
{
vm_flags_t vm_flags = VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE;
@@ -33,7 +53,287 @@ static bool test_copy_vma(void)
return true;
}
+static bool test_vma_flags_unchanged(void)
+{
+ vma_flags_t flags = EMPTY_VMA_FLAGS;
+ vm_flags_t legacy_flags = 0;
+ int bit;
+ struct vm_area_struct vma;
+ struct vm_area_desc desc;
+
+
+ vma.flags = EMPTY_VMA_FLAGS;
+ desc.vma_flags = EMPTY_VMA_FLAGS;
+
+ for (bit = 0; bit < BITS_PER_LONG; bit++) {
+ vma_flags_t mask = mk_vma_flags(bit);
+
+ legacy_flags |= (1UL << bit);
+
+ /* Individual flags. */
+ vma_flags_set(&flags, bit);
+ ASSERT_TRUE(compare_legacy_flags(legacy_flags, flags));
+
+ /* Via mask. */
+ vma_flags_set_mask(&flags, mask);
+ ASSERT_TRUE(compare_legacy_flags(legacy_flags, flags));
+
+ /* Same for VMA. */
+ vma_set_flags(&vma, bit);
+ ASSERT_TRUE(compare_legacy_flags(legacy_flags, vma.flags));
+ vma_set_flags_mask(&vma, mask);
+ ASSERT_TRUE(compare_legacy_flags(legacy_flags, vma.flags));
+
+ /* Same for VMA descriptor. */
+ vma_desc_set_flags(&desc, bit);
+ ASSERT_TRUE(compare_legacy_flags(legacy_flags, desc.vma_flags));
+ vma_desc_set_flags_mask(&desc, mask);
+ ASSERT_TRUE(compare_legacy_flags(legacy_flags, desc.vma_flags));
+ }
+
+ return true;
+}
+
+static bool test_vma_flags_cleared(void)
+{
+ const vma_flags_t empty = EMPTY_VMA_FLAGS;
+ vma_flags_t flags;
+ int i;
+
+ /* Set all bits high. */
+ memset(&flags, 1, sizeof(flags));
+ /* Try to clear. */
+ vma_flags_clear_all(&flags);
+ /* Equal to EMPTY_VMA_FLAGS? */
+ ASSERT_EQ(memcmp(&empty, &flags, sizeof(flags)), 0);
+ /* Make sure every unsigned long entry in bitmap array zero. */
+ for (i = 0; i < sizeof(flags) / BITS_PER_LONG; i++) {
+ const unsigned long val = flags.__vma_flags[i];
+
+ ASSERT_EQ(val, 0);
+ }
+
+ return true;
+}
+
+/*
+ * Assert that VMA flag functions that operate at the system word level function
+ * correctly.
+ */
+static bool test_vma_flags_word(void)
+{
+ vma_flags_t flags = EMPTY_VMA_FLAGS;
+ const vma_flags_t comparison =
+ mk_vma_flags(VMA_READ_BIT, VMA_WRITE_BIT, 64, 65);
+
+ /* Set some custom high flags. */
+ vma_flags_set(&flags, 64, 65);
+ /* Now overwrite the first word. */
+ vma_flags_overwrite_word(&flags, VM_READ | VM_WRITE);
+ /* Ensure they are equal. */
+ ASSERT_EQ(memcmp(&flags, &comparison, sizeof(flags)), 0);
+
+ flags = EMPTY_VMA_FLAGS;
+ vma_flags_set(&flags, 64, 65);
+
+ /* Do the same with the _once() equivalent. */
+ vma_flags_overwrite_word_once(&flags, VM_READ | VM_WRITE);
+ ASSERT_EQ(memcmp(&flags, &comparison, sizeof(flags)), 0);
+
+ flags = EMPTY_VMA_FLAGS;
+ vma_flags_set(&flags, 64, 65);
+
+ /* Make sure we can set a word without disturbing other bits. */
+ vma_flags_set(&flags, VMA_WRITE_BIT);
+ vma_flags_set_word(&flags, VM_READ);
+ ASSERT_EQ(memcmp(&flags, &comparison, sizeof(flags)), 0);
+
+ flags = EMPTY_VMA_FLAGS;
+ vma_flags_set(&flags, 64, 65);
+
+ /* Make sure we can clear a word without disturbing other bits. */
+ vma_flags_set(&flags, VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT);
+ vma_flags_clear_word(&flags, VM_EXEC);
+ ASSERT_EQ(memcmp(&flags, &comparison, sizeof(flags)), 0);
+
+ return true;
+}
+
+/* Ensure that vma_flags_test() and friends works correctly. */
+static bool test_vma_flags_test(void)
+{
+ const vma_flags_t flags = mk_vma_flags(VMA_READ_BIT, VMA_WRITE_BIT,
+ VMA_EXEC_BIT, 64, 65);
+ struct vm_area_struct vma;
+ struct vm_area_desc desc;
+
+ vma.flags = flags;
+ desc.vma_flags = flags;
+
+#define do_test(...) \
+ ASSERT_TRUE(vma_flags_test(&flags, __VA_ARGS__)); \
+ ASSERT_TRUE(vma_desc_test_flags(&desc, __VA_ARGS__))
+
+#define do_test_all_true(...) \
+ ASSERT_TRUE(vma_flags_test_all(&flags, __VA_ARGS__)); \
+ ASSERT_TRUE(vma_test_all_flags(&vma, __VA_ARGS__))
+
+#define do_test_all_false(...) \
+ ASSERT_FALSE(vma_flags_test_all(&flags, __VA_ARGS__)); \
+ ASSERT_FALSE(vma_test_all_flags(&vma, __VA_ARGS__))
+
+ /*
+ * Testing for some flags that are present, some that are not - should
+ * pass. ANY flags matching should work.
+ */
+ do_test(VMA_READ_BIT, VMA_MAYREAD_BIT, VMA_SEQ_READ_BIT);
+ /* However, the ...test_all() variant should NOT pass. */
+ do_test_all_false(VMA_READ_BIT, VMA_MAYREAD_BIT, VMA_SEQ_READ_BIT);
+ /* But should pass for flags present. */
+ do_test_all_true(VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT, 64, 65);
+ /* Also subsets... */
+ do_test_all_true(VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT, 64);
+ do_test_all_true(VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT);
+ do_test_all_true(VMA_READ_BIT, VMA_WRITE_BIT);
+ do_test_all_true(VMA_READ_BIT);
+ /*
+ * Check _mask variant. We don't need to test extensively as macro
+ * helper is the equivalent.
+ */
+ ASSERT_TRUE(vma_flags_test_mask(&flags, flags));
+ ASSERT_TRUE(vma_flags_test_all_mask(&flags, flags));
+
+ /* Single bits. */
+ do_test(VMA_READ_BIT);
+ do_test(VMA_WRITE_BIT);
+ do_test(VMA_EXEC_BIT);
+#if NUM_VMA_FLAG_BITS > 64
+ do_test(64);
+ do_test(65);
+#endif
+
+ /* Two bits. */
+ do_test(VMA_READ_BIT, VMA_WRITE_BIT);
+ do_test(VMA_READ_BIT, VMA_EXEC_BIT);
+ do_test(VMA_WRITE_BIT, VMA_EXEC_BIT);
+ /* Ordering shouldn't matter. */
+ do_test(VMA_WRITE_BIT, VMA_READ_BIT);
+ do_test(VMA_EXEC_BIT, VMA_READ_BIT);
+ do_test(VMA_EXEC_BIT, VMA_WRITE_BIT);
+#if NUM_VMA_FLAG_BITS > 64
+ do_test(VMA_READ_BIT, 64);
+ do_test(VMA_WRITE_BIT, 64);
+ do_test(64, VMA_READ_BIT);
+ do_test(64, VMA_WRITE_BIT);
+ do_test(VMA_READ_BIT, 65);
+ do_test(VMA_WRITE_BIT, 65);
+ do_test(65, VMA_READ_BIT);
+ do_test(65, VMA_WRITE_BIT);
+#endif
+ /* Three bits. */
+ do_test(VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT);
+#if NUM_VMA_FLAG_BITS > 64
+ /* No need to consider every single permutation. */
+ do_test(VMA_READ_BIT, VMA_WRITE_BIT, 64);
+ do_test(VMA_READ_BIT, VMA_WRITE_BIT, 65);
+
+ /* Four bits. */
+ do_test(VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT, 64);
+ do_test(VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT, 65);
+
+ /* Five bits. */
+ do_test(VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT, 64, 65);
+#endif
+
+#undef do_test
+#undef do_test_all_true
+#undef do_test_all_false
+
+ return true;
+}
+
+/* Ensure that vma_flags_clear() and friends works correctly. */
+static bool test_vma_flags_clear(void)
+{
+ vma_flags_t flags = mk_vma_flags(VMA_READ_BIT, VMA_WRITE_BIT,
+ VMA_EXEC_BIT, 64, 65);
+ vma_flags_t mask = mk_vma_flags(VMA_EXEC_BIT, 64);
+ struct vm_area_struct vma;
+ struct vm_area_desc desc;
+
+ vma.flags = flags;
+ desc.vma_flags = flags;
+
+ /* Cursory check of _mask() variant, as the helper macros imply. */
+ vma_flags_clear_mask(&flags, mask);
+ vma_flags_clear_mask(&vma.flags, mask);
+ vma_desc_clear_flags_mask(&desc, mask);
+ ASSERT_FALSE(vma_flags_test(&flags, VMA_EXEC_BIT, 64));
+ ASSERT_FALSE(vma_flags_test(&vma.flags, VMA_EXEC_BIT, 64));
+ ASSERT_FALSE(vma_desc_test_flags(&desc, VMA_EXEC_BIT, 64));
+ /* Reset. */
+ vma_flags_set(&flags, VMA_EXEC_BIT, 64);
+ vma_set_flags(&vma, VMA_EXEC_BIT, 64);
+ vma_desc_set_flags(&desc, VMA_EXEC_BIT, 64);
+
+ /*
+ * Clear the flags and assert clear worked, then reset flags back to
+ * include specified flags.
+ */
+#define do_test_and_reset(...) \
+ vma_flags_clear(&flags, __VA_ARGS__); \
+ vma_flags_clear(&vma.flags, __VA_ARGS__); \
+ vma_desc_clear_flags(&desc, __VA_ARGS__); \
+ ASSERT_FALSE(vma_flags_test(&flags, __VA_ARGS__)); \
+ ASSERT_FALSE(vma_flags_test(&vma.flags, __VA_ARGS__)); \
+ ASSERT_FALSE(vma_desc_test_flags(&desc, __VA_ARGS__)); \
+ vma_flags_set(&flags, __VA_ARGS__); \
+ vma_set_flags(&vma, __VA_ARGS__); \
+ vma_desc_set_flags(&desc, __VA_ARGS__)
+
+ /* Single flags. */
+ do_test_and_reset(VMA_READ_BIT);
+ do_test_and_reset(VMA_WRITE_BIT);
+ do_test_and_reset(VMA_EXEC_BIT);
+ do_test_and_reset(64);
+ do_test_and_reset(65);
+
+ /* Two flags, in different orders. */
+ do_test_and_reset(VMA_READ_BIT, VMA_WRITE_BIT);
+ do_test_and_reset(VMA_READ_BIT, VMA_EXEC_BIT);
+ do_test_and_reset(VMA_READ_BIT, 64);
+ do_test_and_reset(VMA_READ_BIT, 65);
+ do_test_and_reset(VMA_WRITE_BIT, VMA_READ_BIT);
+ do_test_and_reset(VMA_WRITE_BIT, VMA_EXEC_BIT);
+ do_test_and_reset(VMA_WRITE_BIT, 64);
+ do_test_and_reset(VMA_WRITE_BIT, 65);
+ do_test_and_reset(VMA_EXEC_BIT, VMA_READ_BIT);
+ do_test_and_reset(VMA_EXEC_BIT, VMA_WRITE_BIT);
+ do_test_and_reset(VMA_EXEC_BIT, 64);
+ do_test_and_reset(VMA_EXEC_BIT, 65);
+ do_test_and_reset(64, VMA_READ_BIT);
+ do_test_and_reset(64, VMA_WRITE_BIT);
+ do_test_and_reset(64, VMA_EXEC_BIT);
+ do_test_and_reset(64, 65);
+ do_test_and_reset(65, VMA_READ_BIT);
+ do_test_and_reset(65, VMA_WRITE_BIT);
+ do_test_and_reset(65, VMA_EXEC_BIT);
+ do_test_and_reset(65, 64);
+
+ /* Three flags. */
+
+#undef do_test_some_missing
+#undef do_test_and_reset
+
+ return true;
+}
+
static void run_vma_tests(int *num_tests, int *num_fail)
{
TEST(copy_vma);
+ TEST(vma_flags_unchanged);
+ TEST(vma_flags_cleared);
+ TEST(vma_flags_word);
+ TEST(vma_flags_test);
+ TEST(vma_flags_clear);
}
diff --git a/tools/testing/vma/vma_internal.h b/tools/testing/vma/vma_internal.h
index e3ed05b57819..0e1121e2ef23 100644
--- a/tools/testing/vma/vma_internal.h
+++ b/tools/testing/vma/vma_internal.h
@@ -36,11 +36,11 @@
* ahead of all other headers.
*/
#define __private
-#define NUM_MM_FLAG_BITS (64)
+/* NUM_MM_FLAG_BITS defined by test code. */
typedef struct {
__private DECLARE_BITMAP(__mm_flags, NUM_MM_FLAG_BITS);
} mm_flags_t;
-#define NUM_VMA_FLAG_BITS BITS_PER_LONG
+/* NUM_VMA_FLAG_BITS defined by test code. */
typedef struct {
DECLARE_BITMAP(__vma_flags, NUM_VMA_FLAG_BITS);
} __private vma_flags_t;
--
2.52.0
^ permalink raw reply [flat|nested] 56+ messages in thread* Re: [PATCH v2 13/13] tools/testing/vma: add VMA userland tests for VMA flag functions
2026-01-22 16:06 ` [PATCH v2 13/13] tools/testing/vma: add VMA userland tests for VMA flag functions Lorenzo Stoakes
@ 2026-02-09 20:23 ` Liam R. Howlett
0 siblings, 0 replies; 56+ messages in thread
From: Liam R. Howlett @ 2026-02-09 20:23 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin,
Arnd Bergmann, Greg Kroah-Hartman, Dan Williams, Vishal Verma,
Dave Jiang, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Hugh Dickins, Baolin Wang, Zi Yan, Nico Pache, Ryan Roberts,
Dev Jain, Barry Song, Lance Yang, Jann Horn, Pedro Falcato,
David Howells, Paul Moore, James Morris, Serge E . Hallyn,
Yury Norov, Rasmus Villemoes, linux-sgx, linux-kernel, nvdimm,
linux-cxl, dri-devel, intel-gfx, linux-fsdevel, linux-aio,
linux-erofs, linux-ext4, linux-mm, ntfs3, devel, linux-xfs,
keyrings, linux-security-module, Jason Gunthorpe
* Lorenzo Stoakes <lorenzo.stoakes@oracle.com> [260122 16:06]:
> Now we have the capability to test the new helpers for the bitmap VMA flags
> in userland, do so.
>
> We also update the Makefile such that both VMA (and while we're here)
> mm_struct flag sizes can be customised on build. We default to 128-bit to
> enable testing of flags above word size even on 64-bit systems.
>
> We add userland tests to ensure that we do not regress VMA flag behaviour
> with the introduction when using bitmap VMA flags, nor accidentally
> introduce unexpected results due to for instance higher bit values not
> being correctly cleared/set.
>
> As part of this change, make __mk_vma_flags() a custom function so we can
> handle specifying invalid VMA bits. This is purposeful so we can have the
> VMA tests work at lower and higher number of VMA flags without having to
> duplicate code too much.
>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Reviewed-by: Liam R. Howlett <Liam.Howlett@oracle.com>
> ---
> tools/testing/vma/Makefile | 3 +
> tools/testing/vma/include/custom.h | 16 ++
> tools/testing/vma/include/dup.h | 11 +-
> tools/testing/vma/tests/vma.c | 300 +++++++++++++++++++++++++++++
> tools/testing/vma/vma_internal.h | 4 +-
> 5 files changed, 322 insertions(+), 12 deletions(-)
>
> diff --git a/tools/testing/vma/Makefile b/tools/testing/vma/Makefile
> index 50aa4301b3a6..e72b45dedda5 100644
> --- a/tools/testing/vma/Makefile
> +++ b/tools/testing/vma/Makefile
> @@ -9,6 +9,9 @@ include ../shared/shared.mk
> OFILES = $(SHARED_OFILES) main.o shared.o maple-shim.o
> TARGETS = vma
>
> +# These can be varied to test different sizes.
> +CFLAGS += -DNUM_VMA_FLAG_BITS=128 -DNUM_MM_FLAG_BITS=128
> +
> main.o: main.c shared.c shared.h vma_internal.h tests/merge.c tests/mmap.c tests/vma.c ../../../mm/vma.c ../../../mm/vma_init.c ../../../mm/vma_exec.c ../../../mm/vma.h include/custom.h include/dup.h include/stubs.h
>
> vma: $(OFILES)
> diff --git a/tools/testing/vma/include/custom.h b/tools/testing/vma/include/custom.h
> index f567127efba9..802a76317245 100644
> --- a/tools/testing/vma/include/custom.h
> +++ b/tools/testing/vma/include/custom.h
> @@ -101,3 +101,19 @@ static inline void vma_lock_init(struct vm_area_struct *vma, bool reset_refcnt)
> if (reset_refcnt)
> refcount_set(&vma->vm_refcnt, 0);
> }
> +
> +static inline vma_flags_t __mk_vma_flags(size_t count, const vma_flag_t *bits)
> +{
> + vma_flags_t flags;
> + int i;
> +
> + /*
> + * For testing purposes: allow invalid bit specification so we can
> + * easily test.
> + */
> + vma_flags_clear_all(&flags);
> + for (i = 0; i < count; i++)
> + if (bits[i] < NUM_VMA_FLAG_BITS)
> + vma_flag_set(&flags, bits[i]);
> + return flags;
> +}
> diff --git a/tools/testing/vma/include/dup.h b/tools/testing/vma/include/dup.h
> index ed8708afb7af..31ee02f709b2 100644
> --- a/tools/testing/vma/include/dup.h
> +++ b/tools/testing/vma/include/dup.h
> @@ -838,16 +838,7 @@ static inline void vm_flags_clear(struct vm_area_struct *vma,
> vma_flags_clear_word(&vma->flags, flags);
> }
>
> -static inline vma_flags_t __mk_vma_flags(size_t count, const vma_flag_t *bits)
> -{
> - vma_flags_t flags;
> - int i;
> -
> - vma_flags_clear_all(&flags);
> - for (i = 0; i < count; i++)
> - vma_flag_set(&flags, bits[i]);
> - return flags;
> -}
> +static inline vma_flags_t __mk_vma_flags(size_t count, const vma_flag_t *bits);
>
> #define mk_vma_flags(...) __mk_vma_flags(COUNT_ARGS(__VA_ARGS__), \
> (const vma_flag_t []){__VA_ARGS__})
> diff --git a/tools/testing/vma/tests/vma.c b/tools/testing/vma/tests/vma.c
> index 6d9775aee243..c54ffc954f11 100644
> --- a/tools/testing/vma/tests/vma.c
> +++ b/tools/testing/vma/tests/vma.c
> @@ -1,5 +1,25 @@
> // SPDX-License-Identifier: GPL-2.0-or-later
>
> +static bool compare_legacy_flags(vm_flags_t legacy_flags, vma_flags_t flags)
> +{
> + const unsigned long legacy_val = legacy_flags;
> + /* The lower word should contain the precise same value. */
> + const unsigned long flags_lower = flags.__vma_flags[0];
> +#if NUM_VMA_FLAGS > BITS_PER_LONG
> + int i;
> +
> + /* All bits in higher flag values should be zero. */
> + for (i = 1; i < NUM_VMA_FLAGS / BITS_PER_LONG; i++) {
> + if (flags.__vma_flags[i] != 0)
> + return false;
> + }
> +#endif
> +
> + static_assert(sizeof(legacy_flags) == sizeof(unsigned long));
> +
> + return legacy_val == flags_lower;
> +}
> +
> static bool test_copy_vma(void)
> {
> vm_flags_t vm_flags = VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE;
> @@ -33,7 +53,287 @@ static bool test_copy_vma(void)
> return true;
> }
>
> +static bool test_vma_flags_unchanged(void)
> +{
> + vma_flags_t flags = EMPTY_VMA_FLAGS;
> + vm_flags_t legacy_flags = 0;
> + int bit;
> + struct vm_area_struct vma;
> + struct vm_area_desc desc;
> +
> +
> + vma.flags = EMPTY_VMA_FLAGS;
> + desc.vma_flags = EMPTY_VMA_FLAGS;
> +
> + for (bit = 0; bit < BITS_PER_LONG; bit++) {
> + vma_flags_t mask = mk_vma_flags(bit);
> +
> + legacy_flags |= (1UL << bit);
> +
> + /* Individual flags. */
> + vma_flags_set(&flags, bit);
> + ASSERT_TRUE(compare_legacy_flags(legacy_flags, flags));
> +
> + /* Via mask. */
> + vma_flags_set_mask(&flags, mask);
> + ASSERT_TRUE(compare_legacy_flags(legacy_flags, flags));
> +
> + /* Same for VMA. */
> + vma_set_flags(&vma, bit);
> + ASSERT_TRUE(compare_legacy_flags(legacy_flags, vma.flags));
> + vma_set_flags_mask(&vma, mask);
> + ASSERT_TRUE(compare_legacy_flags(legacy_flags, vma.flags));
> +
> + /* Same for VMA descriptor. */
> + vma_desc_set_flags(&desc, bit);
> + ASSERT_TRUE(compare_legacy_flags(legacy_flags, desc.vma_flags));
> + vma_desc_set_flags_mask(&desc, mask);
> + ASSERT_TRUE(compare_legacy_flags(legacy_flags, desc.vma_flags));
> + }
> +
> + return true;
> +}
> +
> +static bool test_vma_flags_cleared(void)
> +{
> + const vma_flags_t empty = EMPTY_VMA_FLAGS;
> + vma_flags_t flags;
> + int i;
> +
> + /* Set all bits high. */
> + memset(&flags, 1, sizeof(flags));
> + /* Try to clear. */
> + vma_flags_clear_all(&flags);
> + /* Equal to EMPTY_VMA_FLAGS? */
> + ASSERT_EQ(memcmp(&empty, &flags, sizeof(flags)), 0);
> + /* Make sure every unsigned long entry in bitmap array zero. */
> + for (i = 0; i < sizeof(flags) / BITS_PER_LONG; i++) {
> + const unsigned long val = flags.__vma_flags[i];
> +
> + ASSERT_EQ(val, 0);
> + }
> +
> + return true;
> +}
> +
> +/*
> + * Assert that VMA flag functions that operate at the system word level function
> + * correctly.
> + */
> +static bool test_vma_flags_word(void)
> +{
> + vma_flags_t flags = EMPTY_VMA_FLAGS;
> + const vma_flags_t comparison =
> + mk_vma_flags(VMA_READ_BIT, VMA_WRITE_BIT, 64, 65);
> +
> + /* Set some custom high flags. */
> + vma_flags_set(&flags, 64, 65);
> + /* Now overwrite the first word. */
> + vma_flags_overwrite_word(&flags, VM_READ | VM_WRITE);
> + /* Ensure they are equal. */
> + ASSERT_EQ(memcmp(&flags, &comparison, sizeof(flags)), 0);
> +
> + flags = EMPTY_VMA_FLAGS;
> + vma_flags_set(&flags, 64, 65);
> +
> + /* Do the same with the _once() equivalent. */
> + vma_flags_overwrite_word_once(&flags, VM_READ | VM_WRITE);
> + ASSERT_EQ(memcmp(&flags, &comparison, sizeof(flags)), 0);
> +
> + flags = EMPTY_VMA_FLAGS;
> + vma_flags_set(&flags, 64, 65);
> +
> + /* Make sure we can set a word without disturbing other bits. */
> + vma_flags_set(&flags, VMA_WRITE_BIT);
> + vma_flags_set_word(&flags, VM_READ);
> + ASSERT_EQ(memcmp(&flags, &comparison, sizeof(flags)), 0);
> +
> + flags = EMPTY_VMA_FLAGS;
> + vma_flags_set(&flags, 64, 65);
> +
> + /* Make sure we can clear a word without disturbing other bits. */
> + vma_flags_set(&flags, VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT);
> + vma_flags_clear_word(&flags, VM_EXEC);
> + ASSERT_EQ(memcmp(&flags, &comparison, sizeof(flags)), 0);
> +
> + return true;
> +}
> +
> +/* Ensure that vma_flags_test() and friends works correctly. */
> +static bool test_vma_flags_test(void)
> +{
> + const vma_flags_t flags = mk_vma_flags(VMA_READ_BIT, VMA_WRITE_BIT,
> + VMA_EXEC_BIT, 64, 65);
> + struct vm_area_struct vma;
> + struct vm_area_desc desc;
> +
> + vma.flags = flags;
> + desc.vma_flags = flags;
> +
> +#define do_test(...) \
> + ASSERT_TRUE(vma_flags_test(&flags, __VA_ARGS__)); \
> + ASSERT_TRUE(vma_desc_test_flags(&desc, __VA_ARGS__))
> +
> +#define do_test_all_true(...) \
> + ASSERT_TRUE(vma_flags_test_all(&flags, __VA_ARGS__)); \
> + ASSERT_TRUE(vma_test_all_flags(&vma, __VA_ARGS__))
> +
> +#define do_test_all_false(...) \
> + ASSERT_FALSE(vma_flags_test_all(&flags, __VA_ARGS__)); \
> + ASSERT_FALSE(vma_test_all_flags(&vma, __VA_ARGS__))
> +
> + /*
> + * Testing for some flags that are present, some that are not - should
> + * pass. ANY flags matching should work.
> + */
> + do_test(VMA_READ_BIT, VMA_MAYREAD_BIT, VMA_SEQ_READ_BIT);
> + /* However, the ...test_all() variant should NOT pass. */
> + do_test_all_false(VMA_READ_BIT, VMA_MAYREAD_BIT, VMA_SEQ_READ_BIT);
> + /* But should pass for flags present. */
> + do_test_all_true(VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT, 64, 65);
> + /* Also subsets... */
> + do_test_all_true(VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT, 64);
> + do_test_all_true(VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT);
> + do_test_all_true(VMA_READ_BIT, VMA_WRITE_BIT);
> + do_test_all_true(VMA_READ_BIT);
> + /*
> + * Check _mask variant. We don't need to test extensively as macro
> + * helper is the equivalent.
> + */
> + ASSERT_TRUE(vma_flags_test_mask(&flags, flags));
> + ASSERT_TRUE(vma_flags_test_all_mask(&flags, flags));
> +
> + /* Single bits. */
> + do_test(VMA_READ_BIT);
> + do_test(VMA_WRITE_BIT);
> + do_test(VMA_EXEC_BIT);
> +#if NUM_VMA_FLAG_BITS > 64
> + do_test(64);
> + do_test(65);
> +#endif
> +
> + /* Two bits. */
> + do_test(VMA_READ_BIT, VMA_WRITE_BIT);
> + do_test(VMA_READ_BIT, VMA_EXEC_BIT);
> + do_test(VMA_WRITE_BIT, VMA_EXEC_BIT);
> + /* Ordering shouldn't matter. */
> + do_test(VMA_WRITE_BIT, VMA_READ_BIT);
> + do_test(VMA_EXEC_BIT, VMA_READ_BIT);
> + do_test(VMA_EXEC_BIT, VMA_WRITE_BIT);
> +#if NUM_VMA_FLAG_BITS > 64
> + do_test(VMA_READ_BIT, 64);
> + do_test(VMA_WRITE_BIT, 64);
> + do_test(64, VMA_READ_BIT);
> + do_test(64, VMA_WRITE_BIT);
> + do_test(VMA_READ_BIT, 65);
> + do_test(VMA_WRITE_BIT, 65);
> + do_test(65, VMA_READ_BIT);
> + do_test(65, VMA_WRITE_BIT);
> +#endif
> + /* Three bits. */
> + do_test(VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT);
> +#if NUM_VMA_FLAG_BITS > 64
> + /* No need to consider every single permutation. */
> + do_test(VMA_READ_BIT, VMA_WRITE_BIT, 64);
> + do_test(VMA_READ_BIT, VMA_WRITE_BIT, 65);
> +
> + /* Four bits. */
> + do_test(VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT, 64);
> + do_test(VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT, 65);
> +
> + /* Five bits. */
> + do_test(VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT, 64, 65);
> +#endif
> +
> +#undef do_test
> +#undef do_test_all_true
> +#undef do_test_all_false
> +
> + return true;
> +}
> +
> +/* Ensure that vma_flags_clear() and friends works correctly. */
> +static bool test_vma_flags_clear(void)
> +{
> + vma_flags_t flags = mk_vma_flags(VMA_READ_BIT, VMA_WRITE_BIT,
> + VMA_EXEC_BIT, 64, 65);
> + vma_flags_t mask = mk_vma_flags(VMA_EXEC_BIT, 64);
> + struct vm_area_struct vma;
> + struct vm_area_desc desc;
> +
> + vma.flags = flags;
> + desc.vma_flags = flags;
> +
> + /* Cursory check of _mask() variant, as the helper macros imply. */
> + vma_flags_clear_mask(&flags, mask);
> + vma_flags_clear_mask(&vma.flags, mask);
> + vma_desc_clear_flags_mask(&desc, mask);
> + ASSERT_FALSE(vma_flags_test(&flags, VMA_EXEC_BIT, 64));
> + ASSERT_FALSE(vma_flags_test(&vma.flags, VMA_EXEC_BIT, 64));
> + ASSERT_FALSE(vma_desc_test_flags(&desc, VMA_EXEC_BIT, 64));
> + /* Reset. */
> + vma_flags_set(&flags, VMA_EXEC_BIT, 64);
> + vma_set_flags(&vma, VMA_EXEC_BIT, 64);
> + vma_desc_set_flags(&desc, VMA_EXEC_BIT, 64);
> +
> + /*
> + * Clear the flags and assert clear worked, then reset flags back to
> + * include specified flags.
> + */
> +#define do_test_and_reset(...) \
> + vma_flags_clear(&flags, __VA_ARGS__); \
> + vma_flags_clear(&vma.flags, __VA_ARGS__); \
> + vma_desc_clear_flags(&desc, __VA_ARGS__); \
> + ASSERT_FALSE(vma_flags_test(&flags, __VA_ARGS__)); \
> + ASSERT_FALSE(vma_flags_test(&vma.flags, __VA_ARGS__)); \
> + ASSERT_FALSE(vma_desc_test_flags(&desc, __VA_ARGS__)); \
> + vma_flags_set(&flags, __VA_ARGS__); \
> + vma_set_flags(&vma, __VA_ARGS__); \
> + vma_desc_set_flags(&desc, __VA_ARGS__)
> +
> + /* Single flags. */
> + do_test_and_reset(VMA_READ_BIT);
> + do_test_and_reset(VMA_WRITE_BIT);
> + do_test_and_reset(VMA_EXEC_BIT);
> + do_test_and_reset(64);
> + do_test_and_reset(65);
> +
> + /* Two flags, in different orders. */
> + do_test_and_reset(VMA_READ_BIT, VMA_WRITE_BIT);
> + do_test_and_reset(VMA_READ_BIT, VMA_EXEC_BIT);
> + do_test_and_reset(VMA_READ_BIT, 64);
> + do_test_and_reset(VMA_READ_BIT, 65);
> + do_test_and_reset(VMA_WRITE_BIT, VMA_READ_BIT);
> + do_test_and_reset(VMA_WRITE_BIT, VMA_EXEC_BIT);
> + do_test_and_reset(VMA_WRITE_BIT, 64);
> + do_test_and_reset(VMA_WRITE_BIT, 65);
> + do_test_and_reset(VMA_EXEC_BIT, VMA_READ_BIT);
> + do_test_and_reset(VMA_EXEC_BIT, VMA_WRITE_BIT);
> + do_test_and_reset(VMA_EXEC_BIT, 64);
> + do_test_and_reset(VMA_EXEC_BIT, 65);
> + do_test_and_reset(64, VMA_READ_BIT);
> + do_test_and_reset(64, VMA_WRITE_BIT);
> + do_test_and_reset(64, VMA_EXEC_BIT);
> + do_test_and_reset(64, 65);
> + do_test_and_reset(65, VMA_READ_BIT);
> + do_test_and_reset(65, VMA_WRITE_BIT);
> + do_test_and_reset(65, VMA_EXEC_BIT);
> + do_test_and_reset(65, 64);
> +
> + /* Three flags. */
> +
> +#undef do_test_some_missing
> +#undef do_test_and_reset
> +
> + return true;
> +}
> +
> static void run_vma_tests(int *num_tests, int *num_fail)
> {
> TEST(copy_vma);
> + TEST(vma_flags_unchanged);
> + TEST(vma_flags_cleared);
> + TEST(vma_flags_word);
> + TEST(vma_flags_test);
> + TEST(vma_flags_clear);
> }
> diff --git a/tools/testing/vma/vma_internal.h b/tools/testing/vma/vma_internal.h
> index e3ed05b57819..0e1121e2ef23 100644
> --- a/tools/testing/vma/vma_internal.h
> +++ b/tools/testing/vma/vma_internal.h
> @@ -36,11 +36,11 @@
> * ahead of all other headers.
> */
> #define __private
> -#define NUM_MM_FLAG_BITS (64)
> +/* NUM_MM_FLAG_BITS defined by test code. */
> typedef struct {
> __private DECLARE_BITMAP(__mm_flags, NUM_MM_FLAG_BITS);
> } mm_flags_t;
> -#define NUM_VMA_FLAG_BITS BITS_PER_LONG
> +/* NUM_VMA_FLAG_BITS defined by test code. */
> typedef struct {
> DECLARE_BITMAP(__vma_flags, NUM_VMA_FLAG_BITS);
> } __private vma_flags_t;
> --
> 2.52.0
>
^ permalink raw reply [flat|nested] 56+ messages in thread
* Re: [PATCH v2 00/13] mm: add bitmap VMA flag helpers and convert all mmap_prepare to use them
2026-01-22 16:06 [PATCH v2 00/13] mm: add bitmap VMA flag helpers and convert all mmap_prepare to use them Lorenzo Stoakes
` (12 preceding siblings ...)
2026-01-22 16:06 ` [PATCH v2 13/13] tools/testing/vma: add VMA userland tests for VMA flag functions Lorenzo Stoakes
@ 2026-01-22 16:56 ` Andrew Morton
2026-01-27 13:53 ` Yury Norov
14 siblings, 0 replies; 56+ messages in thread
From: Andrew Morton @ 2026-01-22 16:56 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Jarkko Sakkinen, Dave Hansen, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, x86, H . Peter Anvin, Arnd Bergmann,
Greg Kroah-Hartman, Dan Williams, Vishal Verma, Dave Jiang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
On Thu, 22 Jan 2026 16:06:09 +0000 Lorenzo Stoakes <lorenzo.stoakes@oracle.com> wrote:
> We introduced the bitmap VMA type vma_flags_t in the aptly named commit
> 9ea35a25d51b ("mm: introduce VMA flags bitmap type") in order to permit
> future growth in VMA flags and to prevent the asinine requirement that VMA
> flags be available to 64-bit kernels only if they happened to use a bit
> number about 32-bits.
>
> This is a long-term project as there are very many users of VMA flags
> within the kernel that need to be updated in order to utilise this new
> type.
>
> In order to further this aim, this series adds a number of helper functions
> to enable ordinary interactions with VMA flags - that is testing, setting
> and clearing them.
Thanks, I updated mm.git to this version.
I dropped the memfd_luo.c hunk due to today's inclusion of
https://lkml.kernel.org/r/20260122151842.4069702-3-pratyush@kernel.org
`get_maintainer --nogit' wants me to cc 72 people on this patchset. I
didn't ;)
^ permalink raw reply [flat|nested] 56+ messages in thread* Re: [PATCH v2 00/13] mm: add bitmap VMA flag helpers and convert all mmap_prepare to use them
2026-01-22 16:06 [PATCH v2 00/13] mm: add bitmap VMA flag helpers and convert all mmap_prepare to use them Lorenzo Stoakes
` (13 preceding siblings ...)
2026-01-22 16:56 ` [PATCH v2 00/13] mm: add bitmap VMA flag helpers and convert all mmap_prepare to use them Andrew Morton
@ 2026-01-27 13:53 ` Yury Norov
2026-01-27 14:40 ` Lorenzo Stoakes
14 siblings, 1 reply; 56+ messages in thread
From: Yury Norov @ 2026-01-27 13:53 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin,
Arnd Bergmann, Greg Kroah-Hartman, Dan Williams, Vishal Verma,
Dave Jiang, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
On Thu, Jan 22, 2026 at 04:06:09PM +0000, Lorenzo Stoakes wrote:
> We introduced the bitmap VMA type vma_flags_t in the aptly named commit
> 9ea35a25d51b ("mm: introduce VMA flags bitmap type") in order to permit
> future growth in VMA flags and to prevent the asinine requirement that VMA
> flags be available to 64-bit kernels only if they happened to use a bit
> number about 32-bits.
>
> This is a long-term project as there are very many users of VMA flags
> within the kernel that need to be updated in order to utilise this new
> type.
>
> In order to further this aim, this series adds a number of helper functions
> to enable ordinary interactions with VMA flags - that is testing, setting
> and clearing them.
>
> In order to make working with VMA bit numbers less cumbersome this series
> introduces the mk_vma_flags() helper macro which generates a vma_flags_t
> from a variadic parameter list, e.g.:
>
> vma_flags_t flags = mk_vma_flags(VMA_READ_BIT, VMA_WRITE_BIT,
> VMA_EXEC_BIT);
This should go on the bitmaps level. There's at least one another
possible client for this function - mm_flags_t. Maybe another generic
header bitmap_flags.h?
> It turns out that the compiler optimises this very well to the point that
> this is just as efficient as using VM_xxx pre-computed bitmap values.
It turns out, it's not a compiler - it's people writing code well. :)
Can you please mention the test_bitmap_const_eval() here and also
discuss configurations that break compile-time evaluation, like
KASAN+GCOV?
> This series then introduces the following functions:
>
> bool vma_flags_test_mask(vma_flags_t flags, vma_flags_t to_test);
> bool vma_flags_test_all_mask(vma_flags_t flags, vma_flags_t to_test);
> void vma_flags_set_mask(vma_flags_t *flags, vma_flags_t to_set);
> void vma_flags_clear_mask(vma_flags_t *flags, vma_flags_t to_clear);
>
> Providing means of testing any flag, testing all flags, setting, and clearing a
> specific vma_flags_t mask.
>
> For convenience, helper macros are provided - vma_flags_test(),
> vma_flags_set() and vma_flags_clear(), each of which utilise mk_vma_flags()
> to make these operations easier, as well as an EMPTY_VMA_FLAGS macro to
> make initialisation of an empty vma_flags_t value easier, e.g.:
>
> vma_flags_t flags = EMPTY_VMA_FLAGS;
>
> vma_flags_set(&flags, VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT);
> ...
> if (vma_flags_test(flags, VMA_READ_BIT)) {
> ...
> }
> ...
> if (vma_flags_test_all_mask(flags, VMA_REMAP_FLAGS)) {
> ...
> }
> ...
> vma_flags_clear(&flags, VMA_READ_BIT);
>
> Since callers are often dealing with a vm_area_struct (VMA) or vm_area_desc
> (VMA descriptor as used in .mmap_prepare) object, this series further
> provides helpers for these - firstly vma_set_flags_mask() and vma_set_flags() for a
> VMA:
>
> vma_flags_t flags = EMPTY_VMA_FLAGS:
>
> vma_flags_set(&flags, VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT);
> ...
> vma_set_flags_mask(&vma, flags);
> ...
> vma_set_flags(&vma, VMA_DONTDUMP_BIT);
Having both vma_set_flags() and vma_flags_set() looks confusing...
> Note that these do NOT ensure appropriate locks are taken and assume the
> callers takes care of this.
>
> For VMA descriptors this series adds vma_desc_[test, set,
> clear]_flags_mask() and vma_desc_[test, set, clear]_flags() for a VMA
> descriptor, e.g.:
>
> static int foo_mmap_prepare(struct vm_area_desc *desc)
> {
> ...
> vma_desc_set_flags(desc, VMA_SEQ_READ_BIT);
> vma_desc_clear_flags(desc, VMA_RAND_READ_BIT);
> ...
> if (vma_desc_test_flags(desc, VMA_SHARED_BIT) {
> ...
> }
> ...
> }
>
> With these helpers introduced, this series then updates all mmap_prepare
> users to make use of the vma_flags_t vm_area_desc->vma_flags field rather
> than the legacy vm_flags_t vm_area_desc->vm_flags field.
>
> In order to do so, several other related functions need to be updated, with
> separate patches for larger changes in hugetlbfs, secretmem and shmem
> before finally removing vm_area_desc->vm_flags altogether.
>
> This lays the foundations for future elimination of vm_flags_t and
> associated defines and functionality altogether in the long run, and
> elimination of the use of vm_flags_t in f_op->mmap() hooks in the near term
> as mmap_prepare replaces these.
>
> There is a useful synergy between the VMA flags and mmap_prepare work here
> as with this change in place, converting f_op->mmap() to f_op->mmap_prepare
> naturally also converts use of vm_flags_t to vma_flags_t in all drivers
> which declare mmap handlers.
>
> This accounts for the majority of the users of the legacy vm_flags_*()
> helpers and thus a large number of drivers which need to interact with VMA
> flags in general.
>
> This series also updates the userland VMA tests to account for the change,
> and adds unit tests for these helper functions to assert that they behave
> as expected.
>
> In order to faciliate this change in a sensible way, the series also
> separates out the VMA unit tests into - code that is duplicated from the
> kernel that should be kept in sync, code that is customised for test
> purposes and code that is stubbed out.
>
> We also separate out the VMA userland tests into separate files to make it
> easier to manage and to provide a sensible baseline for adding the userland
> tests for these helpers.
>
>
> REVIEWS NOTE: I rebased this on
> https://lore.kernel.org/linux-mm/cover.1769086312.git.lorenzo.stoakes@oracle.com/
> in order to make life easier with conflict resolutions.
Before I deep into implementation details, can you share more background?
It seems you're implementing an arbitrary-length flags for VMAs, but the
length that you actually set is unconditionally 64. So why just not use
u64 for this?
Even if you expect adding more flags, u128 would double your capacity,
and people will still be able to use language-supported operation on
the bits in flag. Which looks simpler to me...
Thanks,
Yury
^ permalink raw reply [flat|nested] 56+ messages in thread* Re: [PATCH v2 00/13] mm: add bitmap VMA flag helpers and convert all mmap_prepare to use them
2026-01-27 13:53 ` Yury Norov
@ 2026-01-27 14:40 ` Lorenzo Stoakes
2026-01-27 21:36 ` Yury Norov
0 siblings, 1 reply; 56+ messages in thread
From: Lorenzo Stoakes @ 2026-01-27 14:40 UTC (permalink / raw)
To: Yury Norov
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin,
Arnd Bergmann, Greg Kroah-Hartman, Dan Williams, Vishal Verma,
Dave Jiang, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
On Tue, Jan 27, 2026 at 08:53:44AM -0500, Yury Norov wrote:
> On Thu, Jan 22, 2026 at 04:06:09PM +0000, Lorenzo Stoakes wrote:
> > We introduced the bitmap VMA type vma_flags_t in the aptly named commit
> > 9ea35a25d51b ("mm: introduce VMA flags bitmap type") in order to permit
> > future growth in VMA flags and to prevent the asinine requirement that VMA
> > flags be available to 64-bit kernels only if they happened to use a bit
> > number about 32-bits.
> >
> > This is a long-term project as there are very many users of VMA flags
> > within the kernel that need to be updated in order to utilise this new
> > type.
> >
> > In order to further this aim, this series adds a number of helper functions
> > to enable ordinary interactions with VMA flags - that is testing, setting
> > and clearing them.
> >
> > In order to make working with VMA bit numbers less cumbersome this series
> > introduces the mk_vma_flags() helper macro which generates a vma_flags_t
> > from a variadic parameter list, e.g.:
> >
> > vma_flags_t flags = mk_vma_flags(VMA_READ_BIT, VMA_WRITE_BIT,
> > VMA_EXEC_BIT);
>
> This should go on the bitmaps level. There's at least one another
> possible client for this function - mm_flags_t. Maybe another generic
> header bitmap_flags.h?
Well as the implementor of mm_flags_t I'm aware of this case :P
mm flags doesn't really need it as users were already using set_bit(),
clear_bit(), etc. and don't often set multiple flags.
I also would rather not make this too generic at this point, I explicitly want
an opaque type for describing VMA flags for type safety even if underneath it's
a bitmap.
>
> > It turns out that the compiler optimises this very well to the point that
> > this is just as efficient as using VM_xxx pre-computed bitmap values.
>
> It turns out, it's not a compiler - it's people writing code well. :)
> Can you please mention the test_bitmap_const_eval() here and also
> discuss configurations that break compile-time evaluation, like
> KASAN+GCOV?
Ah I wasn't even aware of this... :) so thanks for the heads up and thanks to
everybody who worked to make sure this was the case :)
That's useful information re:kasan,gcov. And I see you addressed this in the
test there in commit 2356d198d2b4 :)
If it makes sense to you I'll update it if I do a respin, since the Link: to
this discussion should provide this very additional background :) But I have
noted it down to change if/when any respin of this happens, if that's ok with
you?
In terms of impact, well users who are using KASAN/GCOV are already asking for
performance impact so it isn't too egregious.
>
> > This series then introduces the following functions:
> >
> > bool vma_flags_test_mask(vma_flags_t flags, vma_flags_t to_test);
> > bool vma_flags_test_all_mask(vma_flags_t flags, vma_flags_t to_test);
> > void vma_flags_set_mask(vma_flags_t *flags, vma_flags_t to_set);
> > void vma_flags_clear_mask(vma_flags_t *flags, vma_flags_t to_clear);
> >
> > Providing means of testing any flag, testing all flags, setting, and clearing a
> > specific vma_flags_t mask.
> >
> > For convenience, helper macros are provided - vma_flags_test(),
> > vma_flags_set() and vma_flags_clear(), each of which utilise mk_vma_flags()
> > to make these operations easier, as well as an EMPTY_VMA_FLAGS macro to
> > make initialisation of an empty vma_flags_t value easier, e.g.:
> >
> > vma_flags_t flags = EMPTY_VMA_FLAGS;
> >
> > vma_flags_set(&flags, VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT);
> > ...
> > if (vma_flags_test(flags, VMA_READ_BIT)) {
> > ...
> > }
> > ...
> > if (vma_flags_test_all_mask(flags, VMA_REMAP_FLAGS)) {
> > ...
> > }
> > ...
> > vma_flags_clear(&flags, VMA_READ_BIT);
> >
> > Since callers are often dealing with a vm_area_struct (VMA) or vm_area_desc
> > (VMA descriptor as used in .mmap_prepare) object, this series further
> > provides helpers for these - firstly vma_set_flags_mask() and vma_set_flags() for a
> > VMA:
> >
> > vma_flags_t flags = EMPTY_VMA_FLAGS:
> >
> > vma_flags_set(&flags, VMA_READ_BIT, VMA_WRITE_BIT, VMA_EXEC_BIT);
> > ...
> > vma_set_flags_mask(&vma, flags);
> > ...
> > vma_set_flags(&vma, VMA_DONTDUMP_BIT);
>
> Having both vma_set_flags() and vma_flags_set() looks confusing...
It's a trade-off against readability. I don't want these helpers to be too long.
Yes it's possibly confusing, but I keep a
consistent convention of [thing we are doing action on]_[action]_flags() and when
dealing with pure vma flags - vma_flags_[action]().
You're not going to run into issues with accidentally choosing the wrong one -
as it's strongly typed (well as strongly typed as C gets anyway) so the compiler
will catch mistakes.
So I think it's not too bad this way.
>
> > Note that these do NOT ensure appropriate locks are taken and assume the
> > callers takes care of this.
> >
> > For VMA descriptors this series adds vma_desc_[test, set,
> > clear]_flags_mask() and vma_desc_[test, set, clear]_flags() for a VMA
> > descriptor, e.g.:
> >
> > static int foo_mmap_prepare(struct vm_area_desc *desc)
> > {
> > ...
> > vma_desc_set_flags(desc, VMA_SEQ_READ_BIT);
> > vma_desc_clear_flags(desc, VMA_RAND_READ_BIT);
> > ...
> > if (vma_desc_test_flags(desc, VMA_SHARED_BIT) {
> > ...
> > }
> > ...
> > }
> >
> > With these helpers introduced, this series then updates all mmap_prepare
> > users to make use of the vma_flags_t vm_area_desc->vma_flags field rather
> > than the legacy vm_flags_t vm_area_desc->vm_flags field.
> >
> > In order to do so, several other related functions need to be updated, with
> > separate patches for larger changes in hugetlbfs, secretmem and shmem
> > before finally removing vm_area_desc->vm_flags altogether.
> >
> > This lays the foundations for future elimination of vm_flags_t and
> > associated defines and functionality altogether in the long run, and
> > elimination of the use of vm_flags_t in f_op->mmap() hooks in the near term
> > as mmap_prepare replaces these.
> >
> > There is a useful synergy between the VMA flags and mmap_prepare work here
> > as with this change in place, converting f_op->mmap() to f_op->mmap_prepare
> > naturally also converts use of vm_flags_t to vma_flags_t in all drivers
> > which declare mmap handlers.
> >
> > This accounts for the majority of the users of the legacy vm_flags_*()
> > helpers and thus a large number of drivers which need to interact with VMA
> > flags in general.
> >
> > This series also updates the userland VMA tests to account for the change,
> > and adds unit tests for these helper functions to assert that they behave
> > as expected.
> >
> > In order to faciliate this change in a sensible way, the series also
> > separates out the VMA unit tests into - code that is duplicated from the
> > kernel that should be kept in sync, code that is customised for test
> > purposes and code that is stubbed out.
> >
> > We also separate out the VMA userland tests into separate files to make it
> > easier to manage and to provide a sensible baseline for adding the userland
> > tests for these helpers.
> >
> >
> > REVIEWS NOTE: I rebased this on
> > https://lore.kernel.org/linux-mm/cover.1769086312.git.lorenzo.stoakes@oracle.com/
> > in order to make life easier with conflict resolutions.
>
> Before I deep into implementation details, can you share more background?
I'm surprised the above isn't enough but the background is that we currently
cannot implement certain features for all kernels because for 32-bit kernels we
have run out of VMA flags.
We are utilising new VMA flags for new features which make them 64-bit only with
annoying checks added everywhere to account for this, and there are a finite
number avaialble.
To future-proof the kernel we want to be able to adjust this as we please in
future.
>
> It seems you're implementing an arbitrary-length flags for VMAs, but the
> length that you actually set is unconditionally 64. So why just not use
> u64 for this?
It's not unconditionaly 64 (yet), it's currently equal to the system word size
so we can union this with the existing legacy VMA flags:
#define NUM_VMA_FLAG_BITS BITS_PER_LONG
I'll answer the 'why not u64' below.
>
> Even if you expect adding more flags, u128 would double your capacity,
> and people will still be able to use language-supported operation on
> the bits in flag. Which looks simpler to me...
u128 isn't supported on all architectures, VMA flags have to have absolutely
universal support.
We want to be able to arbitrarily extend this as we please in the future. So
using u64 wouldn't buy us _anything_ except getting the 32-bit kernels in line.
Using an integral value doesn't give us any kind of type safety, nor does it
give us as easy a means to track what users are doing with flags - both
additional benefits of this change.
>
> Thanks,
> Yury
Cheers, Lorenzo
^ permalink raw reply [flat|nested] 56+ messages in thread* Re: [PATCH v2 00/13] mm: add bitmap VMA flag helpers and convert all mmap_prepare to use them
2026-01-27 14:40 ` Lorenzo Stoakes
@ 2026-01-27 21:36 ` Yury Norov
2026-01-28 9:33 ` Lorenzo Stoakes
0 siblings, 1 reply; 56+ messages in thread
From: Yury Norov @ 2026-01-27 21:36 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin,
Arnd Bergmann, Greg Kroah-Hartman, Dan Williams, Vishal Verma,
Dave Jiang, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
On Tue, Jan 27, 2026 at 02:40:03PM +0000, Lorenzo Stoakes wrote:
> On Tue, Jan 27, 2026 at 08:53:44AM -0500, Yury Norov wrote:
> > On Thu, Jan 22, 2026 at 04:06:09PM +0000, Lorenzo Stoakes wrote:
...
> > Even if you expect adding more flags, u128 would double your capacity,
> > and people will still be able to use language-supported operation on
> > the bits in flag. Which looks simpler to me...
>
> u128 isn't supported on all architectures, VMA flags have to have absolutely
What about big integers?
typedef unsigned _BitInt(VMA_FLAGS_COUNT) vma_flags_t
> We want to be able to arbitrarily extend this as we please in the future. So
> using u64 wouldn't buy us _anything_ except getting the 32-bit kernels in line.
So enabling 32-bit arches is a big deal, even if it's a temporary
solution. Again, how many flags in your opinion are blocked because of
32-bit integer limitation? How soon 64-bit capacity will get fully
used?
> Using an integral value doesn't give us any kind of type safety, nor does it
> give us as easy a means to track what users are doing with flags - both
> additional benefits of this change.
I tried the below, and it works OK for me with i386:
$ cat bi.c
#include <stdio.h>
#include <limits.h>
int main() {
unsigned _BitInt(128) a = (_BitInt(128))1 << 65;
unsigned _BitInt(128) b = (_BitInt(128))1 << 66;
printf("a | b == %llx\n", (unsigned long long)((a | b)>>64));
printf("BITINT_MAXWIDTH == 0x%x\n", BITINT_MAXWIDTH);
return 0;
}
$ clang -m32 -std=c2x bi.c
$ ./a.out
a | b == 6
BITINT_MAXWIDTH == 0x800000
I didn't make GCC building it, at least out of the box. So the above
question about 64-bit capacity has a practical meaning. If we've got a
few years to let GCC fully support big integers as clang does, we don't
have to wish anything else.
I'd like to put it right. I maintain bitmaps, and I like it widely
adopted. But when it comes to flags, being able to use plain logic
operations looks so important to me so I'd like to make sure that
switching to bitmaps is the only working option.
^ permalink raw reply [flat|nested] 56+ messages in thread* Re: [PATCH v2 00/13] mm: add bitmap VMA flag helpers and convert all mmap_prepare to use them
2026-01-27 21:36 ` Yury Norov
@ 2026-01-28 9:33 ` Lorenzo Stoakes
2026-01-28 15:50 ` Pedro Falcato
0 siblings, 1 reply; 56+ messages in thread
From: Lorenzo Stoakes @ 2026-01-28 9:33 UTC (permalink / raw)
To: Yury Norov
Cc: Andrew Morton, Jarkko Sakkinen, Dave Hansen, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, x86, H . Peter Anvin,
Arnd Bergmann, Greg Kroah-Hartman, Dan Williams, Vishal Verma,
Dave Jiang, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Jani Nikula, Joonas Lahtinen,
Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig, Huang Rui,
Matthew Auld, Matthew Brost, Alexander Viro, Christian Brauner,
Jan Kara, Benjamin LaHaise, Gao Xiang, Chao Yu, Yue Hu,
Jeffle Xu, Sandeep Dhavale, Hongbo Li, Chunhai Guo,
Theodore Ts'o, Andreas Dilger, Muchun Song, Oscar Salvador,
David Hildenbrand, Konstantin Komarov, Mike Marshall,
Martin Brandenburg, Tony Luck, Reinette Chatre, Dave Martin,
James Morse, Babu Moger, Carlos Maiolino, Damien Le Moal,
Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, Pedro Falcato, David Howells, Paul Moore,
James Morris, Serge E . Hallyn, Yury Norov, Rasmus Villemoes,
linux-sgx, linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
On Tue, Jan 27, 2026 at 04:36:44PM -0500, Yury Norov wrote:
> On Tue, Jan 27, 2026 at 02:40:03PM +0000, Lorenzo Stoakes wrote:
> > On Tue, Jan 27, 2026 at 08:53:44AM -0500, Yury Norov wrote:
> > > On Thu, Jan 22, 2026 at 04:06:09PM +0000, Lorenzo Stoakes wrote:
>
> ...
>
> > > Even if you expect adding more flags, u128 would double your capacity,
> > > and people will still be able to use language-supported operation on
> > > the bits in flag. Which looks simpler to me...
> >
> > u128 isn't supported on all architectures, VMA flags have to have absolutely
>
> What about big integers?
>
> typedef unsigned _BitInt(VMA_FLAGS_COUNT) vma_flags_t
There is no use of _BitInt anywhere in the kernel. That seems to be a
C23-only feature with limited compiler support that we simply couldn't use
yet.
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3639r0.html tells
me that it's supported in clang 16+ and gcc 14+.
We cannot put such a restriction on compilers in the kernel, obviously.
>
> > We want to be able to arbitrarily extend this as we please in the future. So
> > using u64 wouldn't buy us _anything_ except getting the 32-bit kernels in line.
>
> So enabling 32-bit arches is a big deal, even if it's a temporary
> solution. Again, how many flags in your opinion are blocked because of
> 32-bit integer limitation? How soon 64-bit capacity will get fully
> used?
In my opinion? I'm not sure where my opinion comes into this? There are 43 VMA
flags and 32-bits available in 32-bit kernels.
As I said to you before Yury, when adding new flags you have to add a whole
load of mess of #ifdef CONFIG_64BIT ... #endif etc. around things that have
nothing to do with 64-bit vs 32-bit architecture as a result.
It's a mess, we've run out.
Also something that might not have occurred to you - there is a chilling
effect of limited VMA flag availability - the bar to adding flags is
higher, and features that might have used VMA flags but need general kernel
support (incl. 32-bit) have to find other ways to store state like this.
>
> > Using an integral value doesn't give us any kind of type safety, nor does it
> > give us as easy a means to track what users are doing with flags - both
> > additional benefits of this change.
>
> I tried the below, and it works OK for me with i386:
>
> $ cat bi.c
> #include <stdio.h>
> #include <limits.h>
>
> int main() {
> unsigned _BitInt(128) a = (_BitInt(128))1 << 65;
> unsigned _BitInt(128) b = (_BitInt(128))1 << 66;
>
> printf("a | b == %llx\n", (unsigned long long)((a | b)>>64));
> printf("BITINT_MAXWIDTH == 0x%x\n", BITINT_MAXWIDTH);
>
> return 0;
> }
>
> $ clang -m32 -std=c2x bi.c
> $ ./a.out
> a | b == 6
> BITINT_MAXWIDTH == 0x800000
I'm not sure why you're replying to my points about type safety,
traceability with this program but OK?
I mean thanks for that, I wasn't aware of the c23 standard (proposal?)
_BitInt(). It's useful to know that.
We can't use it right now, but it's good to know for the future.
>
> I didn't make GCC building it, at least out of the box. So the above
> question about 64-bit capacity has a practical meaning. If we've got a
> few years to let GCC fully support big integers as clang does, we don't
> have to wish anything else.
As long as you assume that all architectures will be supported, all
compilers used by users to build the kernel will support it, and Linus will
be fine with us using this.
That could be years, that could be never.
Also - and here's a really important point - the underlying implementation
_doesn't matter_.
Right now it's bitmaps.
By abstracting the VMA flags into an opaque type and providing helper
functions we also enable the ability to _change the implementation_.
So if this time comes, we can simply switch everything over. Job done.
Your suggested 'do nothing and hope' approach achieves none of this.
>
> I'd like to put it right. I maintain bitmaps, and I like it widely
> adopted. But when it comes to flags, being able to use plain logic
> operations looks so important to me so I'd like to make sure that
> switching to bitmaps is the only working option.
I'm not sure you're making a technical argument here?
From the point of view of mm, the ability to arbitrarily manipulate VMA
flags is a bug not a feature. The other part of this series is to make
changes to the f_op->mmap_prepare feature, which was explicitly implemented
in order to avoid such arbitrarily behaviour from drivers.
It's actually hugely valueable to make this change in such a way as we can
trace, with type safety, VMA flag usage throughout the kernel, and know
that for instance - on mmap setup - we don't need to worry about VMA
stabilisation - which feeds into other work re: killable VMA locks.
In summary, this series represents a workable and sensible means of
addressing all of these issues in one fell swoop, similar to the means
through which mm flags were extended across both 32-bit and 64-bit kernels.
We can in future choose to use _BitInt(), u128, or whatever we please
underneath, and which makes sense to use should conditions change and we
choose to do so for good technical reasons.
Any argument on the basis of 'allow the flags to continue to be manipulated
as they are' is I think mistaken.
Keep in mind that bitmap VMA flags are _already_ a merged feature in the
kernel, and this series only works to add sensible helper functions to
manipulate these flags and moves mmap_prepare to using them exclusively.
If we find cases where somehow the compiler does the wrong thing, we
already have functions in mm_types.h that allow us to address the first
system-word bits of the underlying type and can restrict core flags to
being at system word count or less.
I hope that won't ever be necessary, but we have means of adressing that
should any issue arise like that.
Thanks, Lorenzo
^ permalink raw reply [flat|nested] 56+ messages in thread* Re: [PATCH v2 00/13] mm: add bitmap VMA flag helpers and convert all mmap_prepare to use them
2026-01-28 9:33 ` Lorenzo Stoakes
@ 2026-01-28 15:50 ` Pedro Falcato
0 siblings, 0 replies; 56+ messages in thread
From: Pedro Falcato @ 2026-01-28 15:50 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Yury Norov, Andrew Morton, Jarkko Sakkinen, Dave Hansen,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, x86,
H . Peter Anvin, Arnd Bergmann, Greg Kroah-Hartman, Dan Williams,
Vishal Verma, Dave Jiang, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Jani Nikula,
Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Christian Koenig,
Huang Rui, Matthew Auld, Matthew Brost, Alexander Viro,
Christian Brauner, Jan Kara, Benjamin LaHaise, Gao Xiang,
Chao Yu, Yue Hu, Jeffle Xu, Sandeep Dhavale, Hongbo Li,
Chunhai Guo, Theodore Ts'o, Andreas Dilger, Muchun Song,
Oscar Salvador, David Hildenbrand, Konstantin Komarov,
Mike Marshall, Martin Brandenburg, Tony Luck, Reinette Chatre,
Dave Martin, James Morse, Babu Moger, Carlos Maiolino,
Damien Le Moal, Naohiro Aota, Johannes Thumshirn, Matthew Wilcox,
Liam R . Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Hugh Dickins, Baolin Wang,
Zi Yan, Nico Pache, Ryan Roberts, Dev Jain, Barry Song,
Lance Yang, Jann Horn, David Howells, Paul Moore, James Morris,
Serge E . Hallyn, Yury Norov, Rasmus Villemoes, linux-sgx,
linux-kernel, nvdimm, linux-cxl, dri-devel, intel-gfx,
linux-fsdevel, linux-aio, linux-erofs, linux-ext4, linux-mm,
ntfs3, devel, linux-xfs, keyrings, linux-security-module,
Jason Gunthorpe
On Wed, Jan 28, 2026 at 09:33:44AM +0000, Lorenzo Stoakes wrote:
> On Tue, Jan 27, 2026 at 04:36:44PM -0500, Yury Norov wrote:
> > On Tue, Jan 27, 2026 at 02:40:03PM +0000, Lorenzo Stoakes wrote:
> > > On Tue, Jan 27, 2026 at 08:53:44AM -0500, Yury Norov wrote:
> > > > On Thu, Jan 22, 2026 at 04:06:09PM +0000, Lorenzo Stoakes wrote:
> >
> > ...
> >
> > > > Even if you expect adding more flags, u128 would double your capacity,
> > > > and people will still be able to use language-supported operation on
> > > > the bits in flag. Which looks simpler to me...
> > >
> > > u128 isn't supported on all architectures, VMA flags have to have absolutely
> >
> > What about big integers?
> >
> > typedef unsigned _BitInt(VMA_FLAGS_COUNT) vma_flags_t
>
> There is no use of _BitInt anywhere in the kernel. That seems to be a
> C23-only feature with limited compiler support that we simply couldn't use
> yet.
>
> https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p3639r0.html tells
> me that it's supported in clang 16+ and gcc 14+.
>
> We cannot put such a restriction on compilers in the kernel, obviously.
>
> >
> > > We want to be able to arbitrarily extend this as we please in the future. So
> > > using u64 wouldn't buy us _anything_ except getting the 32-bit kernels in line.
> >
> > So enabling 32-bit arches is a big deal, even if it's a temporary
> > solution. Again, how many flags in your opinion are blocked because of
> > 32-bit integer limitation? How soon 64-bit capacity will get fully
> > used?
>
> In my opinion? I'm not sure where my opinion comes into this? There are 43 VMA
> flags and 32-bits available in 32-bit kernels.
>
> As I said to you before Yury, when adding new flags you have to add a whole
> load of mess of #ifdef CONFIG_64BIT ... #endif etc. around things that have
> nothing to do with 64-bit vs 32-bit architecture as a result.
>
> It's a mess, we've run out.
>
> Also something that might not have occurred to you - there is a chilling
> effect of limited VMA flag availability - the bar to adding flags is
> higher, and features that might have used VMA flags but need general kernel
> support (incl. 32-bit) have to find other ways to store state like this.
>
For the record, I fully agree with all of the points you made. I don't think
it makes sense to hold this change back waiting for a feature that right
now is relatively unobtainable (also IIRC the ABI around _BitInt was a bit
unstable and confusing in general, I don't know if that changed).
The goals are to:
1) get more than sizeof(unsigned long) * 8 flags so we don't have to uglify
and gatekeep things behind 64-bit. Also letting us use VMA flags more freely.
2) not cause any performance/codegen regression
Yes, the current patchset (and the current state of things too) uglifies
things a bit, but it also provides things like type safety which are sorely
needed here. And which 128-bit integers, or N-bit integers would not provide.
And if any of the above suddenly become available to us in the future, it
will be trivial to change because the VMA flags types will be fully
encapsulated with proper accessors.
Or perhaps we'll rewrite it all in rust by the end of the decade and this is
all a moot point, who knows ;)
--
Pedro
^ permalink raw reply [flat|nested] 56+ messages in thread