diff options
| author | Catalin Marinas <catalin.marinas@arm.com> | 2014-06-06 17:38:17 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-06-06 19:08:17 -0400 |
| commit | ffe2c748e283c5dc1b9b9ac116299dbfc11a609b (patch) | |
| tree | ef16269fb598e941c9e0c90004a8cc20f2133760 | |
| parent | aae0ad7ae5a997bff1862e6e5eebed39cdf08ff3 (diff) | |
mm: introduce kmemleak_update_trace()
The memory allocation stack trace is not always useful for debugging a
memory leak (e.g. radix_tree_preload). This function, when called,
updates the stack trace for an already allocated object.
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
| -rw-r--r-- | Documentation/kmemleak.txt | 1 | ||||
| -rw-r--r-- | include/linux/kmemleak.h | 4 | ||||
| -rw-r--r-- | mm/kmemleak.c | 34 |
3 files changed, 39 insertions, 0 deletions
diff --git a/Documentation/kmemleak.txt b/Documentation/kmemleak.txt index a7563ec4ea7b..b772418bf064 100644 --- a/Documentation/kmemleak.txt +++ b/Documentation/kmemleak.txt | |||
| @@ -142,6 +142,7 @@ kmemleak_alloc_percpu - notify of a percpu memory block allocation | |||
| 142 | kmemleak_free - notify of a memory block freeing | 142 | kmemleak_free - notify of a memory block freeing |
| 143 | kmemleak_free_part - notify of a partial memory block freeing | 143 | kmemleak_free_part - notify of a partial memory block freeing |
| 144 | kmemleak_free_percpu - notify of a percpu memory block freeing | 144 | kmemleak_free_percpu - notify of a percpu memory block freeing |
| 145 | kmemleak_update_trace - update object allocation stack trace | ||
| 145 | kmemleak_not_leak - mark an object as not a leak | 146 | kmemleak_not_leak - mark an object as not a leak |
| 146 | kmemleak_ignore - do not scan or report an object as leak | 147 | kmemleak_ignore - do not scan or report an object as leak |
| 147 | kmemleak_scan_area - add scan areas inside a memory block | 148 | kmemleak_scan_area - add scan areas inside a memory block |
diff --git a/include/linux/kmemleak.h b/include/linux/kmemleak.h index 5bb424659c04..057e95971014 100644 --- a/include/linux/kmemleak.h +++ b/include/linux/kmemleak.h | |||
| @@ -30,6 +30,7 @@ extern void kmemleak_alloc_percpu(const void __percpu *ptr, size_t size) __ref; | |||
| 30 | extern void kmemleak_free(const void *ptr) __ref; | 30 | extern void kmemleak_free(const void *ptr) __ref; |
| 31 | extern void kmemleak_free_part(const void *ptr, size_t size) __ref; | 31 | extern void kmemleak_free_part(const void *ptr, size_t size) __ref; |
| 32 | extern void kmemleak_free_percpu(const void __percpu *ptr) __ref; | 32 | extern void kmemleak_free_percpu(const void __percpu *ptr) __ref; |
| 33 | extern void kmemleak_update_trace(const void *ptr) __ref; | ||
| 33 | extern void kmemleak_not_leak(const void *ptr) __ref; | 34 | extern void kmemleak_not_leak(const void *ptr) __ref; |
| 34 | extern void kmemleak_ignore(const void *ptr) __ref; | 35 | extern void kmemleak_ignore(const void *ptr) __ref; |
| 35 | extern void kmemleak_scan_area(const void *ptr, size_t size, gfp_t gfp) __ref; | 36 | extern void kmemleak_scan_area(const void *ptr, size_t size, gfp_t gfp) __ref; |
| @@ -83,6 +84,9 @@ static inline void kmemleak_free_recursive(const void *ptr, unsigned long flags) | |||
| 83 | static inline void kmemleak_free_percpu(const void __percpu *ptr) | 84 | static inline void kmemleak_free_percpu(const void __percpu *ptr) |
| 84 | { | 85 | { |
| 85 | } | 86 | } |
| 87 | static inline void kmemleak_update_trace(const void *ptr) | ||
| 88 | { | ||
| 89 | } | ||
| 86 | static inline void kmemleak_not_leak(const void *ptr) | 90 | static inline void kmemleak_not_leak(const void *ptr) |
| 87 | { | 91 | { |
| 88 | } | 92 | } |
diff --git a/mm/kmemleak.c b/mm/kmemleak.c index 5d4aec44982e..3cda50c1e394 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c | |||
| @@ -990,6 +990,40 @@ void __ref kmemleak_free_percpu(const void __percpu *ptr) | |||
| 990 | EXPORT_SYMBOL_GPL(kmemleak_free_percpu); | 990 | EXPORT_SYMBOL_GPL(kmemleak_free_percpu); |
| 991 | 991 | ||
| 992 | /** | 992 | /** |
| 993 | * kmemleak_update_trace - update object allocation stack trace | ||
| 994 | * @ptr: pointer to beginning of the object | ||
| 995 | * | ||
| 996 | * Override the object allocation stack trace for cases where the actual | ||
| 997 | * allocation place is not always useful. | ||
| 998 | */ | ||
| 999 | void __ref kmemleak_update_trace(const void *ptr) | ||
| 1000 | { | ||
| 1001 | struct kmemleak_object *object; | ||
| 1002 | unsigned long flags; | ||
| 1003 | |||
| 1004 | pr_debug("%s(0x%p)\n", __func__, ptr); | ||
| 1005 | |||
| 1006 | if (!kmemleak_enabled || IS_ERR_OR_NULL(ptr)) | ||
| 1007 | return; | ||
| 1008 | |||
| 1009 | object = find_and_get_object((unsigned long)ptr, 1); | ||
| 1010 | if (!object) { | ||
| 1011 | #ifdef DEBUG | ||
| 1012 | kmemleak_warn("Updating stack trace for unknown object at %p\n", | ||
| 1013 | ptr); | ||
| 1014 | #endif | ||
| 1015 | return; | ||
| 1016 | } | ||
| 1017 | |||
| 1018 | spin_lock_irqsave(&object->lock, flags); | ||
| 1019 | object->trace_len = __save_stack_trace(object->trace); | ||
| 1020 | spin_unlock_irqrestore(&object->lock, flags); | ||
| 1021 | |||
| 1022 | put_object(object); | ||
| 1023 | } | ||
| 1024 | EXPORT_SYMBOL(kmemleak_update_trace); | ||
| 1025 | |||
| 1026 | /** | ||
| 993 | * kmemleak_not_leak - mark an allocated object as false positive | 1027 | * kmemleak_not_leak - mark an allocated object as false positive |
| 994 | * @ptr: pointer to beginning of the object | 1028 | * @ptr: pointer to beginning of the object |
| 995 | * | 1029 | * |
