On Sat, May 30, 2026 at 07:52:25PM +0300, Mike Rapoport wrote:
> On Fri, May 29, 2026 at 03:00:14PM +0100, Lorenzo Stoakes wrote:
> > On Tue, May 26, 2026 at 02:04:52PM +0100, Kiryl Shutsemau wrote:
> > > From: "Kiryl Shutsemau (Meta)" <[email protected]>
> > >
> > > vma_flags_t is one unsigned long on 32-bit -- NUM_VMA_FLAG_BITS ==
> > > BITS_PER_LONG by design, so VM_xxx-declared bits sit in the first
> > > word and hit the single-long fast path. But the bit enum declares
> > > some bits unconditionally above BITS_PER_LONG (VMA_UFFD_MINOR_BIT
> > > == 41 today, with VM_UFFD_MINOR == VM_NONE on 32-bit so no VMA
> > > actually carries the bit).
> >
> > Yeah ugh.
> >
> > > Passing such a bit to mk_vma_flags() goes through __set_bit(41,
> > > &one_long) and writes one word past the end. The compiler folds
> > > the OOB store with wraparound (1UL << (41 % 32) == bit 9) into
> > > the first word. Bit 9 is already in __VMA_UFFD_FLAGS so the mask
> > > happens to come out right today, but any high-numbered bit whose
> >
> > That is... helpful :) but not great that this is the situation, an
> > oversight, clearly! How I hate 32-bit kernels :)
> >
> > > mod-BITS_PER_LONG position is otherwise unused would silently OR
> > > an extra bit into the mask.
> > >
> > > Add VMA_NO_BIT and have DECLARE_VMA_BIT() resolve any bitnum out
> > > of range to it. vma_flags_set_flag() drops negative bit values.
> > > The ternary collapses at compile time, the runtime check folds
> > > away when the bit is in range, and the common path is unchanged.
> >
> > Hmm are you sure it does?
> >
> > A key design goal was that mk_vma_flags() generates compile-time constants
> > the same as if the bitmap were constructed independently.
> >
> > This surely must generate code? Or at least runs a significant risk of it?
>
> ...
>
> > A simple solution that doesn't require change to the core is to just uglify
> > userfaultfd_k.h a bit with:
> >
> > #ifdef HAVE_ARCH_USERFAULTFD_MINOR
> > #define __VMA_UFFD_FLAGS mk_vma_flags(VMA_UFFD_MISSING_BIT, 
> > VMA_UFFD_WP_BIT, \
> >                                   VMA_UFFD_MINOR_BIT)
> > #else
> > #define __VMA_UFFD_FLAGS mk_vma_flags(VMA_UFFD_MISSING_BIT, VMA_UFFD_WP_BIT)
> > #endif
> >
> > But of course that becomes much more horrible with your changes...
> >
> > Another alternative, which I used for VMA_DROPPABLE is to add something
> > like this in mm.h:
> >
> > #ifdef CONFIG_HAVE_ARCH_USERFAULTFD_MINOR
> > #define VM_UFFD_MINOR       INIT_VM_FLAG(UFFD_MINOR)
> > +define VMA_UFFD_MINOR      mk_vma_flags(VMA_UFFD_MINOR_BIT)
> > #else
> > #define VM_UFFD_MINOR       VM_NONE
> > +define VMA_UFFD_MINOR      EMPTY_VMA_FLAGS
> > #endif
>
> I have a PoC of yet another alternative:
>
> https://git.kernel.org/pub/scm/linux/kernel/git/rppt/linux.git/log/?h=uffd/vm-flags
>
> The idea there is to keep a single VMA flag, VMA_UFFD_BIT/VM_UFFD and move
> all the rest into what's now struct vm_userfaultfd_ctx.

*Gives Mike a big kiss*

YES PLEASE!

>
> --
> Sincerely yours,
> Mike.

Thanks, Lorenzo

Reply via email to