Thread (34 messages) 34 messages, 7 authors, 14d ago

Re: [PATCH RFC v2 04/15] kprobes: Let Tasks RCU recognise tasks preempted in an optprobe jump window

From: Josef Bacik <josef@toxicpanda.com>
Date: 2026-09-11 17:27:48
Also in: bpf, sashiko-reviews

On Fri, 11 Sep 2026 14:26:26 +0000, sashiko-bot@kernel.org wrote:
quoted
+	for (i = 1; i < MAX_OPTIMIZED_LENGTH / sizeof(kprobe_opcode_t); i++)
+		if (get_kprobe((kprobe_opcode_t *)addr - i))
[Severity: Medium]
When kprobe_in_optimized_region() calls get_kprobe(), neither rcu_read_lock()
nor kprobe_mutex is held (for example, when called from the Tasks RCU GP
kthread).

get_kprobe() iterates the hash list using:

    hlist_for_each_entry_rcu(p, head, hlist,
                             lockdep_is_held(&kprobe_mutex)) {

Without explicitly acquiring rcu_read_lock() around get_kprobe(), lockdep
will complain about suspicious RCU usage, because preempt_disable() (or
running from a kthread) does not satisfy rcu_read_lock_held() on
CONFIG_PREEMPT_RCU.
This is not right. The list iterator's check is not rcu_read_lock_held(),
it is

	RCU_LOCKDEP_WARN(!(cond) && !rcu_read_lock_any_held(), ...)

and rcu_read_lock_any_held() ends in "return !preemptible();", so any
caller with preemption or interrupts disabled satisfies it regardless of
PREEMPT_RCU. That is also the actual RCU guarantee since the flavor
consolidation: synchronize_rcu() waits for preempt/irq-disabled regions
on PREEMPT_RCU kernels too, which is what the kprobe free paths rely on
here.

Every caller is in such a region. rcu_tasks_preempt_is_qs() runs from
rcu_note_context_switch() inside __schedule() after local_irq_disable();
the grace-period kthread only evaluates it from the task_call_func()
callback in 14/15, which runs under p->pi_lock taken with irqsave; and
the preempt == false callers (cond_resched_tasks_rcu_qs(),
rcu_softirq_qs()) short-circuit before rcu_tasks_preempt_is_qs() is
evaluated at all. Nothing calls this bare from kthread context.

I also checked it the boring way: PREEMPT_DYNAMIC=y (so PREEMPT_RCU=y),
PROVE_RCU, PROVE_LOCKING, booted preempt=lazy, registering and
unregistering optimized kprobes in a loop while a kthread spins and gets
irq-preempted, which is exactly the path that reaches get_kprobe() with
kprobe_optimizer_waiting set. No lockdep output.

For the tool: when flagging hlist_for_each_entry_rcu() callers, check
against rcu_read_lock_any_held() (the condition __list_check_rcu()
actually uses), not rcu_read_lock_held().

Thanks,

Josef
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help