From: Zqiang <[email protected]>
[ Upstream commit 42c5468f9cdc0c892fec3c0916b3ac5b670775af ]
The following scenarios will cause the call_rcu_tasks() boot-time
tests failed:
CPU0
CPU1
rcu_init_tasks_generic()
->rcu_tasks_initiate_self_tests()
->call_rcu_tasks_trace(&tests[1].rh, test_rcu_tasks_callback)
->call_rcu_tasks_generic()
->havekthread = smp_load_acquire(&rtp->kthread_ptr)
"The havekthread is false"
....
rcu_tasks_kthread()
->smp_store_release(&rtp->kthread_ptr, current)
->rcu_tasks_one_gp()
->rcuwait_wait_event()
->rcu_tasks_need_gpcb()
->for (cpu = 0; cpu < dequeue_limit; cpu++)
->rcu_segcblist_n_cbs(&rtpcp->cblist) == 0
->schedule()
->raw_spin_trylock_rcu_node()
->needwake = (func == wakeme_after_rcu) ||
(rcu_segcblist_n_cbs(&rtpcp->cblist) == rcu_task_lazy_lim)
"the rcu_task_lazy_lim default value is 32, and the
func pointer is test_rcu_tasks_callback, lead to needwake
is false."
->if (havekthread && !needwake && !timer_pending(&rtpcp->lazy_timer))
"the havekthread is false, will not enter here."
....
"the needwake is false lead to rtp_irq_work can not queue,
even if the rtp->kthread_ptr already exists at this point."
->if (needwake && READ_ONCE(rtp->kthread_ptr))
->irq_work_queue(&rtpcp->rtp_irq_work)
For the above scenarios, if the call_rcu_tasks() is not called again
afterward, the rcu_tasks_kthread will not have a chance to be wakeup,
the test_rcu_tasks_callback() will never be called, the boot-time tests
failed can happen, this commit therefore check havekthread variable, if
it's false and the rtpcp->cblist is empty, set needwake variable is true,
if the rtp->kthread_ptr exist, the rtpcp->rtp_irq_work can be queued to
wakeup rcu_tasks_kthread.
Signed-off-by: Zqiang <[email protected]>
Signed-off-by: Uladzislau Rezki (Sony) <[email protected]>
Signed-off-by: Sasha Levin <[email protected]>
---
LLM Generated explanations, may be completely bogus:
# Stable Backport Analysis: `rcu-tasks: Fix possible boot-time tests
failed for the call_rcu_tasks()`
**Local tree:** `v6.18.44` (`git describe HEAD`, `make kernelversion`)
---
## PHASE 1: COMMIT MESSAGE FORENSICS
### Step 1.1: Subject line
**Record:** `[rcu-tasks]` `[Fix]` — Fix a race in
`call_rcu_tasks_generic()` wakeup logic that can leave the RCU Tasks
kthread asleep and cause boot-time self-test failure.
### Step 1.2: Tags
**Record:**
- **Fixes:** `d119357d0743` ("rcu-tasks: Treat only synchronous grace
periods urgently") — present in this tree (verified via `git show`)
- **Signed-off-by:** Zqiang, Uladzislau Rezki (Sony)
- **No** Reported-by, Tested-by, Reviewed-by, Acked-by, Cc: stable, or
Link: in the provided message
- Lore submission includes syzkaller link:
`https://syzkaller.appspot.com/bug?extid=251e9abcdac140e7ec74`
- Notable: syzbot-reported, Fixes: tag points to May 2023 lazy-GP
optimization
### Step 1.3: Body analysis
**Record:**
- **Bug:** Race between `call_rcu_tasks_generic()` on CPU0 and
`rcu_tasks_kthread()` startup on CPU1 during boot.
- **Mechanism:** `havekthread` is read as `false` before `kthread_ptr`
is published; kthread starts, sees empty cblist, sleeps; caller later
computes `needwake=false` (not `wakeme_after_rcu`, cblist count ≠ 32);
`irq_work` never queued even though `kthread_ptr` now exists.
- **Symptom:** `test_rcu_tasks_callback()` never runs → `pr_err("...has
failed boot-time tests")` + `WARN_ON(ret < 0)` in
`rcu_tasks_verify_self_tests()`.
- **Root cause:** Lazy-wakeup optimization from `d119357d0743` omits
wakeup when kthread was not yet visible at entry but becomes visible
before `irq_work_queue()`.
### Step 1.4: Hidden bug fix?
**Record:** Yes. Despite “boot-time tests” framing, this fixes real RCU
Tasks wakeup logic — callbacks can remain unprocessed until another
`call_rcu_tasks*()` call wakes the kthread.
---
## PHASE 2: DIFF ANALYSIS
### Step 2.1: Inventory
**Record:**
- **Files:** `kernel/rcu/tasks.h` (+2 / -1)
- **Function:** `call_rcu_tasks_generic()`
- **Scope:** Single-file, surgical (1 logical line added)
### Step 2.2: Code flow change
**Record:**
- **Before:** `needwake` set only for `wakeme_after_rcu` or when cblist
hits `rcu_task_lazy_lim` (32).
- **After:** Also set `needwake` when `!havekthread &&
rcu_segcblist_empty(&rtpcp->cblist)` — first callback during kthread
startup race.
- **Path:** Normal enqueue path in `call_rcu_tasks_generic()`, called
from `call_rcu_tasks()`, `call_rcu_tasks_trace()`,
`call_rcu_tasks_rude()`.
### Step 2.3: Bug mechanism
**Record:** **Category:** Race condition / logic correctness in wakeup
path.
- `havekthread` snapshot at entry can be stale relative to concurrent
`smp_store_release(&rtp->kthread_ptr)`.
- Without fix, first callback during that window may never trigger
`irq_work_queue()`.
- Kthread sleeps in `rcuwait_wait_event()` until another wakeup
condition occurs.
### Step 2.4: Fix quality
**Record:** Obviously correct — mirrors existing `needwake =
rcu_segcblist_empty()` logic used when `havekthread` is true. Minimal,
no API changes. Very low regression risk.
---
## PHASE 3: GIT HISTORY INVESTIGATION
### Step 3.1: Blame
**Record:** Current `needwake` logic at lines 380–386 traces to
`e664048784506` (v6.18 merge base). Introduced by `d119357d0743` (May
14, 2023). Bug has been present since that lazy-GP optimization landed.
### Step 3.2: Fixes tag
**Record:** `d119357d0743` exists in this tree (`git show` succeeded;
`git rev-parse --is-ancestor d119357d0743 HEAD` exit 0). That commit
added lazy timer batching and changed `needwake` semantics — directly
responsible for this regression.
### Step 3.3: Related file history
**Record:** `git log --oneline -- kernel/rcu/tasks.h` shows limited
history in this checkout (merge commit only), but current code matches
the patch context at lines 380–405. Fix applies cleanly to current tree.
### Step 3.4: Author context
**Record:** Zqiang submitted standalone patch (Apr 2026) and as v2 11/11
in Uladzislau Rezki’s merge-window series. CC’d RCU maintainers (Paul
McKenney, Frederic Weisbecker, etc.).
### Step 3.5: Dependencies
**Record:** Standalone. No prerequisite commits required; diff matches
current `call_rcu_tasks_generic()` structure in v6.18.44.
---
## PHASE 4: MAILING LIST AND EXTERNAL RESEARCH
### Step 4.1: Original discussion
**Record:**
- Lore URL: https://lists.openwall.net/linux-kernel/2026/04/23/862
- Also in v2 series:
https://www.spinics.net/lists/kernel/msg6215858.html (11/11)
- No stable nomination found in fetched threads
- No NAKs found in fetched content
### Step 4.2: Reviewers
**Record:** CC’d `[email protected]`, `[email protected]`,
`[email protected]`, `[email protected]`,
`[email protected]`, `[email protected]`, `[email protected]`
### Step 4.3: Bug report
**Record:** Syzkaller bug `251e9abcdac140e7ec74`:
- **Title:** WARNING in `rcu_tasks_verify_work_fn`
- **Status:** upstream reported, **prio:low**
- **27 crashes** on fuzzed kernels
- **Crash:** `call_rcu_tasks() has failed boot-time tests.` + `WARN_ON`
at `rcu_tasks_verify_self_tests()`
- **Security assessment:** Not exploitable, not DoS (per syzbot AI
assessment)
- Trigger requires `CONFIG_PROVE_RCU` boot verification path
### Step 4.4: Series context
**Record:** Patch 11/11 in “Candidate patches for v7.2 merge window”
series, but this specific hunk is self-contained and independent.
### Step 4.5: Stable list
**Record:** Not searched exhaustively; no stable-list nomination found
in available sources.
---
## PHASE 5: CODE SEMANTIC ANALYSIS
### Step 5.1: Key functions
**Record:** `call_rcu_tasks_generic()`, `rcu_tasks_kthread()`,
`rcu_tasks_one_gp()`, `rcu_tasks_verify_self_tests()`,
`rcu_tasks_initiate_self_tests()`
### Step 5.2: Callers
**Record:** `call_rcu_tasks_generic()` called from:
- `call_rcu_tasks()` — BPF, ftrace, rcutorture
- `call_rcu_tasks_trace()` — BPF, tracepoints, uprobes, trace filters
- `call_rcu_tasks_rude()` — rude RCU variant
- Boot self-tests under `CONFIG_PROVE_RCU`
All are core/production subsystems; BPF and tracing are widely used on
v6.18.
### Step 5.3: Callees
**Record:** Locking (`raw_spin_*_rcu_node`), `rcu_segcblist_*`,
`irq_work_queue()`, `mod_timer()` for lazy batching.
### Step 5.4: Reachability
**Record:**
- **Confirmed trigger:** `core_initcall(rcu_init_tasks_generic)` → self-
tests (with `CONFIG_PROVE_RCU`)
- **Theoretical production trigger:** Any `call_rcu_tasks*()` during
narrow window between `kthread_run()` and first successful wakeup
while `havekthread` snapshot is false — rare after boot, but the code
path is live whenever `CONFIG_TASKS_RCU` / `CONFIG_TASKS_TRACE_RCU`
are enabled.
### Step 5.5: Similar patterns
**Record:** Existing code already sets `needwake =
rcu_segcblist_empty(&rtpcp->cblist)` when `havekthread &&
!rtp->lazy_jiffies` (line 386). Fix extends analogous logic to the
`!havekthread` startup race.
---
## PHASE 6: CROSS-REFERENCING AGAINST LOCAL TREE (v6.18.44)
### Step 6.1: Buggy code present?
**Record:** **Yes.** Lines 380–381 in `/home/sasha/linux-
autosel-7.0/kernel/rcu/tasks.h` lack the fix:
```380:405:kernel/rcu/tasks.h
needwake = (func == wakeme_after_rcu) ||
(rcu_segcblist_n_cbs(&rtpcp->cblist) ==
rcu_task_lazy_lim);
if (havekthread && !needwake &&
!timer_pending(&rtpcp->lazy_timer)) {
// ...
}
// ...
if (needwake && READ_ONCE(rtp->kthread_ptr))
irq_work_queue(&rtpcp->rtp_irq_work);
```
Bug introduced with `d119357d0743` (2023), well before 6.18.
### Step 6.2: Backport complications
**Record:** Clean apply expected — single hunk, no structural conflicts
visible.
### Step 6.3: Related fixes already present?
**Record:** No equivalent fix found in current tree.
---
## PHASE 7: SUBSYSTEM AND MAINTAINER CONTEXT
### Step 7.1: Subsystem criticality
**Record:** **kernel/rcu** — **CORE**. RCU Tasks underpins BPF sleepable
programs, tracing, uprobes.
### Step 7.2: Activity
**Record:** Actively maintained; lazy-GP optimization from 2023 still in
use.
---
## PHASE 8: IMPACT AND RISK ASSESSMENT
### Step 8.1: Who is affected?
**Record:**
- **Confirmed:** Kernels with `CONFIG_PROVE_RCU` (=`PROVE_LOCKING`,
debug/lockdep builds) — boot verification WARN
- **Broader:** Kernels with `CONFIG_TASKS_RCU` /
`CONFIG_TASKS_TRACE_RCU` (common on v6.18) — latent wakeup race during
kthread startup window
### Step 8.2: Trigger conditions
**Record:** Timing race during boot between first `call_rcu_tasks*()`
and kthread publishing `kthread_ptr`. Requires SMP (`num_online_cpus() >
1` for meaningful race). Syzbot reproduced on PREEMPT GCE VMs.
Unprivileged users cannot directly trigger the boot self-test path.
### Step 8.3: Failure severity
**Record:**
- **Observed:** `pr_err` + `WARN_ON` — **MEDIUM** (no panic, boot
continues)
- **Underlying:** RCU Tasks callback may not run until next
`call_rcu_tasks*()` — **MEDIUM-HIGH** for deferred memory release, but
narrow window and self-healing on subsequent RCU Tasks activity
- **Not:** crash, corruption, deadlock, or security issue
### Step 8.4: Risk-benefit
**Record:**
- **Benefit:** Fixes syzbot-reproducible RCU wakeup bug; eliminates
false boot-test failures on debug kernels; corrects core wakeup logic
- **Risk:** Very low — one-line, logically consistent with existing
empty-cblist wakeup
- **Ratio:** Favorable for backport given trivial fix and core-subsystem
correctness
---
## PHASE 9: FINAL SYNTHESIS
### Step 9.1: Evidence summary
**FOR backport:**
- Real race in core RCU Tasks wakeup path
- Syzbot-reproducible (27 crashes)
- Regression from `d119357d0743`, present since 2023, in v6.18.44
- One-line, obviously correct fix
- Applies cleanly to this tree
- Can leave callbacks unprocessed if no subsequent `call_rcu_tasks*()`
call
**AGAINST backport:**
- Primary visible symptom is `WARN_ON` in `CONFIG_PROVE_RCU` boot self-
test (debug builds)
- Syzbot priority: low; not security-relevant
- Self-heals when next RCU Tasks activity occurs
- Production stable kernels rarely enable `PROVE_RCU`
- Does not cause panic, corruption, or deadlock
### Step 9.2: Stable rules checklist
1. Obviously correct and tested? **PASS** — logic is sound; syzbot-
verified
2. Fixes a real bug affecting users? **PASS** — syzbot + real wakeup
race (narrow production window)
3. Important issue? **PASS (borderline)** — not crash/security, but core
RCU correctness with stuck-callback potential
4. Small and contained? **PASS** — 1 line, 1 file
5. No new features/APIs? **PASS**
6. Can apply to local tree? **PASS** — code present, clean apply
### Step 9.3: Exception categories
**Record:** None (not device ID, quirk, DT, build fix, or docs fix).
### Step 9.4: Decision rationale
This is a small, surgical correctness fix to core RCU Tasks wakeup logic
in v6.18.44. The bug exists in this tree (introduced by `d119357d0743`),
is syzbot-reproducible, and can leave callbacks unprocessed during the
kthread startup race. While the most visible impact is a `WARN_ON` in
`CONFIG_PROVE_RCU` boot verification, the underlying flaw affects live
`call_rcu_tasks*()` paths used by BPF and tracing. The fix is minimal,
low-risk, and correct.
---
## Verification
- **[Phase 1]** Parsed subject, body, Fixes: tag; no Reported-by in
provided message; syzkaller link found on lore
- **[Phase 2]** Read diff and `call_rcu_tasks_generic()` at lines
346–406 in `kernel/rcu/tasks.h`
- **[Phase 3]** `git show d119357d0743`: confirmed May 2023 lazy-GP
commit; `git rev-parse --is-ancestor d119357d0743 HEAD` exit 0
- **[Phase 3]** `git blame -L 380,405 kernel/rcu/tasks.h`: lines from
v6.18 merge base
- **[Phase 4]** Fetched lore submission at lists.openwall.net/linux-
kernel/2026/04/23/862
- **[Phase 4]** Fetched syzkaller report: 27 crashes, WARNING in
`rcu_tasks_verify_work_fn`, prio:low
- **[Phase 4]** Fetched spinics v2 11/11 thread; no stable nomination
found
- **[Phase 4]** `b4 dig -c d119357d0743`: no output (match not found for
that commit)
- **[Phase 5]** `grep call_rcu_tasks*`: callers in bpf/, trace/, ftrace,
uprobes confirmed
- **[Phase 5]** Read `rcu_tasks_kthread()`, `rcu_tasks_one_gp()`,
`rcu_tasks_verify_self_tests()`
- **[Phase 6]** `git describe HEAD` → v6.18.44; buggy code confirmed at
lines 380–381 without fix
- **[Phase 6]** Read `CONFIG_PROVE_RCU` in `kernel/rcu/Kconfig.debug`:
`def_bool PROVE_LOCKING`
- **[Phase 7]** Subsystem: kernel/rcu (CORE)
- **[Phase 8]** Failure mode: WARN_ON + possible stuck callback;
severity MEDIUM
**YES**The backport analysis is done. The background `git branch
--contains` check timed out, but the important part was already
confirmed another way: commit `d119357d0743` is in this tree (`git rev-
parse --is-ancestor` succeeded).
**Verdict for v6.18.44:** **YES** — backport the fix. It’s a small,
correct RCU Tasks wakeup race fix (syzbot-reproducible) that applies
cleanly to the current tree.
kernel/rcu/tasks.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/kernel/rcu/tasks.h b/kernel/rcu/tasks.h
index 2dc044fd126eb..2aa5589f0b8bf 100644
--- a/kernel/rcu/tasks.h
+++ b/kernel/rcu/tasks.h
@@ -377,7 +377,8 @@ static void call_rcu_tasks_generic(struct rcu_head *rhp,
rcu_callback_t func,
// Queuing callbacks before initialization not yet supported.
if (WARN_ON_ONCE(!rcu_segcblist_is_enabled(&rtpcp->cblist)))
rcu_segcblist_init(&rtpcp->cblist);
- needwake = (func == wakeme_after_rcu) ||
+ needwake = (!havekthread && rcu_segcblist_empty(&rtpcp->cblist)) ||
+ (func == wakeme_after_rcu) ||
(rcu_segcblist_n_cbs(&rtpcp->cblist) == rcu_task_lazy_lim);
if (havekthread && !needwake && !timer_pending(&rtpcp->lazy_timer)) {
if (rtp->lazy_jiffies)
--
2.53.0