diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-23 14:25:04 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-23 14:25:04 -0400 |
| commit | 95b3692d9c22c659312acb466d0608bf8509f296 (patch) | |
| tree | a6978e2f84ab45833f402227d5920a44eca00f1e | |
| parent | d26ed650d9947a786bbda8de9cd914dbeebc1a68 (diff) | |
| parent | bf96d1e3e7a35a17cea255048ffb3243bd9c8123 (diff) | |
Merge branch 'kmemleak' of git://linux-arm.org/linux-2.6
* 'kmemleak' of git://linux-arm.org/linux-2.6:
kmemleak: Do not force the slab debugging Kconfig options
kmemleak: use pr_fmt
| -rw-r--r-- | lib/Kconfig.debug | 5 | ||||
| -rw-r--r-- | mm/kmemleak.c | 52 |
2 files changed, 27 insertions, 30 deletions
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 23067ab1a73c..4c32b1a1a06e 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug | |||
| @@ -340,8 +340,6 @@ config DEBUG_KMEMLEAK | |||
| 340 | bool "Kernel memory leak detector" | 340 | bool "Kernel memory leak detector" |
| 341 | depends on DEBUG_KERNEL && EXPERIMENTAL && (X86 || ARM) && \ | 341 | depends on DEBUG_KERNEL && EXPERIMENTAL && (X86 || ARM) && \ |
| 342 | !MEMORY_HOTPLUG | 342 | !MEMORY_HOTPLUG |
| 343 | select DEBUG_SLAB if SLAB | ||
| 344 | select SLUB_DEBUG if SLUB | ||
| 345 | select DEBUG_FS if SYSFS | 343 | select DEBUG_FS if SYSFS |
| 346 | select STACKTRACE if STACKTRACE_SUPPORT | 344 | select STACKTRACE if STACKTRACE_SUPPORT |
| 347 | select KALLSYMS | 345 | select KALLSYMS |
| @@ -355,6 +353,9 @@ config DEBUG_KMEMLEAK | |||
| 355 | allocations. See Documentation/kmemleak.txt for more | 353 | allocations. See Documentation/kmemleak.txt for more |
| 356 | details. | 354 | details. |
| 357 | 355 | ||
| 356 | Enabling DEBUG_SLAB or SLUB_DEBUG may increase the chances | ||
| 357 | of finding leaks due to the slab objects poisoning. | ||
| 358 | |||
| 358 | In order to access the kmemleak file, debugfs needs to be | 359 | In order to access the kmemleak file, debugfs needs to be |
| 359 | mounted (usually at /sys/kernel/debug). | 360 | mounted (usually at /sys/kernel/debug). |
| 360 | 361 | ||
diff --git a/mm/kmemleak.c b/mm/kmemleak.c index ec759b60077a..c96f2c8700aa 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c | |||
| @@ -61,6 +61,8 @@ | |||
| 61 | * structure. | 61 | * structure. |
| 62 | */ | 62 | */ |
| 63 | 63 | ||
| 64 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
| 65 | |||
| 64 | #include <linux/init.h> | 66 | #include <linux/init.h> |
| 65 | #include <linux/kernel.h> | 67 | #include <linux/kernel.h> |
| 66 | #include <linux/list.h> | 68 | #include <linux/list.h> |
| @@ -311,7 +313,7 @@ static int unreferenced_object(struct kmemleak_object *object) | |||
| 311 | 313 | ||
| 312 | static void print_referenced(struct kmemleak_object *object) | 314 | static void print_referenced(struct kmemleak_object *object) |
| 313 | { | 315 | { |
| 314 | pr_info("kmemleak: referenced object 0x%08lx (size %zu)\n", | 316 | pr_info("referenced object 0x%08lx (size %zu)\n", |
| 315 | object->pointer, object->size); | 317 | object->pointer, object->size); |
| 316 | } | 318 | } |
| 317 | 319 | ||
| @@ -320,7 +322,7 @@ static void print_unreferenced(struct seq_file *seq, | |||
| 320 | { | 322 | { |
| 321 | int i; | 323 | int i; |
| 322 | 324 | ||
| 323 | print_helper(seq, "kmemleak: unreferenced object 0x%08lx (size %zu):\n", | 325 | print_helper(seq, "unreferenced object 0x%08lx (size %zu):\n", |
| 324 | object->pointer, object->size); | 326 | object->pointer, object->size); |
| 325 | print_helper(seq, " comm \"%s\", pid %d, jiffies %lu\n", | 327 | print_helper(seq, " comm \"%s\", pid %d, jiffies %lu\n", |
| 326 | object->comm, object->pid, object->jiffies); | 328 | object->comm, object->pid, object->jiffies); |
| @@ -344,7 +346,7 @@ static void dump_object_info(struct kmemleak_object *object) | |||
| 344 | trace.nr_entries = object->trace_len; | 346 | trace.nr_entries = object->trace_len; |
| 345 | trace.entries = object->trace; | 347 | trace.entries = object->trace; |
| 346 | 348 | ||
| 347 | pr_notice("kmemleak: Object 0x%08lx (size %zu):\n", | 349 | pr_notice("Object 0x%08lx (size %zu):\n", |
| 348 | object->tree_node.start, object->size); | 350 | object->tree_node.start, object->size); |
| 349 | pr_notice(" comm \"%s\", pid %d, jiffies %lu\n", | 351 | pr_notice(" comm \"%s\", pid %d, jiffies %lu\n", |
| 350 | object->comm, object->pid, object->jiffies); | 352 | object->comm, object->pid, object->jiffies); |
| @@ -372,7 +374,7 @@ static struct kmemleak_object *lookup_object(unsigned long ptr, int alias) | |||
| 372 | object = prio_tree_entry(node, struct kmemleak_object, | 374 | object = prio_tree_entry(node, struct kmemleak_object, |
| 373 | tree_node); | 375 | tree_node); |
| 374 | if (!alias && object->pointer != ptr) { | 376 | if (!alias && object->pointer != ptr) { |
| 375 | kmemleak_warn("kmemleak: Found object by alias"); | 377 | kmemleak_warn("Found object by alias"); |
| 376 | object = NULL; | 378 | object = NULL; |
| 377 | } | 379 | } |
| 378 | } else | 380 | } else |
| @@ -467,8 +469,7 @@ static void create_object(unsigned long ptr, size_t size, int min_count, | |||
| 467 | 469 | ||
| 468 | object = kmem_cache_alloc(object_cache, gfp & GFP_KMEMLEAK_MASK); | 470 | object = kmem_cache_alloc(object_cache, gfp & GFP_KMEMLEAK_MASK); |
| 469 | if (!object) { | 471 | if (!object) { |
| 470 | kmemleak_stop("kmemleak: Cannot allocate a kmemleak_object " | 472 | kmemleak_stop("Cannot allocate a kmemleak_object structure\n"); |
| 471 | "structure\n"); | ||
| 472 | return; | 473 | return; |
| 473 | } | 474 | } |
| 474 | 475 | ||
| @@ -527,8 +528,8 @@ static void create_object(unsigned long ptr, size_t size, int min_count, | |||
| 527 | if (node != &object->tree_node) { | 528 | if (node != &object->tree_node) { |
| 528 | unsigned long flags; | 529 | unsigned long flags; |
| 529 | 530 | ||
| 530 | kmemleak_stop("kmemleak: Cannot insert 0x%lx into the object " | 531 | kmemleak_stop("Cannot insert 0x%lx into the object search tree " |
| 531 | "search tree (already existing)\n", ptr); | 532 | "(already existing)\n", ptr); |
| 532 | object = lookup_object(ptr, 1); | 533 | object = lookup_object(ptr, 1); |
| 533 | spin_lock_irqsave(&object->lock, flags); | 534 | spin_lock_irqsave(&object->lock, flags); |
| 534 | dump_object_info(object); | 535 | dump_object_info(object); |
| @@ -553,7 +554,7 @@ static void delete_object(unsigned long ptr) | |||
| 553 | write_lock_irqsave(&kmemleak_lock, flags); | 554 | write_lock_irqsave(&kmemleak_lock, flags); |
| 554 | object = lookup_object(ptr, 0); | 555 | object = lookup_object(ptr, 0); |
| 555 | if (!object) { | 556 | if (!object) { |
| 556 | kmemleak_warn("kmemleak: Freeing unknown object at 0x%08lx\n", | 557 | kmemleak_warn("Freeing unknown object at 0x%08lx\n", |
| 557 | ptr); | 558 | ptr); |
| 558 | write_unlock_irqrestore(&kmemleak_lock, flags); | 559 | write_unlock_irqrestore(&kmemleak_lock, flags); |
| 559 | return; | 560 | return; |
| @@ -588,8 +589,7 @@ static void make_gray_object(unsigned long ptr) | |||
| 588 | 589 | ||
| 589 | object = find_and_get_object(ptr, 0); | 590 | object = find_and_get_object(ptr, 0); |
| 590 | if (!object) { | 591 | if (!object) { |
| 591 | kmemleak_warn("kmemleak: Graying unknown object at 0x%08lx\n", | 592 | kmemleak_warn("Graying unknown object at 0x%08lx\n", ptr); |
| 592 | ptr); | ||
| 593 | return; | 593 | return; |
| 594 | } | 594 | } |
| 595 | 595 | ||
| @@ -610,8 +610,7 @@ static void make_black_object(unsigned long ptr) | |||
| 610 | 610 | ||
| 611 | object = find_and_get_object(ptr, 0); | 611 | object = find_and_get_object(ptr, 0); |
| 612 | if (!object) { | 612 | if (!object) { |
| 613 | kmemleak_warn("kmemleak: Blacking unknown object at 0x%08lx\n", | 613 | kmemleak_warn("Blacking unknown object at 0x%08lx\n", ptr); |
| 614 | ptr); | ||
| 615 | return; | 614 | return; |
| 616 | } | 615 | } |
| 617 | 616 | ||
| @@ -634,21 +633,20 @@ static void add_scan_area(unsigned long ptr, unsigned long offset, | |||
| 634 | 633 | ||
| 635 | object = find_and_get_object(ptr, 0); | 634 | object = find_and_get_object(ptr, 0); |
| 636 | if (!object) { | 635 | if (!object) { |
| 637 | kmemleak_warn("kmemleak: Adding scan area to unknown " | 636 | kmemleak_warn("Adding scan area to unknown object at 0x%08lx\n", |
| 638 | "object at 0x%08lx\n", ptr); | 637 | ptr); |
| 639 | return; | 638 | return; |
| 640 | } | 639 | } |
| 641 | 640 | ||
| 642 | area = kmem_cache_alloc(scan_area_cache, gfp & GFP_KMEMLEAK_MASK); | 641 | area = kmem_cache_alloc(scan_area_cache, gfp & GFP_KMEMLEAK_MASK); |
| 643 | if (!area) { | 642 | if (!area) { |
| 644 | kmemleak_warn("kmemleak: Cannot allocate a scan area\n"); | 643 | kmemleak_warn("Cannot allocate a scan area\n"); |
| 645 | goto out; | 644 | goto out; |
| 646 | } | 645 | } |
| 647 | 646 | ||
| 648 | spin_lock_irqsave(&object->lock, flags); | 647 | spin_lock_irqsave(&object->lock, flags); |
| 649 | if (offset + length > object->size) { | 648 | if (offset + length > object->size) { |
| 650 | kmemleak_warn("kmemleak: Scan area larger than object " | 649 | kmemleak_warn("Scan area larger than object 0x%08lx\n", ptr); |
| 651 | "0x%08lx\n", ptr); | ||
| 652 | dump_object_info(object); | 650 | dump_object_info(object); |
| 653 | kmem_cache_free(scan_area_cache, area); | 651 | kmem_cache_free(scan_area_cache, area); |
| 654 | goto out_unlock; | 652 | goto out_unlock; |
| @@ -677,8 +675,7 @@ static void object_no_scan(unsigned long ptr) | |||
| 677 | 675 | ||
| 678 | object = find_and_get_object(ptr, 0); | 676 | object = find_and_get_object(ptr, 0); |
| 679 | if (!object) { | 677 | if (!object) { |
| 680 | kmemleak_warn("kmemleak: Not scanning unknown object at " | 678 | kmemleak_warn("Not scanning unknown object at 0x%08lx\n", ptr); |
| 681 | "0x%08lx\n", ptr); | ||
| 682 | return; | 679 | return; |
| 683 | } | 680 | } |
| 684 | 681 | ||
| @@ -699,7 +696,7 @@ static void log_early(int op_type, const void *ptr, size_t size, | |||
| 699 | struct early_log *log; | 696 | struct early_log *log; |
| 700 | 697 | ||
| 701 | if (crt_early_log >= ARRAY_SIZE(early_log)) { | 698 | if (crt_early_log >= ARRAY_SIZE(early_log)) { |
| 702 | kmemleak_stop("kmemleak: Early log buffer exceeded\n"); | 699 | kmemleak_stop("Early log buffer exceeded\n"); |
| 703 | return; | 700 | return; |
| 704 | } | 701 | } |
| 705 | 702 | ||
| @@ -966,7 +963,7 @@ static void kmemleak_scan(void) | |||
| 966 | * 1 reference to any object at this point. | 963 | * 1 reference to any object at this point. |
| 967 | */ | 964 | */ |
| 968 | if (atomic_read(&object->use_count) > 1) { | 965 | if (atomic_read(&object->use_count) > 1) { |
| 969 | pr_debug("kmemleak: object->use_count = %d\n", | 966 | pr_debug("object->use_count = %d\n", |
| 970 | atomic_read(&object->use_count)); | 967 | atomic_read(&object->use_count)); |
| 971 | dump_object_info(object); | 968 | dump_object_info(object); |
| 972 | } | 969 | } |
| @@ -1062,7 +1059,7 @@ static int kmemleak_scan_thread(void *arg) | |||
| 1062 | { | 1059 | { |
| 1063 | static int first_run = 1; | 1060 | static int first_run = 1; |
| 1064 | 1061 | ||
| 1065 | pr_info("kmemleak: Automatic memory scanning thread started\n"); | 1062 | pr_info("Automatic memory scanning thread started\n"); |
| 1066 | 1063 | ||
| 1067 | /* | 1064 | /* |
| 1068 | * Wait before the first scan to allow the system to fully initialize. | 1065 | * Wait before the first scan to allow the system to fully initialize. |
| @@ -1108,7 +1105,7 @@ static int kmemleak_scan_thread(void *arg) | |||
| 1108 | timeout = schedule_timeout_interruptible(timeout); | 1105 | timeout = schedule_timeout_interruptible(timeout); |
| 1109 | } | 1106 | } |
| 1110 | 1107 | ||
| 1111 | pr_info("kmemleak: Automatic memory scanning thread ended\n"); | 1108 | pr_info("Automatic memory scanning thread ended\n"); |
| 1112 | 1109 | ||
| 1113 | return 0; | 1110 | return 0; |
| 1114 | } | 1111 | } |
| @@ -1123,7 +1120,7 @@ void start_scan_thread(void) | |||
| 1123 | return; | 1120 | return; |
| 1124 | scan_thread = kthread_run(kmemleak_scan_thread, NULL, "kmemleak"); | 1121 | scan_thread = kthread_run(kmemleak_scan_thread, NULL, "kmemleak"); |
| 1125 | if (IS_ERR(scan_thread)) { | 1122 | if (IS_ERR(scan_thread)) { |
| 1126 | pr_warning("kmemleak: Failed to create the scan thread\n"); | 1123 | pr_warning("Failed to create the scan thread\n"); |
| 1127 | scan_thread = NULL; | 1124 | scan_thread = NULL; |
| 1128 | } | 1125 | } |
| 1129 | } | 1126 | } |
| @@ -1367,7 +1364,7 @@ static void kmemleak_cleanup(void) | |||
| 1367 | cleanup_thread = kthread_run(kmemleak_cleanup_thread, NULL, | 1364 | cleanup_thread = kthread_run(kmemleak_cleanup_thread, NULL, |
| 1368 | "kmemleak-clean"); | 1365 | "kmemleak-clean"); |
| 1369 | if (IS_ERR(cleanup_thread)) | 1366 | if (IS_ERR(cleanup_thread)) |
| 1370 | pr_warning("kmemleak: Failed to create the clean-up thread\n"); | 1367 | pr_warning("Failed to create the clean-up thread\n"); |
| 1371 | } | 1368 | } |
| 1372 | 1369 | ||
| 1373 | /* | 1370 | /* |
| @@ -1488,8 +1485,7 @@ static int __init kmemleak_late_init(void) | |||
| 1488 | dentry = debugfs_create_file("kmemleak", S_IRUGO, NULL, NULL, | 1485 | dentry = debugfs_create_file("kmemleak", S_IRUGO, NULL, NULL, |
| 1489 | &kmemleak_fops); | 1486 | &kmemleak_fops); |
| 1490 | if (!dentry) | 1487 | if (!dentry) |
| 1491 | pr_warning("kmemleak: Failed to create the debugfs kmemleak " | 1488 | pr_warning("Failed to create the debugfs kmemleak file\n"); |
| 1492 | "file\n"); | ||
| 1493 | mutex_lock(&kmemleak_mutex); | 1489 | mutex_lock(&kmemleak_mutex); |
| 1494 | start_scan_thread(); | 1490 | start_scan_thread(); |
| 1495 | mutex_unlock(&kmemleak_mutex); | 1491 | mutex_unlock(&kmemleak_mutex); |
