diff options
author | Catalin Marinas <catalin.marinas@arm.com> | 2009-06-26 12:38:26 -0400 |
---|---|---|
committer | Catalin Marinas <catalin.marinas@arm.com> | 2009-06-26 12:38:26 -0400 |
commit | bab4a34afc301fdb81b6ea0e3098d96fc356e03a (patch) | |
tree | d9722d26dc944dbad1afd6dd182aa3a21907b96d | |
parent | e0a2a1601bec01243bcad44414d06f59dae2eedb (diff) |
kmemleak: Simplify the reports logged by the scanning thread
Because of false positives, the memory scanning thread may print too
much information. This patch changes the scanning thread to only print
the number of newly suspected leaks. Further information can be read
from the /sys/kernel/debug/kmemleak file.
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
-rw-r--r-- | Documentation/kmemleak.txt | 6 | ||||
-rw-r--r-- | mm/kmemleak.c | 61 |
2 files changed, 19 insertions, 48 deletions
diff --git a/Documentation/kmemleak.txt b/Documentation/kmemleak.txt index 9426e94f291a..c06f7ba64993 100644 --- a/Documentation/kmemleak.txt +++ b/Documentation/kmemleak.txt | |||
@@ -16,9 +16,9 @@ Usage | |||
16 | ----- | 16 | ----- |
17 | 17 | ||
18 | CONFIG_DEBUG_KMEMLEAK in "Kernel hacking" has to be enabled. A kernel | 18 | CONFIG_DEBUG_KMEMLEAK in "Kernel hacking" has to be enabled. A kernel |
19 | thread scans the memory every 10 minutes (by default) and prints any new | 19 | thread scans the memory every 10 minutes (by default) and prints the |
20 | unreferenced objects found. To trigger an intermediate scan and display | 20 | number of new unreferenced objects found. To trigger an intermediate |
21 | all the possible memory leaks: | 21 | scan and display the details of all the possible memory leaks: |
22 | 22 | ||
23 | # mount -t debugfs nodev /sys/kernel/debug/ | 23 | # mount -t debugfs nodev /sys/kernel/debug/ |
24 | # cat /sys/kernel/debug/kmemleak | 24 | # cat /sys/kernel/debug/kmemleak |
diff --git a/mm/kmemleak.c b/mm/kmemleak.c index a38418a95d33..4130a4889fa9 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c | |||
@@ -279,15 +279,6 @@ static int color_gray(const struct kmemleak_object *object) | |||
279 | } | 279 | } |
280 | 280 | ||
281 | /* | 281 | /* |
282 | * Objects are considered referenced if their color is gray and they have not | ||
283 | * been deleted. | ||
284 | */ | ||
285 | static int referenced_object(struct kmemleak_object *object) | ||
286 | { | ||
287 | return (object->flags & OBJECT_ALLOCATED) && color_gray(object); | ||
288 | } | ||
289 | |||
290 | /* | ||
291 | * Objects are considered unreferenced only if their color is white, they have | 282 | * Objects are considered unreferenced only if their color is white, they have |
292 | * not be deleted and have a minimum age to avoid false positives caused by | 283 | * not be deleted and have a minimum age to avoid false positives caused by |
293 | * pointers temporarily stored in CPU registers. | 284 | * pointers temporarily stored in CPU registers. |
@@ -299,38 +290,23 @@ static int unreferenced_object(struct kmemleak_object *object) | |||
299 | } | 290 | } |
300 | 291 | ||
301 | /* | 292 | /* |
302 | * Printing of the (un)referenced objects information, either to the seq file | 293 | * Printing of the unreferenced objects information to the seq file. The |
303 | * or to the kernel log. The print_referenced/print_unreferenced functions | 294 | * print_unreferenced function must be called with the object->lock held. |
304 | * must be called with the object->lock held. | ||
305 | */ | 295 | */ |
306 | #define print_helper(seq, x...) do { \ | ||
307 | struct seq_file *s = (seq); \ | ||
308 | if (s) \ | ||
309 | seq_printf(s, x); \ | ||
310 | else \ | ||
311 | pr_info(x); \ | ||
312 | } while (0) | ||
313 | |||
314 | static void print_referenced(struct kmemleak_object *object) | ||
315 | { | ||
316 | pr_info("referenced object 0x%08lx (size %zu)\n", | ||
317 | object->pointer, object->size); | ||
318 | } | ||
319 | |||
320 | static void print_unreferenced(struct seq_file *seq, | 296 | static void print_unreferenced(struct seq_file *seq, |
321 | struct kmemleak_object *object) | 297 | struct kmemleak_object *object) |
322 | { | 298 | { |
323 | int i; | 299 | int i; |
324 | 300 | ||
325 | print_helper(seq, "unreferenced object 0x%08lx (size %zu):\n", | 301 | seq_printf(seq, "unreferenced object 0x%08lx (size %zu):\n", |
326 | object->pointer, object->size); | 302 | object->pointer, object->size); |
327 | print_helper(seq, " comm \"%s\", pid %d, jiffies %lu\n", | 303 | seq_printf(seq, " comm \"%s\", pid %d, jiffies %lu\n", |
328 | object->comm, object->pid, object->jiffies); | 304 | object->comm, object->pid, object->jiffies); |
329 | print_helper(seq, " backtrace:\n"); | 305 | seq_printf(seq, " backtrace:\n"); |
330 | 306 | ||
331 | for (i = 0; i < object->trace_len; i++) { | 307 | for (i = 0; i < object->trace_len; i++) { |
332 | void *ptr = (void *)object->trace[i]; | 308 | void *ptr = (void *)object->trace[i]; |
333 | print_helper(seq, " [<%p>] %pS\n", ptr, ptr); | 309 | seq_printf(seq, " [<%p>] %pS\n", ptr, ptr); |
334 | } | 310 | } |
335 | } | 311 | } |
336 | 312 | ||
@@ -571,8 +547,6 @@ static void delete_object(unsigned long ptr) | |||
571 | * cannot be freed when it is being scanned. | 547 | * cannot be freed when it is being scanned. |
572 | */ | 548 | */ |
573 | spin_lock_irqsave(&object->lock, flags); | 549 | spin_lock_irqsave(&object->lock, flags); |
574 | if (object->flags & OBJECT_REPORTED) | ||
575 | print_referenced(object); | ||
576 | object->flags &= ~OBJECT_ALLOCATED; | 550 | object->flags &= ~OBJECT_ALLOCATED; |
577 | spin_unlock_irqrestore(&object->lock, flags); | 551 | spin_unlock_irqrestore(&object->lock, flags); |
578 | put_object(object); | 552 | put_object(object); |
@@ -1073,33 +1047,30 @@ static int kmemleak_scan_thread(void *arg) | |||
1073 | while (!kthread_should_stop()) { | 1047 | while (!kthread_should_stop()) { |
1074 | struct kmemleak_object *object; | 1048 | struct kmemleak_object *object; |
1075 | signed long timeout = jiffies_scan_wait; | 1049 | signed long timeout = jiffies_scan_wait; |
1050 | int new_leaks = 0; | ||
1076 | 1051 | ||
1077 | mutex_lock(&scan_mutex); | 1052 | mutex_lock(&scan_mutex); |
1078 | 1053 | ||
1079 | kmemleak_scan(); | 1054 | kmemleak_scan(); |
1080 | reported_leaks = 0; | ||
1081 | 1055 | ||
1082 | rcu_read_lock(); | 1056 | rcu_read_lock(); |
1083 | list_for_each_entry_rcu(object, &object_list, object_list) { | 1057 | list_for_each_entry_rcu(object, &object_list, object_list) { |
1084 | unsigned long flags; | 1058 | unsigned long flags; |
1085 | 1059 | ||
1086 | if (reported_leaks >= REPORTS_NR) | ||
1087 | break; | ||
1088 | spin_lock_irqsave(&object->lock, flags); | 1060 | spin_lock_irqsave(&object->lock, flags); |
1089 | if (!(object->flags & OBJECT_REPORTED) && | 1061 | if (unreferenced_object(object) && |
1090 | unreferenced_object(object)) { | 1062 | !(object->flags & OBJECT_REPORTED)) { |
1091 | print_unreferenced(NULL, object); | ||
1092 | object->flags |= OBJECT_REPORTED; | 1063 | object->flags |= OBJECT_REPORTED; |
1093 | reported_leaks++; | 1064 | new_leaks++; |
1094 | } else if ((object->flags & OBJECT_REPORTED) && | ||
1095 | referenced_object(object)) { | ||
1096 | print_referenced(object); | ||
1097 | object->flags &= ~OBJECT_REPORTED; | ||
1098 | } | 1065 | } |
1099 | spin_unlock_irqrestore(&object->lock, flags); | 1066 | spin_unlock_irqrestore(&object->lock, flags); |
1100 | } | 1067 | } |
1101 | rcu_read_unlock(); | 1068 | rcu_read_unlock(); |
1102 | 1069 | ||
1070 | if (new_leaks) | ||
1071 | pr_info("%d new suspected memory leaks (see " | ||
1072 | "/sys/kernel/debug/kmemleak)\n", new_leaks); | ||
1073 | |||
1103 | mutex_unlock(&scan_mutex); | 1074 | mutex_unlock(&scan_mutex); |
1104 | /* wait before the next scan */ | 1075 | /* wait before the next scan */ |
1105 | while (timeout && !kthread_should_stop()) | 1076 | while (timeout && !kthread_should_stop()) |