mm/kmemleak: add min_unref_scans to suppress transient false positives
Subsystems (6)
cover mm/kmemleak: add min_unref_scans to suppress transient false positives
I have kmemleak on some test tiers to find memory leaks in my fleet, with the reports dumped to dmesg (CONFIG_DEBUG_KMEMLEAK_VERBOSE set). It works super well.
The problem I have is some false positives that show up from time to time and go away on a subsequent scan. Something transiently unreferenced -- whose only reference is briefly invisible during a concurrent RCU update, e.g. a VMA moving between maple-tree nodes, or a page-cache xa_node -- is seen as unreferenced for a single scan and reported as a leak that does not exist.
This series adds a min_unref_scans module parameter requiring an object to stay unreferenced across that many consecutive scans before it is reported. Basically it is a trade-off between report latency and reliability (false-positiveness?).
It defaults to 1 (the unchanged report-on-first-scan behaviour) and, set to 2 or more, filters these single-scan races while still reporting genuine leaks one scan later. Would it be acceptable upstream?
Patch 1 implements it; patch 2 adds an mm selftest that drives the parameter via samples/kmemleak, in case this is useful.
---
Breno Leitao (2):
mm/kmemleak: report leaks only after N consecutive unreferenced scans selftests/mm: test kmemleak's N-consecutive-scan leak confirmation
Documentation/dev-tools/kmemleak.rst | 8 ++ mm/kmemleak.c | 14 ++- tools/testing/selftests/mm/Makefile | 1 + .../testing/selftests/mm/ksft_kmemleak_confirm.sh | 111 +++++++++++++++++++++ 4 files changed, 132 insertions(+), 2 deletions(-)
---
base-commit: 30ffa8de54e5cc80d93fd211ca134d1764a7011f
change-id: 20260626-kmemleak_twice-ed01218aeccb
Best regards,
Signature · 1 line
Breno Leitao <[email protected]>
PATCH 1/2 mm/kmemleak: report leaks only after N consecutive unreferenced scans
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=<n> or at run-time via /sys/module/kmemleak/parameters/min_unref_scans.
--- Documentation/dev-tools/kmemleak.rst | 8 ++++++++ mm/kmemleak.c | 14 ++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-)
Documentation/dev-tools/kmemleak.rst +8 -0
@@ -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. +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=<n>`` or at run-time via +``/sys/module/kmemleak/parameters/min_unref_scans``. + Limitations and Drawbacks -------------------------
mm/kmemleak.c +12 -2
@@ -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;
@@ -232,6 +234,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 =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;
@@ -687,6 +692,7 @@ static struct kmemleak_object *__alloc_object(gfp_t gfp)atomic_set (&object->use_count,1 ); object->excess_ref =0 ; object->count =0 ;/* white color initially */ + object->unref_scans =0 ; object->checksum =0 ; object->del_state =0 ;
@@ -1833,6 +1839,9 @@ static void kmemleak_scan(void)__paint_it (object,KMEMLEAK_BLACK ); } +/* referenced last scan: restart the unreferenced run */ +if (!color_white (object)) + object->unref_scans =0 ;/* reset the reference count (whiten the object) */ object->count =0 ;if (color_gray (object) &&get_object (object))
@@ -1968,8 +1977,9 @@ static void kmemleak_scan(void)raw_spin_lock_irq (&object->lock); trace_handle =0 ; dedup_print = false; -if (unreferenced_object (object) && - !(object->flags &OBJECT_REPORTED )) { +if (!(object->flags &OBJECT_REPORTED ) && +unreferenced_object (object) && + ++object->unref_scans >= min_unref_scans) { object->flags |=OBJECT_REPORTED ;if (kmemleak_verbose) { trace_handle = object->trace_handle;
Signature · 1 line
2.53.0-Meta
Re: [PATCH 1/2] mm/kmemleak: report leaks only after N consecutive unreferenced scans
Quoted 15 lines · Breno 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.
Quoted 4 lines
min_unref_scanscan be set at boot with kmemleak.min_unref_scans=<n> or at run-time via/sys/module/kmemleak/parameters/min_unref_scans.Signed-off-by Breno Leitao <[email protected]>
It looks like a good addition to me. All objects require a second pass initially to get their checksum updated but that's not sufficient when they are moved between nodes without having their content changed (list in a linked list).
Quoted 14 lines
mm/kmemleak.c +2
-0@@ -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;
mm/kmemleak.c static unsigned long max_percpu_addr; · line 239
Quoted 6 lines
mm/kmemleak.c +3
-0@@ -232,6 +234,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 =1 ; +module_param (min_unref_scans, uint,0644 );
0644 is fine. Not sure why kmemleak_verbose was 0600.
Signature · 1 line
Catalin
PATCH 2/2 selftests/mm: test kmemleak's N-consecutive-scan leak confirmation
In reply to Breno LeitaoAdd a functional test for the min_unref_scans kmemleak module parameter. Using samples/kmemleak's helper module it checks that min_unref_scans=1 reports an orphan on the first scan, min_unref_scans=2 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.
--- tools/testing/selftests/mm/Makefile | 1 + .../testing/selftests/mm/ksft_kmemleak_confirm.sh | 111 +++++++++++++++++++++ 2 files changed, 112 insertions(+)
tools/testing/selftests/mm/Makefile +1 -0
@@ -150,6 +150,7 @@ TEST_PROGS += ksft_gup_test.sh TEST_PROGS += ksft_hmm.sh TEST_PROGS += ksft_hugetlb.sh TEST_PROGS += ksft_hugevm.sh +TEST_PROGS += ksft_kmemleak_confirm.sh TEST_PROGS += ksft_kmemleak_dedup.sh TEST_PROGS += ksft_ksm.sh TEST_PROGS += ksft_ksm_numa.sh
tools/testing/selftests/mm/ksft_kmemleak_confirm.sh new file +111 -0
111 lines not on this page · raw message
Signature · 1 line
2.53.0-Meta
Catalin Marinas
maintainerRe: [PATCH 2/2] selftests/mm: test kmemleak's N-consecutive-scan leak confirmation
Quoted 104 lines · Breno Leitao
tools/testing/selftests/mm/ksft_kmemleak_confirm.sh new file +101
-0@@ -0,0 +1,111 @@ +#!/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: +# - min_unref_scans=1 reports them on the first scan, +# - min_unref_scans=2 reports nothing on the first scan but does on the +# second, +# - the parameter reads back what was written. +# +# The "nothing on the first scan" check is the core regression test: with +# min_unref_scans=2 no object can be reported in fewer than two scans. 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 <[email protected]> + +ksft_skip=4 +KMEMLEAK=/sys/kernel/debug/kmemleak +PARAM=/sys/module/kmemleak/parameters/min_unref_scans +MODULE=kmemleak-test +AGE=6 # seconds; must exceed kmemleak's 5s minimum object age + +skip() { echo "SKIP: $*"; exit $ksft_skip; } +fail() { echo "FAIL: $*"; exit 1; } +pass() { echo "PASS: $*"; exit 0; } + +[ "$(id -u)" -eq 0 ] || skip "must run as root" +[ -r "$KMEMLEAK" ] || skip "no kmemleak debugfs (CONFIG_DEBUG_KMEMLEAK)" +[ -w "$PARAM" ] || skip "min_unref_scans module parameter not present" +modinfo "$MODULE" >/dev/null 2>&1 || + skip "$MODULE not built (CONFIG_SAMPLE_KMEMLEAK)" + +# kmemleak can be present but disabled at runtime (kmemleak=off 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 || + skip "kmemleak is disabled (check dmesg or kmemleak= boot arg)" + +prev=$(cat "$PARAM") +# shellcheck disable=SC2317 # invoked indirectly via trap +cleanup() { + echo "$prev" > "$PARAM" 2>/dev/null # restore the parameter + echo scan=on > "$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=off > "$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" || skip "failed to load $MODULE" + 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=$(grep -c '\[kmemleak_test\]' "$KMEMLEAK" 2>/dev/null) + echo "${c:-0}" +} + +# 0) the parameter reads back what was written. +echo 3 > "$PARAM" +[ "$(cat "$PARAM")" = "3" ] || fail "min_unref_scans did not read back as 3" + +# 1) min_unref_scans=1 (default): orphans reported on the first scan. This +# also establishes that the helper produces detectable orphans here. +echo 1 > "$PARAM" +gen_orphans +scan +first=$(count_orphans) +[ "$first" -gt 0 ] || + skip "$MODULE produced no detectable orphans (cannot test min_unref_scans)" +
tools/testing/selftests/mm/ksft_kmemleak_confirm.sh line 111
Quoted 10 lines
tools/testing/selftests/mm/ksft_kmemleak_confirm.sh new file +10
-0+# 2) min_unref_scans=2: nothing reported after the first scan, reported +# after the second. The first-scan-zero check is the core regression. +echo 2 > "$PARAM" +gen_orphans +scan; s1=$(count_orphans) +scan; s2=$(count_orphans) +[ "$s1" -eq 0 ] || fail "min_unref_scans=2: $s1 orphan(s) reported after the 1st scan (must be 0)" +[ "$s2" -gt 0 ] || fail "min_unref_scans=2: no report on the 2nd scan (false negative)" + +pass "min_unref_scans=1 immediate; =2 gated to 2nd scan (counts $first/$s1/$s2); param read-back ok"
Are these off by one? Kmemleak has a mechanism to detect live objects via the checksum. A side effect is that on allocation, the checksum is 0 and only after the first scan the checksum is changed. On checksum mismatch (i.e. the first scan), we mark the object gray temporarily and won't increment unref_scans. So we already have an implicit two scans required to report an object as unreferenced during its early life.
I think this test needs a priming scan to update the checksums followed by the actual check for min_unref_scans (with scan=off, otherwise random scanning will skew the results).
Signature · 1 line
Catalin
Re: [PATCH 2/2] selftests/mm: test kmemleak's N-consecutive-scan leak confirmation
Quoted 4 lines · Catalin Marinas
Quoted 1 line · Breno Leitao
+pass "min_unref_scans=1 immediate; =2 gated to 2nd scan (counts $first/$s1/$s2); param read-back ok"
Are these off by one?
They seem to be OK, and I've tested it multiple times.
Quoted 3 lines
Kmemleak has a mechanism to detect live objects
via the checksum. A side effect is that on allocation, the checksum is 0 and only after the first scan the checksum is changed.
I got the impression that checksum continues to be zero for these objects during the whole life time? (weird).
If you think this selftest brings value, let me investigate what the heck is happening here.
Quoted 8 lines
On checksum mismatch (i.e. the first scan), we mark the object gray temporarily and won't increment
unref_scans. So we already have an implicit two scans required to report an object as unreferenced during its early life.I think this test needs a priming scan to update the checksums followed by the actual check for
min_unref_scans(with scan=off, otherwise random scanning will skew the results).
I tried a priming scan and it actually breaks the min_unref_scans=2 case
Re: [PATCH 2/2] selftests/mm: test kmemleak's N-consecutive-scan leak confirmation
Quoted 6 lines · Breno Leitao
Quoted 4 lines · Catalin Marinas
Quoted 1 line · Breno Leitao
+pass "min_unref_scans=1 immediate; =2 gated to 2nd scan (counts $first/$s1/$s2); param read-back ok"
Are these off by one?
Quoted 8 lines
They seem to be OK, and I've tested it multiple times.
Quoted 3 lines
Kmemleak has a mechanism to detect live objects
via the checksum. A side effect is that on allocation, the checksum is 0 and only after the first scan the checksum is changed.I got the impression that checksum continues to be zero for these objects during the whole life time? (weird).
I've investigated this a bit more and I found something interesting, in our per_pcu checksum. The code in update_checksum() is:
for_each_possible_cpu(cpu) {
void *ptr = per_cpu_ptr((void __percpu *)object->pointer, cpu);
object->checksum ^= crc32(0, kasan_reset_tag((void *)ptr), object->size);
}From my naive view, this has two concerns:
1) In the kernel, crc32(0, <64 zero bytes>, 64) is zero, and the samples' test I am using (kmemleak-test.c) has:
pr_info("__alloc_percpu(64, 4) = 0x%px\n", __alloc_percpu(64, 4)); alloc_percpu returns ZEROed memory, so, we are checkingsuming zero content. Because we are using 0 as seed, that is returning zero.
object->checksum is a bunch of 0 XOR 0 XOR 0 and so forth.
2) that XOR above seems very weird. Basically we want to detect if some of
those per-cpu areas changed, here, but, if checksum goes to zero if two object content is similar.
Let me give you a simple example. We have SMP=2, and both objects have crc32 = 0x42. At the end of that function, object->checksum will be zero, given 0x42 XOR 0x42 is zero.
If both object changes their content at the same time, object->checksum will continue to be zero (although the content (and checksum) HAS changed).
I understand we want to detect any change in any of these per cpu field and catch it independent of the CPU. I am inclined toward that.
--- a/mm/kmemleak.c
+++ b/mm/kmemleak.c
@@ -1409,8 +1409,9 @@ static bool update_checksum(struct kmemleak_object *object)
object->checksum = 0;
for_each_possible_cpu(cpu) {
void *ptr = per_cpu_ptr((void __percpu *)object->pointer, cpu);
+ u32 seed = object->checksum + cpu;
- object->checksum ^= crc32(0, kasan_reset_tag((void *)ptr), object->size);
+ object->checksum ^= crc32(seed, kasan_reset_tag((void *)ptr), object->size);
}
} else {
object->checksum = crc32(0, kasan_reset_tag((void *)object->pointer), object->size);Once this is fixed, then I priming would make sense.
Please let me know if my flaky logic is worse than usual this Friday.
--breno
Catalin Marinas
maintainerRe: [PATCH 2/2] selftests/mm: test kmemleak's N-consecutive-scan leak confirmation
Quoted 30 lines · Breno Leitao
Quoted 6 lines · Breno Leitao
Quoted 4 lines · Catalin Marinas
Quoted 1 line · Breno Leitao
+pass "min_unref_scans=1 immediate; =2 gated to 2nd scan (counts $first/$s1/$s2); param read-back ok"
Are these off by one?
Quoted 8 lines
They seem to be OK, and I've tested it multiple times.
Quoted 3 lines
Kmemleak has a mechanism to detect live objects
via the checksum. A side effect is that on allocation, the checksum is 0 and only after the first scan the checksum is changed.I got the impression that checksum continues to be zero for these objects during the whole life time? (weird).
I've investigated this a bit more and I found something interesting, in our
per_pcuchecksum. The code inupdate_checksum()is:for_each_possible_cpu(cpu) { void *ptr = per_cpu_ptr((void __percpu *)object->pointer, cpu); object->checksum ^= crc32(0, kasan_reset_tag((void *)ptr), object->size); }From my naive view, this has two concerns:
1) In the kernel,
crc32(0, <64 zero bytes>, 64)is zero, and the samples' test I am using (kmemleak-test.c) has:
Quoted 6 lines
pr_info("__alloc_percpu(64, 4) = 0x%px\n", __alloc_percpu(64, 4));
alloc_percpureturns ZEROed memory, so, we are checkingsuming zero content. Because we are using 0 as seed, that is returning zero.
object->checksumis a bunch of 0 XOR 0 XOR 0 and so forth.
Ah, yes, you are right. Irrespective of the per-cpu xor, I think we should seed the checksum with something other than 0 (say -1 or some random clock value).
Quoted 13 lines
2) that XOR above seems very weird. Basically we want to detect if some of
those per-cpu areas changed, here, but, if checksum goes to zero if two object content is similar.Let me give you a simple example. We have SMP=2, and both objects have crc32 =
0x42. At the end of that function,object->checksumwill be zero, given0x42XOR0x42is zero.If both object changes their content at the same time,
object->checksumwill continue to be zero (although the content (and checksum) HAS changed).I understand we want to detect any change in any of these per cpu field and catch it independent of the CPU. I am inclined toward that.
Quoted 10 lines
--- a/mm/kmemleak.c
+++ b/mm/kmemleak.c
@@ -1409,8 +1409,9 @@ static bool update_checksum(struct kmemleak_object *object)
object->checksum = 0;
for_each_possible_cpu(cpu) {
void *ptr = per_cpu_ptr((void __percpu *)object->pointer, cpu);
+ u32 seed = object->checksum + cpu;
- object->checksum ^= crc32(0, kasan_reset_tag((void *)ptr), object->size);
+ object->checksum ^= crc32(seed, kasan_reset_tag((void *)ptr), object->size);Yeah, the xor wasn't a great idea. What about initialising the checksum value on object allocation to ~0 (for the two-scans idea) and for per-cpu, just build the crc on top of the previous crc, something like:
mm/kmemleak.c +4 -3
@@ -687,7 +687,7 @@ static struct kmemleak_object *__alloc_object(gfp_t gfp)atomic_set (&object->use_count,1 ); object->excess_ref =0 ; object->count =0 ;/* white color initially */ - object->checksum =0 ; + object->checksum = ~0 ; object->del_state =0 ;/* task information */
@@ -981,7 +981,7 @@ static void reset_checksum(unsigned long ptr) }raw_spin_lock_irqsave (&object->lock, flags); - object->checksum =0 ; + object->checksum = ~0 ;raw_spin_unlock_irqrestore (&object->lock, flags);put_object (object); }
@@ -1410,7 +1410,8 @@ static bool update_checksum(struct kmemleak_object *object)for_each_possible_cpu (cpu) {void *ptr =per_cpu_ptr ((void __percpu *)object->pointer, cpu); - object->checksum ^=crc32 (0 ,kasan_reset_tag ((void *)ptr), object->size); + object->checksum =crc32 (object->checksum, +kasan_reset_tag ((void *)ptr), object->size); } }else { object->checksum =crc32 (0 ,kasan_reset_tag ((void *)object->pointer), object->size);
Signature · 1 line
Catalin
Re: [PATCH 2/2] selftests/mm: test kmemleak's N-consecutive-scan leak confirmation
Quoted 41 lines · Catalin Marinas
Quoted 13 lines
I understand we want to detect any change in any of these per cpu field and catch it independent of the CPU. I am inclined toward that.
--- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -1409,8 +1409,9 @@ static bool update_checksum(struct kmemleak_object *object) object->checksum = 0; for_each_possible_cpu(cpu) { void *ptr = per_cpu_ptr((void __percpu *)object->pointer, cpu); + u32 seed = object->checksum + cpu; - object->checksum ^= crc32(0, kasan_reset_tag((void *)ptr), object->size); + object->checksum ^= crc32(seed, kasan_reset_tag((void *)ptr), object->size);Yeah, the xor wasn't a great idea. What about initialising the checksum value on object allocation to ~0 (for the two-scans idea) and for per-cpu, just build the crc on top of the previous crc, something like:
mm/kmemleak.c +2
-2@@ -687,7 +687,7 @@ static struct kmemleak_object *__alloc_object(gfp_t gfp)atomic_set (&object->use_count,1 ); object->excess_ref =0 ; object->count =0 ;/* white color initially */ - object->checksum =0 ; + object->checksum = ~0 ; object->del_state =0 ;/* task information */ @@ -981,7 +981,7 @@ static void reset_checksum(unsigned long ptr) }raw_spin_lock_irqsave (&object->lock, flags); - object->checksum =0 ; + object->checksum = ~0 ;raw_spin_unlock_irqrestore (&object->lock, flags);put_object (object); }
mm/kmemleak.c static bool update_checksum(struct kmemleak_object *object) · line 1417
Quoted 9 lines
mm/kmemleak.c +2
-1@@ -1410,7 +1410,8 @@ static bool update_checksum(struct kmemleak_object *object)for_each_possible_cpu (cpu) {void *ptr =per_cpu_ptr ((void __percpu *)object->pointer, cpu); - object->checksum ^=crc32 (0 ,kasan_reset_tag ((void *)ptr), object->size); + object->checksum =crc32 (object->checksum, +kasan_reset_tag ((void *)ptr), object->size); } }else { object->checksum =crc32 (0 ,kasan_reset_tag ((void *)object->pointer), object->size);
Ack, this seems more robust and easier to follow than my approach, thanks for your insight here.
I will spin this "fix" separated (CCing stable), and send a v2 for this selftest with priming enabled.
Thanks for your suggestion,
--breno
Re: [PATCH 2/2] selftests/mm: test kmemleak's N-consecutive-scan leak confirmation
Quoted 4 lines · Breno Leitao
On Fri, Jul 03, 2026 at 03:55:52PM +0100, Catalin Marinas wrote:
I will spin this "fix" separated (CCing stable), and send a v2 for this selftest with priming enabled.
Quick update on this plan. The v2 for this patch depends on checksum fix[0], given it touches a similar code:
@@ -687,6 +692,7 @@ static struct kmemleak_object *__alloc_object(gfp_t gfp) atomic_set(&object->use_count, 1); object->excess_ref = 0; object->count = 0; + object->unref_scans = 0; object->checksum = ~0; <-- Adde by the fix [0]
I will wait the "Fix" to land first, before sending v2, avoiding merge conflicts and being able to rely on sashiko to review it (instead of having merging issues)