From nobody Sat Jul 25 21:21:33 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 E32A53EDE7E; Mon, 13 Jul 2026 11:48:36 +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=1783943323; cv=none; b=HgwL5vtuqiZKQMJ9RDGYhKrf33183CfOdX62RVPzJ12uUBizG8/oE7Kw7AthPKu+KvuLYpMhphzF17a7HnxCcl0qtlmLrBmiKKWnGgCJbOtSq3JLEEi4M/+yMo6XWe503h+IM1z9hQriFJdwVwLG1lets/FbPAV/fmTl88on+k4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783943323; c=relaxed/simple; bh=MfoHjzWLvzBg0lQMWcDC/wF9znVs8BNW7DCTyn2CF7A=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=TR/6zSbK1355T1HBZ/zW1Dh9dWOWD1QhbHgTTwDS75RUvx49KJvCbKU0GarLLEdue4YL1ue2zrNKIHrLTeokCQN3x74UzWgj+PIuOcC+ViG7/b6IaLPpBg+DzFOIhRPXLQ56wbYUEoerQaBhGJJgxnu7WGwe44KCqrgGJZzGYuI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org; spf=pass smtp.mailfrom=debian.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b=ZoSryOM6; arc=none smtp.client-ip=82.195.75.108 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org Authentication-Results: smtp.subspace.kernel.org; spf=pass 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="ZoSryOM6" 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=8LzjJcbcBOXrfLADuXXmAbo73ajPyy8OrPW+mEAjdK4=; b=ZoSryOM6Ov3DSqe5rhcu0hpRgy 9nPDwffqAXSVVcZLie7XqTNa6I08xHjd8ztoSRCJrb5XVCa6NSJD3l0inU9tx5r+TF9ZIC/2d+flT tDUgXuwb2hOGsN81/uUdThVyxEa9RQhCGFcCWrrPrw0iXdj9zM377Yp9t2RR+NYdV5IhGo2GYqgh6 h0bKjCg4FPrhCZ8ps92Yi8JLzIqg/l/v1ww1bKLaf7eETNsYxPVWzFJ+v8DU/XE3ponBxbujUfvgJ 0jzNJp7sIPRbkvnwvcBUQEpoQ9QN6mdcRqAaVm+wBc9eTS2KtkC5w9c0Qi1yG255Z3FS/KG+g5QJI o2qPzl+A==; 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 1wjF9C-001Tie-0A; Mon, 13 Jul 2026 11:48:30 +0000 From: Breno Leitao Date: Mon, 13 Jul 2026 04:48:04 -0700 Subject: [PATCH 1/4] mm: kmemleak: confirm suspected leaks with a second scan 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: <20260713-catalin_pto-v1-1-5b93b1131089@debian.org> References: <20260713-catalin_pto-v1-0-5b93b1131089@debian.org> In-Reply-To: <20260713-catalin_pto-v1-0-5b93b1131089@debian.org> To: Catalin Marinas , Andrew Morton , Jonathan Corbet , Shuah Khan , David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Shuah Khan Cc: linux-mm@kvack.org, linux-kernel@vger.kernel.org, workflows@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, Breno Leitao , kernel-team@meta.com X-Mailer: b4 0.16-dev-d5d98 X-Developer-Signature: v=1; a=openpgp-sha256; l=5439; i=leitao@debian.org; h=from:subject:message-id; bh=2Ik36nD5Ymen0igsLFiFN5pbHvbZF0V0k4IOFO34tCM=; b=owEBbQKS/ZANAwAIATWjk5/8eHdtAcsmYgBqVNCDe9n1M9YNOiQ/yUFY2MBL+A8LR6gq6LZuK UWDOMGVhmmJAjMEAAEIAB0WIQSshTmm6PRnAspKQ5s1o5Of/Hh3bQUCalTQgwAKCRA1o5Of/Hh3 bRU8EAChIkFYicCYva6mq7aO2tlOJyY4KTdiQFZL5K3tXxDOFUh9nxGrlQOzkVvtyYfOsPiIrsD nfWCwHcQVbyWANPt4qyA0G3rTI+M9f7pfk4Q6PPmgM+gVKTFUNfVyma47kdgItlSycJNfqZLYiI Ex5W/qBFwdefN8ey2pxvRc02VreAv4XpDv9T77OqaCC75SzG81fI/qrpMRUcjoAZLZCJZdRb/O1 vmWed4KgnZMcVKFOkQg8HYCAwxiwB59b110PPiZUFV6V0XIJYrWMeg6aKxm2BHUou7y/fP1E+3j L8Q2WPjllunX66rVivlHMCS7gdBlZnpj5JEcUAUN9aNSj8McwdI5cI5vsung2EUM4PomAb2wDnB GED78mm8KOr+I6iPAbMA2bXSaEXjjZL2QIDx98zbc2tNOMuKHmv4BmQ3+vJG46dWGhYApAgr/OQ ickcPUwvRdGBOMwrvPXi3M/35QeHkVaOl3RzJr0nvda9v9Q7JDiUqLI2gPfiKrawcSIfJi5/fps DKia5+UqAAQue+DIcHdFHmFAGlYzvRtXPfdRwc+CI0zG2llHgKUyvyDO4Ew9r2dHVv9Hx5xEuVm 8bC8c2HmbD1CGMnNV5yOdPwqmtCrTn12E8WG73WdrcnPEObU7xEPknF5YNfviaV2DyvmEtR+YJP 9XJsusLKdLazP+Q== X-Developer-Key: i=leitao@debian.org; a=openpgp; fpr=AC8539A6E8F46702CA4A439B35A3939FFC78776D X-Debian-User: leitao From: Catalin Marinas The kmemleak marking phase is not atomic. While the object graph is traversed, the kernel can modify pointers, free objects or allocate new ones. If a reference to an object is moved from one location to another, kmemleak scanning may miss it. We have explicit annotations like kmemleak_transient_leak() but identifying and maintaining them is not trivial. Given that such transient leaks are short-lived, rather than just reporting such objects as leaks, do another scan to confirm the suspected objects. If no new leaks are found during the first scan, skip the confirmation one. Signed-off-by: Catalin Marinas Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Breno Leitao Cc: Andrew Morton --- mm/kmemleak.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-= -- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/mm/kmemleak.c b/mm/kmemleak.c index e96e9efd19b0d..ac77bab580688 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 confi= rmation */ +#define OBJECT_SUSPECT (1 << 6) =20 /* set when __remove_object() called */ #define DELSTATE_REMOVED (1 << 0) @@ -235,6 +237,8 @@ static unsigned long jiffies_min_age; static unsigned long jiffies_last_scan; /* delay between automatic memory scannings */ static unsigned long jiffies_scan_wait; +/* number of objects flagged OBJECT_SUSPECT during the current scan */ +static int nr_suspects; /* enables or disables the task stacks scanning */ static int kmemleak_stack_scan =3D 1; /* protects the memory scanning, parameters and debug/kmemleak file access= */ @@ -1440,6 +1444,11 @@ static void update_refs(struct kmemleak_object *obje= ct) */ object->count++; if (color_gray(object)) { + /* referenced after all, no longer a suspect */ + if (object->flags & OBJECT_SUSPECT) { + object->flags &=3D ~OBJECT_SUSPECT; + nr_suspects--; + } /* put_object() called when removing from gray_list */ WARN_ON(!get_object(object)); list_add_tail(&object->gray_list, &gray_list); @@ -1844,16 +1853,16 @@ 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 int __kmemleak_scan(bool full) { struct kmemleak_object *object; struct zone *zone; int __maybe_unused i; - struct xarray dedup; - int new_leaks =3D 0; int stop =3D 0; =20 jiffies_last_scan =3D jiffies; + if (full) + nr_suspects =3D 0; =20 /* prepare the kmemleak_object's */ rcu_read_lock(); @@ -1883,6 +1892,8 @@ static void kmemleak_scan(void) =20 /* reset the reference count (whiten the object) */ object->count =3D 0; + if (full) + object->flags &=3D ~OBJECT_SUSPECT; if (color_gray(object) && get_object(object)) list_add_tail(&object->gray_list, &gray_list); =20 @@ -1950,6 +1961,10 @@ static void kmemleak_scan(void) scan_gray: scan_gray_list(); =20 + /* a confirmation scan does not look for modified objects */ + if (!full) + return nr_suspects; + /* * Check for new or unreferenced objects modified since the previous * scan and color them gray until the next scan. @@ -1972,6 +1987,11 @@ static void kmemleak_scan(void) /* color it gray temporarily */ object->count =3D object->min_count; list_add_tail(&object->gray_list, &gray_list); + } else if (unreferenced_object(object) && + !(object->flags & OBJECT_REPORTED)) { + /* flag the objects left unreferenced by this scan */ + object->flags |=3D OBJECT_SUSPECT; + nr_suspects++; } raw_spin_unlock_irq(&object->lock); } @@ -1982,12 +2002,42 @@ static void kmemleak_scan(void) */ scan_gray_list(); =20 + return nr_suspects; +} + +/* + * 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 =3D 0; + + /* + * Full scan. Objects left unreferenced are flagged OBJECT_SUSPECT and + * counted in the return value; nothing to confirm or report otherwise. + */ + if (!__kmemleak_scan(true)) + return; + /* * If scanning was stopped do not report any new unreferenced objects. */ if (scan_should_stop()) return; =20 + /* + * 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. Scan again and only report the objects + * left unreferenced (still flagged OBJECT_SUSPECT) by both scans. + */ + __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 @@ -2015,6 +2065,7 @@ static void kmemleak_scan(void) trace_handle =3D 0; dedup_print =3D false; if (unreferenced_object(object) && + (object->flags & OBJECT_SUSPECT) && !(object->flags & OBJECT_REPORTED)) { object->flags |=3D OBJECT_REPORTED; if (kmemleak_verbose) { --=20 2.53.0-Meta From nobody Sat Jul 25 21:21:33 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 948CC3BB104; Mon, 13 Jul 2026 11:48:40 +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=1783943326; cv=none; b=mdIJ+L0S4hVTL8/UHvN18/LQWtR9APIV2gUi6lpf40XQxlC19rOhgfcrwH54BjmlJPMYfD8rBU1/lkpdzwAAHOiIhDBq3kSVDq0HnmsoKk3DsK8qVqcTjqzsuKbBwSIesOPgmXhVYEoVMHQtODQOfQXPZmjf3A6bVpzB8LW1x/E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783943326; c=relaxed/simple; bh=YBPJ0mqcwhJO4nOJvC72HAXZ4ErujEc7xC2rk3ArDDU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=GBLM+APHqo7UdTt1GOd/e+4vOZVH0apPHHzkgQ8hVMpp7IlxjXIFdEmAD/A79ipNmYFkUKo+CSp1lUkJKp/AUBwj+mEgijCfKXPGCB/pUByMzd9UkC+wXFFFXVZoxlo5k358xO8HftV19aRGg531oykRhBXcTF+bAz6fmTRCiAU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org; spf=pass smtp.mailfrom=debian.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b=N8JkedrF; arc=none smtp.client-ip=82.195.75.108 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org Authentication-Results: smtp.subspace.kernel.org; spf=pass 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="N8JkedrF" 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=3PyMSDdhZBE9vEjgfp5OzX/2Lfp7N6HnZTWVkO5qI/k=; b=N8JkedrFp067HCVQay8inu9u1z h83J6ZhcSMk1hIUwslGZNCaiZyFqnaWOOsJk78AZTNS1tiI5I5lutnyQ2lLdSgfVpCv13fvzq4W5w Jesr6LxsBYoDyr92CCet2I/Gr2FmfW8wZ2E6riiDe1JTrJ57enaSMpbor/2nvGGwNCRhOvbvmOVLy x5celDTdld0oC5m6x5c6wGkRexupSwwMHuD5jJG27ycFpFJwLD7XYlZIh++WdVURcDUyiP1qifAeo uUMSzIAsax437bwUusG8r2IbBGIWZwFdvIU4e/nnPfnxxFyUm+BUxZRCLOXNtqFqpYbU7Mg7k0kkN u50fa91Q==; 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 1wjF9H-001Tiq-0i; Mon, 13 Jul 2026 11:48:35 +0000 From: Breno Leitao Date: Mon, 13 Jul 2026 04:48:05 -0700 Subject: [PATCH 2/4] mm: kmemleak: report leaks only after N consecutive unreferenced scans 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: <20260713-catalin_pto-v1-2-5b93b1131089@debian.org> References: <20260713-catalin_pto-v1-0-5b93b1131089@debian.org> In-Reply-To: <20260713-catalin_pto-v1-0-5b93b1131089@debian.org> To: Catalin Marinas , Andrew Morton , Jonathan Corbet , Shuah Khan , David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Shuah Khan Cc: linux-mm@kvack.org, linux-kernel@vger.kernel.org, workflows@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, Breno Leitao , kernel-team@meta.com X-Mailer: b4 0.16-dev-d5d98 X-Developer-Signature: v=1; a=openpgp-sha256; l=4344; i=leitao@debian.org; h=from:subject:message-id; bh=YBPJ0mqcwhJO4nOJvC72HAXZ4ErujEc7xC2rk3ArDDU=; b=owEBbQKS/ZANAwAIATWjk5/8eHdtAcsmYgBqVNCDmJoWE4BMqrcZuuBB18LglsrEY2eFnhOvK 1EfO5TjQAmJAjMEAAEIAB0WIQSshTmm6PRnAspKQ5s1o5Of/Hh3bQUCalTQgwAKCRA1o5Of/Hh3 bXuAD/9lsfBVuMajHKh8kGKHEKDGGScReuyPF9mfQyBxoY4s107cMCBzbUi/pMqEBi2m0B67sEy 6XWG7EZlOGqW6IgVcv+vDl0/RMSWBMf3BETrnbSI43C1Qf+bE0McySykdVWWvddgc3cFEqkpx4U cPJZlZr5W7wOSZdUXez+yZYFAr8F8/ZYLWtUaYY3a1PoKpvVgsmUDS4XBjA5UDGmfztDO9uShm9 hhLlpKkkxUnnnYjEvvxTWpIiQvAzkMP+vScEtsw0bnhx+Y8ew4prxijoLTrWvUs6beu5FLVOhkV 5AL71WmJyCoy3z5wEM0L46Kvq/h8NT2tC9gbl/gDciQZKo9xlIBOXph51YULGnEpyLzty2/4/DF u1DLJviSgu0j2pbe/GOO1i3GhQStWMpCg+88eOmRLdMZpAx4a5aOFSjRnbXLlnj0Uut3PjQ7eiX k5+QryctC9FgYRhpPxD8+d8glFwRbl407dt8GcAsc2UClwaFg//FbzivwKOYtx2LKY0vJ1qEJb4 JBYCWKWCb9u0EhicC0FTNbGF1ol1e1KuMVa57VtOWBkJILZdrBudqSfm9kMlJFDtAmW7JBeFgJp r8O/yymkSwOa1Y7akjrjyXPXCegs+pVJ21VAb9dFaM4LVlH3BDdOuVZuZntJl5PxJ0HWU6j7CST VaIvB0nICkpc5/Q== X-Developer-Key: i=leitao@debian.org; a=openpgp; fpr=AC8539A6E8F46702CA4A439B35A3939FFC78776D X-Debian-User: leitao kmemleak reports an object the first scan it is found unreferenced. Its mark phase runs without stopping the rest of the kernel and without a write barrier, so a live object whose only reference is briefly invisible during a concurrent RCU update -- e.g. a VMA moved between maple tree nodes, or a page-cache xa_node -- can be seen as unreferenced for that one scan. Because an object is flagged as reported only once, such a transient race turns into a permanent false positive. Track how many consecutive scans each object has been seen unreferenced and only report it once that reaches min_unref_scans, a new module parameter. It defaults to 1, leaving the behaviour unchanged; setting it higher (e.g. 2) still reports a genuine leak, one scan later, while an object referenced again before the threshold restarts its run and is never reported. min_unref_scans can be set at boot with kmemleak.min_unref_scans=3D or at run-time via /sys/module/kmemleak/parameters/min_unref_scans. Signed-off-by: Breno Leitao Reviewed-by: Catalin Marinas --- Documentation/dev-tools/kmemleak.rst | 8 ++++++++ mm/kmemleak.c | 13 ++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/Documentation/dev-tools/kmemleak.rst b/Documentation/dev-tools= /kmemleak.rst index 7d784e03f3f9d..a8a83bc69ceb8 100644 --- a/Documentation/dev-tools/kmemleak.rst +++ b/Documentation/dev-tools/kmemleak.rst @@ -198,6 +198,14 @@ systems, because of pointers temporarily stored in CPU= registers or stacks. Kmemleak defines MSECS_MIN_AGE (defaulting to 1000) representing the minimum age of an object to be reported as a memory leak. =20 +The ``min_unref_scans`` module parameter (default 1) requires an object to +be seen unreferenced in that many consecutive scans before it is reported. +Keeping it at 1 preserves the historical behaviour; higher values filter +the transient false positives described above, at the cost of delaying +genuine reports by up to that many scans. It can be set at boot with +``kmemleak.min_unref_scans=3D`` or at run-time via +``/sys/module/kmemleak/parameters/min_unref_scans``. + Limitations and Drawbacks ------------------------- =20 diff --git a/mm/kmemleak.c b/mm/kmemleak.c index ac77bab580688..2fff11637e490 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -151,6 +151,8 @@ struct kmemleak_object { int min_count; /* the total number of pointers found pointing to this object */ int count; + /* consecutive scans the object has been seen unreferenced */ + unsigned int unref_scans; /* checksum for detecting modified objects */ u32 checksum; depot_stack_handle_t trace_handle; @@ -234,6 +236,9 @@ static unsigned long max_percpu_addr; static struct task_struct *scan_thread; /* used to avoid reporting of recently allocated objects */ static unsigned long jiffies_min_age; +/* consecutive scans an object must stay unreferenced before reporting */ +static unsigned int min_unref_scans =3D 1; +module_param(min_unref_scans, uint, 0644); static unsigned long jiffies_last_scan; /* delay between automatic memory scannings */ static unsigned long jiffies_scan_wait; @@ -692,6 +697,7 @@ static struct kmemleak_object *__alloc_object(gfp_t gfp) object->excess_ref =3D 0; object->count =3D 0; /* white color initially */ object->checksum =3D ~0; + object->unref_scans =3D 0; object->del_state =3D 0; =20 /* task information */ @@ -1890,6 +1896,9 @@ static int __kmemleak_scan(bool full) __paint_it(object, KMEMLEAK_BLACK); } =20 + /* referenced last scan: restart the unreferenced run */ + if (!color_white(object)) + object->unref_scans =3D 0; /* reset the reference count (whiten the object) */ object->count =3D 0; if (full) @@ -2064,9 +2073,11 @@ static void kmemleak_scan(void) raw_spin_lock_irq(&object->lock); trace_handle =3D 0; dedup_print =3D false; + if (unreferenced_object(object) && (object->flags & OBJECT_SUSPECT) && - !(object->flags & OBJECT_REPORTED)) { + !(object->flags & OBJECT_REPORTED) && + ++object->unref_scans >=3D min_unref_scans) { object->flags |=3D OBJECT_REPORTED; if (kmemleak_verbose) { trace_handle =3D object->trace_handle; --=20 2.53.0-Meta From nobody Sat Jul 25 21:21:33 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 E8A323F076E; Mon, 13 Jul 2026 11:48:43 +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=1783943332; cv=none; b=c9n+dK3LXooV4GPjp+KfzVL/ZGcKnVKskddXDjVX5KUc884fylNbLUYA9WrN8a1GgxbBbwa8qq4+b5Lw/NfsM2BMwoAIFDAy3VH25C55OK+GF+590TgsShqHBgH06xXFl0NHYrltIaDgSjlSZsGvyQlMYiHyGya0jcYb/rcs8uA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783943332; c=relaxed/simple; bh=k5syoIA9ysnV4wrEyuCwDG5+YSh/+ARvdAvSvQ1nHGE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Lab/YRGi1TVRRQPt4rF3mTjMmQHwlZJ0cFD6qYNSresgiTRydASR6Px1VIeG9dFwDX/2GfobwKKI1c0t3AqRwbvfVAxB7s1GCv6tOhg09utvlG4eUliNZ2v5kBZYLyfedwmb17ts8ABaI/+3+/Rr2GQAGuzC8WPSHglu/OUNIzc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org; spf=pass smtp.mailfrom=debian.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b=b8FGLVCJ; arc=none smtp.client-ip=82.195.75.108 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org Authentication-Results: smtp.subspace.kernel.org; spf=pass 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="b8FGLVCJ" 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=XFSQUx8TCZyAA/EWJdMDpeVC+kFXZt9qXST9blJikws=; b=b8FGLVCJ2eKvCoKVZHHQKvWQHF MVLYqoWxGVp02+HcmJfS3idd/2A0b3yUUxp0ooxKtpVaQRe4nCXBBBFeQHuWUVqRaMYEvOizMDxG9 2J+USEj/5SZNlDUZAfYY44XDdPOHEV/U38/WfYN9xVCpRJgl8BQP2RmdNqt3YohAS/hBSy5YwSMl2 zKzQtn2VLd+RWtzTDKl1ITOqUUPmEL87SuUwMhrB0XKcixNSp6Bc7OBDDnEyt5YAXcy8DCimL9NlB VnCxT8dNVkenBHebr5dLp7nvTNFJxt8NO/qAdVVp3oP8bUknz7ACwL7jmIJc+VN1rI2vquQJ93ihb Y6QC6xaw==; 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 1wjF9M-001TjD-0n; Mon, 13 Jul 2026 11:48:40 +0000 From: Breno Leitao Date: Mon, 13 Jul 2026 04:48:06 -0700 Subject: [PATCH 3/4] mm: kmemleak: factor leak confirmation into a helper 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: <20260713-catalin_pto-v1-3-5b93b1131089@debian.org> References: <20260713-catalin_pto-v1-0-5b93b1131089@debian.org> In-Reply-To: <20260713-catalin_pto-v1-0-5b93b1131089@debian.org> To: Catalin Marinas , Andrew Morton , Jonathan Corbet , Shuah Khan , David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Shuah Khan Cc: linux-mm@kvack.org, linux-kernel@vger.kernel.org, workflows@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, Breno Leitao , kernel-team@meta.com X-Mailer: b4 0.16-dev-d5d98 X-Developer-Signature: v=1; a=openpgp-sha256; l=2095; i=leitao@debian.org; h=from:subject:message-id; bh=k5syoIA9ysnV4wrEyuCwDG5+YSh/+ARvdAvSvQ1nHGE=; b=owEBbQKS/ZANAwAIATWjk5/8eHdtAcsmYgBqVNCDS3n2w9ikiBluKn3vjF/Zn4wkchKX7fc89 7Nrft+gaBSJAjMEAAEIAB0WIQSshTmm6PRnAspKQ5s1o5Of/Hh3bQUCalTQgwAKCRA1o5Of/Hh3 bbCID/wKUKccUQxdsMVZO1R4Q7HhjfNs9AH2FcscwKsWjIPGbXxfqVrrLXVMlYkLmFnxT5C8wLp EvwBeNeklecRZlmsQEAG4SvVFaTUIYFbpOpW0rRrFfhCU5K6w3FWOsb6TGBKAxA6FFyLf+7LbGe gBjdJZlYQt14eBFnTWqofAttBeVdQvUzOkbJ4wqSlvRgUWnL1zpSFdNHSImQF/zaMbNwmYwG8Vb Lvi3FcYhlwkjH0lI+Y/z31xmqQmNd2R/Ci8ddMtfu/kxgseY8cLbeM6WzAo2pQ4Ga5T0gr3bJo3 o4BieTxQdMSHE6YYDnGpns5aNHshdebQyRatmVq9WTz62xsvEVrQ5oxUPTGcIIgNpn61ijsyH8d n78QcKFX/elGtBxP0bYjQxiynlpb8pwXI6i4IlU5B69Y3PKQi27na84Su57z/BSnOqCQgRi0zsF YRzOWBQCrvNG6NoQjHZ3LFoeDZgE6Dfz/O2K1kqDJMBmvvuggpULbNjjSwb+79+2V3u+YOIb3Oh fUcW7n3ULWCZL7NWyg8YoxQ5ewc95SfJjI8neE17OsSBB9Tq59FXfEFk4Z43+QYF8+rWqk90OiQ tiuXyJ95Chv+1WhyyT246ylon36UWQy+w6/wI33/53rpYpnnkrKoVtuAp8od2HKQcF7kPjFO1rK XKTq4QzgpdQCq7Q== X-Developer-Key: i=leitao@debian.org; a=openpgp; fpr=AC8539A6E8F46702CA4A439B35A3939FFC78776D X-Debian-User: leitao The reporting loop in kmemleak_scan() decided whether to tag an object as a reported leak with a four-term compound condition whose last operand also had a side effect (++object->unref_scans). Mixing the candidate tests with the counter update made the check hard to read. Move the state transition into confirm_leak(): it returns true when a still-unreferenced suspect crosses min_unref_scans consecutive scans and is newly flagged OBJECT_REPORTED, leaving only the reporting bookkeeping in the caller. No functional change. Signed-off-by: Breno Leitao --- mm/kmemleak.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/mm/kmemleak.c b/mm/kmemleak.c index 2fff11637e490..85f18b17e79c4 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -2014,6 +2014,26 @@ static int __kmemleak_scan(bool full) return nr_suspects; } =20 +/* + * Promote a suspected object to a reported leak once it has stayed + * unreferenced for min_unref_scans consecutive scans. Called with + * object->lock held; returns true when the object is newly reported. + */ +static bool confirm_leak(struct kmemleak_object *object) +{ + if (!unreferenced_object(object) || + !(object->flags & OBJECT_SUSPECT) || + (object->flags & OBJECT_REPORTED)) + return false; + + object->unref_scans +=3D 1; + if (object->unref_scans < min_unref_scans) + return false; + + object->flags |=3D OBJECT_REPORTED; + return true; +} + /* * Scan the memory and report the unreferenced objects as leaks. Must be * called with the scan_mutex held. @@ -2074,11 +2094,7 @@ static void kmemleak_scan(void) trace_handle =3D 0; dedup_print =3D false; =20 - if (unreferenced_object(object) && - (object->flags & OBJECT_SUSPECT) && - !(object->flags & OBJECT_REPORTED) && - ++object->unref_scans >=3D min_unref_scans) { - object->flags |=3D OBJECT_REPORTED; + if (confirm_leak(object)) { if (kmemleak_verbose) { trace_handle =3D object->trace_handle; dedup_print =3D true; --=20 2.53.0-Meta From nobody Sat Jul 25 21:21:33 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 1AB163EEAEF; Mon, 13 Jul 2026 11:48:50 +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=1783943338; cv=none; b=sLTJELz4o88RRCXyvvRMFuZhyMY6tl1d9GH46x93baiBvwy1j/DCjBzTw/Q0Ug4Ih+8950qCVnzzdhND/TcUXw1Q4bfN6If2gLKoAWcLm2SETz+pAJQbCFm8qjQcufhYYtrrEAI943MkO48N/oZpE5I7l6KNagLYB4CBDRTDWiY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1783943338; c=relaxed/simple; bh=3eQR/Kd3kFCe8YoRP/xKeQGlrrGIS3gsS7iBDPNwGWE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=hItxZWoQVn7WjzpuIo3qkiXM9CUjscfztnOxdA/ds9pzTrEN5grGVK7cvlUOtCamR+Gwv+DTIu4FOcX8tj52bXnKzSCLXxBkOIPSjwQO3BtGyiaTJFdxhF/LNcRn58gosPqbnrlRFRmF25CWvaCxudxXi+Gu8ahkQRbmToLXofo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org; spf=pass smtp.mailfrom=debian.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b=O4dNFxzZ; arc=none smtp.client-ip=82.195.75.108 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org Authentication-Results: smtp.subspace.kernel.org; spf=pass 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="O4dNFxzZ" 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=J+3Dbo69/AiAclmmo0zFVcKt382p+VuW4vPQJlc8PVc=; b=O4dNFxzZco/bBX6I7886Md286z BQdURH8Wz2iXtTqc7u1PFtdADvAk6Pv75xV0JNWaucThbzig+4x3+wWCLuWGzwwLJVFMeG6dcl1yw qurQvJggsW8mwlI0sToNfH/sCmpveQGapeCYfdO8FQN7scPzfeaA0wIxb2xV4cxVEMDlp+qFBlgFY t75mvoaPJ/wD3M3vkPM7VjrKdgEJx43WP3UisV25dqzvL4uJLKsSmM2EXvgAIhHfvJfhULflyge9L ms1K+O5ue209ncKJXF6/OyAJoJEOmoAo0da3nZnMHpvR0ZGzhoGDpWJowZUHWdIE4vmDxWBgtpBL3 hsMjYyWQ==; 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 1wjF9R-001Tjd-1y; Mon, 13 Jul 2026 11:48:45 +0000 From: Breno Leitao Date: Mon, 13 Jul 2026 04:48:07 -0700 Subject: [PATCH 4/4] selftests: mm: test kmemleak's N-consecutive-scan leak confirmation 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: <20260713-catalin_pto-v1-4-5b93b1131089@debian.org> References: <20260713-catalin_pto-v1-0-5b93b1131089@debian.org> In-Reply-To: <20260713-catalin_pto-v1-0-5b93b1131089@debian.org> To: Catalin Marinas , Andrew Morton , Jonathan Corbet , Shuah Khan , David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Shuah Khan Cc: linux-mm@kvack.org, linux-kernel@vger.kernel.org, workflows@vger.kernel.org, linux-doc@vger.kernel.org, linux-kselftest@vger.kernel.org, Breno Leitao , kernel-team@meta.com X-Mailer: b4 0.16-dev-d5d98 X-Developer-Signature: v=1; a=openpgp-sha256; l=7712; i=leitao@debian.org; h=from:subject:message-id; bh=3eQR/Kd3kFCe8YoRP/xKeQGlrrGIS3gsS7iBDPNwGWE=; b=owEBbQKS/ZANAwAIATWjk5/8eHdtAcsmYgBqVNCEK5BL8aTovIa4ZM4PGTSVv0NXeVIOLzzHd QS5UNwaN1aJAjMEAAEIAB0WIQSshTmm6PRnAspKQ5s1o5Of/Hh3bQUCalTQhAAKCRA1o5Of/Hh3 bT3fD/9z7pPIA0FZEM18v9wAENnYMgC5wBEQ92lbjmm0+47fWixv3W1cLGZJ9XQK5jTaO7zWayd ZAlGg5VlwjSzjYaaqtw1+fySCVdYHPtEeb79re7GpXkvgn0shL0Z/dlDS2e6qGZQrD2QHoQVKif +IrXlqd+e8TlUyNvMcso2iJzEEc0772PlC7y/2z9O0vjGYSzRMP7vC0mhrIZ9TE2Vgva/HvJfx3 tOV8j0eDI/4Rh3+LS3jmbRetY4vGP4vFbhgwuNlspydCoJRU3lAnTp8x+b1I4K8LiDjzHFqE899 XYUMnjbaaHSzT0RIwAm3PmFlmNyJVFmCLcSMGdKq51XzQKWgKs/u+IUW0HlEyC5VHlcUMpCowy+ tdrjS+gMpHrTQXinSsJj7NvU9qPjKZpM2ju/leu9WpMRENOOj0jqdDKrkWdJhXCDjf93BHEjJfK 9rmbj6keQk2/Jc7wHG/REuHe2HuLTHFDPQ227mX7SXkCJvDt9hMpy36BRG0j/JgVckLIWP3LN9H iF/YcAPoJC7KqrZBnLj9QRR2aoWZBI+E3jGWBzrTNbFxWzusUM1yGx4pP2JgNNXFr5+B7ut7H7i 9/j/FddfwKk2KPC5xoJC6seTdwTrQBVnKbRatCz706fyFqxzBgLEvd6ginAAI42COkKwnAGqb4F AWZ/LjSek/G+Q3w== X-Developer-Key: i=leitao@debian.org; a=openpgp; fpr=AC8539A6E8F46702CA4A439B35A3939FFC78776D X-Debian-User: leitao Add a functional test for the min_unref_scans kmemleak module parameter. Using samples/kmemleak's helper module it checks that min_unref_scans=3D1 reports an orphan on the first scan, min_unref_scans=3D2 reports nothing on the first scan but does on the second, and that the parameter reads back what was written. It counts only the helper module's own orphans (matched by their [kmemleak_test] backtrace, with the module kept loaded so the symbols resolve) so unrelated leaks already present on the system do not perturb the result. The test skips when run as non-root, without CONFIG_DEBUG_KMEMLEAK / CONFIG_SAMPLE_KMEMLEAK, on a kernel without the parameter, or when the helper yields no detectable orphan. Signed-off-by: Breno Leitao --- tools/testing/selftests/mm/Makefile | 1 + .../testing/selftests/mm/ksft_kmemleak_confirm.sh | 132 +++++++++++++++++= ++++ 2 files changed, 133 insertions(+) diff --git a/tools/testing/selftests/mm/Makefile b/tools/testing/selftests/= mm/Makefile index ed321ae709dac..786b1d73d93b0 100644 --- a/tools/testing/selftests/mm/Makefile +++ b/tools/testing/selftests/mm/Makefile @@ -150,6 +150,7 @@ TEST_PROGS +=3D ksft_gup_test.sh TEST_PROGS +=3D ksft_hmm.sh TEST_PROGS +=3D ksft_hugetlb.sh TEST_PROGS +=3D ksft_hugevm.sh +TEST_PROGS +=3D ksft_kmemleak_confirm.sh TEST_PROGS +=3D ksft_kmemleak_dedup.sh TEST_PROGS +=3D ksft_ksm.sh TEST_PROGS +=3D ksft_ksm_numa.sh diff --git a/tools/testing/selftests/mm/ksft_kmemleak_confirm.sh b/tools/te= sting/selftests/mm/ksft_kmemleak_confirm.sh new file mode 100755 index 0000000000000..3a8576e835c8d --- /dev/null +++ b/tools/testing/selftests/mm/ksft_kmemleak_confirm.sh @@ -0,0 +1,132 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Functional test for kmemleak's N-consecutive-scan leak confirmation +# (the min_unref_scans module parameter). +# +# kmemleak only reports an object once it has stayed unreferenced for +# min_unref_scans consecutive scans. The default of 1 reports on the first +# scan (historical behaviour); higher values filter transient false +# positives where a live object's only reference is briefly invisible to a +# single scan (e.g. an RCU tree update in flight while the scan runs). The +# test loads samples/kmemleak's helper module to create orphan allocations +# and, counting only those orphans (matched by their [kmemleak_test] +# backtrace so unrelated leaks already present on the system are ignored), +# checks that: +# - a freshly allocated object is greyed on its first scan (its checksum +# settles then), so nothing can be reported before that priming scan; +# each case below primes once first, +# - with the default threshold (min_unref_scans=3D1) one scan after prim= ing +# reports the orphans, +# - raising the threshold to 2 needs two scans after priming: one is not +# enough, the second reports, +# - the parameter reads back what was written. +# +# The "one post-prime scan is not enough at min_unref_scans=3D2" check is = the +# core regression test: raising min_unref_scans must push the report +# strictly later. Like ksft_kmemleak_dedup.sh, if the module yields no +# detectable orphan at all in the running environment the test skips rather +# than failing. +# +# Author: Breno Leitao + +# KTAP output helpers (ktap_skip_all, ktap_exit_fail_msg, ktap_test_pass, = ...). +DIR=3D"$(dirname "$(readlink -f "$0")")" +# shellcheck source=3D../kselftest/ktap_helpers.sh +source "${DIR}"/../kselftest/ktap_helpers.sh + +KMEMLEAK=3D/sys/kernel/debug/kmemleak +PARAM=3D/sys/module/kmemleak/parameters/min_unref_scans +MODULE=3Dkmemleak-test +AGE=3D6 # seconds; must exceed kmemleak's 5s minimum object age + +ktap_print_header + +[ "$(id -u)" -eq 0 ] || { ktap_skip_all "must run as root"; exit "$KSFT_SK= IP"; } +[ -r "$KMEMLEAK" ] || + { ktap_skip_all "no kmemleak debugfs (CONFIG_DEBUG_KMEMLEAK)"; exit "$KSF= T_SKIP"; } +[ -w "$PARAM" ] || + { ktap_skip_all "min_unref_scans module parameter not present"; exit "$KS= FT_SKIP"; } +modinfo "$MODULE" >/dev/null 2>&1 || + { ktap_skip_all "$MODULE not built (CONFIG_SAMPLE_KMEMLEAK)"; exit "$KSFT= _SKIP"; } + +# kmemleak can be present but disabled at runtime (kmemleak=3Doff boot arg, +# or it self-disabled after an internal error); a "scan" then returns +# EPERM. Probe once and skip if so. +echo scan > "$KMEMLEAK" 2>/dev/null || + { ktap_skip_all "kmemleak is disabled (check dmesg or kmemleak=3D boot ar= g)"; exit "$KSFT_SKIP"; } + +prev=3D$(cat "$PARAM") +# shellcheck disable=3DSC2317 # invoked indirectly via trap +cleanup() { + echo "$prev" > "$PARAM" 2>/dev/null # restore the parameter + echo scan=3Don > "$KMEMLEAK" 2>/dev/null # re-enable auto scan + rmmod "$MODULE" 2>/dev/null + echo clear > "$KMEMLEAK" 2>/dev/null +} +trap cleanup EXIT + +# Stop the automatic scan thread: only our manual scans should advance an +# object's consecutive-unreferenced run. An auto scan landing between two +# manual scans would change the result and make the test flaky. +echo scan=3Doff > "$KMEMLEAK" 2>/dev/null + +# Create a fresh, aged set of orphan objects from the helper module's init +# path (its kmalloc/vmalloc/percpu allocations are dropped right away). +# Pre-existing reported leaks are greyed first ("clear") so only our +# orphans are counted. The module is left loaded on purpose: once it is +# unloaded its symbols are gone, so the orphan backtraces no longer resolve +# to [kmemleak_test] and could not be matched below. +gen_orphans() { + rmmod "$MODULE" 2>/dev/null + echo clear > "$KMEMLEAK" + modprobe "$MODULE" || + { ktap_skip_all "failed to load $MODULE"; exit "$KSFT_SKIP"; } + sleep "$AGE" +} + +scan() { echo scan > "$KMEMLEAK"; } + +# Number of helper-module orphans currently reported by kmemleak. Matching +# the module's own backtrace ([kmemleak_test]) keeps the count immune to +# unrelated leaks on the running system. kmemleak only lists an object here +# once it has been reported, so this reflects the confirmation gating. +count_orphans() { + c=3D$(grep -c '\[kmemleak_test\]' "$KMEMLEAK" 2>/dev/null) + echo "${c:-0}" +} + +# 0) the parameter reads back what was written. +echo 3 > "$PARAM" +[ "$(cat "$PARAM")" =3D "3" ] || ktap_exit_fail_msg "min_unref_scans did n= ot read back as 3" + +# Priming scan: kmemleak greys a freshly allocated object on its first scan +# (its checksum settles then), so nothing can be reported until a second +# scan. Every case below runs this priming scan before counting. +prime() { scan; } + +# 1) min_unref_scans=3D1 (default): one scan after priming reports the +# orphans. This also establishes that the helper produces detectable +# orphans here. +echo 1 > "$PARAM" +gen_orphans +prime +scan +first=3D$(count_orphans) +[ "$first" -gt 0 ] || + { ktap_skip_all "$MODULE produced no detectable orphans (cannot test min_= unref_scans)"; exit "$KSFT_SKIP"; } + +# 2) min_unref_scans=3D2: after priming, one scan is not enough (still +# gated), the second reports. The gated-scan-zero check is the core +# regression. +echo 2 > "$PARAM" +gen_orphans +prime +scan; s1=3D$(count_orphans) +scan; s2=3D$(count_orphans) +[ "$s1" -eq 0 ] || ktap_exit_fail_msg "min_unref_scans=3D2: $s1 orphan(s) = after 1 post-prime scan (must be 0)" +[ "$s2" -gt 0 ] || ktap_exit_fail_msg "min_unref_scans=3D2: no report afte= r 2 post-prime scans (false negative)" + +ktap_set_plan 1 +ktap_test_pass "min_unref_scans=3D1 reported $first orphan(s) one scan aft= er priming; =3D2 held them one scan longer ($s1 after one scan, $s2 after t= wo); param read-back ok" +ktap_finished --=20 2.53.0-Meta