We are currently in the bizarre situation where we are constrained on the
number of flags we can set in an mm_struct based on whether this is a
32-bit or 64-bit kernel.
This is because mm->flags is an unsigned long field, which is 32-bits on a
32-bit system and 64-bits on a 64-bit system.
In order to keep things functional across both architectures, we do not
permit mm flag bits to be set above flag 31 (i.e. the 32nd bit).
This is a silly situation, especially given how profligate we are in
storing metadata in mm_struct, so let's convert mm->flags into a bitmap and
allow ourselves as many bits as we like.
To keep things manageable, firstly we introduce the bitmap at a system word
system as a new field mm->_flags, in union.
This means the new bitmap mm->_flags is bitwise exactly identical to the
existing mm->flags field.
We have an opportunity to also introduce some type safety here, so let's
wrap the mm flags field as a struct and declare it as an mm_flags_t typedef
to keep it consistent with vm_flags_t for VMAs.
We make the internal field privately accessible, in order to force the use
of helper functions so we can enforce that accesses are bitwise as
required.
We therefore introduce accessors prefixed with mm_flags_*() for callers to
use. We place the bit parameter first so as to match the parameter ordering
of the *_bit() functions.
Having this temporary union arrangement allows us to incrementally swap
over users of mm->flags patch-by-patch rather than having to do everything
in one fell swoop.
Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
---
include/linux/mm.h | 32 ++++++++++++++++++++++++++++++++
include/linux/mm_types.h | 39 ++++++++++++++++++++++++++++++++++++++-
2 files changed, 70 insertions(+), 1 deletion(-)
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 3868ca1a25f9..4ed4a0b9dad6 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -34,6 +34,8 @@
#include <linux/slab.h>
#include <linux/cacheinfo.h>
#include <linux/rcuwait.h>
+#include <linux/bitmap.h>
+#include <linux/bitops.h>
struct mempolicy;
struct anon_vma;
@@ -720,6 +722,36 @@ static inline void assert_fault_locked(struct vm_fault *vmf)
}
#endif /* CONFIG_PER_VMA_LOCK */
+static inline bool mm_flags_test(int flag, const struct mm_struct *mm)
+{
+ return test_bit(flag, ACCESS_PRIVATE(&mm->_flags, __mm_flags));
+}
+
+static inline bool mm_flags_test_and_set(int flag, struct mm_struct *mm)
+{
+ return test_and_set_bit(flag, ACCESS_PRIVATE(&mm->_flags, __mm_flags));
+}
+
+static inline bool mm_flags_test_and_clear(int flag, struct mm_struct *mm)
+{
+ return test_and_clear_bit(flag, ACCESS_PRIVATE(&mm->_flags, __mm_flags));
+}
+
+static inline void mm_flags_set(int flag, struct mm_struct *mm)
+{
+ set_bit(flag, ACCESS_PRIVATE(&mm->_flags, __mm_flags));
+}
+
+static inline void mm_flags_clear(int flag, struct mm_struct *mm)
+{
+ clear_bit(flag, ACCESS_PRIVATE(&mm->_flags, __mm_flags));
+}
+
+static inline void mm_flags_clear_all(struct mm_struct *mm)
+{
+ bitmap_zero(ACCESS_PRIVATE(&mm->_flags, __mm_flags), NUM_MM_FLAG_BITS);
+}
+
extern const struct vm_operations_struct vma_dummy_vm_ops;
static inline void vma_init(struct vm_area_struct *vma, struct mm_struct *mm)
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index cf94df4955c7..46d3fb8935c7 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -20,6 +20,7 @@
#include <linux/seqlock.h>
#include <linux/percpu_counter.h>
#include <linux/types.h>
+#include <linux/bitmap.h>
#include <asm/mmu.h>
@@ -927,6 +928,15 @@ struct mm_cid {
};
#endif
+/*
+ * Opaque type representing current mm_struct flag state. Must be accessed via
+ * mm_flags_xxx() helper functions.
+ */
+#define NUM_MM_FLAG_BITS BITS_PER_LONG
+typedef struct {
+ __private DECLARE_BITMAP(__mm_flags, NUM_MM_FLAG_BITS);
+} mm_flags_t;
+
struct kioctx_table;
struct iommu_mm_data;
struct mm_struct {
@@ -1109,7 +1119,11 @@ struct mm_struct {
/* Architecture-specific MM context */
mm_context_t context;
- unsigned long flags; /* Must use atomic bitops to access */
+ /* Temporary union while we convert users to mm_flags_t. */
+ union {
+ unsigned long flags; /* Must use atomic bitops to access */
+ mm_flags_t _flags; /* Must use mm_flags_* helpers to access */
+ };
#ifdef CONFIG_AIO
spinlock_t ioctx_lock;
@@ -1219,6 +1233,29 @@ struct mm_struct {
unsigned long cpu_bitmap[];
};
+/* Read the first system word of mm flags, non-atomically. */
+static inline unsigned long __mm_flags_get_word(struct mm_struct *mm)
+{
+ unsigned long *bitmap = ACCESS_PRIVATE(&mm->_flags, __mm_flags);
+
+ return bitmap_read(bitmap, 0, BITS_PER_LONG);
+}
+
+/* Set the first system word of mm flags, non-atomically. */
+static inline void __mm_flags_set_word(struct mm_struct *mm,
+ unsigned long value)
+{
+ unsigned long *bitmap = ACCESS_PRIVATE(&mm->_flags, __mm_flags);
+
+ bitmap_copy(bitmap, &value, BITS_PER_LONG);
+}
+
+/* Obtain a read-only view of the bitmap. */
+static inline const unsigned long *__mm_flags_get_bitmap(const struct mm_struct *mm)
+{
+ return (const unsigned long *)ACCESS_PRIVATE(&mm->_flags, __mm_flags);
+}
+
#define MM_MT_FLAGS (MT_FLAGS_ALLOC_RANGE | MT_FLAGS_LOCK_EXTERN | \
MT_FLAGS_USE_RCU)
extern struct mm_struct init_mm;
--
2.50.1
On 12.08.25 17:44, Lorenzo Stoakes wrote: > We are currently in the bizarre situation where we are constrained on the > number of flags we can set in an mm_struct based on whether this is a > 32-bit or 64-bit kernel. > > This is because mm->flags is an unsigned long field, which is 32-bits on a > 32-bit system and 64-bits on a 64-bit system. > > In order to keep things functional across both architectures, we do not > permit mm flag bits to be set above flag 31 (i.e. the 32nd bit). > > This is a silly situation, especially given how profligate we are in > storing metadata in mm_struct, so let's convert mm->flags into a bitmap and > allow ourselves as many bits as we like. > > To keep things manageable, firstly we introduce the bitmap at a system word > system as a new field mm->_flags, in union. > > This means the new bitmap mm->_flags is bitwise exactly identical to the > existing mm->flags field. > > We have an opportunity to also introduce some type safety here, so let's > wrap the mm flags field as a struct and declare it as an mm_flags_t typedef > to keep it consistent with vm_flags_t for VMAs. > > We make the internal field privately accessible, in order to force the use > of helper functions so we can enforce that accesses are bitwise as > required. > > We therefore introduce accessors prefixed with mm_flags_*() for callers to > use. We place the bit parameter first so as to match the parameter ordering > of the *_bit() functions. > > Having this temporary union arrangement allows us to incrementally swap > over users of mm->flags patch-by-patch rather than having to do everything > in one fell swoop. > > Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com> > --- Incl. fixup LGTM Acked-by: David Hildenbrand <david@redhat.com> -- Cheers David / dhildenb
Hi Andrew, Apologies, it turns out I put the __private sparse decorator in the wrong place :) I enclose a fix-patch that fixes this (now *ahem* tested with sparse...) as well as fixing some trivial whitespace/code reuse/const stuff in a couple accessors. Cheers, Lorenzo ----8<---- From cbe60f2c5e35bf1fcffb00c51f79f700edc17e06 Mon Sep 17 00:00:00 2001 From: Lorenzo Stoakes <lorenzo.stoakes@oracle.com> Date: Wed, 13 Aug 2025 20:40:10 +0100 Subject: [PATCH] mm: place __private in correct place, const-ify __mm_flags_get_word The __private sparse indicator was placed in the wrong location, resulting in sparse errors, correct this by placing it where it ought to be. Also, share some code for __mm_flags_get_word() and const-ify it to be consistent. Finally, fixup inconsistency in __mm_flags_set_word() param alignment. Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com> --- include/linux/mm_types.h | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index 46d3fb8935c7..0e001dbad455 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -934,8 +934,8 @@ struct mm_cid { */ #define NUM_MM_FLAG_BITS BITS_PER_LONG typedef struct { - __private DECLARE_BITMAP(__mm_flags, NUM_MM_FLAG_BITS); -} mm_flags_t; + DECLARE_BITMAP(__mm_flags, NUM_MM_FLAG_BITS); +} __private mm_flags_t; struct kioctx_table; struct iommu_mm_data; @@ -1233,17 +1233,8 @@ struct mm_struct { unsigned long cpu_bitmap[]; }; -/* Read the first system word of mm flags, non-atomically. */ -static inline unsigned long __mm_flags_get_word(struct mm_struct *mm) -{ - unsigned long *bitmap = ACCESS_PRIVATE(&mm->_flags, __mm_flags); - - return bitmap_read(bitmap, 0, BITS_PER_LONG); -} - /* Set the first system word of mm flags, non-atomically. */ -static inline void __mm_flags_set_word(struct mm_struct *mm, - unsigned long value) +static inline void __mm_flags_set_word(struct mm_struct *mm, unsigned long value) { unsigned long *bitmap = ACCESS_PRIVATE(&mm->_flags, __mm_flags); @@ -1256,6 +1247,14 @@ static inline const unsigned long *__mm_flags_get_bitmap(const struct mm_struct return (const unsigned long *)ACCESS_PRIVATE(&mm->_flags, __mm_flags); } +/* Read the first system word of mm flags, non-atomically. */ +static inline unsigned long __mm_flags_get_word(const struct mm_struct *mm) +{ + const unsigned long *bitmap = __mm_flags_get_bitmap(mm); + + return bitmap_read(bitmap, 0, BITS_PER_LONG); +} + #define MM_MT_FLAGS (MT_FLAGS_ALLOC_RANGE | MT_FLAGS_LOCK_EXTERN | \ MT_FLAGS_USE_RCU) extern struct mm_struct init_mm; -- 2.50.1
* Lorenzo Stoakes <lorenzo.stoakes@oracle.com> [250812 11:47]: > We are currently in the bizarre situation where we are constrained on the > number of flags we can set in an mm_struct based on whether this is a > 32-bit or 64-bit kernel. > > This is because mm->flags is an unsigned long field, which is 32-bits on a > 32-bit system and 64-bits on a 64-bit system. > > In order to keep things functional across both architectures, we do not > permit mm flag bits to be set above flag 31 (i.e. the 32nd bit). > > This is a silly situation, especially given how profligate we are in > storing metadata in mm_struct, so let's convert mm->flags into a bitmap and > allow ourselves as many bits as we like. > > To keep things manageable, firstly we introduce the bitmap at a system word > system as a new field mm->_flags, in union. > > This means the new bitmap mm->_flags is bitwise exactly identical to the > existing mm->flags field. > > We have an opportunity to also introduce some type safety here, so let's > wrap the mm flags field as a struct and declare it as an mm_flags_t typedef > to keep it consistent with vm_flags_t for VMAs. > > We make the internal field privately accessible, in order to force the use > of helper functions so we can enforce that accesses are bitwise as > required. > > We therefore introduce accessors prefixed with mm_flags_*() for callers to > use. We place the bit parameter first so as to match the parameter ordering > of the *_bit() functions. > > Having this temporary union arrangement allows us to incrementally swap > over users of mm->flags patch-by-patch rather than having to do everything > in one fell swoop. > > Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com> Reviewed-by: Liam R. Howlett <Liam.Howlett@oracle.com> > --- > include/linux/mm.h | 32 ++++++++++++++++++++++++++++++++ > include/linux/mm_types.h | 39 ++++++++++++++++++++++++++++++++++++++- > 2 files changed, 70 insertions(+), 1 deletion(-) > > diff --git a/include/linux/mm.h b/include/linux/mm.h > index 3868ca1a25f9..4ed4a0b9dad6 100644 > --- a/include/linux/mm.h > +++ b/include/linux/mm.h > @@ -34,6 +34,8 @@ > #include <linux/slab.h> > #include <linux/cacheinfo.h> > #include <linux/rcuwait.h> > +#include <linux/bitmap.h> > +#include <linux/bitops.h> > > struct mempolicy; > struct anon_vma; > @@ -720,6 +722,36 @@ static inline void assert_fault_locked(struct vm_fault *vmf) > } > #endif /* CONFIG_PER_VMA_LOCK */ > > +static inline bool mm_flags_test(int flag, const struct mm_struct *mm) > +{ > + return test_bit(flag, ACCESS_PRIVATE(&mm->_flags, __mm_flags)); > +} > + > +static inline bool mm_flags_test_and_set(int flag, struct mm_struct *mm) > +{ > + return test_and_set_bit(flag, ACCESS_PRIVATE(&mm->_flags, __mm_flags)); > +} > + > +static inline bool mm_flags_test_and_clear(int flag, struct mm_struct *mm) > +{ > + return test_and_clear_bit(flag, ACCESS_PRIVATE(&mm->_flags, __mm_flags)); > +} > + > +static inline void mm_flags_set(int flag, struct mm_struct *mm) > +{ > + set_bit(flag, ACCESS_PRIVATE(&mm->_flags, __mm_flags)); > +} > + > +static inline void mm_flags_clear(int flag, struct mm_struct *mm) > +{ > + clear_bit(flag, ACCESS_PRIVATE(&mm->_flags, __mm_flags)); > +} > + > +static inline void mm_flags_clear_all(struct mm_struct *mm) > +{ > + bitmap_zero(ACCESS_PRIVATE(&mm->_flags, __mm_flags), NUM_MM_FLAG_BITS); > +} > + > extern const struct vm_operations_struct vma_dummy_vm_ops; > > static inline void vma_init(struct vm_area_struct *vma, struct mm_struct *mm) > diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h > index cf94df4955c7..46d3fb8935c7 100644 > --- a/include/linux/mm_types.h > +++ b/include/linux/mm_types.h > @@ -20,6 +20,7 @@ > #include <linux/seqlock.h> > #include <linux/percpu_counter.h> > #include <linux/types.h> > +#include <linux/bitmap.h> > > #include <asm/mmu.h> > > @@ -927,6 +928,15 @@ struct mm_cid { > }; > #endif > > +/* > + * Opaque type representing current mm_struct flag state. Must be accessed via > + * mm_flags_xxx() helper functions. > + */ > +#define NUM_MM_FLAG_BITS BITS_PER_LONG > +typedef struct { > + __private DECLARE_BITMAP(__mm_flags, NUM_MM_FLAG_BITS); > +} mm_flags_t; > + > struct kioctx_table; > struct iommu_mm_data; > struct mm_struct { > @@ -1109,7 +1119,11 @@ struct mm_struct { > /* Architecture-specific MM context */ > mm_context_t context; > > - unsigned long flags; /* Must use atomic bitops to access */ > + /* Temporary union while we convert users to mm_flags_t. */ > + union { > + unsigned long flags; /* Must use atomic bitops to access */ > + mm_flags_t _flags; /* Must use mm_flags_* helpers to access */ > + }; > > #ifdef CONFIG_AIO > spinlock_t ioctx_lock; > @@ -1219,6 +1233,29 @@ struct mm_struct { > unsigned long cpu_bitmap[]; > }; > > +/* Read the first system word of mm flags, non-atomically. */ > +static inline unsigned long __mm_flags_get_word(struct mm_struct *mm) > +{ > + unsigned long *bitmap = ACCESS_PRIVATE(&mm->_flags, __mm_flags); > + > + return bitmap_read(bitmap, 0, BITS_PER_LONG); > +} > + > +/* Set the first system word of mm flags, non-atomically. */ > +static inline void __mm_flags_set_word(struct mm_struct *mm, > + unsigned long value) > +{ > + unsigned long *bitmap = ACCESS_PRIVATE(&mm->_flags, __mm_flags); > + > + bitmap_copy(bitmap, &value, BITS_PER_LONG); > +} > + > +/* Obtain a read-only view of the bitmap. */ > +static inline const unsigned long *__mm_flags_get_bitmap(const struct mm_struct *mm) > +{ > + return (const unsigned long *)ACCESS_PRIVATE(&mm->_flags, __mm_flags); > +} > + > #define MM_MT_FLAGS (MT_FLAGS_ALLOC_RANGE | MT_FLAGS_LOCK_EXTERN | \ > MT_FLAGS_USE_RCU) > extern struct mm_struct init_mm; > -- > 2.50.1 >
© 2016 - 2025 Red Hat, Inc.