All of lore.kernel.org
 help / color / mirror / Atom feed
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>,
	"Harry Yoo" <harry@kernel.org>
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>,
	"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 v2 09/18] mm/memory-failure: handle folios with PG_rcu_free
Date: Thu, 05 Nov 2026 13:03:41 +0000	[thread overview]
Message-ID: <sashiko-outbox-199102@kernel.org> (raw)
In-Reply-To: <20261104130118.2507513-10-kas@kernel.org>

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] mm/memory-failure: unsafe RCU wait in memory_failure() already-poisoned path
- [High] mm/memory-failure: mf_free_rcu_pages() skips sync while rcu_free_pages() runs
- [Medium] mm/memory-failure: order-0 PG_rcu_free page dropped after setting PG_hwpoison
--

commit 3d8069abfad786882a48d6ce85e757674239a9ca
Author: Kiryl Shutsemau (Meta) <kas@kernel.org>

mm/memory-failure: handle folios with PG_rcu_free

This commit updates memory_failure() and get_any_page() to drain pages
waiting for an RCU grace period via rcu_free_sync() and waits for a
grace period via synchronize_rcu() before returning success on a
PG_rcu_free folio.

> diff --git a/mm/memory-failure.c b/mm/memory-failure.c
> index 7dde7c3c9a0c5..398463b2e82d5 100644
> --- a/mm/memory-failure.c
> +++ b/mm/memory-failure.c
> @@ -1419,6 +1419,19 @@ static int __get_hwpoison_page(struct page *page, unsigned long flags)
>  	return 0;
>  }
>  
> +/* A page waiting for a grace period is not in the buddy yet: free it */
> +static void mf_free_rcu_pages(struct page *p)
> +{
> +	if (!zone_rcu_free_waiting(page_zone(p)))
> +		return;
> +	if (page_count(p))
> +		return;
> +	if (is_free_buddy_page(p))
> +		return;
> +
> +	rcu_free_sync();
> +}

[Severity: High]
As reported by Sashiko on RFC [1], can mf_free_rcu_pages() return early
without calling rcu_free_sync() while rcu_free_pages() is still freeing
the target folio?

In mm/page_alloc.c:rcu_free_pages(), NR_FREE_RCU_PAGES is decremented
before the folios are actually freed to the buddy allocator:

mm/page_alloc.c:rcu_free_pages() {
	list_for_each_entry_safe(folio, next, list, lru) {
		nr += folio_nr_pages(folio);
		mod_zone_page_state(folio_zone(folio), NR_FREE_RCU_PAGES,
				    -folio_nr_pages(folio));
		if (direct) {
			__free_pages_ok(&folio->page, folio_order(folio),
					FPI_NONE);
			cond_resched();
		} else if (!folio_batch_add(&fbatch, folio)) {
			free_unref_folios(&fbatch);
			cond_resched_tasks_rcu_qs();
		}
	}
	if (folio_batch_count(&fbatch))
		free_unref_folios(&fbatch);
}

Similarly, during folio release, folio_put_testzero() drops _refcount to
0 before __free_pages_prepare() -> rcu_free_defer() increments
NR_FREE_RCU_PAGES.

When the last waiting folios in a zone are in either window,
page_count(p) is 0, is_free_buddy_page(p) is false, and
zone_rcu_free_waiting(page_zone(p)) evaluates to false.

If memory_failure() calls mf_free_rcu_pages(p) during this window, it
skips rcu_free_sync() and proceeds to TestSetPageHWPoison(p) before
__free_pages_prepare() runs. For an order-0 page, __free_pages_prepare()
then sees PageHWPoison(page) && !order and drops the page instead of
placing it in the buddy allocator, causing get_hwpoison_page() to fail
with -EIO and leaving the hardware error ignored as MF_IGNORED.

In addition, because memory_failure() calls mf_free_rcu_pages(p) before
get_hwpoison_page() calls zone_pcp_disable(), if rcu_free_workfn() or
rcu_free_expedite_workfn() already spliced p off the per-CPU list,
rcu_free_pages(..., false) -> free_unref_folios() will free p onto a
per-CPU pageset (PCP) list rather than the buddy allocator before
TestSetPageHWPoison(p) runs.

