diff options
author | Catalin Marinas <catalin.marinas@arm.com> | 2009-08-27 09:29:12 -0400 |
---|---|---|
committer | Catalin Marinas <catalin.marinas@arm.com> | 2009-08-27 09:29:12 -0400 |
commit | af98603dad87e393d2fc57117fe8a2aa6d620a0c (patch) | |
tree | 7a86d844fe5b43d8894607c16e4945f7ebe51b79 | |
parent | 1e23502cc57cef33455ac7cb9111e3c6d991a894 (diff) |
kmemleak: Allow rescheduling during an object scanning
If the object size is bigger than a predefined value (4K in this case),
release the object lock during scanning and call cond_resched().
Re-acquire the lock after rescheduling and test whether the object is
still valid.
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
-rw-r--r-- | mm/kmemleak.c | 21 |
1 files changed, 17 insertions, 4 deletions
diff --git a/mm/kmemleak.c b/mm/kmemleak.c index 487267310a84..6debe0d80e64 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c | |||
@@ -107,6 +107,7 @@ | |||
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 | #define GRAY_LIST_PASSES 25 /* maximum number of gray list scans */ |
110 | #define MAX_SCAN_SIZE 4096 /* maximum size of a scanned block */ | ||
110 | 111 | ||
111 | #define BYTES_PER_POINTER sizeof(void *) | 112 | #define BYTES_PER_POINTER sizeof(void *) |
112 | 113 | ||
@@ -642,6 +643,7 @@ static void make_black_object(unsigned long ptr) | |||
642 | 643 | ||
643 | spin_lock_irqsave(&object->lock, flags); | 644 | spin_lock_irqsave(&object->lock, flags); |
644 | object->min_count = -1; | 645 | object->min_count = -1; |
646 | object->flags |= OBJECT_NO_SCAN; | ||
645 | spin_unlock_irqrestore(&object->lock, flags); | 647 | spin_unlock_irqrestore(&object->lock, flags); |
646 | put_object(object); | 648 | put_object(object); |
647 | } | 649 | } |
@@ -949,10 +951,21 @@ static void scan_object(struct kmemleak_object *object) | |||
949 | if (!(object->flags & OBJECT_ALLOCATED)) | 951 | if (!(object->flags & OBJECT_ALLOCATED)) |
950 | /* already freed object */ | 952 | /* already freed object */ |
951 | goto out; | 953 | goto out; |
952 | if (hlist_empty(&object->area_list)) | 954 | if (hlist_empty(&object->area_list)) { |
953 | scan_block((void *)object->pointer, | 955 | void *start = (void *)object->pointer; |
954 | (void *)(object->pointer + object->size), object, 0); | 956 | void *end = (void *)(object->pointer + object->size); |
955 | else | 957 | |
958 | while (start < end && (object->flags & OBJECT_ALLOCATED) && | ||
959 | !(object->flags & OBJECT_NO_SCAN)) { | ||
960 | scan_block(start, min(start + MAX_SCAN_SIZE, end), | ||
961 | object, 0); | ||
962 | start += MAX_SCAN_SIZE; | ||
963 | |||
964 | spin_unlock_irqrestore(&object->lock, flags); | ||
965 | cond_resched(); | ||
966 | spin_lock_irqsave(&object->lock, flags); | ||
967 | } | ||
968 | } else | ||
956 | hlist_for_each_entry(area, elem, &object->area_list, node) | 969 | hlist_for_each_entry(area, elem, &object->area_list, node) |
957 | scan_block((void *)(object->pointer + area->offset), | 970 | scan_block((void *)(object->pointer + area->offset), |
958 | (void *)(object->pointer + area->offset | 971 | (void *)(object->pointer + area->offset |