From: Peter Zijlstra <peterz@infradead.org>
To: Chris Mason <mason@kernel.org>
Cc: tglx@kernel.org, linux-kernel@vger.kernel.org,
Paul McKenney <paulmck@kernel.org>
Subject: Re: [PATCH] futex: sample poll cookie after publishing new hash
Date: Thu, 20 Aug 2026 12:40:15 +0200 [thread overview]
Message-ID: <20260820104015.GE687043@noisy.programming.kicks-ass.net> (raw)
In-Reply-To: <20260818011036.1138213-2-mason@kernel.org>
On Mon, Aug 17, 2026 at 06:01:42PM -0700, Chris Mason wrote:
> futex_ref_drop() may only skip its grace period when one has already
> elapsed since the current private hash was published:
>
> kernel/futex/core.c:futex_ref_drop
> if (poll_state_synchronize_rcu(mm->futex.phash.batches)) {
> /*
> * There was a grace-period, we can begin now.
> */
> __futex_ref_atomic_begin(fph);
> return;
> }
>
> The cookie it polls is sampled one statement before that publication:
>
> kernel/futex/core.c:__futex_pivot_hash
> new->state = FR_PERCPU;
> scoped_guard(rcu) {
> mmph->batches = get_state_synchronize_rcu();
> rcu_assign_pointer(mmph->hash, new);
> }
> kvfree_rcu(fph, rcu);
>
> get_state_synchronize_rcu() anchors its guarantee at the snapshot, so
> the cookie is cleared by the first grace period that starts from there
> on, including one starting between the two stores which never waited
> for a reader that loaded the old hash after it began.
>
> CPU 0 (resize) CPU 1 (futex_hash)
> ============== ==================
> __futex_pivot_hash()
> batches = get_state_...()
> grace period starts
> guard(rcu)
> fph = old hash
> rcu_assign_pointer(hash, new)
> kvfree_rcu(old hash)
> futex_hash_allocate()
> futex_ref_drop(new hash)
> poll_state_...() -> true
> __futex_ref_atomic_begin()
> atomic = LONG_MAX
> futex_ref_get(old hash) -> true
> spin_lock(&fph->queues[i].lock)
>
> The reference count lives in the mm and has just been biased for the
> new generation, so the stalled reader pins and then locks the retired
> hash that is already queued for free, and its later put is charged
> against the live generation.
>
> Fix by sampling the cookie after rcu_assign_pointer() publishes the
> new hash. Drop the surrounding scoped_guard(rcu) while at it: it only
> delayed completion of the prematurely anchored grace-period and serves
> no purpose once the cookie is sampled after publication. The writer
> side is serialized by mm->futex.phash.lock and neither
> rcu_assign_pointer() nor kvfree_rcu() requires a read-side section.
God, how I hate reading AI output :-(
Anyway, the thinking was that by holding rcu_read_lock(), the current
RCU-GP cannot change and the cookie and assignment are effectively
'atomic'.
Paul?
> Fixes: 56180dd20c19 ("futex: Use RCU-based per-CPU reference counting instead of rcuref_t")
> Assisted-by: kres:claude-opus-5
> Signed-off-by: Chris Mason <mason@kernel.org>
> ---
> kernel/futex/core.c | 12 ++++++++----
> 1 file changed, 8 insertions(+), 4 deletions(-)
>
> diff --git a/kernel/futex/core.c b/kernel/futex/core.c
> index 128c5752f225..05619eb8329c 100644
> --- a/kernel/futex/core.c
> +++ b/kernel/futex/core.c
> @@ -209,10 +209,14 @@ static bool __futex_pivot_hash(struct mm_struct *mm, struct futex_private_hash *
> futex_rehash_private(fph, new);
> }
> new->state = FR_PERCPU;
> - scoped_guard(rcu) {
> - mmph->batches = get_state_synchronize_rcu();
> - rcu_assign_pointer(mmph->hash, new);
> - }
> + rcu_assign_pointer(mmph->hash, new);
> + /*
> + * Pairs with futex_ref_drop(): ->batches must be sampled at or after
> + * the rcu_assign_pointer() above, so any grace-period satisfying
> + * poll_state_synchronize_rcu() provably started once no reader could
> + * still load the retired fph. Both stores are done under mmph->lock.
> + */
> + mmph->batches = get_state_synchronize_rcu();
> kvfree_rcu(fph, rcu);
> return true;
> }
> --
> 2.53.0-Meta
>
prev parent reply other threads:[~2026-08-20 10:40 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-18 1:01 [PATCH RFC] __futex_pivot_hash() race Chris Mason
2026-08-18 1:01 ` [PATCH] futex: sample poll cookie after publishing new hash Chris Mason
2026-08-20 10:40 ` Peter Zijlstra [this message]
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=20260820104015.GE687043@noisy.programming.kicks-ass.net \
--to=peterz@infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mason@kernel.org \
--cc=paulmck@kernel.org \
--cc=tglx@kernel.org \
/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.