]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
mm: kmemleak: add support for dumping physical and __percpu object info
authorCatalin Marinas <catalin.marinas@arm.com>
Thu, 6 Feb 2025 11:45:36 +0000 (11:45 +0000)
committerAndrew Morton <akpm@linux-foundation.org>
Mon, 17 Mar 2025 05:06:08 +0000 (22:06 -0700)
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>
mm/kmemleak.c

index c6ed68604136a3108fa161b036a651effff4f6b9..c12cef3eeb32a596350ba20e97a0c1e8ac25a7d7 100644 (file)
@@ -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;
+
+       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;
-       object = find_and_get_object(addr, 0);
-       if (!object) {
+
+       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;
        }
 
-       raw_spin_lock_irqsave(&object->lock, flags);
-       dump_object_info(object);
-       raw_spin_unlock_irqrestore(&object->lock, flags);
-
-       put_object(object);
        return 0;
 }