diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/kmemleak.c | 43 |
1 files changed, 40 insertions, 3 deletions
diff --git a/mm/kmemleak.c b/mm/kmemleak.c index 7cfb7d014a20..466d39007264 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c | |||
@@ -106,6 +106,7 @@ | |||
106 | #define MSECS_MIN_AGE 5000 /* minimum object age for reporting */ | 106 | #define MSECS_MIN_AGE 5000 /* minimum object age for reporting */ |
107 | #define SECS_FIRST_SCAN 60 /* delay before the first scan */ | 107 | #define SECS_FIRST_SCAN 60 /* delay before the first scan */ |
108 | #define SECS_SCAN_WAIT 600 /* subsequent auto scanning delay */ | 108 | #define SECS_SCAN_WAIT 600 /* subsequent auto scanning delay */ |
109 | #define GRAY_LIST_PASSES 25 /* maximum number of gray list scans */ | ||
109 | 110 | ||
110 | #define BYTES_PER_POINTER sizeof(void *) | 111 | #define BYTES_PER_POINTER sizeof(void *) |
111 | 112 | ||
@@ -157,6 +158,8 @@ struct kmemleak_object { | |||
157 | #define OBJECT_REPORTED (1 << 1) | 158 | #define OBJECT_REPORTED (1 << 1) |
158 | /* flag set to not scan the object */ | 159 | /* flag set to not scan the object */ |
159 | #define OBJECT_NO_SCAN (1 << 2) | 160 | #define OBJECT_NO_SCAN (1 << 2) |
161 | /* flag set on newly allocated objects */ | ||
162 | #define OBJECT_NEW (1 << 3) | ||
160 | 163 | ||
161 | /* the list of all allocated objects */ | 164 | /* the list of all allocated objects */ |
162 | static LIST_HEAD(object_list); | 165 | static LIST_HEAD(object_list); |
@@ -270,6 +273,11 @@ static int color_gray(const struct kmemleak_object *object) | |||
270 | return object->min_count != -1 && object->count >= object->min_count; | 273 | return object->min_count != -1 && object->count >= object->min_count; |
271 | } | 274 | } |
272 | 275 | ||
276 | static int color_black(const struct kmemleak_object *object) | ||
277 | { | ||
278 | return object->min_count == -1; | ||
279 | } | ||
280 | |||
273 | /* | 281 | /* |
274 | * 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 |
275 | * 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 |
@@ -447,7 +455,7 @@ static void create_object(unsigned long ptr, size_t size, int min_count, | |||
447 | INIT_HLIST_HEAD(&object->area_list); | 455 | INIT_HLIST_HEAD(&object->area_list); |
448 | spin_lock_init(&object->lock); | 456 | spin_lock_init(&object->lock); |
449 | atomic_set(&object->use_count, 1); | 457 | atomic_set(&object->use_count, 1); |
450 | object->flags = OBJECT_ALLOCATED; | 458 | object->flags = OBJECT_ALLOCATED | OBJECT_NEW; |
451 | object->pointer = ptr; | 459 | object->pointer = ptr; |
452 | object->size = size; | 460 | object->size = size; |
453 | object->min_count = min_count; | 461 | object->min_count = min_count; |
@@ -901,6 +909,7 @@ static void kmemleak_scan(void) | |||
901 | struct task_struct *task; | 909 | struct task_struct *task; |
902 | int i; | 910 | int i; |
903 | int new_leaks = 0; | 911 | int new_leaks = 0; |
912 | int gray_list_pass = 0; | ||
904 | 913 | ||
905 | jiffies_last_scan = jiffies; | 914 | jiffies_last_scan = jiffies; |
906 | 915 | ||
@@ -921,6 +930,7 @@ static void kmemleak_scan(void) | |||
921 | #endif | 930 | #endif |
922 | /* reset the reference count (whiten the object) */ | 931 | /* reset the reference count (whiten the object) */ |
923 | object->count = 0; | 932 | object->count = 0; |
933 | object->flags &= ~OBJECT_NEW; | ||
924 | if (color_gray(object) && get_object(object)) | 934 | if (color_gray(object) && get_object(object)) |
925 | list_add_tail(&object->gray_list, &gray_list); | 935 | list_add_tail(&object->gray_list, &gray_list); |
926 | 936 | ||
@@ -983,6 +993,7 @@ static void kmemleak_scan(void) | |||
983 | * kmemleak objects cannot be freed from outside the loop because their | 993 | * kmemleak objects cannot be freed from outside the loop because their |
984 | * use_count was increased. | 994 | * use_count was increased. |
985 | */ | 995 | */ |
996 | repeat: | ||
986 | object = list_entry(gray_list.next, typeof(*object), gray_list); | 997 | object = list_entry(gray_list.next, typeof(*object), gray_list); |
987 | while (&object->gray_list != &gray_list) { | 998 | while (&object->gray_list != &gray_list) { |
988 | cond_resched(); | 999 | cond_resched(); |
@@ -1000,12 +1011,38 @@ static void kmemleak_scan(void) | |||
1000 | 1011 | ||
1001 | object = tmp; | 1012 | object = tmp; |
1002 | } | 1013 | } |
1014 | |||
1015 | if (scan_should_stop() || ++gray_list_pass >= GRAY_LIST_PASSES) | ||
1016 | goto scan_end; | ||
1017 | |||
1018 | /* | ||
1019 | * Check for new objects allocated during this scanning and add them | ||
1020 | * to the gray list. | ||
1021 | */ | ||
1022 | rcu_read_lock(); | ||
1023 | list_for_each_entry_rcu(object, &object_list, object_list) { | ||
1024 | spin_lock_irqsave(&object->lock, flags); | ||
1025 | if ((object->flags & OBJECT_NEW) && !color_black(object) && | ||
1026 | get_object(object)) { | ||
1027 | object->flags &= ~OBJECT_NEW; | ||
1028 | list_add_tail(&object->gray_list, &gray_list); | ||
1029 | } | ||
1030 | spin_unlock_irqrestore(&object->lock, flags); | ||
1031 | } | ||
1032 | rcu_read_unlock(); | ||
1033 | |||
1034 | if (!list_empty(&gray_list)) | ||
1035 | goto repeat; | ||
1036 | |||
1037 | scan_end: | ||
1003 | WARN_ON(!list_empty(&gray_list)); | 1038 | WARN_ON(!list_empty(&gray_list)); |
1004 | 1039 | ||
1005 | /* | 1040 | /* |
1006 | * If scanning was stopped do not report any new unreferenced objects. | 1041 | * If scanning was stopped or new objects were being allocated at a |
1042 | * higher rate than gray list scanning, do not report any new | ||
1043 | * unreferenced objects. | ||
1007 | */ | 1044 | */ |
1008 | if (scan_should_stop()) | 1045 | if (scan_should_stop() || gray_list_pass >= GRAY_LIST_PASSES) |
1009 | return; | 1046 | return; |
1010 | 1047 | ||
1011 | /* | 1048 | /* |