Commit d06f1e21 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] slab: redzoning cleanup

slab redzoning errors are very hard to decrypt.

The patch adds a human-readable interpretation to each error and changes it
to not go BUG() when an error is detected.
parent 6dec67d3
...@@ -335,8 +335,8 @@ struct kmem_cache_s { ...@@ -335,8 +335,8 @@ struct kmem_cache_s {
/* Magic nums for obj red zoning. /* Magic nums for obj red zoning.
* Placed in the first word before and the first word after an obj. * Placed in the first word before and the first word after an obj.
*/ */
#define RED_MAGIC1 0x5A2CF071UL /* when obj is active */ #define RED_INACTIVE 0x5A2CF071UL /* when obj is inactive */
#define RED_MAGIC2 0x170FC2A5UL /* when obj is inactive */ #define RED_ACTIVE 0x170FC2A5UL /* when obj is active */
/* ...and for poisoning */ /* ...and for poisoning */
#define POISON_BEFORE 0x5a /* for use-uninitialised poisoning */ #define POISON_BEFORE 0x5a /* for use-uninitialised poisoning */
...@@ -498,6 +498,19 @@ static void cache_estimate (unsigned long gfporder, size_t size, ...@@ -498,6 +498,19 @@ static void cache_estimate (unsigned long gfporder, size_t size,
*left_over = wastage; *left_over = wastage;
} }
#if DEBUG
#define slab_error(cachep, msg) __slab_error(__FUNCTION__, cachep, msg)
static void __slab_error(char *function, kmem_cache_t *cachep, char *msg)
{
printk(KERN_ERR "slab error in %s(): cache `%s': %s\n",
function, cachep->name, msg);
dump_stack();
}
#endif
/* /*
* Start the reap timer running on the target CPU. We run at around 1 to 2Hz. * Start the reap timer running on the target CPU. We run at around 1 to 2Hz.
* Add the CPU number into the expiry time to minimize the possibility of the * Add the CPU number into the expiry time to minimize the possibility of the
...@@ -780,16 +793,19 @@ static void slab_destroy (kmem_cache_t *cachep, struct slab *slabp) ...@@ -780,16 +793,19 @@ static void slab_destroy (kmem_cache_t *cachep, struct slab *slabp)
#if DEBUG #if DEBUG
int i; int i;
for (i = 0; i < cachep->num; i++) { for (i = 0; i < cachep->num; i++) {
void* objp = slabp->s_mem+cachep->objsize*i; void *objp = slabp->s_mem + cachep->objsize * i;
if (cachep->flags & SLAB_POISON) if (cachep->flags & SLAB_POISON)
check_poison_obj(cachep, objp); check_poison_obj(cachep, objp);
if (cachep->flags & SLAB_RED_ZONE) { if (cachep->flags & SLAB_RED_ZONE) {
if (*((unsigned long*)(objp)) != RED_MAGIC1) if (*((unsigned long*)(objp)) != RED_INACTIVE)
BUG(); slab_error(cachep, "start of a freed object "
"was overwritten");
if (*((unsigned long*)(objp + cachep->objsize - if (*((unsigned long*)(objp + cachep->objsize -
BYTES_PER_WORD)) != RED_MAGIC1) BYTES_PER_WORD)) != RED_INACTIVE)
BUG(); slab_error(cachep, "end of a freed object "
"was overwritten");
objp += BYTES_PER_WORD; objp += BYTES_PER_WORD;
} }
if (cachep->dtor && !(cachep->flags & SLAB_POISON)) if (cachep->dtor && !(cachep->flags & SLAB_POISON))
...@@ -1270,9 +1286,9 @@ static void cache_init_objs (kmem_cache_t * cachep, ...@@ -1270,9 +1286,9 @@ static void cache_init_objs (kmem_cache_t * cachep,
poison_obj(cachep, objp, POISON_BEFORE); poison_obj(cachep, objp, POISON_BEFORE);
if (cachep->flags & SLAB_RED_ZONE) { if (cachep->flags & SLAB_RED_ZONE) {
*((unsigned long*)(objp)) = RED_MAGIC1; *((unsigned long*)(objp)) = RED_INACTIVE;
*((unsigned long*)(objp + cachep->objsize - *((unsigned long*)(objp + cachep->objsize -
BYTES_PER_WORD)) = RED_MAGIC1; BYTES_PER_WORD)) = RED_INACTIVE;
objp += BYTES_PER_WORD; objp += BYTES_PER_WORD;
} }
/* /*
...@@ -1285,11 +1301,13 @@ static void cache_init_objs (kmem_cache_t * cachep, ...@@ -1285,11 +1301,13 @@ static void cache_init_objs (kmem_cache_t * cachep,
if (cachep->flags & SLAB_RED_ZONE) { if (cachep->flags & SLAB_RED_ZONE) {
objp -= BYTES_PER_WORD; objp -= BYTES_PER_WORD;
if (*((unsigned long*)(objp)) != RED_MAGIC1) if (*((unsigned long*)(objp)) != RED_INACTIVE)
BUG(); slab_error(cachep, "constructor overwrote the"
" start of an object");
if (*((unsigned long*)(objp + cachep->objsize - if (*((unsigned long*)(objp + cachep->objsize -
BYTES_PER_WORD)) != RED_MAGIC1) BYTES_PER_WORD)) != RED_INACTIVE)
BUG(); slab_error(cachep, "constructor overwrote the"
" end of an object");
} }
#else #else
if (cachep->ctor) if (cachep->ctor)
...@@ -1444,13 +1462,13 @@ static inline void *cache_free_debugcheck (kmem_cache_t * cachep, void * objp) ...@@ -1444,13 +1462,13 @@ static inline void *cache_free_debugcheck (kmem_cache_t * cachep, void * objp)
if (cachep->flags & SLAB_RED_ZONE) { if (cachep->flags & SLAB_RED_ZONE) {
objp -= BYTES_PER_WORD; objp -= BYTES_PER_WORD;
if (xchg((unsigned long *)objp, RED_MAGIC1) != RED_MAGIC2) if (xchg((unsigned long *)objp, RED_INACTIVE) != RED_ACTIVE)
/* Either write before start, or a double free. */ slab_error(cachep, "double free, or memory before"
BUG(); " object was overwritten");
if (xchg((unsigned long *)(objp+cachep->objsize - if (xchg((unsigned long *)(objp+cachep->objsize -
BYTES_PER_WORD), RED_MAGIC1) != RED_MAGIC2) BYTES_PER_WORD), RED_INACTIVE) != RED_ACTIVE)
/* Either write past end, or a double free. */ slab_error(cachep, "double free, or memory after "
BUG(); " object was overwritten");
} }
objnr = (objp-slabp->s_mem)/cachep->objsize; objnr = (objp-slabp->s_mem)/cachep->objsize;
...@@ -1614,12 +1632,13 @@ cache_alloc_debugcheck_after(kmem_cache_t *cachep, ...@@ -1614,12 +1632,13 @@ cache_alloc_debugcheck_after(kmem_cache_t *cachep,
BUG(); BUG();
if (cachep->flags & SLAB_RED_ZONE) { if (cachep->flags & SLAB_RED_ZONE) {
/* Set alloc red-zone, and check old one. */ /* Set alloc red-zone, and check old one. */
if (xchg((unsigned long *)objp, RED_MAGIC2) != if (xchg((unsigned long *)objp, RED_ACTIVE) != RED_INACTIVE)
RED_MAGIC1) slab_error(cachep, "memory before object was "
BUG(); "overwritten");
if (xchg((unsigned long *)(objp+cachep->objsize - if (xchg((unsigned long *)(objp+cachep->objsize -
BYTES_PER_WORD), RED_MAGIC2) != RED_MAGIC1) BYTES_PER_WORD), RED_ACTIVE) != RED_INACTIVE)
BUG(); slab_error(cachep, "memory after object was "
"overwritten");
objp += BYTES_PER_WORD; objp += BYTES_PER_WORD;
} }
if (cachep->ctor && cachep->flags & SLAB_POISON) { if (cachep->ctor && cachep->flags & SLAB_POISON) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment