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.mari...@arm.com>
Cc: Andrew Morton <a...@linux-foundation.org>
Cc: Johannes Weiner <han...@cmpxchg.org>
---
 Documentation/kmemleak.txt |  1 +
 include/linux/kmemleak.h   |  4 ++++
 mm/kmemleak.c              | 34 ++++++++++++++++++++++++++++++++++
 3 files changed, 39 insertions(+)

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
 kmemleak_free           - notify of a memory block freeing
 kmemleak_free_part      - notify of a partial memory block freeing
 kmemleak_free_percpu    - notify of a percpu memory block freeing
+kmemleak_update_trace   - update object allocation stack trace
 kmemleak_not_leak       - mark an object as not a leak
 kmemleak_ignore                 - do not scan or report an object as leak
 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;
 extern void kmemleak_free(const void *ptr) __ref;
 extern void kmemleak_free_part(const void *ptr, size_t size) __ref;
 extern void kmemleak_free_percpu(const void __percpu *ptr) __ref;
+extern void kmemleak_update_trace(const void *ptr) __ref;
 extern void kmemleak_not_leak(const void *ptr) __ref;
 extern void kmemleak_ignore(const void *ptr) __ref;
 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)
 static inline void kmemleak_free_percpu(const void __percpu *ptr)
 {
 }
+static inline void kmemleak_update_trace(const void *ptr)
+{
+}
 static inline void kmemleak_not_leak(const void *ptr)
 {
 }
diff --git a/mm/kmemleak.c b/mm/kmemleak.c
index 3a36e2b16cba..61a64ed2fbef 100644
--- a/mm/kmemleak.c
+++ b/mm/kmemleak.c
@@ -990,6 +990,40 @@ void __ref kmemleak_free_percpu(const void __percpu *ptr)
 EXPORT_SYMBOL_GPL(kmemleak_free_percpu);
 
 /**
+ * kmemleak_update_trace - update object allocation stack trace
+ * @ptr:       pointer to beginning of the object
+ *
+ * Override the object allocation stack trace for cases where the actual
+ * allocation place is not always useful.
+ */
+void __ref kmemleak_update_trace(const void *ptr)
+{
+       struct kmemleak_object *object;
+       unsigned long flags;
+
+       pr_debug("%s(0x%p)\n", __func__, ptr);
+
+       if (!kmemleak_enabled || IS_ERR_OR_NULL(ptr))
+               return;
+
+       object = find_and_get_object((unsigned long)ptr, 1);
+       if (!object) {
+#ifdef DEBUG
+               kmemleak_warn("Updating stack trace for unknown object at %p\n",
+                             ptr);
+#endif
+               return;
+       }
+
+       spin_lock_irqsave(&object->lock, flags);
+       object->trace_len = __save_stack_trace(object->trace);
+       spin_unlock_irqrestore(&object->lock, flags);
+
+       put_object(object);
+}
+EXPORT_SYMBOL(kmemleak_update_trace);
+
+/**
  * kmemleak_not_leak - mark an allocated object as false positive
  * @ptr:       pointer to beginning of the object
  *
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to