diff options
Diffstat (limited to 'mm/kmemleak.c')
-rw-r--r-- | mm/kmemleak.c | 61 |
1 files changed, 16 insertions, 45 deletions
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()) |