Re: [PATCH v2 03/13] mm: add mk_vma_flags() bitmap flag macro helper

Liam R. Howlett
2026-02-09T18:45:18Z

* 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
>