Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mm: kmemleak: add support for dumping physical and __percpu object info

Patch series "mm: kmemleak: Usability improvements".

Following a recent false positive tracking that led to commit 488b5b9eca68
("mm: kmemleak: fix upper boundary check for physical address objects"), I
needed kmemleak to give me more debug information about the objects it is
tracking. This lead to the first patch of this series. The second patch
changes the kmemleak-test module to show the raw pointers for debugging
purposes.


This patch (of 2):

Currently, echo dump=... > /sys/kernel/debug/kmemleak only looks up the
main virtual address object tree. However, for debugging, it's useful to
dump information about physical address and __percpu objects.

Search all three object trees for the dump= command and also print the
type of the object if not virtual: "(phys)" or "(percpu)". In addition,
allow search by alias (pointer within the object).

Link: https://lkml.kernel.org/r/20250206114537.2597764-1-catalin.marinas@arm.com
Link: https://lkml.kernel.org/r/20250206114537.2597764-2-catalin.marinas@arm.com
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Catalin Marinas and committed by
Andrew Morton
7ddeb91f 9a5b1839

+40 -14
+40 -14
mm/kmemleak.c
··· 352 352 jiffies_last_scan); 353 353 } 354 354 355 + static const char *__object_type_str(struct kmemleak_object *object) 356 + { 357 + if (object->flags & OBJECT_PHYS) 358 + return " (phys)"; 359 + if (object->flags & OBJECT_PERCPU) 360 + return " (percpu)"; 361 + return ""; 362 + } 363 + 355 364 /* 356 365 * Printing of the unreferenced objects information to the seq file. The 357 366 * print_unreferenced function must be called with the object->lock held. ··· 373 364 unsigned int nr_entries; 374 365 375 366 nr_entries = stack_depot_fetch(object->trace_handle, &entries); 376 - warn_or_seq_printf(seq, "unreferenced object 0x%08lx (size %zu):\n", 377 - object->pointer, object->size); 367 + warn_or_seq_printf(seq, "unreferenced object%s 0x%08lx (size %zu):\n", 368 + __object_type_str(object), 369 + object->pointer, object->size); 378 370 warn_or_seq_printf(seq, " comm \"%s\", pid %d, jiffies %lu\n", 379 371 object->comm, object->pid, object->jiffies); 380 372 hex_dump_object(seq, object); ··· 394 384 */ 395 385 static void dump_object_info(struct kmemleak_object *object) 396 386 { 397 - pr_notice("Object 0x%08lx (size %zu):\n", 398 - object->pointer, object->size); 387 + pr_notice("Object%s 0x%08lx (size %zu):\n", 388 + __object_type_str(object), object->pointer, object->size); 399 389 pr_notice(" comm \"%s\", pid %d, jiffies %lu\n", 400 - object->comm, object->pid, object->jiffies); 390 + object->comm, object->pid, object->jiffies); 401 391 pr_notice(" min_count = %d\n", object->min_count); 402 392 pr_notice(" count = %d\n", object->count); 403 393 pr_notice(" flags = 0x%x\n", object->flags); ··· 2008 1998 return seq_open(file, &kmemleak_seq_ops); 2009 1999 } 2010 2000 2011 - static int dump_str_object_info(const char *str) 2001 + static bool __dump_str_object_info(unsigned long addr, unsigned int objflags) 2012 2002 { 2013 2003 unsigned long flags; 2014 2004 struct kmemleak_object *object; 2015 - unsigned long addr; 2016 2005 2017 - if (kstrtoul(str, 0, &addr)) 2018 - return -EINVAL; 2019 - object = find_and_get_object(addr, 0); 2020 - if (!object) { 2021 - pr_info("Unknown object at 0x%08lx\n", addr); 2022 - return -EINVAL; 2023 - } 2006 + object = __find_and_get_object(addr, 1, objflags); 2007 + if (!object) 2008 + return false; 2024 2009 2025 2010 raw_spin_lock_irqsave(&object->lock, flags); 2026 2011 dump_object_info(object); 2027 2012 raw_spin_unlock_irqrestore(&object->lock, flags); 2028 2013 2029 2014 put_object(object); 2015 + 2016 + return true; 2017 + } 2018 + 2019 + static int dump_str_object_info(const char *str) 2020 + { 2021 + unsigned long addr; 2022 + bool found = false; 2023 + 2024 + if (kstrtoul(str, 0, &addr)) 2025 + return -EINVAL; 2026 + 2027 + found |= __dump_str_object_info(addr, 0); 2028 + found |= __dump_str_object_info(addr, OBJECT_PHYS); 2029 + found |= __dump_str_object_info(addr, OBJECT_PERCPU); 2030 + 2031 + if (!found) { 2032 + pr_info("Unknown object at 0x%08lx\n", addr); 2033 + return -EINVAL; 2034 + } 2035 + 2030 2036 return 0; 2031 2037 } 2032 2038