* [PATCH 0/1] rcu: drain kfree_rcu sheaves from the userspace barrier hook
@ 2026-09-10 10:11 Matthias Goergens
2026-09-10 10:11 ` [PATCH 1/1] " Matthias Goergens
2026-09-10 17:00 ` [PATCH v2 0/1] rcu: make userspace barrier hook drain kvfree_rcu work Matthias Goergens
0 siblings, 2 replies; 8+ messages in thread
From: Matthias Goergens @ 2026-09-10 10:11 UTC (permalink / raw)
To: paulmck, frederic, neeraj.upadhyay, joelagnelf, josh, boqun, urezki
Cc: rostedt, mathieu.desnoyers, jiangshanlai, qiang.zhang, corbet,
skhan, rdunlap, harry, surenb, vbabka, rcu, linux-doc,
linux-kernel
The rcutree.do_rcu_barrier test hook currently waits for ordinary RCU
callbacks, but it can return while kfree_rcu() still retains an object in a
partial per-CPU sheaf. This defeats the hook's purpose of preventing deferred
frees from one test spilling into the next.
The patch drains kfree_rcu sheaves and batches before retaining the hook's
explicit ordinary rcu_barrier(). Four counterbalanced fresh-VM pairs with the
full validation fixture reported 60 -> 60 active objects on the unpatched
kernel and 60 -> 59 on the patched kernel. An ordinary-callback regression
test passed on both kernels.
The primary reproducer below removes that separate regression machinery. One
fresh control/treatment pair with this exact 41-line source reproduced the
same 60 -> 60 versus 60 -> 59 split; both cells reached TEST SUCCESS with no
problem-class kernel records.
Save the source as rcu_barrier_sheaf_repro.c and create a Makefile containing:
obj-m := rcu_barrier_sheaf_repro.o
Build it with:
make -C /lib/modules/$(uname -r)/build M="$PWD" modules
Then, as root on a disposable test kernel:
insmod rcu_barrier_sheaf_repro.ko
awk '$1 == "rcu_barrier_sheaf_repro" { print $2 }' /proc/slabinfo
cat /sys/kernel/slab/rcu_barrier_sheaf_repro/sheaf_capacity
echo 1 > /sys/module/rcutree/parameters/do_rcu_barrier
awk '$1 == "rcu_barrier_sheaf_repro" { print $2 }' /proc/slabinfo
rmmod rcu_barrier_sheaf_repro
The first and second slabinfo readings are 60 and 60 without the patch, and
60 and 59 with it. kmem_cache_destroy() performs per-cache deferred-free
cleanup when the module is removed, after the measurement.
// SPDX-License-Identifier: GPL-2.0
#include <linux/init.h>
#include <linux/module.h>
#include <linux/rcupdate.h>
#include <linux/slab.h>
struct repro_object {
struct rcu_head rcu;
unsigned long payload;
};
static struct kmem_cache *repro_cache;
static int __init rcu_barrier_sheaf_repro_init(void)
{
struct repro_object *object;
repro_cache = kmem_cache_create("rcu_barrier_sheaf_repro",
sizeof(*object), 0, SLAB_NO_MERGE, NULL);
if (!repro_cache)
return -ENOMEM;
object = kmem_cache_alloc(repro_cache, GFP_KERNEL);
if (!object) {
kmem_cache_destroy(repro_cache);
return -ENOMEM;
}
kfree_rcu(object, rcu);
return 0;
}
static void __exit rcu_barrier_sheaf_repro_exit(void)
{
kmem_cache_destroy(repro_cache);
}
module_init(rcu_barrier_sheaf_repro_init);
module_exit(rcu_barrier_sheaf_repro_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Reproduce incomplete rcutree.do_rcu_barrier drains");
Matthias Goergens (1):
rcu: drain kfree_rcu sheaves from the userspace barrier hook
.../admin-guide/kernel-parameters.txt | 7 ++---
kernel/rcu/tree.c | 27 ++++++++++++-------
2 files changed, 21 insertions(+), 13 deletions(-)
base-commit: 50d05c7c76c96b90462f24debacca971d2e86713
--
2.55.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/1] rcu: drain kfree_rcu sheaves from the userspace barrier hook
2026-09-10 10:11 [PATCH 0/1] rcu: drain kfree_rcu sheaves from the userspace barrier hook Matthias Goergens
@ 2026-09-10 10:11 ` Matthias Goergens
2026-09-10 12:03 ` Harry Yoo
2026-09-10 17:00 ` [PATCH v2 0/1] rcu: make userspace barrier hook drain kvfree_rcu work Matthias Goergens
1 sibling, 1 reply; 8+ messages in thread
From: Matthias Goergens @ 2026-09-10 10:11 UTC (permalink / raw)
To: paulmck, frederic, neeraj.upadhyay, joelagnelf, josh, boqun, urezki
Cc: rostedt, mathieu.desnoyers, jiangshanlai, qiang.zhang, corbet,
skhan, rdunlap, harry, surenb, vbabka, rcu, linux-doc,
linux-kernel
The rcutree.do_rcu_barrier test hook is intended to prevent deferred RCU
callbacks from one stress test spilling into the next. Since kfree_rcu()
sheaves were added, an object can remain deferred without appearing on an
ordinary RCU callback list. rcu_barrier() therefore no longer fulfils the
hook's stated purpose by itself.
Drain kfree_rcu sheaves and kvfree_rcu batches before completing the
ordinary RCU barrier. Keep the explicit rcu_barrier() because the hook's
original ordinary-callback contract should not depend on the current,
undocumented fact that kvfree_rcu_barrier() includes one internally.
Keep the existing throttling because this remains a deliberately expensive
test-only action. Do not coalesce requests based on the ordinary
rcu_barrier() sequence: an unrelated ordinary barrier does not prove that
sheaves were drained.
A reproducer creates a private SLAB_NO_MERGE cache whose first allocation
populates a 60-object slab. It queues that object with kfree_rcu(), invokes
the hook, and reads the active-object count from /proc/slabinfo. In four
fresh VM pairs, the parent retained the object (60 to 60). The patched hook
drained it (60 to 59).
Fixes: ec66e0d59952 ("slab: add sheaf support for batching kfree_rcu() operations")
Signed-off-by: Matthias Goergens <matthias.goergens@gmail.com>
---
.../admin-guide/kernel-parameters.txt | 7 ++---
kernel/rcu/tree.c | 27 ++++++++++++-------
2 files changed, 21 insertions(+), 13 deletions(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 68647ff4bdd2..244a53166249 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -5699,9 +5699,10 @@ Kernel parameters
there is an ongoing too-long CSD-lock wait.
rcutree.do_rcu_barrier= [KNL]
- Request a call to rcu_barrier(). This is
- throttled so that userspace tests can safely
- hammer on the sysfs variable if they so choose.
+ Request that deferred kfree_rcu() objects and
+ ordinary call_rcu() callbacks be drained. This is
+ throttled so that userspace tests can safely hammer
+ on the sysfs variable if they so choose.
If triggered before the RCU grace-period machinery
is fully active, this will error out with EAGAIN.
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index 96848fc1f02b..014e28ec3bd3 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -3989,12 +3989,12 @@ EXPORT_SYMBOL_GPL(rcu_barrier);
static unsigned long rcu_barrier_last_throttle;
/**
- * rcu_barrier_throttled - Do rcu_barrier(), but limit to one per second
+ * rcu_barrier_throttled - Drain deferred RCU frees, but rate-limit starts
*
- * This can be thought of as guard rails around rcu_barrier() that
- * permits unrestricted userspace use, at least assuming the hardware's
- * try_cmpxchg() is robust. There will be at most one call per second to
- * rcu_barrier() system-wide from use of this function, which means that
+ * This can be thought of as guard rails around the deferred-free barriers
+ * that permit unrestricted userspace use, at least assuming the hardware's
+ * try_cmpxchg() is robust. There will be at most one drain operation started
+ * per sixteenth of a second from use of this function, which means that
* callers might needlessly wait a second or three.
*
* This is intended for use by test suites to avoid OOM by flushing RCU
@@ -4011,18 +4011,25 @@ static void rcu_barrier_throttled(void)
{
unsigned long j = jiffies;
unsigned long old = READ_ONCE(rcu_barrier_last_throttle);
- unsigned long s = rcu_seq_snap(&rcu_state.barrier_sequence);
while (time_in_range(j, old, old + HZ / 16) ||
!try_cmpxchg(&rcu_barrier_last_throttle, &old, j)) {
schedule_timeout_idle(HZ / 16);
- if (rcu_seq_done(&rcu_state.barrier_sequence, s)) {
- smp_mb(); /* caller's subsequent code after above check. */
- return;
- }
j = jiffies;
old = READ_ONCE(rcu_barrier_last_throttle);
}
+ /*
+ * kfree_rcu() can retain objects outside the ordinary callback lists in
+ * per-CPU SLUB sheaves and kvfree_rcu batches. Test suites use this hook
+ * to prevent deferred frees from spilling into the following test, so
+ * drain those queues as well as ordinary call_rcu() callbacks.
+ *
+ * kvfree_rcu_barrier() currently includes an ordinary barrier, but that
+ * is not part of its documented API. Keep the explicit rcu_barrier() so
+ * this hook's original contract does not depend on slab implementation
+ * details.
+ */
+ kvfree_rcu_barrier();
rcu_barrier();
}
--
2.55.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/1] rcu: drain kfree_rcu sheaves from the userspace barrier hook
2026-09-10 10:11 ` [PATCH 1/1] " Matthias Goergens
@ 2026-09-10 12:03 ` Harry Yoo
2026-09-10 13:46 ` Matthias Goergens
0 siblings, 1 reply; 8+ messages in thread
From: Harry Yoo @ 2026-09-10 12:03 UTC (permalink / raw)
To: Matthias Goergens
Cc: paulmck, frederic, neeraj.upadhyay, joelagnelf, josh, boqun,
urezki, rostedt, mathieu.desnoyers, jiangshanlai, qiang.zhang,
corbet, skhan, rdunlap, surenb, vbabka, rcu, linux-doc,
linux-kernel
On Thu, Sep 10, 2026 at 06:11:12PM +0800, Matthias Goergens wrote:
> The rcutree.do_rcu_barrier test hook is intended to prevent deferred RCU
> callbacks from one stress test spilling into the next. Since kfree_rcu()
> sheaves were added, an object can remain deferred without appearing on an
> ordinary RCU callback list. rcu_barrier() therefore no longer fulfils the
> hook's stated purpose by itself.
>
> Drain kfree_rcu sheaves and kvfree_rcu batches before completing the
> ordinary RCU barrier.
I'm convinced that the behavior of "do rcu_barrier()" knob
to imply a kvfree_rcu_barrier() is the right fix.
And also I wonder what's the user-facing problem you are trying to fix.
You can't pile up unbounded amount of objects via kvfree_rcu() to cause
an OOM during the userspace tests?
How did you discover the problem?
> Keep the explicit rcu_barrier() because the hook's
> original ordinary-callback contract should not depend on the current,
> undocumented fact that kvfree_rcu_barrier() includes one internally.
>
> Keep the existing throttling because this remains a deliberately expensive
> test-only action. Do not coalesce requests based on the ordinary
> rcu_barrier() sequence: an unrelated ordinary barrier does not prove that
> sheaves were drained.
>
> A reproducer creates a private SLAB_NO_MERGE cache whose first allocation
> populates a 60-object slab. It queues that object with kfree_rcu(), invokes
> the hook, and reads the active-object count from /proc/slabinfo. In four
> fresh VM pairs, the parent retained the object (60 to 60). The patched hook
> drained it (60 to 59).
>
> Fixes: ec66e0d59952 ("slab: add sheaf support for batching kfree_rcu() operations")
This Fixes: commit is incorrect because the problem was introduced
by kvfree_rcu(), not sheaves.
> Signed-off-by: Matthias Goergens <matthias.goergens@gmail.com>
> ---
> .../admin-guide/kernel-parameters.txt | 7 ++---
> kernel/rcu/tree.c | 27 ++++++++++++-------
> 2 files changed, 21 insertions(+), 13 deletions(-)
>
--
Cheers,
Harry / Hyeonggon
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/1] rcu: drain kfree_rcu sheaves from the userspace barrier hook
2026-09-10 12:03 ` Harry Yoo
@ 2026-09-10 13:46 ` Matthias Goergens
2026-09-10 15:37 ` Harry Yoo
0 siblings, 1 reply; 8+ messages in thread
From: Matthias Goergens @ 2026-09-10 13:46 UTC (permalink / raw)
To: Harry Yoo
Cc: Matthias Goergens, paulmck, frederic, neeraj.upadhyay,
joelagnelf, josh, boqun, urezki, rostedt, mathieu.desnoyers,
jiangshanlai, qiang.zhang, corbet, skhan, rdunlap, surenb,
vbabka, rcu, linux-doc, linux-kernel
Thanks. I ran into this while testing bcachefs performance changes. The bcachefs ktest end checks write `do_rcu_barrier` before reading `/proc/allocinfo`, with the expectation that allocations still reported afterwards are leaks. Small objects released with `kfree_rcu()` remained visible after repeated writes to the hook and 20 seconds of waiting, so otherwise clean tests failed their leak check.
Strictly, that ktest is assuming a stronger contract than the hook currently documents: `do_rcu_barrier` promises an ordinary `rcu_barrier()`, not a complete drain of objects still held in `kfree_rcu()` batching. I nevertheless think the stronger behaviour is useful for this test-only quiescence hook, because it lets allocation-leak checks reliably separate deferred frees from genuine leaks.
I followed those allocations across repeated filesystem lifecycles. Their number eventually fell when an RCU sheaf filled, so I have no evidence that this path grows without bound or causes OOM. The problem I observed is limited to test isolation: the hook can leave deferred frees behind and make them look like leaks. With the proposed change, the same unmodified bcachefs workload passed the leak check.
After tracing that behaviour, I wrote the private-cache module in the cover letter to reproduce it without bcachefs. I can publish the original bcachefs workload and results if anyone is interested.
I also found that this exact follow-on was discussed when `kvfree_rcu_barrier()` was added in 2024: Paul proposed calling it from `rcu_barrier_throttled()` for clean userspace benchmark baselines, and Uladzislau agreed that adding it and documenting both operations was safest: https://lore.kernel.org/all/20240820155935.1167988-1-urezki@gmail.com/
You are right about the `Fixes:` tag. `kvfree_rcu()` batching predates `do_rcu_barrier`, and the existing interface does what it documents, so the later sheaf commit is not the right introduction point. I will omit the `Fixes:` tag in v2 and present this as a strengthening of the test interface.
--
Matthias
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 1/1] rcu: drain kfree_rcu sheaves from the userspace barrier hook
2026-09-10 13:46 ` Matthias Goergens
@ 2026-09-10 15:37 ` Harry Yoo
0 siblings, 0 replies; 8+ messages in thread
From: Harry Yoo @ 2026-09-10 15:37 UTC (permalink / raw)
To: Matthias Goergens
Cc: paulmck, frederic, neeraj.upadhyay, joelagnelf, josh, boqun,
urezki, rostedt, mathieu.desnoyers, jiangshanlai, qiang.zhang,
corbet, skhan, rdunlap, surenb, vbabka, rcu, linux-doc,
linux-kernel
Hi Matthias, thanks for reply.
Would you please wraparound the text when writing a reply?
Each line becomes way too long on text based editors :-)
Anyway, moving on to the topic...
On Thu, Sep 10, 2026 at 09:46:40PM +0800, Matthias Goergens wrote:
> Thanks. I ran into this while testing bcachefs performance changes.
> The bcachefs ktest end checks write `do_rcu_barrier` before reading
> `/proc/allocinfo`, with the expectation that allocations still
> reported afterwards are leaks. Small objects released with
> `kfree_rcu()` remained visible after repeated writes to the hook and
> 20 seconds of waiting, so otherwise clean tests failed their leak
> check.
Thanks. Some background like this would be nice to be covered in the
cover letter or commit message :-)
> Strictly, that ktest is assuming a stronger contract than the hook
> currently documents: `do_rcu_barrier` promises an ordinary
> `rcu_barrier()`, not a complete drain of objects still held in
> `kfree_rcu()` batching. I nevertheless think the stronger behaviour
> is useful for this test-only quiescence hook, because it lets
> allocation-leak checks reliably separate deferred frees from genuine
> leaks.
Ack.
> I followed those allocations across repeated filesystem lifecycles.
> Their number eventually fell when an RCU sheaf filled, so I have no
> evidence that this path grows without bound or causes OOM.
Ah, the reason I mentioned unbounded amount of objects was because
the commit 16128b1f8c823438dc that introduced the knob explains
what can go wrong (e.g OOMs during the test) without the
rcutree.do_rcu_barrier.
> The problem I observed is limited to test isolation: the hook can
> leave deferred frees behind and make them look like leaks. With the
> proposed change, the same unmodified bcachefs workload passed the
> leak check.
It'd be more convincing if this part is included in the changelog ;-)
> I also found that this exact follow-on was discussed when
> `kvfree_rcu_barrier()` was added in 2024: Paul proposed calling it
> from `rcu_barrier_throttled()` for clean userspace benchmark
> baselines, and Uladzislau agreed that adding it and documenting both
> operations was safest:
> https://lore.kernel.org/all/20240820155935.1167988-1-urezki@gmail.com/
Didn't notice that, and makes sense given the purpose of the knob.
> I will omit the `Fixes:` tag in v2 and present this as a strengthening
> of the test interface.
Makes sense to me.
--
Cheers,
Harry / Hyeonggon
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 0/1] rcu: make userspace barrier hook drain kvfree_rcu work
2026-09-10 10:11 [PATCH 0/1] rcu: drain kfree_rcu sheaves from the userspace barrier hook Matthias Goergens
2026-09-10 10:11 ` [PATCH 1/1] " Matthias Goergens
@ 2026-09-10 17:00 ` Matthias Goergens
2026-09-10 17:00 ` [PATCH v2 1/1] " Matthias Goergens
1 sibling, 1 reply; 8+ messages in thread
From: Matthias Goergens @ 2026-09-10 17:00 UTC (permalink / raw)
To: paulmck, urezki, harry
Cc: frederic, neeraj.upadhyay, joelagnelf, josh, boqun, rostedt,
mathieu.desnoyers, jiangshanlai, qiang.zhang, corbet, skhan,
rdunlap, surenb, vbabka, rcu, linux-doc, linux-kernel
The rcutree.do_rcu_barrier hook currently waits for ordinary RCU
callbacks, but objects may still be retained in kfree_rcu() batching or a
partial per-CPU SLUB sheaf. This is consistent with the hook's documented
rcu_barrier() operation, but incomplete for its intended use as a boundary
between userspace tests.
The immediate trigger was a false allocation-leak failure in the bcachefs
ktest suite while testing performance changes. Its end check writes the
hook before reading /proc/allocinfo, assuming a complete deferred-free
drain. Small objects remained visible after repeated hook writes and
20 seconds of waiting, so otherwise clean tests failed their leak check.
Changing the hook to drain kvfree_rcu() work let the same unmodified
bcachefs workload pass its allocation check. All eight checkpoints in
one VM, after 50 through 400 option changes, reported zero retained
reconcile_scan objects. The retained population on the original kernel
eventually fell as a sheaf filled; there is no evidence here of unbounded
growth or OOM.
Calling kvfree_rcu_barrier() from rcu_barrier_throttled() was proposed and
agreed during review of the former API in 2024, specifically to restore a
clean baseline between userspace benchmark runs:
https://lore.kernel.org/all/20240820155935.1167988-1-urezki@gmail.com/
This patch implements that follow-up and documents the expanded hook. It
also removes the old ordinary-barrier completion shortcut: an unrelated
rcu_barrier() does not establish that kvfree_rcu() work was drained.
Four counterbalanced fresh-VM pairs with the full private-cache fixture
reported 60 to 60 active objects on the unpatched kernel and 60 to 59 on
the patched kernel. A separate ordinary-callback regression test passed
on both kernels.
The simplified reproducer below removes that separate regression
machinery. One additional fresh control/treatment pair with this exact
41-line source confirmed the same 60 to 60 versus 60 to 59 split. These
counts reflect the slab layout in the tested configuration.
Save the source as rcu_barrier_sheaf_repro.c and create a Makefile
containing:
obj-m := rcu_barrier_sheaf_repro.o
Build it with:
make -C /lib/modules/$(uname -r)/build M="$PWD" modules
Then, as root on a disposable test kernel:
insmod rcu_barrier_sheaf_repro.ko
awk '$1 == "rcu_barrier_sheaf_repro" { print $2 }' /proc/slabinfo
cat /sys/kernel/slab/rcu_barrier_sheaf_repro/sheaf_capacity
echo 1 > /sys/module/rcutree/parameters/do_rcu_barrier
awk '$1 == "rcu_barrier_sheaf_repro" { print $2 }' /proc/slabinfo
rmmod rcu_barrier_sheaf_repro
The first and second slabinfo readings are 60 and 60 without the patch,
and 60 and 59 with it. kmem_cache_destroy() performs per-cache
deferred-free cleanup when the module is removed, after the measurement.
// SPDX-License-Identifier: GPL-2.0
#include <linux/init.h>
#include <linux/module.h>
#include <linux/rcupdate.h>
#include <linux/slab.h>
struct repro_object {
struct rcu_head rcu;
unsigned long payload;
};
static struct kmem_cache *repro_cache;
static int __init rcu_barrier_sheaf_repro_init(void)
{
struct repro_object *object;
repro_cache = kmem_cache_create("rcu_barrier_sheaf_repro",
sizeof(*object), 0, SLAB_NO_MERGE, NULL);
if (!repro_cache)
return -ENOMEM;
object = kmem_cache_alloc(repro_cache, GFP_KERNEL);
if (!object) {
kmem_cache_destroy(repro_cache);
return -ENOMEM;
}
kfree_rcu(object, rcu);
return 0;
}
static void __exit rcu_barrier_sheaf_repro_exit(void)
{
kmem_cache_destroy(repro_cache);
}
module_init(rcu_barrier_sheaf_repro_init);
module_exit(rcu_barrier_sheaf_repro_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Reproduce incomplete rcutree.do_rcu_barrier drains");
---
Changes since v1:
- Add the motivating bcachefs failure and the successful unmodified
workload result to both the cover letter and commit message.
- Drop the incorrect sheaf Fixes: tag and regression framing; describe
this as a strengthening of the existing test interface.
- Credit the agreed 2024 proposal for this extension.
- Broaden the subject and changelog from sheaves to kvfree_rcu work.
- Hard-wrap the prose for text-based mail readers.
The code diff is unchanged from v1. The results above are the existing
validation results; no new kernel tests were run for this prose revision.
v1:
https://lore.kernel.org/all/20260910101112.1648978-1-matthias.goergens@gmail.com/
Matthias Goergens (1):
rcu: make userspace barrier hook drain kvfree_rcu work
.../admin-guide/kernel-parameters.txt | 7 ++---
kernel/rcu/tree.c | 27 ++++++++++++-------
2 files changed, 21 insertions(+), 13 deletions(-)
base-commit: 50d05c7c76c96b90462f24debacca971d2e86713
--
2.55.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 1/1] rcu: make userspace barrier hook drain kvfree_rcu work
2026-09-10 17:00 ` [PATCH v2 0/1] rcu: make userspace barrier hook drain kvfree_rcu work Matthias Goergens
@ 2026-09-10 17:00 ` Matthias Goergens
2026-09-10 17:51 ` Paul E. McKenney
0 siblings, 1 reply; 8+ messages in thread
From: Matthias Goergens @ 2026-09-10 17:00 UTC (permalink / raw)
To: paulmck, urezki, harry
Cc: frederic, neeraj.upadhyay, joelagnelf, josh, boqun, rostedt,
mathieu.desnoyers, jiangshanlai, qiang.zhang, corbet, skhan,
rdunlap, surenb, vbabka, rcu, linux-doc, linux-kernel
The bcachefs ktest allocation-leak check writes rcutree.do_rcu_barrier
before reading /proc/allocinfo. While testing bcachefs performance
changes, small objects released with kfree_rcu() remained visible after
repeated writes to the hook and 20 seconds of waiting, causing otherwise
clean tests to fail their leak check.
The test assumes a stronger contract than the hook currently documents:
rcu_barrier() waits for ordinary callbacks, but does not flush objects
still held in kfree_rcu() batching or per-CPU SLUB sheaves. The retained
population eventually fell as a sheaf filled; there is no evidence here
of unbounded growth or OOM.
Changing the hook to drain kvfree_rcu() work let the same unmodified
bcachefs workload pass its allocation check. All eight checkpoints in
one VM, after 50 through 400 option changes, reported zero retained
reconcile_scan objects. This motivated the separate private-cache
reproducer used to isolate the incomplete drain from bcachefs.
Calling kvfree_rcu_barrier() from rcu_barrier_throttled() was proposed
when the former API was added in 2024, to restore a clean baseline
between userspace benchmark runs. The discussion concluded that keeping
the existing hook name, adding the second operation and documenting both
was the safest compatibility choice, but the follow-up was not added.
Add that drain and document the stronger test interface. Keep the
explicit rcu_barrier() so the hook's ordinary-callback contract does not
depend on kvfree_rcu_barrier() reaching an ordinary barrier internally.
Do not reuse the ordinary rcu_barrier() sequence as an early-completion
check while throttling: an unrelated ordinary barrier does not establish
that kvfree_rcu() work was drained. Retain the existing start-rate limit.
Four fresh VM pairs with the full private-cache fixture retained the
queued object without the patch (60 to 60 active objects) and drained it
with the patch (60 to 59). A separate ordinary-callback regression test
passed on both kernels.
Link: https://lore.kernel.org/all/20240820155935.1167988-1-urezki@gmail.com/
Signed-off-by: Matthias Goergens <matthias.goergens@gmail.com>
---
.../admin-guide/kernel-parameters.txt | 7 ++---
kernel/rcu/tree.c | 27 ++++++++++++-------
2 files changed, 21 insertions(+), 13 deletions(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 68647ff4bdd2..244a53166249 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -5699,9 +5699,10 @@ Kernel parameters
there is an ongoing too-long CSD-lock wait.
rcutree.do_rcu_barrier= [KNL]
- Request a call to rcu_barrier(). This is
- throttled so that userspace tests can safely
- hammer on the sysfs variable if they so choose.
+ Request that deferred kfree_rcu() objects and
+ ordinary call_rcu() callbacks be drained. This is
+ throttled so that userspace tests can safely hammer
+ on the sysfs variable if they so choose.
If triggered before the RCU grace-period machinery
is fully active, this will error out with EAGAIN.
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index 96848fc1f02b..014e28ec3bd3 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -3989,12 +3989,12 @@ EXPORT_SYMBOL_GPL(rcu_barrier);
static unsigned long rcu_barrier_last_throttle;
/**
- * rcu_barrier_throttled - Do rcu_barrier(), but limit to one per second
+ * rcu_barrier_throttled - Drain deferred RCU frees, but rate-limit starts
*
- * This can be thought of as guard rails around rcu_barrier() that
- * permits unrestricted userspace use, at least assuming the hardware's
- * try_cmpxchg() is robust. There will be at most one call per second to
- * rcu_barrier() system-wide from use of this function, which means that
+ * This can be thought of as guard rails around the deferred-free barriers
+ * that permit unrestricted userspace use, at least assuming the hardware's
+ * try_cmpxchg() is robust. There will be at most one drain operation started
+ * per sixteenth of a second from use of this function, which means that
* callers might needlessly wait a second or three.
*
* This is intended for use by test suites to avoid OOM by flushing RCU
@@ -4011,18 +4011,25 @@ static void rcu_barrier_throttled(void)
{
unsigned long j = jiffies;
unsigned long old = READ_ONCE(rcu_barrier_last_throttle);
- unsigned long s = rcu_seq_snap(&rcu_state.barrier_sequence);
while (time_in_range(j, old, old + HZ / 16) ||
!try_cmpxchg(&rcu_barrier_last_throttle, &old, j)) {
schedule_timeout_idle(HZ / 16);
- if (rcu_seq_done(&rcu_state.barrier_sequence, s)) {
- smp_mb(); /* caller's subsequent code after above check. */
- return;
- }
j = jiffies;
old = READ_ONCE(rcu_barrier_last_throttle);
}
+ /*
+ * kfree_rcu() can retain objects outside the ordinary callback lists in
+ * per-CPU SLUB sheaves and kvfree_rcu batches. Test suites use this hook
+ * to prevent deferred frees from spilling into the following test, so
+ * drain those queues as well as ordinary call_rcu() callbacks.
+ *
+ * kvfree_rcu_barrier() currently includes an ordinary barrier, but that
+ * is not part of its documented API. Keep the explicit rcu_barrier() so
+ * this hook's original contract does not depend on slab implementation
+ * details.
+ */
+ kvfree_rcu_barrier();
rcu_barrier();
}
--
2.55.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 1/1] rcu: make userspace barrier hook drain kvfree_rcu work
2026-09-10 17:00 ` [PATCH v2 1/1] " Matthias Goergens
@ 2026-09-10 17:51 ` Paul E. McKenney
0 siblings, 0 replies; 8+ messages in thread
From: Paul E. McKenney @ 2026-09-10 17:51 UTC (permalink / raw)
To: Matthias Goergens
Cc: urezki, harry, frederic, neeraj.upadhyay, joelagnelf, josh,
boqun, rostedt, mathieu.desnoyers, jiangshanlai, qiang.zhang,
corbet, skhan, rdunlap, surenb, vbabka, rcu, linux-doc,
linux-kernel
On Fri, Sep 11, 2026 at 01:00:40AM +0800, Matthias Goergens wrote:
> The bcachefs ktest allocation-leak check writes rcutree.do_rcu_barrier
> before reading /proc/allocinfo. While testing bcachefs performance
> changes, small objects released with kfree_rcu() remained visible after
> repeated writes to the hook and 20 seconds of waiting, causing otherwise
> clean tests to fail their leak check.
>
> The test assumes a stronger contract than the hook currently documents:
> rcu_barrier() waits for ordinary callbacks, but does not flush objects
> still held in kfree_rcu() batching or per-CPU SLUB sheaves. The retained
> population eventually fell as a sheaf filled; there is no evidence here
> of unbounded growth or OOM.
>
> Changing the hook to drain kvfree_rcu() work let the same unmodified
> bcachefs workload pass its allocation check. All eight checkpoints in
> one VM, after 50 through 400 option changes, reported zero retained
> reconcile_scan objects. This motivated the separate private-cache
> reproducer used to isolate the incomplete drain from bcachefs.
>
> Calling kvfree_rcu_barrier() from rcu_barrier_throttled() was proposed
> when the former API was added in 2024, to restore a clean baseline
> between userspace benchmark runs. The discussion concluded that keeping
> the existing hook name, adding the second operation and documenting both
> was the safest compatibility choice, but the follow-up was not added.
>
> Add that drain and document the stronger test interface. Keep the
> explicit rcu_barrier() so the hook's ordinary-callback contract does not
> depend on kvfree_rcu_barrier() reaching an ordinary barrier internally.
>
> Do not reuse the ordinary rcu_barrier() sequence as an early-completion
> check while throttling: an unrelated ordinary barrier does not establish
> that kvfree_rcu() work was drained. Retain the existing start-rate limit.
>
> Four fresh VM pairs with the full private-cache fixture retained the
> queued object without the patch (60 to 60 active objects) and drained it
> with the patch (60 to 59). A separate ordinary-callback regression test
> passed on both kernels.
>
> Link: https://lore.kernel.org/all/20240820155935.1167988-1-urezki@gmail.com/
> Signed-off-by: Matthias Goergens <matthias.goergens@gmail.com>
> ---
> .../admin-guide/kernel-parameters.txt | 7 ++---
> kernel/rcu/tree.c | 27 ++++++++++++-------
> 2 files changed, 21 insertions(+), 13 deletions(-)
>
> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> index 68647ff4bdd2..244a53166249 100644
> --- a/Documentation/admin-guide/kernel-parameters.txt
> +++ b/Documentation/admin-guide/kernel-parameters.txt
> @@ -5699,9 +5699,10 @@ Kernel parameters
> there is an ongoing too-long CSD-lock wait.
>
> rcutree.do_rcu_barrier= [KNL]
> - Request a call to rcu_barrier(). This is
> - throttled so that userspace tests can safely
> - hammer on the sysfs variable if they so choose.
> + Request that deferred kfree_rcu() objects and
> + ordinary call_rcu() callbacks be drained. This is
> + throttled so that userspace tests can safely hammer
> + on the sysfs variable if they so choose.
> If triggered before the RCU grace-period machinery
> is fully active, this will error out with EAGAIN.
>
> diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
> index 96848fc1f02b..014e28ec3bd3 100644
> --- a/kernel/rcu/tree.c
> +++ b/kernel/rcu/tree.c
> @@ -3989,12 +3989,12 @@ EXPORT_SYMBOL_GPL(rcu_barrier);
> static unsigned long rcu_barrier_last_throttle;
>
> /**
> - * rcu_barrier_throttled - Do rcu_barrier(), but limit to one per second
> + * rcu_barrier_throttled - Drain deferred RCU frees, but rate-limit starts
> *
> - * This can be thought of as guard rails around rcu_barrier() that
> - * permits unrestricted userspace use, at least assuming the hardware's
> - * try_cmpxchg() is robust. There will be at most one call per second to
> - * rcu_barrier() system-wide from use of this function, which means that
> + * This can be thought of as guard rails around the deferred-free barriers
> + * that permit unrestricted userspace use, at least assuming the hardware's
> + * try_cmpxchg() is robust. There will be at most one drain operation started
> + * per sixteenth of a second from use of this function, which means that
> * callers might needlessly wait a second or three.
> *
> * This is intended for use by test suites to avoid OOM by flushing RCU
> @@ -4011,18 +4011,25 @@ static void rcu_barrier_throttled(void)
> {
> unsigned long j = jiffies;
> unsigned long old = READ_ONCE(rcu_barrier_last_throttle);
> - unsigned long s = rcu_seq_snap(&rcu_state.barrier_sequence);
>
> while (time_in_range(j, old, old + HZ / 16) ||
> !try_cmpxchg(&rcu_barrier_last_throttle, &old, j)) {
> schedule_timeout_idle(HZ / 16);
> - if (rcu_seq_done(&rcu_state.barrier_sequence, s)) {
> - smp_mb(); /* caller's subsequent code after above check. */
> - return;
Don't we still want to skip the rcu_barrier() in this case? Or am I missing
something subtle here?
Thanx, Paul
> - }
> j = jiffies;
> old = READ_ONCE(rcu_barrier_last_throttle);
> }
> + /*
> + * kfree_rcu() can retain objects outside the ordinary callback lists in
> + * per-CPU SLUB sheaves and kvfree_rcu batches. Test suites use this hook
> + * to prevent deferred frees from spilling into the following test, so
> + * drain those queues as well as ordinary call_rcu() callbacks.
> + *
> + * kvfree_rcu_barrier() currently includes an ordinary barrier, but that
> + * is not part of its documented API. Keep the explicit rcu_barrier() so
> + * this hook's original contract does not depend on slab implementation
> + * details.
> + */
> + kvfree_rcu_barrier();
> rcu_barrier();
> }
>
> --
> 2.55.0
>
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-09-10 17:51 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-10 10:11 [PATCH 0/1] rcu: drain kfree_rcu sheaves from the userspace barrier hook Matthias Goergens
2026-09-10 10:11 ` [PATCH 1/1] " Matthias Goergens
2026-09-10 12:03 ` Harry Yoo
2026-09-10 13:46 ` Matthias Goergens
2026-09-10 15:37 ` Harry Yoo
2026-09-10 17:00 ` [PATCH v2 0/1] rcu: make userspace barrier hook drain kvfree_rcu work Matthias Goergens
2026-09-10 17:00 ` [PATCH v2 1/1] " Matthias Goergens
2026-09-10 17:51 ` Paul E. McKenney
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®