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: Mon, 6 Jul 2026 17:25:25 +0100 [thread overview]
Message-ID: <akvW9RwjVmRnNzHM@arm.com> (raw)
In-Reply-To: <akuzsny_3EpxaPww@gmail.com>
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.
Pasting the diff I was playing with below for reference (with some debug
printks):
---------------8<--------------------
diff --git a/mm/kmemleak.c b/mm/kmemleak.c
index 7c7ba17ce7af..fad0a01ddbcf 100644
--- a/mm/kmemleak.c
+++ b/mm/kmemleak.c
@@ -1797,13 +1797,13 @@ 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;
+
+ printk("### %s scan started\n", full ? "full" : "confirmation");
jiffies_last_scan = jiffies;
@@ -1833,8 +1833,13 @@ static void kmemleak_scan(void)
__paint_it(object, KMEMLEAK_BLACK);
}
- /* reset the reference count (whiten the object) */
- object->count = 0;
+ /*
+ * Reset the reference count (whiten the object). A confirmation
+ * scan re-tests only the objects still white, keeping (and
+ * re-scanning) the references already found by the full scan.
+ */
+ if (full || color_white(object))
+ object->count = 0;
if (color_gray(object) && get_object(object))
list_add_tail(&object->gray_list, &gray_list);
@@ -1904,6 +1909,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 +1944,47 @@ static void kmemleak_scan(void)
* Re-scan the gray list for modified unreferenced objects.
*/
scan_gray_list();
+}
+
+/*
+ * Return true if the last scan left any object that would be reported as a
+ * leak. Racy: it only gates the optional confirmation scan.
+ */
+static bool kmemleak_has_candidates(void)
+{
+ struct kmemleak_object *object;
+ int candidates = 0;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(object, &object_list, object_list) {
+ if (unreferenced_object(object) &&
+ !(object->flags & OBJECT_REPORTED)) {
+ candidates++;
+ printk("### candidate 0x%px size %zu comm %s\n",
+ (void *)object->pointer, object->size,
+ object->comm);
+ }
+ if (need_resched())
+ kmemleak_cond_resched(object);
+ }
+ rcu_read_unlock();
+
+ printk("### has_candidates: %d\n", candidates);
+ return candidates != 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;
+
+ printk("### ===== scan start =====\n");
+ __kmemleak_scan(true);
/*
* If scanning was stopped do not report any new unreferenced objects.
@@ -1942,6 +1992,20 @@ static void kmemleak_scan(void)
if (scan_should_stop())
return;
+ /*
+ * The marking phase is not atomic: a live object whose only reference
+ * is moved by a concurrent RCU update can be missed for one scan and
+ * reported as a transient false positive. If a leak is suspected, mark
+ * again keeping the references already found; an object referenced by
+ * either scan is not reported, a genuine leak (white in both) still is.
+ */
+ if (kmemleak_has_candidates()) {
+ printk("### running confirmation scan\n");
+ __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
@@ -1971,6 +2035,9 @@ static void kmemleak_scan(void)
if (unreferenced_object(object) &&
!(object->flags & OBJECT_REPORTED)) {
object->flags |= OBJECT_REPORTED;
+ printk("### reported 0x%px size %zu comm %s\n",
+ (void *)object->pointer, object->size,
+ object->comm);
if (kmemleak_verbose) {
trace_handle = object->trace_handle;
dedup_print = true;
next prev parent reply other threads:[~2026-07-06 16:25 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 [this message]
2026-07-06 23:19 ` Catalin Marinas
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=akvW9RwjVmRnNzHM@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