On Thu, Feb 09, 2023 at 05:48:28PM +0000, David Chen wrote: > So the problem is the check PageHead is racy because at this point we > already dropped our reference to the page. So even if we came in with > compound page, the page can already be freed and PageHead can return > false and we will end up freeing all the tail pages causing double free. > > Fixes: e320d3012d25 ("mm/page_alloc.c: fix freeing non-compound pages") > Cc: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> > Cc: Matthew Wilcox (Oracle) <willy@xxxxxxxxxxxxx> > Cc: linux-mm@xxxxxxxxx > Cc: stable@xxxxxxxxxxxxxxx > Signed-off-by: Chunwei Chen <david.chen@xxxxxxxxxxx> Reviewed-by: Matthew Wilcox (Oracle) <willy@xxxxxxxxxxxxx> That's a pretty narrow window you managed to hit! Just a few instructions wide. I guess that answers the question Andrew originally had (Does this ever happen?) I just changed it from a silent memory leak into a double-free. > --- > mm/page_alloc.c | 5 ++++- > 1 file changed, 4 insertions(+), 1 deletion(-) > > diff --git a/mm/page_alloc.c b/mm/page_alloc.c > index 0745aedebb37..3bb3484563ed 100644 > --- a/mm/page_alloc.c > +++ b/mm/page_alloc.c > @@ -5631,9 +5631,12 @@ EXPORT_SYMBOL(get_zeroed_page); > */ > void __free_pages(struct page *page, unsigned int order) > { > + /* get PageHead before we drop reference */ > + int head = PageHead(page); > + > if (put_page_testzero(page)) > free_the_page(page, order); > - else if (!PageHead(page)) > + else if (!head) > while (order-- > 0) > free_the_page(page + (1 << order), order); > } > -- > 2.22.3