Linux Trace Kernel
 help / color / mirror / Atom feed
From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
To: sashiko-reviews@lists.linux.dev
Cc: sashiko-bot@kernel.org, bpf@vger.kernel.org,
	linux-trace-kernel@vger.kernel.org
Subject: Re: [RESEND PATCH v2] kprobes: Make optprobe optimizer multi-generational and asynchronous
Date: Wed, 30 Sep 2026 10:33:26 +0900	[thread overview]
Message-ID: <20260930103326.161812f00774be79848248ab@kernel.org> (raw)
In-Reply-To: <20260930001024.4F2371F00893@smtp.kernel.org>

On Wed, 30 Sep 2026 00:10:23 +0000
sashiko-bot@kernel.org wrote:

> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
> - [High] kprobes: 100% CPU busy-loop livelock when flushing optimizer
> - [High] kprobes: memory leak of optinsn slots during async unoptimization
> --
> 
> commit 9f64df8dc4c148639fefa4dcd4859438e335848a
> Author: Masami Hiramatsu (Google) <mhiramat@kernel.org>
> 
> kprobes: Make optprobe optimizer multi-generational and asynchronous
> 
> This patch decouples kprobe jump optimization from synchronous waiting by
> moving to an asynchronous, multi-generational model using call_rcu_tasks().
> 
> > diff --git a/kernel/kprobes.c b/kernel/kprobes.c
> > index 4edd8ca5c6578..377fa9bfa0291 100644
> > --- a/kernel/kprobes.c
> > +++ b/kernel/kprobes.c
> [ ... ]
> > @@ -588,17 +653,25 @@ static void do_unoptimize_kprobes(void)
> [ ... ]
> > -/* Reclaim all kprobes on the 'freeing_list' */
> > -static void do_free_cleaned_kprobes(void)
> > +/* Reclaim all kprobes on the 'free_list' */
> > +static void do_free_cleaned_kprobes(struct list_head *free_list)
> >  {
> >  	struct optimized_kprobe *op, *tmp;
> >  
> > -	list_for_each_entry_safe(op, tmp, &freeing_list, list) {
> > +	list_for_each_entry_safe(op, tmp, free_list, list) {
> > +		struct kprobe *_p;
> > +
> >  		list_del_init(&op->list);
> [ ... ]
> > -		struct kprobe *_p = get_optimized_kprobe(op->kp.addr);
> > +		_p = get_optimized_kprobe(op->kp.addr);
> >  		if (unlikely(_p))
> >  			optimize_kprobe(_p);
> >  
> > -		free_aggr_kprobe(&op->kp);
> > +		free_aggr_kprobe(&op->kp);
> >  	}
> >  }
> 
> [Severity: High]
> Does this leak the dynamically allocated optinsn memory slots?
> 
> Later in the patch, kill_optimized_kprobe() is modified to intentionally
> defer calling arch_remove_optimized_kprobe(op) if the probe is queued,
> leaving the optimizer to reclaim it after the quiescence period.
> 
> However, when do_free_cleaned_kprobes() runs to reclaim the probe after the
> grace period, free_aggr_kprobe() only frees the kprobe struct. Without a
> call to arch_remove_optimized_kprobe(op) here, the executable memory slots
> allocated for the optimized kprobes appear to be permanently leaked.

This is false positive. There are 2 implementations of free_aggr_kprobe(),
with CONFIG_OPTPROBES=y, it frees optinsn correctly.

(Hmm, this is interesting failure pattern. Maybe I should not make
 configure-selectable implementation except for empty alternatives.)

> 
> [ ... ]
> > @@ -624,67 +696,138 @@ static void do_free_cleaned_kprobes(void)
> [ ... ]
> > +/* Kprobe jump optimizer */
> > +static void kprobe_optimizer(void)
> > +{
> [ ... ]
> > +	/* Step 3: Wake up flushers and kick optimizer again if needed */
> >  	optimizer_passes++;
> >  	wake_up_var_locked(&optimizer_passes, &kprobe_mutex);
> 
> [Severity: High]
> Does unconditionally incrementing optimizer_passes here cause a 100% CPU
> busy-loop livelock?
> 
> When wait_for_kprobe_optimizer_locked() is called while a Tasks RCU grace
> period is in flight, it sees optprobe_optimizer_busy() is true and wakes the
> optimizer thread.
> 
> The optimizer thread wakes up, clears its flushing state, and calls
> kprobe_optimizer(). Since the RCU callback hasn't fired yet, it makes no
> progress but unconditionally increments optimizer_passes here.
> 
> This wakes wait_for_kprobe_optimizer_locked(), which loops, wakes the
> optimizer again, and waits for another optimizer_passes change. Both threads
> could spin in this tight loop until the Tasks RCU grace period completes.

Ah, good catch!
OK, to avoid that, wakeup flushers only if any progress has been made.

Thank you!

-- 
Masami Hiramatsu (Google) <mhiramat@kernel.org>

      reply	other threads:[~2026-09-30  1:33 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-29 23:59 [RESEND PATCH v2] kprobes: Make optprobe optimizer multi-generational and asynchronous Masami Hiramatsu (Google)
2026-09-30  0:10 ` sashiko-bot
2026-09-30  1:33   ` Masami Hiramatsu [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260930103326.161812f00774be79848248ab@kernel.org \
    --to=mhiramat@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=linux-trace-kernel@vger.kernel.org \
    --cc=sashiko-bot@kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox