mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
To: Puranjay Mohan <puranjay@kernel.org>
Cc: "Paul E . McKenney" <paulmck@kernel.org>,
	linux-kernel@vger.kernel.org, Boqun Feng <boqun@kernel.org>,
	Josh Triplett <josh@joshtriplett.org>,
	Frederic Weisbecker <frederic@kernel.org>,
	Neeraj Upadhyay <neeraj.upadhyay@kernel.org>,
	Joel Fernandes <joelagnelf@nvidia.com>,
	Uladzislau Rezki <urezki@gmail.com>,
	Steven Rostedt <rostedt@goodmis.org>,
	Lai Jiangshan <jiangshanlai@gmail.com>,
	Zqiang <qiang.zhang@linux.dev>,
	Linus Torvalds <torvalds@linux-foundation.org>,
	Matthew Wilcox <willy@infradead.org>,
	Christian Brauner <brauner@kernel.org>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	"Liam R . Howlett" <liam@infradead.org>,
	Lorenzo Stoakes <ljs@kernel.org>,
	Alice Ryhl <aliceryhl@google.com>,
	Andrew Ballance <andrewjballance@gmail.com>,
	Peter Zijlstra <peterz@infradead.org>,
	Will Deacon <will@kernel.org>,
	Mark Rutland <mark.rutland@arm.com>,
	Ingo Molnar <mingo@kernel.org>, Thomas Gleixner <tglx@kernel.org>,
	rcu@vger.kernel.org
Subject: Re: [RFC PATCH 00/12] RCU pseudo-transactions
Date: Tue, 27 Oct 2026 15:57:19 -0400	[thread overview]
Message-ID: <f785237c-ee5e-4ad3-8ee9-79474f5f45c8@efficios.com> (raw)
In-Reply-To: <20261023181940.457424-1-puranjay@kernel.org>

On 2026-10-23 14:19, Puranjay Mohan wrote:
> Hi Mathieu,
> 
> On Fri, Oct 16, 2026 at 09:33:07AM -0400, Mathieu Desnoyers wrote:
>> I'd specifically like feedback on:
>>
>> - Where this should live (kernel/rcu/, lib/?),
>>
>> - Naming and API shape (descriptor + records),
>>
>> - Whether the Bloom filter threshold should be a config knob,
>>
>> - Subsystems where this could apply.
> 
> I went through the series and ran the KUnit suite on arm64 (QEMU/KVM)
> with PROVE_LOCKING, PROVE_RAW_LOCK_NESTING and DEBUG_RCU_TXN.  All 59
> cases pass, and herd7 agrees with all 21 litmus tests.  The
> install/flip/settle ordering and the descriptor lifetime look right to
> me.


Thank you for the review and testing!

[...]

> API shape: every rcu_txn_list add, delete and replace allocates a
> descriptor and frees it with kfree_rcu(), so all of them can fail with
> -ENOMEM, delete included.  That is hard to use on teardown paths, and
> reserving first only moves the failure.  Since a descriptor can be
> reused a grace period after its commit, have you considered a small
> cache of them, tagged with start_poll_synchronize_rcu() and checked with
> poll_state_synchronize_rcu()?

This question is really the crux of your feedback. There are many options
to explore here, and it all depends on the user expectations. Let's focus
on this one and keep your other questions for separate replies.

First, I suspect that the "add" and "replace" cases could fail with -ENOMEM
without too much problem, which really leaves "remove" as problematic.

The problem with the cache of descriptors (which I've done in my userspace
implementation already, a per-cpu "txn slab cache") is that it does not
fully address your concern: a thread doing a batch list removal in a huge
linked list can run out of pre-allocated descriptors before the grace period
ends and the descriptors are freed. How should we handle that ?

We should consider the way struct rcu_head is designed for call_rcu as a
precedent here. The tradeoff is to accept a waste of 16 bytes within
objects to make sure there is no memory allocation needed when call_rcu
is invoked. This ensures there is no situation where the caller may need
to block and wait for memory to be freed when invoking call_rcu, e.g. in
teardown scenarios.

