Linux MM tree latest commits
 help / color / mirror / Atom feed
From: Catalin Marinas <catalin.marinas@arm.com>
To: Breno Leitao <leitao@debian.org>
Cc: Matthew Wilcox <willy@infradead.org>,
	Andrew Morton <akpm@linux-foundation.org>,
	mm-commits@vger.kernel.org, kent.overstreet@linux.dev,
	bigeasy@linutronix.de, arnd@arndb.de
Subject: Re: + radix-tree-fix-kmemleak-false-positives-on-tree-head-reassignment.patch added to mm-new branch
Date: Tue, 7 Jul 2026 00:19:50 +0100	[thread overview]
Message-ID: <akw4FspAoT60tQeu@arm.com> (raw)
In-Reply-To: <akvW9RwjVmRnNzHM@arm.com>

On Mon, Jul 06, 2026 at 05:25:25PM +0100, Catalin Marinas wrote:
> On Mon, Jul 06, 2026 at 07:53:30AM -0700, Breno Leitao wrote:
> > On Mon, Jul 06, 2026 at 12:39:30PM +0100, Catalin Marinas wrote:
> > > I wonder whether we should force the scanning to happen twice in a row
> > > and drop the min_unref_count. Those transient leaks happen because of
> > > some micro/milliseconds miss of a pointer. If we have new white objects
> > > of the end of a scan, go one more round through the root and gray
> > > objects (but do not reset them to white) and only then report the leaks.
> > > If the white objects have been reported already or we don't have any
> > > left, skip this additional scan or bail out early. We could have a
> > > tunable for this one to go 2-3 times if needed, though I guess twice is
> > > sufficient. The interface is also preserved as you do an echo scan only
> > > once (or twice initially with the checksum calculation).
> > 
> > That is a good proposal, and I am happy to hack it up.
> > 
> > On the other side, I _think_ we want to have both approaches
> > (your rescan-after-white) and min_unref_count. They serve different
> > purposes. This is how I see them serving different purposes:
> > 
> > 1) This rescan-after-white proposal:
> > 
> >   Target: Developers that cat manually scanning for leaks when they
> >   develop something.
> > 
> >     a) The goal is to produce a memory leaks after the scan is done.
> >     b) Latency is more important than false positives
> >     c) min_unref_count = 1
> > 
> > 2) min_unref_count 
> > 
> >   Target: Production servers running kmemleak on some cloud "probe
> >   points", where the service will run for hours/days.
> > 
> >     a) Latency is not important (system is automatically deployed and
> >     tested)
> >     b) False positives is heavily undesirable. It causes an alarm to get
> >     some engineer to investigate.
> >     c) In this case min_unref_count will be super high (>10)
> >       - I.e, just report when you are pretty sure this is a real issue.
> >    
> > Anyway, that's what I'm seeing from my angle. Let me know if I'm way
> > off.
> 
> You are right. If you only ever use min_unref_count of 2, then the first
> option might be alright but for larger numbers, you can't just keep
> scanning 10 times in a row. If option 1 works, we might be able to get
> rid of the transient leak annotations.
> 
> I got Claude to refactor for the first idea and it mostly works. For
> some reason, after modprobe kmemleak-test, it always does the
> confirmation scan. There's an object (vmalloc) left that's reported as
> a potential leak candidate but not confirmed in the subsequent scan.
> I'll check tomorrow, need to finish the day early.

I found the issue. It was the passing of the excess_ref on the
subsequent scan. I thought I could avoid marking gray objects as white
again in the second scan but it messes up the excess_ref since they are
counted only after the object became gray. I had to add a flag,
OBJECT_SUSPECT, since we mark all objects white again for the second
pass. In principle, it's not different from your two scans approach,
only that they are done back to back.

Anyway, a better diff for the first idea below. I need to do more
testing and can turn it into a proper commit (if we don't deem it
redundant because of the other min_unref_count).

FTR, Assisted-by: Claude:claude-opus-4-8.

