From: Johannes Weiner <hannes@cmpxchg.org>
To: Yafang Shao <laoar.shao@gmail.com>
Cc: Liam.Howlett@oracle.com, david@kernel.org,
linux-kernel@vger.kernel.org, linux-mm@kvack.org, ljs@kernel.org,
riel@surriel.com, vbabka@suse.cz, ziy@nvidia.com
Subject: Re: [RFC 2/2] mm: page_alloc: per-cpu pageblock buddy allocator
Date: Mon, 21 Sep 2026 16:03:09 -0400 [thread overview]
Message-ID: <arGNfQQAVRZpEoPl@cmpxchg.org> (raw)
In-Reply-To: <20260918022222.22955-1-laoar.shao@gmail.com>
Hello Yafang,
On Fri, Sep 18, 2026 at 10:22:22AM +0800, Yafang Shao wrote:
> On Fri, 3 Apr 2026 at 15:40 PM Johannes Weiner <hannes@cmpxchg.org> wrote:
>
> [...]
>
> > @@ -2941,15 +3242,45 @@ static void __free_frozen_pages(struct page *page, unsigned int order,
> [...]
> > + pcp = per_cpu_ptr(zone->per_cpu_pageset, cache_cpu);
> > + if (unlikely(fpi_flags & FPI_TRYLOCK) || !in_task()) {
> > + if (!spin_trylock_irqsave(&pcp->lock, UP_flags)) {
> > + free_one_page(zone, page, pfn, order, fpi_flags);
> > return;
> > - pcp_spin_unlock(pcp, UP_flags);
> > + }
> > } else {
> > + spin_lock_irqsave(&pcp->lock, UP_flags);
> > + }
>
> [...]
>
> > @@ -3025,17 +3369,35 @@ void free_unref_folios(struct folio_batch *folios)
> [...]
> > + if (!in_task()) {
> > + if (unlikely(!spin_trylock_irqsave(
> > + &pcp->lock, UP_flags))) {
> > + pcp = NULL;
> > + free_one_page(zone, &folio->page, pfn,
> > + order, FPI_NONE);
> > + continue;
> > + }
> > + } else {
> > + spin_lock_irqsave(&pcp->lock, UP_flags);
> > + }
>
> Hello Johannes,
>
> Thank you for the great work on this series -- I hope it is still being
> actively worked on.
Thanks for the kind words.
I am still actively working on it. Since the last iteration I have
addressed a few things:
1. The locking bug you are seeing. Rik had also run into this during
stress testing. The fallback to the zone buddy on PCP contention
brought back some of the original zone->lock contention. So instead
I'm using the zone llist introduced for lockless allocations.
2. The PFN search for block recovery that Vlastimil pointed out. I've
tried various solutions (counters, bitmaps) but the thing that worked
best was having the zone buddy itself maintain free pages of owned
blocks on a per-block loaner list (in addition to the regular zone
freelists). This eliminates the sparse search altogether. Recovery is
then: pcp->owned_blocks -> pbd->buddy_loans -> page. Every page
visited gets recovered. For the loaner list_head, I'm reusing
mapping/index space that's unused in a freed page.
3. Removed the unowned buddy splitting on the PCP. Vlastimil had
actually asked to try that separately, as an incremental step, since
it's self contained. I tried this but realized that part was actually
bad altogether. It violates the rmqueue_smallest policy and causes
runaway fragmentation - just like the new block claiming did before I
added the block recovery step beforehand.
So now refilling is just block recovery -> new blocks -> unowned
singles of the requested order.
Incidentally, this also eliminated the CMA problem that Frank pointed
out, since the other refill paths respect ALLOC_CMA.
4. I realized I'm also violating the smallest-first policy in how I
was mixing owned and unowned chunks on the same freelists. For
example, an order-3 refill from singles sits next to order-3 fragments
from owned blocks. Only owned fragments, which route back to and
reassemble on that PCP, must be split. Unowned singles must be
consumed at their native order to preserve smallest-first policy.
pcp_rmqueue_smallest() could check the PagePCPBuddy() flag to tell
which ones can be split, but that introduces another sparse search
problem, where we might walk higher order lists in the hope to find a
splittable owned buddy.
To avoid this, I retained the legacy/unowned pcp freelists (up to
costly order and THP), and added a second set of buddy freelists up to
pageblock order to the PCP. This way the rule can be maintained with
O(1) list checks instead of O(pcp size) scans.
5. The on-demand merging at drain time proved problematic. Draining
isn't exhaustive, so it can attempt to merge the same unmergeable
fragments repeatedly. I moved merging into the pcp free path instead,
so every page is tried for merging exactly once, which seems to
perform a lot better in performance testing.
Overall, it's gotten a bit bigger than I had hoped for. But it also
looks much more robust. And the additions described above seem well
offset by performance improvements in tests so far, even on smaller
machines.
I'm still testing and polishing right now, and hoping to send a new
version soon.
> We are suffering from heavy zone->lock contention on our production
> servers as well, so I backported this series to our internal 6.18.y
> kernel. However, since deploying it to a few dozen production servers
> running workloads with heavy memory and I/O pressure, we have been
> hitting hard lockups at a rate of roughly one every day or two. The
> hard lockups look as follows:
[...]
> With these changes applied, the affected servers have been running
> lockup-free for more than two weeks so far.
I'm assuming you saw an improvement of zone->lock contention. Would
you be able to share some numbers or observations?
Thanks again!
next prev parent reply other threads:[~2026-09-21 20:03 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-03 19:40 [RFC 0/2] mm: page_alloc: pcp " Johannes Weiner
2026-04-03 19:40 ` [RFC 1/2] mm: page_alloc: replace pageblock_flags bitmap with struct pageblock_data Johannes Weiner
2026-04-04 1:43 ` Rik van Riel
2026-04-20 1:40 ` Zi Yan
2026-04-03 19:40 ` [RFC 2/2] mm: page_alloc: per-cpu pageblock buddy allocator Johannes Weiner
[not found] ` <984aee1a7af2ea4b576a0114a367402537d3deca.camel@surriel.com>
2026-04-06 16:12 ` Johannes Weiner
2026-04-06 17:31 ` Frank van der Linden
2026-04-06 21:58 ` Johannes Weiner
2026-04-10 9:48 ` Vlastimil Babka (SUSE)
2026-04-10 19:12 ` Johannes Weiner
2026-09-18 2:22 ` Yafang Shao
2026-09-21 20:03 ` Johannes Weiner [this message]
2026-09-22 8:32 ` Yafang Shao
2026-04-04 2:27 ` [RFC 0/2] mm: page_alloc: pcp " Zi Yan
2026-04-06 15:24 ` Johannes Weiner
2026-04-07 2:42 ` Zi Yan
2026-09-21 7:07 ` Dev Jain
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=arGNfQQAVRZpEoPl@cmpxchg.org \
--to=hannes@cmpxchg.org \
--cc=Liam.Howlett@oracle.com \
--cc=david@kernel.org \
--cc=laoar.shao@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=ljs@kernel.org \
--cc=riel@surriel.com \
--cc=vbabka@suse.cz \
--cc=ziy@nvidia.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®