slub: Enable backtrace for create/delete points.
Subsystems (2)
PATCH v3 1/2 slub: Enable backtrace for create/delete points.
From: Ben Greear <[email protected]>
This patch attempts to grab a backtrace for the creation and deletion points of the slub object. When a fault is detected, we can then get a better idea of where the item was deleted.
---
v3: Don't rename addr to caddr.
Move 'int i' into #ifdef block to ensure there is no warning when #ifdef'd code is not compiled.
:100644 100644 35f351f... c52fa60... M mm/slub.c
mm/slub.c | 32 ++++++++++++++++++++++++++++++++ 1 files changed, 32 insertions(+), 0 deletions(-)
mm/slub.c +32 -0
@@ -191,8 +191,12 @@ static LIST_HEAD(slab_caches);/* * Tracking user of a slab. */ +#define TRACK_ADDRS_COUNT 16struct track {unsigned long addr;/* Called from address */ +#ifdef CONFIG_STACKTRACE +unsigned long addrs[TRACK_ADDRS_COUNT ];/* Called from address */ +#endif int cpu;/* Was running on cpu */ int pid;/* Pid context */ unsigned long when;/* When did the operation occur */
@@ -420,6 +424,24 @@ static void set_track(struct kmem_cache *s, void *object,struct track *p =get_track (s, object, alloc);if (addr) { +#ifdef CONFIG_STACKTRACE +struct stack_trace trace; +int i; + + trace.nr_entries =0 ; + trace.max_entries =TRACK_ADDRS_COUNT ; + trace.entries = p->addrs; + trace.skip =3 ; +save_stack_trace (&trace); + +/* See rant in lockdep.c */ +if (trace.nr_entries !=0 && + trace.entries[trace.nr_entries -1 ] ==ULONG_MAX ) + trace.nr_entries--; + +for (i = trace.nr_entries; i <TRACK_ADDRS_COUNT ; i++) + p->addrs[i] =0 ; +#endif p->addr = addr; p->cpu =smp_processor_id (); p->pid = current->pid;
@@ -444,6 +466,16 @@ static void print_track(const char *s, struct track *t)printk (KERN_ERR "INFO: %s in %pS age=%lu cpu=%u pid=%d\n" , s, (void *)t->addr, jiffies - t->when, t->cpu, t->pid); +#ifdef CONFIG_STACKTRACE + { +int i; +for (i =0 ; i <TRACK_ADDRS_COUNT ; i++) +if (t->addrs[i]) +printk (KERN_ERR "\t%pS\n" , (void *)t->addrs[i]); +else +break ; + } +#endif }static void print_tracking (struct kmem_cache *s,void *object)
Signature · 1 line
1.7.3.4
PATCH v3 2/2 slub: Add method to verify memory is not freed.
From: Ben Greear <[email protected]>
This is for tracking down suspect memory usage.
---
v3: Move the verify_mem_not_deleted logic from slab.h to slub_dev.h
:100644 100644 c8668d1... eec67ce... M include/linux/slub_def.h
:100644 100644 c52fa60... b2dfc52... M mm/slub.c
include/linux/slub_def.h | 13 +++++++++++++ mm/slub.c | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 0 deletions(-)
include/linux/slub_def.h +13 -0
@@ -228,6 +228,19 @@ kmalloc_order(size_t size, gfp_t flags, unsigned int order)return ret; } +/** +* Calling this on allocated memory will check that the memory +* is expected to be in use, and print warnings if not. +*/ +#ifdef CONFIG_SLUB_DEBUG +extern bool verify_mem_not_deleted (const void *x); +#else +static inline bool verify_mem_not_deleted (const void *x) +{ +return true; +} +#endif +#ifdef CONFIG_TRACING extern void *kmem_cache_alloc_trace (struct kmem_cache *s,gfp_t gfpflags,size_t size);
mm/slub.c +36 -0
@@ -2960,6 +2960,42 @@ size_t ksize(const void *object) }EXPORT_SYMBOL (ksize); +#ifdef CONFIG_SLUB_DEBUG +bool verify_mem_not_deleted (const void *x) +{ +struct page *page; +void *object = (void *)x; +unsigned long flags; +bool rv; + +if (unlikely (ZERO_OR_NULL_PTR (x))) +return false; + +local_irq_save (flags); + + page =virt_to_head_page (x); +if (unlikely (!PageSlab (page))) { +/* maybe it was from stack? */ + rv = true; + goto out_unlock; + } + +slab_lock (page); +if (on_freelist (page->slab, page, object)) { +object_err (page->slab, page, object,"Object is on free-list" ); + rv = false; + }else { + rv = true; + } +slab_unlock (page); + +out_unlock: +local_irq_restore (flags); +return rv; +} +EXPORT_SYMBOL (verify_mem_not_deleted); +#endif +void kfree (const void *x) {struct page *page;
Signature · 1 line
1.7.3.4
Re: [PATCH v3 2/2] slub: Add method to verify memory is not freed.
mm/slub.c size_t ksize(const void *object) · line 2978
Quoted 13 lines · On Thu, 7 Jul 2011, [email protected] wrote:
mm/slub.c +13
-0+struct page *page; +void *object = (void *)x; +unsigned long flags; +bool rv; + +if (unlikely (ZERO_OR_NULL_PTR (x))) +return false; + +local_irq_save (flags); + + page =virt_to_head_page (x); +if (unlikely (!PageSlab (page))) { +/* maybe it was from stack? */
Or it is a compound page that was used because the allocation was larger than an order 2 alloc. Same result though.
Quoted 14 lines
mm/slub.c +13
-0+ rv = true; + goto out_unlock; + } + +slab_lock (page); +if (on_freelist (page->slab, page, object)) { +object_err (page->slab, page, object,"Object is on free-list" ); + rv = false; + }else { + rv = true; + } +slab_unlock (page); +
mm/slub.c size_t ksize(const void *object) · line 3001
Quoted 10 lines
mm/slub.c +7
-0+out_unlock: +local_irq_restore (flags); + return rv; +} +EXPORT_SYMBOL (verify_mem_not_deleted); +#endif +void kfree (const void *x) {struct page *page;
Quoted 1 line · On Thu, 7 Jul 2011, [email protected] wrote:
+#define
TRACK_ADDRS_COUNT16
16 may be a bit high. In the past we used 4 or 6 in the implementation for slab.
Quoted 36 lines · On Thu, 2011-07-07 at 11:36 -0700, [email protected] wrote:
From: Ben Greear <[email protected]>
This patch attempts to grab a backtrace for the creation and deletion points of the slub object. When a fault is detected, we can then get a better idea of where the item was deleted.
Signed-off-by Ben Greear <[email protected]>---
v3: Don't rename addr to caddr.
Move 'int i' into #ifdef block to ensure there is no warning when #ifdef'd code is not compiled.:100644 100644 35f351f... c52fa60... M
mm/slub.cmm/slub.c | 32 ++++++++++++++++++++++++++++++++ 1 files changed, 32 insertions(+), 0 deletions(-)mm/slub.c +4
-0@@ -191,8 +191,12 @@ static LIST_HEAD(slab_caches);/* * Tracking user of a slab. */ +#define TRACK_ADDRS_COUNT 16struct track {unsigned long addr;/* Called from address */ +#ifdef CONFIG_STACKTRACE +unsigned long addrs[TRACK_ADDRS_COUNT ];/* Called from address */ +#endif int cpu;/* Was running on cpu */ int pid;/* Pid context */ unsigned long when;/* When did the operation occur */
mm/slub.c static void set_track(struct kmem_cache *s, void *object, · line 428
Quoted 5 lines
mm/slub.c +2
-0@@ -420,6 +424,24 @@ static void set_track(struct kmem_cache *s, void *object,struct track *p =get_track (s, object, alloc);if (addr) { +#ifdef CONFIG_STACKTRACE +struct stack_trace trace;
This needed <linux/stacktrace.h> - I fixed it myself.
Quoted 36 lines
mm/slub.c +26
-0+int i; + + trace.nr_entries =0 ; + trace.max_entries =TRACK_ADDRS_COUNT ; + trace.entries = p->addrs; + trace.skip =3 ; +save_stack_trace (&trace); + +/* See rant in lockdep.c */ +if (trace.nr_entries !=0 && + trace.entries[trace.nr_entries -1 ] ==ULONG_MAX ) + trace.nr_entries--; + +for (i = trace.nr_entries; i <TRACK_ADDRS_COUNT ; i++) + p->addrs[i] =0 ; +#endif p->addr = addr; p->cpu =smp_processor_id (); p->pid = current->pid;@@ -444,6 +466,16 @@ static void print_track(const char *s, struct track *t)printk (KERN_ERR "INFO: %s in %pS age=%lu cpu=%u pid=%d\n" , s, (void *)t->addr, jiffies - t->when, t->cpu, t->pid); +#ifdef CONFIG_STACKTRACE + { +int i; +for (i =0 ; i <TRACK_ADDRS_COUNT ; i++) +if (t->addrs[i]) +printk (KERN_ERR "\t%pS\n" , (void *)t->addrs[i]); +else +break ; + } +#endif }static void print_tracking (struct kmem_cache *s,void *object)