----------------8<----------------------------
diff --git a/mm/kmemleak.c b/mm/kmemleak.c
index 7c7ba17ce7af..de16c7243847 100644
--- a/mm/kmemleak.c
+++ b/mm/kmemleak.c
@@ -175,6 +175,8 @@ struct kmemleak_object {
 #define OBJECT_PHYS		(1 << 4)
 /* flag set for per-CPU pointers */
 #define OBJECT_PERCPU		(1 << 5)
+/* flag set on an object left unreferenced by the full scan, pending confirmation */
+#define OBJECT_SUSPECT		(1 << 6)
 
 /* set when __remove_object() called */
 #define DELSTATE_REMOVED	(1 << 0)
@@ -1797,13 +1799,11 @@ static void dedup_flush(struct xarray *dedup)
  * kernel's standard allocators. This function must be called with the
  * scan_mutex held.
  */
-static void kmemleak_scan(void)
+static void __kmemleak_scan(bool full)
 {
 	struct kmemleak_object *object;
 	struct zone *zone;
 	int __maybe_unused i;
-	struct xarray dedup;
-	int new_leaks = 0;
 
 	jiffies_last_scan = jiffies;
 
@@ -1904,6 +1904,10 @@ static void kmemleak_scan(void)
 	 */
 	scan_gray_list();
 
+	/* a confirmation scan does not look for modified objects */
+	if (!full)
+		return;
+
 	/*
 	 * Check for new or unreferenced objects modified since the previous
 	 * scan and color them gray until the next scan.
@@ -1935,6 +1939,48 @@ static void kmemleak_scan(void)
 	 * Re-scan the gray list for modified unreferenced objects.
 	 */
 	scan_gray_list();
+}
+
+/*
+ * Mark the objects left unreferenced by the full scan as suspects and return
+ * true if there are any. Only suspects confirmed still unreferenced by the
+ * following scan are reported as leaks.
+ */
+static bool flag_suspects(void)
+{
+	struct kmemleak_object *object;
+	int suspects = 0;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(object, &object_list, object_list) {
+		raw_spin_lock_irq(&object->lock);
+		if (unreferenced_object(object) &&
+		    !(object->flags & OBJECT_REPORTED)) {
+			object->flags |= OBJECT_SUSPECT;
+			suspects++;
+		} else {
+			object->flags &= ~OBJECT_SUSPECT;
+		}
+		raw_spin_unlock_irq(&object->lock);
+		if (need_resched())
+			kmemleak_cond_resched(object);
+	}
+	rcu_read_unlock();
+
+	return suspects != 0;
+}
+
+/*
+ * Scan the memory and report the unreferenced objects as leaks. Must be
+ * called with the scan_mutex held.
+ */
+static void kmemleak_scan(void)
+{
+	struct kmemleak_object *object;
+	struct xarray dedup;
+	int new_leaks = 0;
+
+	__kmemleak_scan(true);
 
 	/*
 	 * If scanning was stopped do not report any new unreferenced objects.
@@ -1942,6 +1988,18 @@ static void kmemleak_scan(void)
 	if (scan_should_stop())
 		return;
 
+	/*
+	 * A live object whose only reference is moved by, for example, a
+	 * concurrent RCU update can be missed for one scan and reported as a
+	 * transient false positive. If a leak is suspected, mark again and
+	 * only report the objects left unreferenced by both scans.
+	 */
+	if (flag_suspects()) {
+		__kmemleak_scan(false);
+		if (scan_should_stop())
+			return;
+	}
+
 	/*
 	 * Scanning result reporting. When verbose printing is enabled, dedupe
 	 * by stackdepot trace_handle so each unique backtrace is logged once
@@ -1969,6 +2027,7 @@ static void kmemleak_scan(void)
 		trace_handle = 0;
 		dedup_print = false;
 		if (unreferenced_object(object) &&
+		    (object->flags & OBJECT_SUSPECT) &&
 		    !(object->flags & OBJECT_REPORTED)) {
 			object->flags |= OBJECT_REPORTED;
 			if (kmemleak_verbose) {

  reply	other threads:[~2026-07-06 23:19 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-05  2:12 + radix-tree-fix-kmemleak-false-positives-on-tree-head-reassignment.patch added to mm-new branch Andrew Morton
2026-07-05 10:45 ` Matthew Wilcox
2026-07-05 18:15   ` Andrew Morton
2026-07-06 10:41   ` Breno Leitao
2026-07-06 11:39     ` Catalin Marinas
2026-07-06 14:53       ` Breno Leitao
2026-07-06 16:25         ` Catalin Marinas
2026-07-06 23:19           ` Catalin Marinas [this message]
2026-07-07 11:26             ` Breno Leitao
2026-07-07 14:01               ` Catalin Marinas
  -- strict thread matches above, loose matches on Subject: below --
2026-07-05  2:11 Andrew Morton
2026-07-02 22:42 Andrew Morton
2026-07-03 15:26 ` Breno Leitao

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=akw4FspAoT60tQeu@arm.com \
    --to=catalin.marinas@arm.com \
    --cc=akpm@linux-foundation.org \
    --cc=arnd@arndb.de \
    --cc=bigeasy@linutronix.de \
    --cc=kent.overstreet@linux.dev \
    --cc=leitao@debian.org \
    --cc=mm-commits@vger.kernel.org \
    --cc=willy@infradead.org \
    /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