From: sashiko-bot@kernel.org
To: "Kiryl Shutsemau (Meta)" <kas@kernel.org>,
"Andrew Morton" <akpm@linux-foundation.org>,
"Linus Torvalds" <torvalds@linux-foundation.org>,
"David Hildenbrand" <david@kernel.org>,
"Matthew Wilcox" <willy@infradead.org>,
"Vlastimil Babka" <vbabka@kernel.org>,
"Lorenzo Stoakes" <ljs@kernel.org>, "Jan Kara" <jack@suse.cz>,
"Hugh Dickins" <hughd@google.com>,
"Christian Brauner" <brauner@kernel.org>,
"Alexander Viro" <viro@zeniv.linux.org.uk>
Cc: "Miklos Szeredi" <miklos@szeredi.hu>,
"Miaohe Lin" <linmiaohe@huawei.com>,
"Naoya Horiguchi" <nao.horiguchi@gmail.com>,
"Oscar Salvador" <osalvador@suse.de>,
"Liam R . Howlett" <liam@infradead.org>,
"Mike Rapoport" <rppt@kernel.org>,
"Suren Baghdasaryan" <surenb@google.com>,
"Michal Hocko" <mhocko@suse.com>,
"Brendan Jackman" <brendan.jackman@linux.dev>,
"Johannes Weiner" <hannes@cmpxchg.org>, "Zi Yan" <ziy@nvidia.com>,
"Baolin Wang" <baolin.wang@linux.alibaba.com>,
"Nico Pache" <nico.pache@linux.dev>,
"Ryan Roberts" <ryan.roberts@arm.com>,
"Dev Jain" <dev.jain@arm.com>, "Barry Song" <baohua@kernel.org>,
"Lance Yang" <lance.yang@linux.dev>,
"Usama Arif" <usama.arif@linux.dev>,
"Kairui Song" <kasong@tencent.com>,
"Qi Zheng" <qi.zheng@linux.dev>,
"Shakeel Butt" <shakeel.butt@linux.dev>,
"Axel Rasmussen" <axelrasmussen@google.com>,
"Yuanchu Xie" <yuanchu@google.com>, "Wei Xu" <weixugc@google.com>,
"Baoquan He" <baoquan.he@linux.dev>,
"Paul E . McKenney" <paulmck@kernel.org>,
"Pedro Falcato" <pfalcato@suse.de>,
"Harry Yoo" <harry@kernel.org>,
"Luis Chamberlain" <mcgrof@kernel.org>,
"Ilya Gladyshev" <ilya.gladyshev@linux.dev>,
"Jaegeuk Kim" <jaegeuk@kernel.org>,
linux-mm@kvack.org, kernel-team@meta.com
Subject: Re: [RFC PATCH 06/18] mm: free the pages waiting for a grace period before OOM
Date: Tue, 20 Oct 2026 15:51:30 +0000 [thread overview]
Message-ID: <sashiko-outbox-179304@kernel.org> (raw)
In-Reply-To: <20261019154913.1765974-7-kas@kernel.org>
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] mm: rcu_free_drain() fails to wait for in-flight RCU free workers
- [High] mm: rcu_free_wait() passes high order to __zone_watermark_ok()
- [High] mm: should_reclaim_retry() splits reclaimable and RCU-waiting pages
- [High] mm: rcu_free_drain() leaves freed pages on PCP lists instead of buddy
--
commit 7de2bde642756023a3c02e6554282a28f501cd38
Author: Kiryl Shutsemau (Meta) <kas@kernel.org>
mm: free the pages waiting for a grace period before OOM
This commit adds rcu_free_wait() and rcu_free_drain() to
should_reclaim_retry() so that pages deferred for an RCU grace period are
drained via an expedited grace period before giving up and invoking the OOM
killer. It also introduces the PGFREE_RCU_DRAIN vmstat event to count drains
that freed pages.
> diff --git a/mm/page_alloc.c b/mm/page_alloc.c
> index a9058d414f92d..bec9128d80db8 100644
> --- a/mm/page_alloc.c
> +++ b/mm/page_alloc.c
> @@ -1445,6 +1445,29 @@ static void rcu_free_defer(struct folio *folio)
> queue_work(rcu_free_wq, &r->expedite);
> }
>
> +/*
> + * Free what every CPU's lists hold. A concurrent drain holds the lock
> + * until it has freed what it took.
> + */
> +static void rcu_free_drain(void)
> +{
> + static DEFINE_MUTEX(lock);
> + LIST_HEAD(list);
> + int cpu;
> +
> + mutex_lock(&lock);
> + for_each_possible_cpu(cpu) {
> + struct rcu_free_pcpu *r = per_cpu_ptr(&rcu_free_pcpu, cpu);
> +
> + spin_lock_irq(&r->lock);
> + rcu_free_take(r, &list);
> + spin_unlock_irq(&r->lock);
> + }
> + if (rcu_free_flush(&list))
> + count_vm_event(PGFREE_RCU_DRAIN);
> + mutex_unlock(&lock);
> +}
[Severity: High]
What happens if rcu_free_expedite_workfn() or rcu_free_workfn() has already
spliced the folios off r->batch and r->pending before rcu_free_drain() runs?
In rcu_free_expedite_workfn(), the worker takes the per-CPU lists into a
local list and drops r->lock before blocking in synchronize_rcu_expedited():
mm/page_alloc.c:rcu_free_expedite_workfn() {
spin_lock_irq(&r->lock);
rcu_free_take(r, &list);
spin_unlock_irq(&r->lock);
if (rcu_free_flush(&list))
count_vm_event(PGFREE_RCU_EXPEDITE);
}
Similarly, rcu_free_workfn() splices r->batch into a local list under r->lock
before calling rcu_free_pages(), and NR_FREE_RCU_PAGES is only decremented
inside rcu_free_pages() as each folio is freed.
Because neither worker acquires the mutex in rcu_free_drain(), a task
entering rcu_free_wait() -> rcu_free_drain() while a worker is in flight
sees elevated NR_FREE_RCU_PAGES, finds r->batch and r->pending empty, and
returns immediately from rcu_free_flush(&list) without waiting. Once
*no_progress_loops > MAX_RECLAIM_RETRIES, should_reclaim_retry() also jumps
to out: and skips cond_resched().
Can __alloc_pages_slowpath() then spin through all MAX_RECLAIM_RETRIES
iterations of rcu_free_waits while the worker is still in
synchronize_rcu_expedited() and trigger a premature OOM kill?
[Severity: High]
Also, when rcu_free_drain() calls rcu_free_flush(&list) -> rcu_free_pages() ->
free_unref_folios(), folios with pcp_allowed_order(order) are freed via
free_frozen_page_commit() onto the local CPU's PCP list rather than directly
into the zone's buddy free_area (and NR_FREE_PAGES is only updated when pages
move from PCP to buddy).
When __alloc_pages_slowpath() jumps back to retry:, get_page_from_freelist()
checks zone_watermark_fast() using NR_FREE_PAGES before reaching rmqueue(),
and when __alloc_pages_direct_reclaim() sees *did_some_progress == 0, it
jumps to out: without calling drain_all_pages(NULL):
mm/page_alloc.c:__alloc_pages_direct_reclaim() {
*did_some_progress = __perform_reclaim(gfp_mask, reclaim_order, ac);
if (unlikely(!(*did_some_progress)))
goto out;
...
drain_all_pages(NULL);
out:
}
If the pages freed by rcu_free_drain() stay on the PCP list and do not
increase NR_FREE_PAGES above min_wmark_pages(zone), won't the subsequent
retry fail the watermark check in get_page_from_freelist() and proceed to
__alloc_pages_may_oom() with those pages still stranded on PCP?
> +
> static void __init rcu_free_init(void)
> {
> int cpu;
> @@ -4792,6 +4815,52 @@ bool gfp_pfmemalloc_allowed(gfp_t gfp_mask)
> return !!__gfp_pfmemalloc_flags(gfp_mask);
> }
>
> +/*
> + * Reclaim is about to give up: if the pages waiting for a grace period
> + * would bring an eligible zone above its min watermark, free them and
> + * retry. Not for a dying task, which frees memory by exiting.
> + */
> +static bool rcu_free_wait(gfp_t gfp_mask, unsigned int order,
> + struct alloc_context *ac, int alloc_flags,
> + int *rcu_free_waits)
> +{
> + struct zone *zone;
> + struct zoneref *z;
> +
> + if (!IS_ENABLED(CONFIG_PAGE_RCU_FREE))
> + return false;
> + if (tsk_is_oom_victim(current) || fatal_signal_pending(current))
> + return false;
> + if (*rcu_free_waits >= MAX_RECLAIM_RETRIES ||
> + order > PAGE_ALLOC_COSTLY_ORDER)
> + return false;
> +
> + for_each_zone_zonelist_nodemask(zone, z, ac->zonelist,
> + ac->highest_zoneidx, ac->nodemask) {
> + unsigned long waiting, available;
> +
> + if (cpusets_enabled() && (alloc_flags & ALLOC_CPUSET) &&
> + !__cpuset_zone_allowed(zone, gfp_mask))
> + continue;
> +
> + waiting = zone_page_state_snapshot(zone, NR_FREE_RCU_PAGES);
> + if (!waiting)
> + continue;
> +
> + available = waiting +
> + zone_page_state_snapshot(zone, NR_FREE_PAGES);
> + if (__zone_watermark_ok(zone, order, min_wmark_pages(zone),
> + ac->highest_zoneidx, alloc_flags,
> + available)) {
[Severity: High]
For non-costly high-order allocations (1 <= order <= PAGE_ALLOC_COSTLY_ORDER),
does passing order to __zone_watermark_ok() here prevent rcu_free_drain()
from being called when z->free_area[o >= order] is currently empty?
In __zone_watermark_ok(), the free_pages argument (available) is only checked
against min + z->lowmem_reserve[highest_zoneidx], after which order > 0
requires an existing free block in z->free_area[o >= order]:
mm/page_alloc.c:__zone_watermark_ok() {
if (free_pages <= min + z->lowmem_reserve[highest_zoneidx])
return false;
/* If this is an order-0 request then the watermark is fine */
if (!order)
return true;
/* For a high-order request, check at least one suitable page is free */
for (o = order; o < NR_PAGE_ORDERS; o++) {
struct free_area *area = &z->free_area[o];
...
}
Because the pages in NR_FREE_RCU_PAGES have not been freed into z->free_area
yet, won't __zone_watermark_ok() return false before rcu_free_drain() has a
chance to free them?
[Severity: High]
Also, should available in should_reclaim_retry() and rcu_free_wait() account
for zone_reclaimable_pages(zone) and NR_FREE_RCU_PAGES together?
When direct reclaim frees folios marked with PG_rcu_free,
__free_pages_prepare() diverts them to rcu_free_defer(), moving those pages
out of zone_reclaimable_pages(zone) and into NR_FREE_RCU_PAGES rather than
NR_FREE_PAGES.
In should_reclaim_retry(), the loop checks:
available = reclaimable = zone_reclaimable_pages(zone);
available += zone_page_state_snapshot(zone, NR_FREE_PAGES);
and if that fails, rcu_free_wait() checks:
available = waiting +
zone_page_state_snapshot(zone, NR_FREE_PAGES);
If the pages needed to reach min_wmark_pages(zone) are split between
remaining reclaimable pages on the LRU and already-reclaimed pages waiting in
NR_FREE_RCU_PAGES, won't both checks fail individually and cause
should_reclaim_retry() to return false while reclaim is still making progress?
> + (*rcu_free_waits)++;
> + rcu_free_drain();
> + return true;
> + }
> + }
> +
> + return false;
> +}
[ ... ]
>dari
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261019154913.1765974-1-kas@kernel.org?part=6
next prev parent reply other threads:[~2026-10-20 15:52 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-19 15:48 [RFC PATCH 00/18] mm: read the page cache without folio references Kiryl Shutsemau (Meta)
2026-10-19 15:48 ` [RFC PATCH 01/18] mm: free PG_rcu_free folios only after an RCU grace period Kiryl Shutsemau (Meta)
2026-10-19 15:48 ` [RFC PATCH 02/18] splice: don't steal page cache folios Kiryl Shutsemau (Meta)
2026-10-19 15:48 ` [RFC PATCH 03/18] fuse: don't move a folio with PG_rcu_free into a fuse file Kiryl Shutsemau (Meta)
2026-10-19 15:48 ` [RFC PATCH 04/18] mm: count the pages waiting for a grace period Kiryl Shutsemau (Meta)
2026-10-19 15:48 ` [RFC PATCH 05/18] mm: expedite the grace period when a CPU has many deferred frees Kiryl Shutsemau (Meta)
2026-10-19 15:48 ` [RFC PATCH 06/18] mm: free the pages waiting for a grace period before OOM Kiryl Shutsemau (Meta)
2026-10-20 15:51 ` sashiko-bot [this message]
2026-10-19 15:49 ` [RFC PATCH 07/18] mm: free the pages waiting for a grace period before isolation fails Kiryl Shutsemau (Meta)
2026-10-20 15:52 ` sashiko-bot
2026-10-19 15:49 ` [RFC PATCH 08/18] mm/memory-failure: handle folios with PG_rcu_free Kiryl Shutsemau (Meta)
2026-10-20 15:52 ` sashiko-bot
2026-10-19 15:49 ` [RFC PATCH 09/18] mm: have folio_mark_accessed() return whether the folio is hot Kiryl Shutsemau (Meta)
2026-10-19 15:49 ` [RFC PATCH 10/18] mm/filemap: mark a folio accessed in one place in filemap_read() Kiryl Shutsemau (Meta)
2026-10-19 15:49 ` [RFC PATCH 11/18] mm/filemap: set PG_rcu_free on the folios that reads keep coming back to Kiryl Shutsemau (Meta)
2026-10-19 15:49 ` [RFC PATCH 12/18] mm/filemap: don't defer the free of folios of an inode being evicted Kiryl Shutsemau (Meta)
2026-10-20 15:53 ` sashiko-bot
2026-10-19 15:49 ` [RFC PATCH 13/18] mm/filemap: store the end of a read in f_ra only when it changes Kiryl Shutsemau (Meta)
2026-10-20 21:20 ` Linus Torvalds
2026-10-19 15:49 ` [RFC PATCH 14/18] mm/filemap: read from the page cache without folio references Kiryl Shutsemau (Meta)
2026-10-20 15:53 ` sashiko-bot
2026-10-19 15:49 ` [RFC PATCH 15/18] mm/filemap: read large folios " Kiryl Shutsemau (Meta)
2026-10-20 15:54 ` sashiko-bot
2026-10-19 15:49 ` [RFC PATCH 16/18] mm/shmem: count accesses to a folio the way filemap_read() does Kiryl Shutsemau (Meta)
2026-10-19 15:49 ` [RFC PATCH 17/18] mm/shmem: read without folio references Kiryl Shutsemau (Meta)
2026-10-19 15:49 ` [RFC PATCH 18/18] mm/filemap: add a debugfs switch for lockless page cache reads Kiryl Shutsemau (Meta)
2026-10-19 21:20 ` [RFC PATCH 00/18] mm: read the page cache without folio references Harry Yoo
2026-10-20 17:27 ` Kiryl Shutsemau
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=sashiko-outbox-179304@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=akpm@linux-foundation.org \
--cc=axelrasmussen@google.com \
--cc=baohua@kernel.org \
--cc=baolin.wang@linux.alibaba.com \
--cc=baoquan.he@linux.dev \
--cc=brauner@kernel.org \
--cc=brendan.jackman@linux.dev \
--cc=david@kernel.org \
--cc=dev.jain@arm.com \
--cc=hannes@cmpxchg.org \
--cc=harry@kernel.org \
--cc=hughd@google.com \
--cc=ilya.gladyshev@linux.dev \
--cc=jack@suse.cz \
--cc=jaegeuk@kernel.org \
--cc=kas@kernel.org \
--cc=kasong@tencent.com \
--cc=kernel-team@meta.com \
--cc=lance.yang@linux.dev \
--cc=liam@infradead.org \
--cc=linmiaohe@huawei.com \
--cc=linux-mm@kvack.org \
--cc=ljs@kernel.org \
--cc=mcgrof@kernel.org \
--cc=mhocko@suse.com \
--cc=miklos@szeredi.hu \
--cc=nao.horiguchi@gmail.com \
--cc=nico.pache@linux.dev \
--cc=osalvador@suse.de \
--cc=paulmck@kernel.org \
--cc=pfalcato@suse.de \
--cc=qi.zheng@linux.dev \
--cc=rppt@kernel.org \
--cc=ryan.roberts@arm.com \
--cc=sashiko-reviews@lists.linux.dev \
--cc=shakeel.butt@linux.dev \
--cc=surenb@google.com \
--cc=torvalds@linux-foundation.org \
--cc=usama.arif@linux.dev \
--cc=vbabka@kernel.org \
--cc=viro@zeniv.linux.org.uk \
--cc=weixugc@google.com \
--cc=willy@infradead.org \
--cc=yuanchu@google.com \
--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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.