* Lorenzo Stoakes <lorenzo.stoakes@xxxxxxxxxx> [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@xxxxxxxxxx> Reviewed-by: Liam R. Howlett <Liam.Howlett@xxxxxxxxxx> > --- > 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 >