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