From nobody Wed Jun 17 01:38:28 2026 Received: from stravinsky.debian.org (stravinsky.debian.org [82.195.75.108]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 58EB43D7D97; Tue, 21 Apr 2026 14:13:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=82.195.75.108 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776780823; cv=none; b=FbmVFkSKuJvXWTL/xH8vmCa90cxVpBmwYkPp0e+rE+DJO4uH5U9tPea0RvbC5QPreayVYg3Ea1IJNi/Cj3FYr+JDHBh2V0y1LsE0fsql2Sq85nAHi33yZsiJ0c5TuZC5J3/kShufuYwuL0034+g5SF4HW3+3QpzbZAwo0bvIeOM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776780823; c=relaxed/simple; bh=Z5xsKdbb1dj+8VU85SeZGqxL3277Mj5PEYA3E5O0VIk=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=JQmesqWW7t8RLcl+ZtdcqvNLMXHmsJWsa9TDm2GGB7NWh3xGMp6vpGfvgh8gMxpPeKhtdxxuZNKC09iXnuinM7XPqC/alROlm7KTtw8yH6o2XS2ia2V/Jsjrfh+avGarA5fzJrFyaBvkks/O8X1KwUAn/hR1jGmGScTU5iIBDYE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=debian.org; spf=none smtp.mailfrom=debian.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b=Kz/rPGIC; arc=none smtp.client-ip=82.195.75.108 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=debian.org Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=debian.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b="Kz/rPGIC" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=debian.org; s=smtpauto.stravinsky; h=X-Debian-User:Cc:To:In-Reply-To:References: Message-Id:Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date: From:Reply-To:Content-ID:Content-Description; bh=hlUmsxjaOV8fnPvProkr8mAom/iLkQvq+HSacis3lno=; b=Kz/rPGICFxDLyCRvV90jgpuPDu kjBYcjuaD6NPfHMmE/1m0wqt4y5k3Q1h3l/7pRyye5a9qyWQtkwEqMcsao9BKI1N+Ehbv8Uhj/KBk y9KVDUv3vFcA9AaEZlKMynxrrvJ2Inc/7YDeRf6/52Ul5IIOyZ4/0khvM1d6XxUYwPmgQic4CBSK3 Mt3zucxcoZPXJCuB6ocJTmEwmtPLQt3EYAljcsPnRmoJdNoVklsKOQhtuffGbWD31U5UPdOMhrG7h 3eTMHuRll7QKm/8QN+74/U+7dWVh4aKE3aoMMgxJwaKnEbrLoAGSPdanip+mAPKEMsbdlPBLujrdr BjTj7kng==; Received: from authenticated user by stravinsky.debian.org with esmtpsa (TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.96) (envelope-from ) id 1wFBPm-000tUc-2j; Tue, 21 Apr 2026 13:45:23 +0000 From: Breno Leitao Date: Tue, 21 Apr 2026 06:45:04 -0700 Subject: [PATCH 1/2] mm/kmemleak: dedupe verbose scan output by allocation backtrace Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260421-kmemleak_dedup-v1-1-65e31c6cdf0c@debian.org> References: <20260421-kmemleak_dedup-v1-0-65e31c6cdf0c@debian.org> In-Reply-To: <20260421-kmemleak_dedup-v1-0-65e31c6cdf0c@debian.org> To: Andrew Morton , David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Shuah Khan , Catalin Marinas Cc: linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-kselftest@vger.kernel.org, kernel-team@meta.com, Breno Leitao X-Mailer: b4 0.16-dev-453a6 X-Developer-Signature: v=1; a=openpgp-sha256; l=6885; i=leitao@debian.org; h=from:subject:message-id; bh=Z5xsKdbb1dj+8VU85SeZGqxL3277Mj5PEYA3E5O0VIk=; b=owEBbQKS/ZANAwAIATWjk5/8eHdtAcsmYgBp539pHvLkqwsjZdrAzwLbngpwIt+uSSJa+hscd vA0i5jPifmJAjMEAAEIAB0WIQSshTmm6PRnAspKQ5s1o5Of/Hh3bQUCaed/aQAKCRA1o5Of/Hh3 bbOIEACBYq4GRdQmktMUMzjqE5ShlIz8N7Qn+Za1YtGsepw7W330xwHkDDcLifcOSTzzUCDhg+B pbLcnEjQ/uXOtUDJLSVDMMYj2CmaOegwzDirJNhN7CRbDm22mxE+zJERoYANCgjWgDFNRzWIHdA XzGWWxOlZRWcOxPTfSTDSk3gKQvjtzy/vSF4BxQo6PBDcOJXdy/9vKBWqjXASjwPQ8x3TL676Yz 3msodUO8fnglsbuY189K2iO9KkMySW4Tdb6Te/NoUsRtTS0LrOGJyFUh2BUtAb7YGGmblsTNHbM mwJ+DUGNbTQvpLfhR1wSLTjhpOyGOXMUA6Ka4s8qZlNGsdOoGu+iVhQN+pC0UQZ6/aUKo5mJY+p wwtXSrnQl/Coul0EPOJX332xd553GiFo5YIehv3lrlTz9eeOrwo1ucggto0rB6T5igdyKfANztr ThPQAIc+Hhw09ZMimNOwjB+X10U2DlbJR5V9t5q+kTtBKk8pO8Oy8ZGmYcTbFpQSOdzGPczb3Kj owng1CZxzk6rsZEBwV6butKtr7QyjSItXch7iNSdlUVpCjikE4/HSGT0p1P0TNZof/Y0SwI34oa tvRPfwL/jvZ+awi2sO2xPnX7c7T76iPkRXIWNa94x9oX6pW2llrFeyyW3PBkpXI7drmFfYtTkkc h7a2ayAs5VWueow== X-Developer-Key: i=leitao@debian.org; a=openpgp; fpr=AC8539A6E8F46702CA4A439B35A3939FFC78776D X-Debian-User: leitao In kmemleak's verbose mode, every unreferenced object found during a scan is logged with its full header, hex dump and 16-frame backtrace. Workloads that leak many objects from a single allocation site flood dmesg with byte-for-byte identical backtraces, drowning out distinct leaks and other kernel messages. Dedupe within each scan using stackdepot's trace_handle as the key: for every leaked object, look up an entry in a per-scan xarray keyed by trace_handle. The first sighting stores a representative object; later sightings just bump a counter. After the scan, walk the xarray once and emit each unique backtrace, followed by a single summary line when more than one object shares it. Important to say that the contents of /sys/kernel/debug/kmemleak are unchanged - only the verbose console output is collapsed. Note 1: The xarray operations and kmalloc(GFP_ATOMIC) for the dedup entry must happen outside object->lock: object->lock is a raw spinlock, while the slab path takes higher wait-context locks (n->list_lock), which lockdep flags as an invalid wait context. trace_handle is read under object->lock, which serialises with kmemleak_update_trace()'s writer, so it is safe to capture and use after dropping the lock. Note 2: Stashed object pointers carry a get_object() reference across rcu_read_unlock() that dedup_flush() drops after printing, preventing use-after-free if the underlying allocation is freed concurrently. Signed-off-by: Breno Leitao --- mm/kmemleak.c | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++++= ++-- 1 file changed, 111 insertions(+), 2 deletions(-) diff --git a/mm/kmemleak.c b/mm/kmemleak.c index 2eff0d6b622b6..046847d372777 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -92,6 +92,7 @@ #include #include #include +#include #include =20 #include @@ -1684,6 +1685,82 @@ static void kmemleak_cond_resched(struct kmemleak_ob= ject *object) put_object(object); } =20 +/* + * Per-scan dedup table for verbose leak printing. Each entry collapses all + * leaks that share one allocation backtrace (keyed by stackdepot + * trace_handle) into a single representative object plus a count. + */ +struct kmemleak_dedup_entry { + struct kmemleak_object *object; + unsigned long count; +}; + +/* + * Record a leaked object in the dedup table. The representative object's + * use_count is incremented so it can be safely dereferenced by dedup_flus= h() + * outside the RCU read section; dedup_flush() drops the reference. On + * allocation failure (or a concurrent insert) the object is printed + * immediately, preserving today's "always log every leak" guarantee. + * Caller must not hold object->lock and must hold rcu_read_lock(). + */ +static void dedup_record(struct xarray *dedup, struct kmemleak_object *obj= ect, + depot_stack_handle_t trace_handle) +{ + struct kmemleak_dedup_entry *entry; + + entry =3D xa_load(dedup, trace_handle); + if (entry) { + /* This is a known beast, just increase the counter */ + entry->count++; + return; + } + + /* + * A brand new report. Object will have object->use_count increased + * in here, and released put_object() at dedup_flush + */ + entry =3D kmalloc(sizeof(*entry), GFP_ATOMIC); + if (entry && get_object(object)) { + if (xa_insert(dedup, trace_handle, entry, GFP_ATOMIC) =3D=3D 0) { + entry->object =3D object; + entry->count =3D 1; + return; + } + put_object(object); + } + kfree(entry); + + /* + * Fallback for kmalloc/get_object(): Just print it straight away + */ + raw_spin_lock_irq(&object->lock); + print_unreferenced(NULL, object); + raw_spin_unlock_irq(&object->lock); +} + +/* + * Drain the dedup table: print one full record per unique backtrace, + * followed by a summary line whenever more than one object shared it. + * Releases the reference dedup_record() took on each representative objec= t. + */ +static void dedup_flush(struct xarray *dedup) +{ + struct kmemleak_dedup_entry *entry; + unsigned long idx; + + xa_for_each(dedup, idx, entry) { + raw_spin_lock_irq(&entry->object->lock); + print_unreferenced(NULL, entry->object); + raw_spin_unlock_irq(&entry->object->lock); + if (entry->count > 1) + pr_warn(" ... and %lu more object(s) with the same backtrace\n", + entry->count - 1); + put_object(entry->object); + kfree(entry); + xa_erase(dedup, idx); + } +} + /* * Scan data sections and all the referenced memory blocks allocated via t= he * kernel's standard allocators. This function must be called with the @@ -1834,10 +1911,19 @@ static void kmemleak_scan(void) return; =20 /* - * Scanning result reporting. + * Scanning result reporting. When verbose printing is enabled, dedupe + * by stackdepot trace_handle so each unique backtrace is logged once + * per scan, annotated with the number of objects that share it. The + * per-leak count below still reflects every object, and + * /sys/kernel/debug/kmemleak still lists them individually. */ + struct xarray dedup; + + xa_init(&dedup); rcu_read_lock(); list_for_each_entry_rcu(object, &object_list, object_list) { + depot_stack_handle_t trace_handle; + if (need_resched()) kmemleak_cond_resched(object); =20 @@ -1849,18 +1935,41 @@ static void kmemleak_scan(void) if (!color_white(object)) continue; raw_spin_lock_irq(&object->lock); + trace_handle =3D 0; if (unreferenced_object(object) && !(object->flags & OBJECT_REPORTED)) { object->flags |=3D OBJECT_REPORTED; =20 if (kmemleak_verbose) - print_unreferenced(NULL, object); + trace_handle =3D object->trace_handle; =20 new_leaks++; } raw_spin_unlock_irq(&object->lock); + + /* + * Dedup bookkeeping must happen outside object->lock. + * dedup_record() may call kmalloc(GFP_ATOMIC), and the slab + * path takes locks (n->list_lock, etc.) at a higher + * wait-context level than the raw_spinlock_t object->lock; + * + * Passing object without object->lock here is safe: + * - the surrounding rcu_read_lock() keeps the memory alive + * even if a concurrent kmemleak_free() drops use_count to + * zero and queues free_object_rcu(); + * - dedup_record() only manipulates use_count via the atomic + * get_object()/put_object() helpers and stores the bare + * pointer into the xarray; + * - on the fallback print path it re-acquires object->lock + * before calling print_unreferenced(). + */ + if (trace_handle) + dedup_record(&dedup, object, trace_handle); } rcu_read_unlock(); + /* Flush'em all */ + dedup_flush(&dedup); + xa_destroy(&dedup); =20 if (new_leaks) { kmemleak_found_leaks =3D true; --=20 2.52.0 From nobody Wed Jun 17 01:38:28 2026 Received: from stravinsky.debian.org (stravinsky.debian.org [82.195.75.108]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E0F1D3D330E; Tue, 21 Apr 2026 13:45:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=82.195.75.108 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776779131; cv=none; b=J1SRg4SLGPfSOEkNbhddt9pf/VO+OFiiK94ckR1loyhYbe+mN1HvbVDJ53hEDAr6/TTFPcrSp60bgghES4JeChh08qU0r7pgjXDdHguCaEm5mfvXCIZkts9JqMkhcmLELeW3pTseAIebfAwln/PgOhLqtOoA33ljtxzoQNSPxuQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776779131; c=relaxed/simple; bh=9Wm7Dl8/F3pYBq3qZXT8kJfTkQ2Zpb38Hb44JyLLdyM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=SteDw3oyB1jNylJg8FPlirnvq92ZWYZYCg8Z5hIkHJdKhgXeu33ZXy2B2ANuYHXO0H1wQ+n23rTEvnCz1h6zBiAlLn9kNzgWWR+X7V2fSuo9+mCq9VrcxX/bOtBVHYTEOlaiO1TJtK4PSe2f995GlnIRFKZ+ob3/NyWs9R5aB7Q= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=debian.org; spf=none smtp.mailfrom=debian.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b=N29+8gwv; arc=none smtp.client-ip=82.195.75.108 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=debian.org Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=debian.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b="N29+8gwv" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=debian.org; s=smtpauto.stravinsky; h=X-Debian-User:Cc:To:In-Reply-To:References: Message-Id:Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date: From:Reply-To:Content-ID:Content-Description; bh=zmmnr8TWW6YxLTw+YepayNd7RYX3r8i4j8goyBNWTgE=; b=N29+8gwvrkSpXl7c4jicvS8gXy 6ta1kv+OwClGLqjvT1ArLhmoGzZp3cSIV6aFXG0+ZGyEe6MRFI+YTmQeA0fTMzFB0GthI/tMj+Tey laWL/wF9g2Oa1lU0ViwqetoDK0HVErkPLUdXGESdi2x0X5z4zbmaVYHEifvEQGQmuvxRK0GVR3hfX sNsWTGPb8dm96X3Hry2ICsCOb102XsjD1wDbwppdLebr6F7ZP2mMaa110BEtOUqFC6WIUXYKbqIie 784EINV6W7umYr/Zy/MSEwDgi7926LvZCqstXQNGDS6vYxQ1JdxB6drsZfArZQdKtXeWxMtCdRv3w UlHQBrEg==; Received: from authenticated user by stravinsky.debian.org with esmtpsa (TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.96) (envelope-from ) id 1wFBPr-000tUk-14; Tue, 21 Apr 2026 13:45:27 +0000 From: Breno Leitao Date: Tue, 21 Apr 2026 06:45:05 -0700 Subject: [PATCH 2/2] selftests/mm: add kmemleak verbose dedup test Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260421-kmemleak_dedup-v1-2-65e31c6cdf0c@debian.org> References: <20260421-kmemleak_dedup-v1-0-65e31c6cdf0c@debian.org> In-Reply-To: <20260421-kmemleak_dedup-v1-0-65e31c6cdf0c@debian.org> To: Andrew Morton , David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Shuah Khan , Catalin Marinas Cc: linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-kselftest@vger.kernel.org, kernel-team@meta.com, Breno Leitao X-Mailer: b4 0.16-dev-453a6 X-Developer-Signature: v=1; a=openpgp-sha256; l=4082; i=leitao@debian.org; h=from:subject:message-id; bh=9Wm7Dl8/F3pYBq3qZXT8kJfTkQ2Zpb38Hb44JyLLdyM=; b=owEBbQKS/ZANAwAIATWjk5/8eHdtAcsmYgBp539pSZsITzdPAca14zLveMIHnMZh4OdAp07TV mIYE4BT87CJAjMEAAEIAB0WIQSshTmm6PRnAspKQ5s1o5Of/Hh3bQUCaed/aQAKCRA1o5Of/Hh3 bQE+D/4puL//7G+Ueti7kPpEa74j38TB6C8TVaq0xhyFPzwKqvkgXIIyQZIvPWFYfWI0qM0g4/u ZQtEt/RgTOs+dfiHFMvKiCAFRKoTxap1JADx117OPqH9gJXB8hDh4N1C1Tkchwbfw6mEUiyjGDQ YGpUFU7iIH1bSSQm/rxKHt2b/DHLu/CDZTbnoYABgiEi379B5vv4UZrbtealqDojBf1ynzml6Vf 8kfeVnSUM4AMk/V3aCYrEZ0WBqTkhOueoxBGAeZdlfVcXy3Mf4bxIxtFikbelLTK95D049gYdnH 9ixA1dwUbcKO909t5Ht4vM4L5HsmM+kM2RP+l7/TdcBytlp/07c3IvMNVG50Ohl4WH3GdlFcQ8Z vb5BisLQHh31KY2d9X/6QPX7BSO0LF/UXR1xjHWd4dd4eU/gzytNtSd89XSyWm6SFbSM8uUnTs4 2mzQHug8xNU0mC9bORJA93FYYFYwhMAe4tErwEN6x8jF6GN00GaaHZpd5x4vLH2hOsE8Xy30RwR qDLuBivyVI8wRcZrZoH8JF6RB3MduoQZVMrcSzQ6nUNVMrM4R2vSEeEj35iqH8BDCHImCdiVRrE r0XOXE014XcmS9fYC8U8c4WNsT7tEiN0rurBKg2KUlV5IlcMyNK28z6IgwdW7VRBlu/WXi/VcJA 5qs3aK+Xx9hJ4jg== X-Developer-Key: i=leitao@debian.org; a=openpgp; fpr=AC8539A6E8F46702CA4A439B35A3939FFC78776D X-Debian-User: leitao Exercise the per-scan dedup of kmemleak's verbose leak output added in the previous commit. The test depends on the kmemleak-test sample module (CONFIG_SAMPLE_KMEMLEAK=3Dm); load it and unload it to orphan ten list entries from a single kzalloc() call site that all share one stackdepot trace_handle, trigger two scans, and assert that the number of "unreferenced object" lines printed in dmesg is strictly less than the number of leaks reported. Skip cleanly when kmemleak is absent, disabled at runtime, or CONFIG_SAMPLE_KMEMLEAK is not built in. Signed-off-by: Breno Leitao --- tools/testing/selftests/mm/test_kmemleak_dedup.sh | 86 +++++++++++++++++++= ++++ 1 file changed, 86 insertions(+) diff --git a/tools/testing/selftests/mm/test_kmemleak_dedup.sh b/tools/test= ing/selftests/mm/test_kmemleak_dedup.sh new file mode 100755 index 0000000000000..1a1b6efd6470a --- /dev/null +++ b/tools/testing/selftests/mm/test_kmemleak_dedup.sh @@ -0,0 +1,86 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Verify that kmemleak's verbose scan output deduplicates leaks that share +# the same allocation backtrace. The kmemleak-test module leaks 10 list +# entries from a single kzalloc() call site, so they share one stackdepot +# trace_handle. With dedup, only one "unreferenced object" line should be +# printed for that backtrace per scan, while the per-scan leak counter +# still accounts for every object. +# +# The expected output is something like: +# PASS: kmemleak verbose output deduplicated (11 printed for 61 leaks) +# +# Author: Breno Leitao + +ksft_skip=3D4 +KMEMLEAK=3D/sys/kernel/debug/kmemleak +VERBOSE_PARAM=3D/sys/module/kmemleak/parameters/verbose +MODULE=3Dkmemleak-test + +skip() { + echo "SKIP: $*" + exit $ksft_skip +} + +fail() { + echo "FAIL: $*" + exit 1 +} + +[ "$(id -u)" -eq 0 ] || skip "must run as root" +[ -r "$KMEMLEAK" ] || skip "no kmemleak debugfs (CONFIG_DEBUG_KMEMLEAK)" +[ -w "$VERBOSE_PARAM" ] || skip "kmemleak verbose param missing" +modinfo "$MODULE" >/dev/null 2>&1 || + skip "$MODULE not built (CONFIG_SAMPLE_KMEMLEAK)" + +# kmemleak can be present but disabled at runtime (boot arg kmemleak=3Doff, +# or it self-disabled after an internal error). In that state writes other +# than "clear" return EPERM, so probe once and skip if so. +if ! echo scan > "$KMEMLEAK" 2>/dev/null; then + skip "kmemleak is disabled (check dmesg or kmemleak=3D boot arg)" +fi + +prev_verbose=3D$(cat "$VERBOSE_PARAM") +cleanup() { + echo "$prev_verbose" > "$VERBOSE_PARAM" 2>/dev/null + rmmod "$MODULE" 2>/dev/null +} +trap cleanup EXIT + +echo 1 > "$VERBOSE_PARAM" + +# Drain the existing leak set so the next scan only reports our objects. +echo clear > "$KMEMLEAK" + +modprobe "$MODULE" || fail "failed to load $MODULE" +# Removing the module orphans the list elements without freeing them. +rmmod "$MODULE" || fail "failed to unload $MODULE" + +# Two scans: kmemleak requires the object to survive a full scan cycle +# before it is reported as unreferenced. +dmesg -C >/dev/null +echo scan > "$KMEMLEAK"; sleep 6 +echo scan > "$KMEMLEAK"; sleep 6 + +log=3D$(dmesg) + +new_leaks=3D$(echo "$log" | + sed -n 's/.*kmemleak: \([0-9]\+\) new suspected.*/\1/p' | tail -1) +[ -n "$new_leaks" ] || fail "no 'new suspected memory leaks' line found" + +# Count "unreferenced object" lines emitted in verbose output. +printed=3D$(echo "$log" | grep -c 'kmemleak: unreferenced object') + +echo "new_leaks=3D$new_leaks printed=3D$printed" + +# The kzalloc(sizeof(*elem)) loop alone contributes 10 leaks sharing one +# backtrace, so without dedup printed >=3D 10. With dedup the printed count +# must be strictly less than the reported leak total. +[ "$new_leaks" -ge 10 ] || fail "expected >=3D10 new leaks, got $new_leaks" +[ "$printed" -lt "$new_leaks" ] || \ + fail "no dedup: printed=3D$printed new_leaks=3D$new_leaks" + +echo "PASS: kmemleak verbose output deduplicated" \ + "($printed printed for $new_leaks leaks)" +exit 0 --=20 2.52.0