Loading lib/Kconfig.debug +3 −2 Original line number Original line Diff line number Diff line Loading @@ -340,8 +340,6 @@ config DEBUG_KMEMLEAK bool "Kernel memory leak detector" bool "Kernel memory leak detector" depends on DEBUG_KERNEL && EXPERIMENTAL && (X86 || ARM) && \ depends on DEBUG_KERNEL && EXPERIMENTAL && (X86 || ARM) && \ !MEMORY_HOTPLUG !MEMORY_HOTPLUG select DEBUG_SLAB if SLAB select SLUB_DEBUG if SLUB select DEBUG_FS if SYSFS select DEBUG_FS if SYSFS select STACKTRACE if STACKTRACE_SUPPORT select STACKTRACE if STACKTRACE_SUPPORT select KALLSYMS select KALLSYMS Loading @@ -355,6 +353,9 @@ config DEBUG_KMEMLEAK allocations. See Documentation/kmemleak.txt for more allocations. See Documentation/kmemleak.txt for more details. details. Enabling DEBUG_SLAB or SLUB_DEBUG may increase the chances of finding leaks due to the slab objects poisoning. In order to access the kmemleak file, debugfs needs to be In order to access the kmemleak file, debugfs needs to be mounted (usually at /sys/kernel/debug). mounted (usually at /sys/kernel/debug). Loading mm/kmemleak.c +24 −28 Original line number Original line Diff line number Diff line Loading @@ -61,6 +61,8 @@ * structure. * structure. */ */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/init.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/kernel.h> #include <linux/list.h> #include <linux/list.h> Loading Loading @@ -311,7 +313,7 @@ static int unreferenced_object(struct kmemleak_object *object) static void print_referenced(struct kmemleak_object *object) static void print_referenced(struct kmemleak_object *object) { { pr_info("kmemleak: referenced object 0x%08lx (size %zu)\n", pr_info("referenced object 0x%08lx (size %zu)\n", object->pointer, object->size); object->pointer, object->size); } } Loading @@ -320,7 +322,7 @@ static void print_unreferenced(struct seq_file *seq, { { int i; int i; print_helper(seq, "kmemleak: unreferenced object 0x%08lx (size %zu):\n", print_helper(seq, "unreferenced object 0x%08lx (size %zu):\n", object->pointer, object->size); object->pointer, object->size); print_helper(seq, " comm \"%s\", pid %d, jiffies %lu\n", print_helper(seq, " comm \"%s\", pid %d, jiffies %lu\n", object->comm, object->pid, object->jiffies); object->comm, object->pid, object->jiffies); Loading @@ -344,7 +346,7 @@ static void dump_object_info(struct kmemleak_object *object) trace.nr_entries = object->trace_len; trace.nr_entries = object->trace_len; trace.entries = object->trace; trace.entries = object->trace; pr_notice("kmemleak: Object 0x%08lx (size %zu):\n", pr_notice("Object 0x%08lx (size %zu):\n", object->tree_node.start, object->size); object->tree_node.start, object->size); pr_notice(" comm \"%s\", pid %d, jiffies %lu\n", pr_notice(" comm \"%s\", pid %d, jiffies %lu\n", object->comm, object->pid, object->jiffies); object->comm, object->pid, object->jiffies); Loading Loading @@ -372,7 +374,7 @@ static struct kmemleak_object *lookup_object(unsigned long ptr, int alias) object = prio_tree_entry(node, struct kmemleak_object, object = prio_tree_entry(node, struct kmemleak_object, tree_node); tree_node); if (!alias && object->pointer != ptr) { if (!alias && object->pointer != ptr) { kmemleak_warn("kmemleak: Found object by alias"); kmemleak_warn("Found object by alias"); object = NULL; object = NULL; } } } else } else Loading Loading @@ -467,8 +469,7 @@ static void create_object(unsigned long ptr, size_t size, int min_count, object = kmem_cache_alloc(object_cache, gfp & GFP_KMEMLEAK_MASK); object = kmem_cache_alloc(object_cache, gfp & GFP_KMEMLEAK_MASK); if (!object) { if (!object) { kmemleak_stop("kmemleak: Cannot allocate a kmemleak_object " kmemleak_stop("Cannot allocate a kmemleak_object structure\n"); "structure\n"); return; return; } } Loading Loading @@ -527,8 +528,8 @@ static void create_object(unsigned long ptr, size_t size, int min_count, if (node != &object->tree_node) { if (node != &object->tree_node) { unsigned long flags; unsigned long flags; kmemleak_stop("kmemleak: Cannot insert 0x%lx into the object " kmemleak_stop("Cannot insert 0x%lx into the object search tree " "search tree (already existing)\n", ptr); "(already existing)\n", ptr); object = lookup_object(ptr, 1); object = lookup_object(ptr, 1); spin_lock_irqsave(&object->lock, flags); spin_lock_irqsave(&object->lock, flags); dump_object_info(object); dump_object_info(object); Loading @@ -553,7 +554,7 @@ static void delete_object(unsigned long ptr) write_lock_irqsave(&kmemleak_lock, flags); write_lock_irqsave(&kmemleak_lock, flags); object = lookup_object(ptr, 0); object = lookup_object(ptr, 0); if (!object) { if (!object) { kmemleak_warn("kmemleak: Freeing unknown object at 0x%08lx\n", kmemleak_warn("Freeing unknown object at 0x%08lx\n", ptr); ptr); write_unlock_irqrestore(&kmemleak_lock, flags); write_unlock_irqrestore(&kmemleak_lock, flags); return; return; Loading Loading @@ -588,8 +589,7 @@ static void make_gray_object(unsigned long ptr) object = find_and_get_object(ptr, 0); object = find_and_get_object(ptr, 0); if (!object) { if (!object) { kmemleak_warn("kmemleak: Graying unknown object at 0x%08lx\n", kmemleak_warn("Graying unknown object at 0x%08lx\n", ptr); ptr); return; return; } } Loading @@ -610,8 +610,7 @@ static void make_black_object(unsigned long ptr) object = find_and_get_object(ptr, 0); object = find_and_get_object(ptr, 0); if (!object) { if (!object) { kmemleak_warn("kmemleak: Blacking unknown object at 0x%08lx\n", kmemleak_warn("Blacking unknown object at 0x%08lx\n", ptr); ptr); return; return; } } Loading @@ -634,21 +633,20 @@ static void add_scan_area(unsigned long ptr, unsigned long offset, object = find_and_get_object(ptr, 0); object = find_and_get_object(ptr, 0); if (!object) { if (!object) { kmemleak_warn("kmemleak: Adding scan area to unknown " kmemleak_warn("Adding scan area to unknown object at 0x%08lx\n", "object at 0x%08lx\n", ptr); ptr); return; return; } } area = kmem_cache_alloc(scan_area_cache, gfp & GFP_KMEMLEAK_MASK); area = kmem_cache_alloc(scan_area_cache, gfp & GFP_KMEMLEAK_MASK); if (!area) { if (!area) { kmemleak_warn("kmemleak: Cannot allocate a scan area\n"); kmemleak_warn("Cannot allocate a scan area\n"); goto out; goto out; } } spin_lock_irqsave(&object->lock, flags); spin_lock_irqsave(&object->lock, flags); if (offset + length > object->size) { if (offset + length > object->size) { kmemleak_warn("kmemleak: Scan area larger than object " kmemleak_warn("Scan area larger than object 0x%08lx\n", ptr); "0x%08lx\n", ptr); dump_object_info(object); dump_object_info(object); kmem_cache_free(scan_area_cache, area); kmem_cache_free(scan_area_cache, area); goto out_unlock; goto out_unlock; Loading Loading @@ -677,8 +675,7 @@ static void object_no_scan(unsigned long ptr) object = find_and_get_object(ptr, 0); object = find_and_get_object(ptr, 0); if (!object) { if (!object) { kmemleak_warn("kmemleak: Not scanning unknown object at " kmemleak_warn("Not scanning unknown object at 0x%08lx\n", ptr); "0x%08lx\n", ptr); return; return; } } Loading @@ -699,7 +696,7 @@ static void log_early(int op_type, const void *ptr, size_t size, struct early_log *log; struct early_log *log; if (crt_early_log >= ARRAY_SIZE(early_log)) { if (crt_early_log >= ARRAY_SIZE(early_log)) { kmemleak_stop("kmemleak: Early log buffer exceeded\n"); kmemleak_stop("Early log buffer exceeded\n"); return; return; } } Loading Loading @@ -966,7 +963,7 @@ static void kmemleak_scan(void) * 1 reference to any object at this point. * 1 reference to any object at this point. */ */ if (atomic_read(&object->use_count) > 1) { if (atomic_read(&object->use_count) > 1) { pr_debug("kmemleak: object->use_count = %d\n", pr_debug("object->use_count = %d\n", atomic_read(&object->use_count)); atomic_read(&object->use_count)); dump_object_info(object); dump_object_info(object); } } Loading Loading @@ -1062,7 +1059,7 @@ static int kmemleak_scan_thread(void *arg) { { static int first_run = 1; static int first_run = 1; pr_info("kmemleak: Automatic memory scanning thread started\n"); pr_info("Automatic memory scanning thread started\n"); /* /* * Wait before the first scan to allow the system to fully initialize. * Wait before the first scan to allow the system to fully initialize. Loading Loading @@ -1108,7 +1105,7 @@ static int kmemleak_scan_thread(void *arg) timeout = schedule_timeout_interruptible(timeout); timeout = schedule_timeout_interruptible(timeout); } } pr_info("kmemleak: Automatic memory scanning thread ended\n"); pr_info("Automatic memory scanning thread ended\n"); return 0; return 0; } } Loading @@ -1123,7 +1120,7 @@ void start_scan_thread(void) return; return; scan_thread = kthread_run(kmemleak_scan_thread, NULL, "kmemleak"); scan_thread = kthread_run(kmemleak_scan_thread, NULL, "kmemleak"); if (IS_ERR(scan_thread)) { if (IS_ERR(scan_thread)) { pr_warning("kmemleak: Failed to create the scan thread\n"); pr_warning("Failed to create the scan thread\n"); scan_thread = NULL; scan_thread = NULL; } } } } Loading Loading @@ -1367,7 +1364,7 @@ static void kmemleak_cleanup(void) cleanup_thread = kthread_run(kmemleak_cleanup_thread, NULL, cleanup_thread = kthread_run(kmemleak_cleanup_thread, NULL, "kmemleak-clean"); "kmemleak-clean"); if (IS_ERR(cleanup_thread)) if (IS_ERR(cleanup_thread)) pr_warning("kmemleak: Failed to create the clean-up thread\n"); pr_warning("Failed to create the clean-up thread\n"); } } /* /* Loading Loading @@ -1488,8 +1485,7 @@ static int __init kmemleak_late_init(void) dentry = debugfs_create_file("kmemleak", S_IRUGO, NULL, NULL, dentry = debugfs_create_file("kmemleak", S_IRUGO, NULL, NULL, &kmemleak_fops); &kmemleak_fops); if (!dentry) if (!dentry) pr_warning("kmemleak: Failed to create the debugfs kmemleak " pr_warning("Failed to create the debugfs kmemleak file\n"); "file\n"); mutex_lock(&kmemleak_mutex); mutex_lock(&kmemleak_mutex); start_scan_thread(); start_scan_thread(); mutex_unlock(&kmemleak_mutex); mutex_unlock(&kmemleak_mutex); Loading Loading
lib/Kconfig.debug +3 −2 Original line number Original line Diff line number Diff line Loading @@ -340,8 +340,6 @@ config DEBUG_KMEMLEAK bool "Kernel memory leak detector" bool "Kernel memory leak detector" depends on DEBUG_KERNEL && EXPERIMENTAL && (X86 || ARM) && \ depends on DEBUG_KERNEL && EXPERIMENTAL && (X86 || ARM) && \ !MEMORY_HOTPLUG !MEMORY_HOTPLUG select DEBUG_SLAB if SLAB select SLUB_DEBUG if SLUB select DEBUG_FS if SYSFS select DEBUG_FS if SYSFS select STACKTRACE if STACKTRACE_SUPPORT select STACKTRACE if STACKTRACE_SUPPORT select KALLSYMS select KALLSYMS Loading @@ -355,6 +353,9 @@ config DEBUG_KMEMLEAK allocations. See Documentation/kmemleak.txt for more allocations. See Documentation/kmemleak.txt for more details. details. Enabling DEBUG_SLAB or SLUB_DEBUG may increase the chances of finding leaks due to the slab objects poisoning. In order to access the kmemleak file, debugfs needs to be In order to access the kmemleak file, debugfs needs to be mounted (usually at /sys/kernel/debug). mounted (usually at /sys/kernel/debug). Loading
mm/kmemleak.c +24 −28 Original line number Original line Diff line number Diff line Loading @@ -61,6 +61,8 @@ * structure. * structure. */ */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/init.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/kernel.h> #include <linux/list.h> #include <linux/list.h> Loading Loading @@ -311,7 +313,7 @@ static int unreferenced_object(struct kmemleak_object *object) static void print_referenced(struct kmemleak_object *object) static void print_referenced(struct kmemleak_object *object) { { pr_info("kmemleak: referenced object 0x%08lx (size %zu)\n", pr_info("referenced object 0x%08lx (size %zu)\n", object->pointer, object->size); object->pointer, object->size); } } Loading @@ -320,7 +322,7 @@ static void print_unreferenced(struct seq_file *seq, { { int i; int i; print_helper(seq, "kmemleak: unreferenced object 0x%08lx (size %zu):\n", print_helper(seq, "unreferenced object 0x%08lx (size %zu):\n", object->pointer, object->size); object->pointer, object->size); print_helper(seq, " comm \"%s\", pid %d, jiffies %lu\n", print_helper(seq, " comm \"%s\", pid %d, jiffies %lu\n", object->comm, object->pid, object->jiffies); object->comm, object->pid, object->jiffies); Loading @@ -344,7 +346,7 @@ static void dump_object_info(struct kmemleak_object *object) trace.nr_entries = object->trace_len; trace.nr_entries = object->trace_len; trace.entries = object->trace; trace.entries = object->trace; pr_notice("kmemleak: Object 0x%08lx (size %zu):\n", pr_notice("Object 0x%08lx (size %zu):\n", object->tree_node.start, object->size); object->tree_node.start, object->size); pr_notice(" comm \"%s\", pid %d, jiffies %lu\n", pr_notice(" comm \"%s\", pid %d, jiffies %lu\n", object->comm, object->pid, object->jiffies); object->comm, object->pid, object->jiffies); Loading Loading @@ -372,7 +374,7 @@ static struct kmemleak_object *lookup_object(unsigned long ptr, int alias) object = prio_tree_entry(node, struct kmemleak_object, object = prio_tree_entry(node, struct kmemleak_object, tree_node); tree_node); if (!alias && object->pointer != ptr) { if (!alias && object->pointer != ptr) { kmemleak_warn("kmemleak: Found object by alias"); kmemleak_warn("Found object by alias"); object = NULL; object = NULL; } } } else } else Loading Loading @@ -467,8 +469,7 @@ static void create_object(unsigned long ptr, size_t size, int min_count, object = kmem_cache_alloc(object_cache, gfp & GFP_KMEMLEAK_MASK); object = kmem_cache_alloc(object_cache, gfp & GFP_KMEMLEAK_MASK); if (!object) { if (!object) { kmemleak_stop("kmemleak: Cannot allocate a kmemleak_object " kmemleak_stop("Cannot allocate a kmemleak_object structure\n"); "structure\n"); return; return; } } Loading Loading @@ -527,8 +528,8 @@ static void create_object(unsigned long ptr, size_t size, int min_count, if (node != &object->tree_node) { if (node != &object->tree_node) { unsigned long flags; unsigned long flags; kmemleak_stop("kmemleak: Cannot insert 0x%lx into the object " kmemleak_stop("Cannot insert 0x%lx into the object search tree " "search tree (already existing)\n", ptr); "(already existing)\n", ptr); object = lookup_object(ptr, 1); object = lookup_object(ptr, 1); spin_lock_irqsave(&object->lock, flags); spin_lock_irqsave(&object->lock, flags); dump_object_info(object); dump_object_info(object); Loading @@ -553,7 +554,7 @@ static void delete_object(unsigned long ptr) write_lock_irqsave(&kmemleak_lock, flags); write_lock_irqsave(&kmemleak_lock, flags); object = lookup_object(ptr, 0); object = lookup_object(ptr, 0); if (!object) { if (!object) { kmemleak_warn("kmemleak: Freeing unknown object at 0x%08lx\n", kmemleak_warn("Freeing unknown object at 0x%08lx\n", ptr); ptr); write_unlock_irqrestore(&kmemleak_lock, flags); write_unlock_irqrestore(&kmemleak_lock, flags); return; return; Loading Loading @@ -588,8 +589,7 @@ static void make_gray_object(unsigned long ptr) object = find_and_get_object(ptr, 0); object = find_and_get_object(ptr, 0); if (!object) { if (!object) { kmemleak_warn("kmemleak: Graying unknown object at 0x%08lx\n", kmemleak_warn("Graying unknown object at 0x%08lx\n", ptr); ptr); return; return; } } Loading @@ -610,8 +610,7 @@ static void make_black_object(unsigned long ptr) object = find_and_get_object(ptr, 0); object = find_and_get_object(ptr, 0); if (!object) { if (!object) { kmemleak_warn("kmemleak: Blacking unknown object at 0x%08lx\n", kmemleak_warn("Blacking unknown object at 0x%08lx\n", ptr); ptr); return; return; } } Loading @@ -634,21 +633,20 @@ static void add_scan_area(unsigned long ptr, unsigned long offset, object = find_and_get_object(ptr, 0); object = find_and_get_object(ptr, 0); if (!object) { if (!object) { kmemleak_warn("kmemleak: Adding scan area to unknown " kmemleak_warn("Adding scan area to unknown object at 0x%08lx\n", "object at 0x%08lx\n", ptr); ptr); return; return; } } area = kmem_cache_alloc(scan_area_cache, gfp & GFP_KMEMLEAK_MASK); area = kmem_cache_alloc(scan_area_cache, gfp & GFP_KMEMLEAK_MASK); if (!area) { if (!area) { kmemleak_warn("kmemleak: Cannot allocate a scan area\n"); kmemleak_warn("Cannot allocate a scan area\n"); goto out; goto out; } } spin_lock_irqsave(&object->lock, flags); spin_lock_irqsave(&object->lock, flags); if (offset + length > object->size) { if (offset + length > object->size) { kmemleak_warn("kmemleak: Scan area larger than object " kmemleak_warn("Scan area larger than object 0x%08lx\n", ptr); "0x%08lx\n", ptr); dump_object_info(object); dump_object_info(object); kmem_cache_free(scan_area_cache, area); kmem_cache_free(scan_area_cache, area); goto out_unlock; goto out_unlock; Loading Loading @@ -677,8 +675,7 @@ static void object_no_scan(unsigned long ptr) object = find_and_get_object(ptr, 0); object = find_and_get_object(ptr, 0); if (!object) { if (!object) { kmemleak_warn("kmemleak: Not scanning unknown object at " kmemleak_warn("Not scanning unknown object at 0x%08lx\n", ptr); "0x%08lx\n", ptr); return; return; } } Loading @@ -699,7 +696,7 @@ static void log_early(int op_type, const void *ptr, size_t size, struct early_log *log; struct early_log *log; if (crt_early_log >= ARRAY_SIZE(early_log)) { if (crt_early_log >= ARRAY_SIZE(early_log)) { kmemleak_stop("kmemleak: Early log buffer exceeded\n"); kmemleak_stop("Early log buffer exceeded\n"); return; return; } } Loading Loading @@ -966,7 +963,7 @@ static void kmemleak_scan(void) * 1 reference to any object at this point. * 1 reference to any object at this point. */ */ if (atomic_read(&object->use_count) > 1) { if (atomic_read(&object->use_count) > 1) { pr_debug("kmemleak: object->use_count = %d\n", pr_debug("object->use_count = %d\n", atomic_read(&object->use_count)); atomic_read(&object->use_count)); dump_object_info(object); dump_object_info(object); } } Loading Loading @@ -1062,7 +1059,7 @@ static int kmemleak_scan_thread(void *arg) { { static int first_run = 1; static int first_run = 1; pr_info("kmemleak: Automatic memory scanning thread started\n"); pr_info("Automatic memory scanning thread started\n"); /* /* * Wait before the first scan to allow the system to fully initialize. * Wait before the first scan to allow the system to fully initialize. Loading Loading @@ -1108,7 +1105,7 @@ static int kmemleak_scan_thread(void *arg) timeout = schedule_timeout_interruptible(timeout); timeout = schedule_timeout_interruptible(timeout); } } pr_info("kmemleak: Automatic memory scanning thread ended\n"); pr_info("Automatic memory scanning thread ended\n"); return 0; return 0; } } Loading @@ -1123,7 +1120,7 @@ void start_scan_thread(void) return; return; scan_thread = kthread_run(kmemleak_scan_thread, NULL, "kmemleak"); scan_thread = kthread_run(kmemleak_scan_thread, NULL, "kmemleak"); if (IS_ERR(scan_thread)) { if (IS_ERR(scan_thread)) { pr_warning("kmemleak: Failed to create the scan thread\n"); pr_warning("Failed to create the scan thread\n"); scan_thread = NULL; scan_thread = NULL; } } } } Loading Loading @@ -1367,7 +1364,7 @@ static void kmemleak_cleanup(void) cleanup_thread = kthread_run(kmemleak_cleanup_thread, NULL, cleanup_thread = kthread_run(kmemleak_cleanup_thread, NULL, "kmemleak-clean"); "kmemleak-clean"); if (IS_ERR(cleanup_thread)) if (IS_ERR(cleanup_thread)) pr_warning("kmemleak: Failed to create the clean-up thread\n"); pr_warning("Failed to create the clean-up thread\n"); } } /* /* Loading Loading @@ -1488,8 +1485,7 @@ static int __init kmemleak_late_init(void) dentry = debugfs_create_file("kmemleak", S_IRUGO, NULL, NULL, dentry = debugfs_create_file("kmemleak", S_IRUGO, NULL, NULL, &kmemleak_fops); &kmemleak_fops); if (!dentry) if (!dentry) pr_warning("kmemleak: Failed to create the debugfs kmemleak " pr_warning("Failed to create the debugfs kmemleak file\n"); "file\n"); mutex_lock(&kmemleak_mutex); mutex_lock(&kmemleak_mutex); start_scan_thread(); start_scan_thread(); mutex_unlock(&kmemleak_mutex); mutex_unlock(&kmemleak_mutex); Loading