diff options
| author | Andrew Morton <akpm@osdl.org> | 2003-09-23 09:42:36 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.osdl.org> | 2003-09-23 09:42:36 -0700 |
| commit | b4aaf1ab197b6fc853256a3859ad600ad45bf075 (patch) | |
| tree | 43781622ffcfcc0ed1f07a78db7c42f49521b96d | |
| parent | 9d5fab503964c1fb814edf1f732c5ef5a9d9ac66 (diff) | |
[PATCH] slab: hexdump structures when things go wrong
From: Manfred Spraul <manfred@colorfullife.com>
- Remove cache_alloc_one_tail and cache_alloc_listfixup - there is no
reason for their existance.
- Print a bit more debugging info when slab corruption is detected.
| -rw-r--r-- | mm/slab.c | 87 |
1 files changed, 49 insertions, 38 deletions
diff --git a/mm/slab.c b/mm/slab.c index d6d1a5e5af1a..9b72c324d8c4 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -153,8 +153,9 @@ * is less than 512 (PAGE_SIZE<<3), but greater than 256. */ -#define BUFCTL_END 0xffffFFFF -#define SLAB_LIMIT 0xffffFFFE +#define BUFCTL_END 0xffffFFFF +#define BUFCTL_FREE 0xffffFFFE +#define SLAB_LIMIT 0xffffFFFD typedef unsigned int kmem_bufctl_t; /* Max number of objs-per-slab for caches which use off-slab slabs. @@ -1727,40 +1728,23 @@ static inline void check_slabp(kmem_cache_t *cachep, struct slab *slabp) /* Check slab's freelist to see if this obj is there. */ for (i = slabp->free; i != BUFCTL_END; i = slab_bufctl(slabp)[i]) { entries++; - BUG_ON(entries > cachep->num); - BUG_ON(i < 0 || i >= cachep->num); + if (entries > cachep->num || i < 0 || i >= cachep->num) + goto bad; } - BUG_ON(entries != cachep->num - slabp->inuse); -#endif -} - -static inline void * cache_alloc_one_tail (kmem_cache_t *cachep, - struct slab *slabp) -{ - void *objp; - - check_spinlock_acquired(cachep); - - STATS_INC_ALLOCED(cachep); - STATS_INC_ACTIVE(cachep); - STATS_SET_HIGH(cachep); - - /* get obj pointer */ - slabp->inuse++; - objp = slabp->s_mem + slabp->free*cachep->objsize; - slabp->free=slab_bufctl(slabp)[slabp->free]; - - return objp; -} - -static inline void cache_alloc_listfixup(struct kmem_list3 *l3, struct slab *slabp) -{ - list_del(&slabp->list); - if (slabp->free == BUFCTL_END) { - list_add(&slabp->list, &l3->slabs_full); - } else { - list_add(&slabp->list, &l3->slabs_partial); + if (entries != cachep->num - slabp->inuse) { + int i; +bad: + printk(KERN_ERR "slab: Internal list corruption detected in cache '%s'(%d), slabp %p(%d). Hexdump:\n", + cachep->name, cachep->num, slabp, slabp->inuse); + for (i=0;i<sizeof(slabp)+cachep->num*sizeof(kmem_bufctl_t);i++) { + if ((i%16)==0) + printk("\n%03x:", i); + printk(" %02x", ((unsigned char*)slabp)[i]); + } + printk("\n"); + BUG(); } +#endif } static void* cache_alloc_refill(kmem_cache_t* cachep, int flags) @@ -1811,11 +1795,31 @@ retry: slabp = list_entry(entry, struct slab, list); check_slabp(cachep, slabp); - while (slabp->inuse < cachep->num && batchcount--) - ac_entry(ac)[ac->avail++] = - cache_alloc_one_tail(cachep, slabp); + check_spinlock_acquired(cachep); + while (slabp->inuse < cachep->num && batchcount--) { + kmem_bufctl_t next; + STATS_INC_ALLOCED(cachep); + STATS_INC_ACTIVE(cachep); + STATS_SET_HIGH(cachep); + + /* get obj pointer */ + ac_entry(ac)[ac->avail++] = slabp->s_mem + slabp->free*cachep->objsize; + + slabp->inuse++; + next = slab_bufctl(slabp)[slabp->free]; +#if DEBUG + slab_bufctl(slabp)[slabp->free] = BUFCTL_FREE; +#endif + slabp->free = next; + } check_slabp(cachep, slabp); - cache_alloc_listfixup(l3, slabp); + + /* move slabp to correct slabp list: */ + list_del(&slabp->list); + if (slabp->free == BUFCTL_END) + list_add(&slabp->list, &l3->slabs_full); + else + list_add(&slabp->list, &l3->slabs_partial); } must_grow: @@ -1939,6 +1943,13 @@ static void free_block(kmem_cache_t *cachep, void **objpp, int nr_objects) list_del(&slabp->list); objnr = (objp - slabp->s_mem) / cachep->objsize; check_slabp(cachep, slabp); +#if DEBUG + if (slab_bufctl(slabp)[objnr] != BUFCTL_FREE) { + printk(KERN_ERR "slab: double free detected in cache '%s', objp %p.\n", + cachep->name, objp); + BUG(); + } +#endif slab_bufctl(slabp)[objnr] = slabp->free; slabp->free = objnr; STATS_DEC_ACTIVE(cachep); |
