RE: [PATCH 1/1] mm: Fix struct page layout on 32-bit systems
From: David Laight
Date: Tue Apr 13 2021 - 04:21:21 EST
From: Matthew Wilcox <willy@xxxxxxxxxxxxx>
> Sent: 12 April 2021 19:24
>
> On Sun, Apr 11, 2021 at 11:43:07AM +0200, Jesper Dangaard Brouer wrote:
> > Could you explain your intent here?
> > I worry about @index.
> >
> > As I mentioned in other thread[1] netstack use page_is_pfmemalloc()
> > (code copy-pasted below signature) which imply that the member @index
> > have to be kept intact. In above, I'm unsure @index is untouched.
>
> Well, I tried three different approaches. Here's the one I hated the least.
>
> From: "Matthew Wilcox (Oracle)" <willy@xxxxxxxxxxxxx>
> Date: Sat, 10 Apr 2021 16:12:06 -0400
> Subject: [PATCH] mm: Fix struct page layout on 32-bit systems
>
> 32-bit architectures which expect 8-byte alignment for 8-byte integers
> and need 64-bit DMA addresses (arc, arm, mips, ppc) had their struct
> page inadvertently expanded in 2019. When the dma_addr_t was added,
> it forced the alignment of the union to 8 bytes, which inserted a 4 byte
> gap between 'flags' and the union.
>
> We could fix this by telling the compiler to use a smaller alignment
> for the dma_addr, but that seems a little fragile. Instead, move the
> 'flags' into the union. That causes dma_addr to shift into the same
> bits as 'mapping', which causes problems with page_mapping() called from
> set_page_dirty() in the munmap path. To avoid this, insert three words
> of padding and use the same bits as ->index and ->private, neither of
> which have to be cleared on free.
This all looks horribly fragile and is bound to get broken again.
Are there two problems?
1) The 'folio' structure needs to match 'rcu' part of the page
so that it can use the same rcu list to free items.
2) Various uses of 'struct page' need to overlay fields to save space.
For (1) the rcu bit should probably be a named structure in an
anonymous union - probably in both structures.
For (2) is it worth explicitly defining the word number for each field?
So you end up with something like:
#define F(offset, member) struct { long _pad_##offset[offset]; member; }
struct page [
union {
struct page_rcu;
unsigned long flags;
F(1, unsigned long xxx);
F(2, unsigned long yyy);
etc.
...
> struct { /* page_pool used by netstack */
> - /**
> - * @dma_addr: might require a 64-bit value even on
> - * 32-bit architectures.
> - */
> - dma_addr_t dma_addr;
> + unsigned long _pp_flags;
> + unsigned long pp_magic;
> + unsigned long xmi;
> + unsigned long _pp_mapping_pad;
> + dma_addr_t dma_addr; /* might be one or two words */
> };
Isn't that 6 words?
David
-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)