Skip to content

Commit

Permalink
uprobes: Avoid false-positive lockdep splat on CONFIG_PREEMPT_RT=y in…
Browse files Browse the repository at this point in the history
… the ri_timer() uprobe timer callback, use raw_write_seqcount_*()

Avoid a false-positive lockdep warning in the CONFIG_PREEMPT_RT=y
configuration when using write_seqcount_begin() in the uprobe timer
callback by using raw_write_* APIs.

Uprobe's use of timer callback is guaranteed to not race with itself
for a given uprobe_task, and as such seqcount's insistence on having
preemption disabled on the writer side is irrelevant. So switch to
raw_ variants of seqcount API instead of disabling preemption unnecessarily.

Also, point out in the comments more explicitly why we use seqcount
despite our reader side being rather simple and never retrying. We favor
well-maintained kernel primitive in favor of open-coding our own memory
barriers.

Fixes: 8622e45 ("uprobes: Reuse return_instances between multiple uretprobes within task")
Reported-by: Alexei Starovoitov <ast@kernel.org>
Suggested-by: Sebastian Siewior <bigeasy@linutronix.de>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Acked-by: Oleg Nesterov <oleg@redhat.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: stable@kernel.org
Link: https://lore.kernel.org/r/20250404194848.2109539-1-andrii@kernel.org
  • Loading branch information
Andrii Nakryiko authored and Ingo Molnar committed Apr 7, 2025
1 parent 0ba3a4a commit 0cd575c
Showing 1 changed file with 13 additions and 2 deletions.
15 changes: 13 additions & 2 deletions kernel/events/uprobes.c
Original file line number Diff line number Diff line change
Expand Up @@ -1956,6 +1956,9 @@ static void free_ret_instance(struct uprobe_task *utask,
* to-be-reused return instances for future uretprobes. If ri_timer()
* happens to be running right now, though, we fallback to safety and
* just perform RCU-delated freeing of ri.
* Admittedly, this is a rather simple use of seqcount, but it nicely
* abstracts away all the necessary memory barriers, so we use
* a well-supported kernel primitive here.
*/
if (raw_seqcount_try_begin(&utask->ri_seqcount, seq)) {
/* immediate reuse of ri without RCU GP is OK */
Expand Down Expand Up @@ -2016,12 +2019,20 @@ static void ri_timer(struct timer_list *timer)
/* RCU protects return_instance from freeing. */
guard(rcu)();

write_seqcount_begin(&utask->ri_seqcount);
/*
* See free_ret_instance() for notes on seqcount use.
* We also employ raw API variants to avoid lockdep false-positive
* warning complaining about enabled preemption. The timer can only be
* invoked once for a uprobe_task. Therefore there can only be one
* writer. The reader does not require an even sequence count to make
* progress, so it is OK to remain preemptible on PREEMPT_RT.
*/
raw_write_seqcount_begin(&utask->ri_seqcount);

for_each_ret_instance_rcu(ri, utask->return_instances)
hprobe_expire(&ri->hprobe, false);

write_seqcount_end(&utask->ri_seqcount);
raw_write_seqcount_end(&utask->ri_seqcount);
}

static struct uprobe_task *alloc_utask(void)
Expand Down

0 comments on commit 0cd575c

Please sign in to comment.