[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250513014200.GA577@system.software.com>
Date: Tue, 13 May 2025 10:42:00 +0900
From: Byungchul Park <byungchul@...com>
To: Matthew Wilcox <willy@...radead.org>
Cc: netdev@...r.kernel.org, linux-kernel@...r.kernel.org,
linux-mm@...ck.org, kernel_team@...ynix.com, kuba@...nel.org,
almasrymina@...gle.com, ilias.apalodimas@...aro.org,
harry.yoo@...cle.com, hawk@...nel.org, akpm@...ux-foundation.org,
ast@...nel.org, daniel@...earbox.net, davem@...emloft.net,
john.fastabend@...il.com, andrew+netdev@...n.ch,
edumazet@...gle.com, pabeni@...hat.com, vishal.moola@...il.com
Subject: Re: [RFC 19/19] mm, netmem: remove the page pool members in struct
page
On Mon, May 12, 2025 at 03:42:54PM +0100, Matthew Wilcox wrote:
> On Mon, May 12, 2025 at 09:51:03PM +0900, Byungchul Park wrote:
> > On Fri, May 09, 2025 at 07:02:30PM +0100, Matthew Wilcox wrote:
> > > > + struct __netmem_desc place_holder_1; /* for page pool */
> > > > struct { /* Tail pages of compound page */
> > > > unsigned long compound_head; /* Bit zero is set */
> > > > };
> > >
> > > The include and the place holder aren't needed.
> >
> > Or netmem_desc overlaying struct page might be conflict with other
> > fields of sturct page e.g. _mapcount, _refcount and the like, once the
> > layout of struct page *extremly changes* in the future before
> > netmem_desc has its own instance.
>
> That's not how it'll happen. When the layout of struct page changes,
> it'll shrink substantially (cut in half). That means that dynamically
> allocating netmem_desc must happen first (along with slab, folio, etc,
> etc).
Just in case, lemme explain what I meant, for *example*:
struct page {
unsigned long flags;
union {
struct A { /* 24 bytes */ };
struct B { /* 40 bytes */ };
struct page_pool { /* 40 bytes */ };
};
atomic_t _mapcount;
atomic_t _refcount;
unsigend long memcf_data;
...
};
/* overlayed on struct page */
struct netmem_desc { /* 8 + 40 bytes */ };
After removing page_pool fields:
struct page {
unsigned long flags;
union {
struct A { /* 24 bytes */ };
struct B { /* 40 bytes */ };
};
atomic_t _mapcount;
atomic_t _refcount;
unsigend long memcf_data;
...
};
/* overlayed on struct page */
struct netmem_desc { /* 8 + 40 bytes */ };
The above still looks okay cuz operating on struct netmem_desc is not
touching _mapcount or _refcount in struct page.
However, either the size of struct B gets reduced to 32 bytes or struct B
gets away out of struct page for some reason, it will look like:
struct page {
unsigned long flags;
union {
struct A { /* 24 bytes */ };
struct B { /* 32 bytes */ };
};
atomic_t _mapcount;
atomic_t _refcount;
unsigend long memcf_data;
...
};
/* overlayed on struct page */
struct netmem_desc { /* 8 + 40 bytes */ };
In here, operating on struct netmem_desc can smash _mapcount and
_refcount in struct page unexpectedly, even though sizeof(struct
netmem_desc) <= sizeof(struct page). That's why I think the place holder
is necessary until it completely gets separated so as to have its own
instance.
If you believe it's still okay, I will remove the place holder, I still
concern it tho.
Byungchul
Powered by blists - more mailing lists