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.

-- 
Sincerely yours,
Mike.

Reply via email to