The basic question is whether there is a _hard_ requirement on making sure
a list removal operation *never* sleeps due to memory allocation.

Another open question is whether what we want to prevent here is only memory
allocation, or do we also want to prevent blocking that waits for a RCU
grace period to complete ? Or RCU deferral the culprit of the issue here ?

Here are a few takes on what the user requirement could look like:


A) Allocate on object creation, no allocation on removal (hard requirement)

If there is a hard requirement on never allocating memory on list removal
(not even GFP_ATOMIC), here is one possible option:

We could embed 2x struct rcu_txn_record into each list node, so it's already
available for the eventual removal. We could then change the txn descriptor
from a flat array into a piecewise scattered set of 2 entries records
(one pair of records per pre-planned removal operation).

This wastes memory during the entire object lifetime. This could sit on
cache lines separate from the hot object cache lines. These objects would
need to plan space for the rcu_txn_group (the selector) so there is really
no rcu-reclaimed memory allocated for the transaction descriptor on removal.

The space overhead would be 4x larger than for rcu_head though, we're talking
about roughly one cache line (64 bytes)­ per object for list removal (2 records).


B) Use a preallocated per-cpu rcu-txn slab, allocate GFP_ATOMIC when slab is empty

Another option is to consider using a per-cpu slab of preallocated txn
descriptors. This suffers from the basic problem that if a user pushes
hard and depletes the reserve, we end up in a scenario where we still
need to allocate from that context.

Relying on GFP_ATOMIC allocation could help, up to a point, but this is not
bulletproof, as a user could also theoretically empty the atomic emergency
reserve as well.


C) Require user to pre-reserve txn descriptors in contexts able to handle allocation error

I've actually used that approach in my userspace fractal trie implementation to facilitate
error handling: each mutation operation first reserves all the memory it needs for
the rcu txns it will need to perform throughout the entire operation (e.g.
insertion, removal, rekey, graft...) so ENOMEM can be handled early before any
externally observable side-effect is done. This requires to carefully design the
data structure mutations so they are split into a planning, allocation and commit
stages.

I find that this approach was a good fit for userspace, but it does require to
allow "removal" operations to fail with ENOMEM if there is no memory available,
so I'm not sure how applicable it is for the kernel.


D) Use a preallocated per-cpu rcu-txn slab, synchronize_rcu when slab is empty
    (sleepable caller)

I would expect users to remove list items from within RCU read-side critical sections,
so calling synchronize_rcu() on the same RCU grace period "domain" would break this.

One alternative there is to consider having a different RCU grace period "domain" for
RCU txn, and wrap all accesses to the txn descriptors within that RCU domain read-side.
This way we could handle OOM by enqueuing the thread hitting OOM on a waitqueue associated
with the rcu-txn slab, which would necessarily be woken up when RCU readers of that
rcu-txn domain complete (typically in a short time frame), and the call-rcu worker moves
the memory back to the rcu-txn slab, and issues the wakeup.


E) Use a preallocated per-cpu rcu-txn slab, synchronize txn descriptor reclaim with
    RCU (steady state) and hazard pointers (OOM)

This is basically just pushing idea (D) further to remove the need for sleepable callers.
We surround the rcu txn proxy pointer resolve with both a RCU read-side critical section
and a hazard pointer slab address guard, thus protecting the use of the txn descriptor
with two types of critical sections. The resolve would run with interrupts disabled.
The "resolve" path of txn proxy is not a fast path, so we don't mind the extra overhead
too much.

On the "remove" side, we typically have plenty of preallocated rcu-txn from the slab.
In the common case, we keep using RCU deferral to free the rcu-txn in batches. This
would implement a custom per-cpu pending list to enable the following "stealing"
scheme.

In the rare cases where a user empties the slab, we move to a more aggressive
mechanism based on synchronize_hazptr: we "steal" the batched in-flight RCU txn
reclaims so we can fast-track their reclaim after a hazptr synchronize. This would
all be using busy-wait and the only contexts we'd wait against have irqs disabled.

The motivation for handling the steady-state with RCU is throughput (no synchronize_hazptr
on the typical "remove" case). Hazard pointers then handle the OOM corner case without
requiring sleepable callers.

