--- include/linux/slab.h | 2 - mm/slub.c | 58 ++++++++++++++++++++++++++++++--------------------- 2 files changed, 36 insertions(+), 24 deletions(-) Index: slub/mm/slub.c =================================================================== --- slub.orig/mm/slub.c 2007-05-17 12:03:23.000000000 -0700 +++ slub/mm/slub.c 2007-05-17 12:11:07.000000000 -0700 @@ -2381,6 +2381,7 @@ static int __kmem_cache_vacate(struct km void *addr = page_address(page); DECLARE_BITMAP(map, s->objects); int leftover; + int abort = 0; printk(KERN_ERR "__kmem_cache_vacate(%s, %p, %tx) inuse=%d\n", s->name, page, flags, page->inuse); @@ -2400,33 +2401,33 @@ static int __kmem_cache_vacate(struct km int i = slab_index(p, s, addr); if (test_bit(i, map)) { - int x = s->ops->get(s, p); + int x; - if (x > 0) + if (abort) { + /* No need to handle this object */ + __clear_bit(i, map); + continue; + } + + x = s->ops->get(s, p); + + if (x > 0) { /* * Concurrent free in progress, there is no * need to do the kick call for this - * object + * object. */ __clear_bit(i, map); - - if (x >= 0) continue; - - /* - * Unfreeable object encountered. We have no chance - * to free up all objects. So free none. - * Drop refcounts. - */ - if (s->ops->put) { - while (p > addr) { - p -= s->size; - if (test_bit(slab_index(p, s, addr), - map)) - s->ops->put(s, p); - } } - goto out; + + if (x < 0) + /* + * Unfreeable object encountered. We have no chance + * to free all objects, so give up. + */ + abort = 1; + } } @@ -2445,17 +2446,29 @@ static int __kmem_cache_vacate(struct km */ for_each_object(p, s, addr) if (test_bit(slab_index(p, s, addr), map)) { - int x = s->ops->kick(s, p); + int x; + + if (abort) { + /* + * Cannot free all objects, so simply drop the + * refcounts of the remaining ones. + */ + if (s->ops->put) + s->ops->put(s, p); + continue; + } + + x = s->ops->kick(s, p); if (x < 0) /* Unfreeable object. Abort kicks */ - break; + abort = 1; } /* * Insure deletion operations have completed. */ - if (s->ops->sync) + if (s->ops->sync && !abort) s->ops->sync(); /* @@ -2463,7 +2476,6 @@ static int __kmem_cache_vacate(struct km */ local_irq_save(flags); slab_lock(page); -out: leftover = page->inuse; if (leftover > 0) /* Index: slub/include/linux/slab.h =================================================================== --- slub.orig/include/linux/slab.h 2007-05-17 12:15:01.000000000 -0700 +++ slub/include/linux/slab.h 2007-05-17 12:15:36.000000000 -0700 @@ -53,7 +53,7 @@ struct kmem_cache_ops { /* * Use to restore the reference count if we abandon the * attempt to vacate a slab page due to an unmovable - * object. + * object. No locks are held, interrupts are enabled. */ void (*put)(struct kmem_cache *, void *);