> +
>  #define GET_PAGE_MAX_RETRY_NUM 3
>  
>  static int get_any_page(struct page *p, unsigned long flags)
> @@ -1443,6 +1456,7 @@ static int get_any_page(struct page *p, unsigned long flags)
>  	}
>  
>  try_again:
> +	mf_free_rcu_pages(p);
>  	if (!count_increased) {

[Severity: Medium]
As reported by Sashiko on RFC [2], what happens in memory_failure() if an
in-use order-0 folio with PG_rcu_free is freed on another CPU after the
initial mf_free_rcu_pages(p) call?

In memory_failure(), the initial mf_free_rcu_pages(p) call returns
immediately when page_count(p) > 0:

mm/memory-failure.c:memory_failure() {
	mf_free_rcu_pages(p);
	if (TestSetPageHWPoison(p)) {
		...
	}
	res = get_hwpoison_page(p, flags);
}

If another CPU drops the last reference on that order-0 folio just before
TestSetPageHWPoison(p), __free_pages_prepare() queues the folio via
rcu_free_defer(folio), and TestSetPageHWPoison(p) then sets PG_hwpoison on
p while it is on the RCU free list. When get_hwpoison_page() ->
get_any_page() then calls mf_free_rcu_pages(p) at try_again,
rcu_free_sync() drains p through __free_pages_ok() ->
__free_pages_prepare():

mm/page_alloc.c:__free_pages_prepare() {
	if (unlikely(folio_test_rcu_free(folio)) &&
	    !(PageHWPoison(page) && !order)) {
		...
		rcu_free_defer(folio);
		return false;
	}
	...
	if (unlikely(PageHWPoison(page)) && !order) {
		/* Do not let hwpoison pages hit pcplists/buddy */
		...
		return false;
	}
}

Because PageHWPoison(p) is already set and order is 0,
__free_pages_prepare() drops the page instead of placing it in the buddy
allocator. And if the last reference is dropped after
TestSetPageHWPoison(p) while get_any_page() is retrying,
__free_pages_prepare() sees PageHWPoison(page) && !order, skips
rcu_free_defer(folio) without waiting for an RCU grace period, and also
drops the page.

In both cases, is_free_buddy_page(p) remains false, get_any_page() fails
with -EIO after retrying, and memory_failure() reports MF_IGNORED without
waiting for lockless RCU readers or accounting the page as recovered.

[ ... ]

> @@ -2440,6 +2454,7 @@ int memory_failure(unsigned long pfn, int flags)
>  	if (res != -ENOENT)
>  		goto unlock_mutex;
>  
> +	mf_free_rcu_pages(p);
>  	if (TestSetPageHWPoison(p)) {
>  		res = -EHWPOISON;
>  		if (flags & MF_ACTION_REQUIRED)
> @@ -2447,6 +2462,13 @@ int memory_failure(unsigned long pfn, int flags)
>  		if (flags & MF_COUNT_INCREASED)
>  			put_page(p);
>  		action_result(pfn, MF_MSG_ALREADY_POISONED, MF_FAILED);
> +		/*
> +		 * The memory_failure() that set PG_hwpoison may have failed
> +		 * without waiting for lockless readers, and the caller may
> +		 * unmap the page once this returns 0.
> +		 */
> +		if (!res && folio_test_rcu_free(page_folio(p)))
> +			synchronize_rcu();
>  		goto unlock_mutex;
>  	}

[Severity: High]
As reported by Sashiko on RFC [3], can this already-poisoned path in
memory_failure() return 0 and allow the caller (such as kill_me_maybe() ->
set_mce_nospec()) to unmap pfn from the kernel direct map while lockless
RCU page-cache readers can still access p?

There appear to be two issues when a previous memory_failure() call set
PG_hwpoison on p and then failed before isolating the page (for example,
in get_hwpoison_page() or try_to_split_thp_page()), and a second
memory_failure(pfn, MF_ACTION_REQUIRED) call enters the
TestSetPageHWPoison(p) branch with kill_accessing_process() returning 0:

1. In the TestSetPageHWPoison(p) branch, put_page(p) drops the
MF_COUNT_INCREASED reference before folio_test_rcu_free(page_folio(p)) is
checked, and no reference is held on p during kill_accessing_process() if
MF_COUNT_INCREASED was not set. If the folio's last reference is dropped
after mf_free_rcu_pages(p) (either by put_page(p) or concurrently on
another CPU), __free_pages_prepare() immediately clears PG_rcu_free before
deferring the free:

mm/page_alloc.c:__free_pages_prepare() {
	if (unlikely(folio_test_rcu_free(folio)) &&
	    !(PageHWPoison(page) && !order)) {
		VM_WARN_ON_ONCE(fpi_flags & FPI_NOLOCK);
		__folio_clear_rcu_free(folio);
		count_vm_events(PGFREE_RCU, 1 << order);
		rcu_free_defer(folio);
		return false;
	}
}

When that happens, folio_test_rcu_free(page_folio(p)) evaluates to false
and skips synchronize_rcu() while the folio is still waiting for its RCU
grace period and lockless readers that looked up the folio before it was
freed are still copying from p.

2. If p is part of a large folio and the first memory_failure() failed in
get_hwpoison_page() (before folio_set_has_hwpoisoned(folio)) or in
try_to_split_thp_page():

mm/memory-failure.c:memory_failure() {
		if (err || new_order) {
			/* get folio again in case the original one is split */
			folio = page_folio(p);
			res = -EHWPOISON;
			kill_procs_now(p, pfn, flags, folio);
			put_page(p);
			action_result(pfn, MF_MSG_UNSPLIT_THP, MF_FAILED);
			goto unlock_mutex;
		}
}

the unsplit large folio remains in the page cache with PG_hwpoison only
set on subpage p. Even after synchronize_rcu() completes, new lockless
page-cache readers can still copy the poisoned subpage as part of the
large folio while the caller unmaps p from the direct map.

[1] https://lore.kernel.org/r/20261019154913.1765974-9-kas@kernel.org
[2] https://lore.kernel.org/r/20261019154913.1765974-9-kas@kernel.org
[3] https://lore.kernel.org/r/20261019154913.1765974-9-kas@kernel.org

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20261104130118.2507513-1-kas@kernel.org?part=9


  reply	other threads:[~2026-11-05 13:03 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-04 13:00 [RFC PATCH v2 00/18] mm: read the page cache without folio references Kiryl Shutsemau (Meta)
2026-11-04 13:00 ` [RFC PATCH v2 01/18] mm: free PG_rcu_free folios only after an RCU grace period Kiryl Shutsemau (Meta)
2026-11-05 20:37   ` David Hildenbrand (Arm)
2026-11-06 10:23     ` Kiryl Shutsemau
2026-11-04 13:00 ` [RFC PATCH v2 02/18] splice: don't steal page cache folios Kiryl Shutsemau (Meta)
2026-11-04 16:05   ` David Hildenbrand (Arm)
2026-11-05 14:55     ` Kiryl Shutsemau
2026-11-04 13:00 ` [RFC PATCH v2 03/18] fuse: don't move a folio with PG_rcu_free into a fuse file Kiryl Shutsemau (Meta)
2026-11-04 13:01 ` [RFC PATCH v2 04/18] mm: count the pages waiting for a grace period Kiryl Shutsemau (Meta)
2026-11-04 13:01 ` [RFC PATCH v2 05/18] mm: expedite the grace period when a CPU has many deferred frees Kiryl Shutsemau (Meta)
2026-11-04 13:01 ` [RFC PATCH v2 06/18] mm: free the pages waiting for a grace period before OOM Kiryl Shutsemau (Meta)
2026-11-05 13:03   ` sashiko-bot
2026-11-04 13:01 ` [RFC PATCH v2 07/18] mm: free the pages waiting for a grace period before isolation fails Kiryl Shutsemau (Meta)
2026-11-05 13:03   ` sashiko-bot
2026-11-04 13:01 ` [RFC PATCH v2 08/18] mm/compaction: free the migrated folios that wait for a grace period Kiryl Shutsemau (Meta)
2026-11-05 13:03   ` sashiko-bot
2026-11-04 13:01 ` [RFC PATCH v2 09/18] mm/memory-failure: handle folios with PG_rcu_free Kiryl Shutsemau (Meta)
2026-11-05 13:03   ` sashiko-bot [this message]
2026-11-04 13:01 ` [RFC PATCH v2 10/18] mm: have folio_mark_accessed() return whether the folio is hot Kiryl Shutsemau (Meta)
2026-11-04 13:01 ` [RFC PATCH v2 11/18] mm/filemap: mark a folio accessed in one place in filemap_read() Kiryl Shutsemau (Meta)
2026-11-04 13:01 ` [RFC PATCH v2 12/18] mm/filemap: set PG_rcu_free on the folios that reads keep coming back to Kiryl Shutsemau (Meta)
2026-11-04 13:01 ` [RFC PATCH v2 13/18] mm/filemap: read from the page cache without folio references Kiryl Shutsemau (Meta)
2026-11-04 13:01 ` [RFC PATCH v2 14/18] mm/filemap: read large folios " Kiryl Shutsemau (Meta)
2026-11-05 13:03   ` sashiko-bot
2026-11-04 13:01 ` [RFC PATCH v2 15/18] mm/filemap: don't store f_ra.prev_pos for FMODE_RANDOM files Kiryl Shutsemau (Meta)
2026-11-04 13:01 ` [RFC PATCH v2 16/18] mm/shmem: count accesses to a folio the way filemap_read() does Kiryl Shutsemau (Meta)
2026-11-04 13:01 ` [RFC PATCH v2 17/18] mm/shmem: read without folio references Kiryl Shutsemau (Meta)
2026-11-05 13:03   ` sashiko-bot
2026-11-04 13:01 ` [RFC PATCH v2 18/18] mm/filemap: add a debugfs switch for lockless page cache reads Kiryl Shutsemau (Meta)

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-199102@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.