Thoughts ?

Thanks,

Mathieu

-- 
Mathieu Desnoyers
EfficiOS Inc.
https://www.efficios.com

  reply	other threads:[~2026-10-27 19:57 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-16 13:33 Mathieu Desnoyers
2026-10-16 13:33 ` [RFC PATCH 01/12] rcu_txn: Add single-writer " Mathieu Desnoyers
2026-10-23 18:22   ` Puranjay Mohan
2026-10-16 13:33 ` [RFC PATCH 02/12] rcu_txn: Add KUnit tests Mathieu Desnoyers
2026-10-16 13:33 ` [RFC PATCH 03/12] rcu_txn: Skip the record lookup with a Bloom filter Mathieu Desnoyers
2026-10-23 18:22   ` Puranjay Mohan
2026-10-16 13:33 ` [RFC PATCH 04/12] rcu_txn: Add CONFIG_DEBUG_RCU_TXN Mathieu Desnoyers
2026-10-23 18:22   ` Puranjay Mohan
2026-10-16 13:33 ` [RFC PATCH 05/12] rcu_txn: Add an hlist edited through transactions Mathieu Desnoyers
2026-10-23 18:22   ` Puranjay Mohan
2026-10-16 13:33 ` [RFC PATCH 06/12] rcu_txn: Add a doubly-linked list coherent in both directions Mathieu Desnoyers
2026-10-23 18:22   ` Puranjay Mohan
2026-10-16 13:33 ` [RFC PATCH 07/12] Documentation/RCU: Describe RCU pseudo-transactions Mathieu Desnoyers
2026-10-16 13:33 ` [RFC PATCH 08/12] Documentation/litmus-tests: Add RCU pseudo-transaction tests Mathieu Desnoyers
2026-10-16 13:33 ` [RFC PATCH 09/12] rcu_txn: Test a list writer against concurrent readers Mathieu Desnoyers
2026-10-23 18:22   ` Puranjay Mohan
2026-10-16 13:33 ` [RFC PATCH 10/12] rcu_txn: Test a commit from atomic context Mathieu Desnoyers
2026-10-23 18:22   ` Puranjay Mohan
2026-10-16 13:33 ` [RFC PATCH 11/12] samples: Add a cache on RCU pseudo-transactions under one mutex Mathieu Desnoyers
2026-10-16 13:33 ` [RFC PATCH 12/12] samples: Add a cache on RCU pseudo-transactions with a lock per node Mathieu Desnoyers
2026-10-23 18:22   ` Puranjay Mohan
2026-10-19  0:55 ` [RFC PATCH 00/12] RCU pseudo-transactions Joel Fernandes
2026-10-23 13:37   ` Mathieu Desnoyers
2026-10-23 18:19 ` Puranjay Mohan
2026-10-27 19:57   ` Mathieu Desnoyers [this message]
2026-10-28  1:13     ` Mathieu Desnoyers

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=f785237c-ee5e-4ad3-8ee9-79474f5f45c8@efficios.com \
    --to=mathieu.desnoyers@efficios.com \
    --cc=aliceryhl@google.com \
    --cc=andrewjballance@gmail.com \
    --cc=boqun@kernel.org \
    --cc=brauner@kernel.org \
    --cc=frederic@kernel.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=jiangshanlai@gmail.com \
    --cc=joelagnelf@nvidia.com \
    --cc=josh@joshtriplett.org \
    --cc=liam@infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=ljs@kernel.org \
    --cc=mark.rutland@arm.com \
    --cc=mingo@kernel.org \
    --cc=neeraj.upadhyay@kernel.org \
    --cc=paulmck@kernel.org \
    --cc=peterz@infradead.org \
    --cc=puranjay@kernel.org \
    --cc=qiang.zhang@linux.dev \
    --cc=rcu@vger.kernel.org \
    --cc=rostedt@goodmis.org \
    --cc=tglx@kernel.org \
    --cc=torvalds@linux-foundation.org \
    --cc=urezki@gmail.com \
    --cc=will@kernel.org \
    --cc=willy@infradead.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 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®