* [PATCH 1/2] mm: kmemleak: Add support for dumping physical and __percpu object info
2025-02-06 11:45 [PATCH 0/2] mm: kmemleak: Usability improvements Catalin Marinas
@ 2025-02-06 11:45 ` Catalin Marinas
2025-02-06 11:45 ` [PATCH 2/2] samples: kmemleak: Print the raw pointers for debugging purposes Catalin Marinas
1 sibling, 0 replies; 3+ messages in thread
From: Catalin Marinas @ 2025-02-06 11:45 UTC (permalink / raw)
To: linux-mm; +Cc: linux-kernel, Andrew Morton
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).
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
---
mm/kmemleak.c | 54 ++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 40 insertions(+), 14 deletions(-)
diff --git a/mm/kmemleak.c b/mm/kmemleak.c
index c6ed68604136..c12cef3eeb32 100644
--- a/mm/kmemleak.c
+++ b/mm/kmemleak.c
@@ -352,6 +352,15 @@ static bool unreferenced_object(struct kmemleak_object *object)
jiffies_last_scan);
}
+static const char *__object_type_str(struct kmemleak_object *object)
+{
+ if (object->flags & OBJECT_PHYS)
+ return " (phys)";
+ if (object->flags & OBJECT_PERCPU)
+ return " (percpu)";
+ return "";
+}
+
/*
* Printing of the unreferenced objects information to the seq file. The
* print_unreferenced function must be called with the object->lock held.
@@ -364,8 +373,9 @@ static void print_unreferenced(struct seq_file *seq,
unsigned int nr_entries;
nr_entries = stack_depot_fetch(object->trace_handle, &entries);
- warn_or_seq_printf(seq, "unreferenced object 0x%08lx (size %zu):\n",
- object->pointer, object->size);
+ warn_or_seq_printf(seq, "unreferenced object%s 0x%08lx (size %zu):\n",
+ __object_type_str(object),
+ object->pointer, object->size);
warn_or_seq_printf(seq, " comm \"%s\", pid %d, jiffies %lu\n",
object->comm, object->pid, object->jiffies);
hex_dump_object(seq, object);
@@ -384,10 +394,10 @@ static void print_unreferenced(struct seq_file *seq,
*/
static void dump_object_info(struct kmemleak_object *object)
{
- pr_notice("Object 0x%08lx (size %zu):\n",
- object->pointer, object->size);
+ pr_notice("Object%s 0x%08lx (size %zu):\n",
+ __object_type_str(object), object->pointer, object->size);
pr_notice(" comm \"%s\", pid %d, jiffies %lu\n",
- object->comm, object->pid, object->jiffies);
+ object->comm, object->pid, object->jiffies);
pr_notice(" min_count = %d\n", object->min_count);
pr_notice(" count = %d\n", object->count);
pr_notice(" flags = 0x%x\n", object->flags);
@@ -1998,25 +2008,41 @@ static int kmemleak_open(struct inode *inode, struct file *file)
return seq_open(file, &kmemleak_seq_ops);
}
-static int dump_str_object_info(const char *str)
+static bool __dump_str_object_info(unsigned long addr, unsigned int objflags)
{
unsigned long flags;
struct kmemleak_object *object;
- unsigned long addr;
- if (kstrtoul(str, 0, &addr))
- return -EINVAL;
- object = find_and_get_object(addr, 0);
- if (!object) {
- pr_info("Unknown object at 0x%08lx\n", addr);
- return -EINVAL;
- }
+ object = __find_and_get_object(addr, 1, objflags);
+ if (!object)
+ return false;
raw_spin_lock_irqsave(&object->lock, flags);
dump_object_info(object);
raw_spin_unlock_irqrestore(&object->lock, flags);
put_object(object);
+
+ return true;
+}
+
+static int dump_str_object_info(const char *str)
+{
+ unsigned long addr;
+ bool found = false;
+
+ if (kstrtoul(str, 0, &addr))
+ return -EINVAL;
+
+ found |= __dump_str_object_info(addr, 0);
+ found |= __dump_str_object_info(addr, OBJECT_PHYS);
+ found |= __dump_str_object_info(addr, OBJECT_PERCPU);
+
+ if (!found) {
+ pr_info("Unknown object at 0x%08lx\n", addr);
+ return -EINVAL;
+ }
+
return 0;
}
^ permalink raw reply [flat|nested] 3+ messages in thread* [PATCH 2/2] samples: kmemleak: Print the raw pointers for debugging purposes
2025-02-06 11:45 [PATCH 0/2] mm: kmemleak: Usability improvements Catalin Marinas
2025-02-06 11:45 ` [PATCH 1/2] mm: kmemleak: Add support for dumping physical and __percpu object info Catalin Marinas
@ 2025-02-06 11:45 ` Catalin Marinas
1 sibling, 0 replies; 3+ messages in thread
From: Catalin Marinas @ 2025-02-06 11:45 UTC (permalink / raw)
To: linux-mm; +Cc: linux-kernel, Andrew Morton
The kmemleak-test.c module is meant to leak some pointers for debugging
the kmemleak detection, pointer information dumping. It's no use if it
prints the hashed values of such pointers.
Change the printk() format from %p to %px. While at it, also display the
raw __percpu pointer rather than this_cpu_ptr() since kmemleak now
tracks such pointers independently of the standard allocations.
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
---
samples/kmemleak/kmemleak-test.c | 36 ++++++++++++++++----------------
1 file changed, 18 insertions(+), 18 deletions(-)
diff --git a/samples/kmemleak/kmemleak-test.c b/samples/kmemleak/kmemleak-test.c
index 544c36d51d56..8609812a37eb 100644
--- a/samples/kmemleak/kmemleak-test.c
+++ b/samples/kmemleak/kmemleak-test.c
@@ -40,25 +40,25 @@ static int kmemleak_test_init(void)
pr_info("Kmemleak testing\n");
/* make some orphan objects */
- pr_info("kmalloc(32) = %p\n", kmalloc(32, GFP_KERNEL));
- pr_info("kmalloc(32) = %p\n", kmalloc(32, GFP_KERNEL));
- pr_info("kmalloc(1024) = %p\n", kmalloc(1024, GFP_KERNEL));
- pr_info("kmalloc(1024) = %p\n", kmalloc(1024, GFP_KERNEL));
- pr_info("kmalloc(2048) = %p\n", kmalloc(2048, GFP_KERNEL));
- pr_info("kmalloc(2048) = %p\n", kmalloc(2048, GFP_KERNEL));
- pr_info("kmalloc(4096) = %p\n", kmalloc(4096, GFP_KERNEL));
- pr_info("kmalloc(4096) = %p\n", kmalloc(4096, GFP_KERNEL));
+ pr_info("kmalloc(32) = 0x%px\n", kmalloc(32, GFP_KERNEL));
+ pr_info("kmalloc(32) = 0x%px\n", kmalloc(32, GFP_KERNEL));
+ pr_info("kmalloc(1024) = 0x%px\n", kmalloc(1024, GFP_KERNEL));
+ pr_info("kmalloc(1024) = 0x%px\n", kmalloc(1024, GFP_KERNEL));
+ pr_info("kmalloc(2048) = 0x%px\n", kmalloc(2048, GFP_KERNEL));
+ pr_info("kmalloc(2048) = 0x%px\n", kmalloc(2048, GFP_KERNEL));
+ pr_info("kmalloc(4096) = 0x%px\n", kmalloc(4096, GFP_KERNEL));
+ pr_info("kmalloc(4096) = 0x%px\n", kmalloc(4096, GFP_KERNEL));
#ifndef CONFIG_MODULES
- pr_info("kmem_cache_alloc(files_cachep) = %p\n",
+ pr_info("kmem_cache_alloc(files_cachep) = 0x%px\n",
kmem_cache_alloc(files_cachep, GFP_KERNEL));
- pr_info("kmem_cache_alloc(files_cachep) = %p\n",
+ pr_info("kmem_cache_alloc(files_cachep) = 0x%px\n",
kmem_cache_alloc(files_cachep, GFP_KERNEL));
#endif
- pr_info("vmalloc(64) = %p\n", vmalloc(64));
- pr_info("vmalloc(64) = %p\n", vmalloc(64));
- pr_info("vmalloc(64) = %p\n", vmalloc(64));
- pr_info("vmalloc(64) = %p\n", vmalloc(64));
- pr_info("vmalloc(64) = %p\n", vmalloc(64));
+ pr_info("vmalloc(64) = 0x%px\n", vmalloc(64));
+ pr_info("vmalloc(64) = 0x%px\n", vmalloc(64));
+ pr_info("vmalloc(64) = 0x%px\n", vmalloc(64));
+ pr_info("vmalloc(64) = 0x%px\n", vmalloc(64));
+ pr_info("vmalloc(64) = 0x%px\n", vmalloc(64));
/*
* Add elements to a list. They should only appear as orphan
@@ -66,7 +66,7 @@ static int kmemleak_test_init(void)
*/
for (i = 0; i < 10; i++) {
elem = kzalloc(sizeof(*elem), GFP_KERNEL);
- pr_info("kzalloc(sizeof(*elem)) = %p\n", elem);
+ pr_info("kzalloc(sizeof(*elem)) = 0x%px\n", elem);
if (!elem)
return -ENOMEM;
INIT_LIST_HEAD(&elem->list);
@@ -75,11 +75,11 @@ static int kmemleak_test_init(void)
for_each_possible_cpu(i) {
per_cpu(kmemleak_test_pointer, i) = kmalloc(129, GFP_KERNEL);
- pr_info("kmalloc(129) = %p\n",
+ pr_info("kmalloc(129) = 0x%px\n",
per_cpu(kmemleak_test_pointer, i));
}
- pr_info("__alloc_percpu(64, 4) = %p\n", __alloc_percpu(64, 4));
+ pr_info("__alloc_percpu(64, 4) = 0x%px\n", __alloc_percpu(64, 4));
return 0;
}
^ permalink raw reply [flat|nested] 3+ messages in thread