Index: linux-2.6.21-rc7-mm2/mm/slub.c =================================================================== --- linux-2.6.21-rc7-mm2.orig/mm/slub.c 2007-04-27 04:40:25.000000000 -0700 +++ linux-2.6.21-rc7-mm2/mm/slub.c 2007-04-27 04:40:29.000000000 -0700 @@ -2237,14 +2237,21 @@ int kmem_cache_shrink(struct kmem_cache * the upper limit. */ list_for_each_entry_safe(page, t, &n->partial, lru) { - if (!page->inuse) { + if (!page->inuse && slab_trylock(page)) { + /* + * Must hold slab lock here because slab_free + * may have freed the last object and be + * waiting to release the slab. + */ list_del(&page->lru); n->nr_partial--; + slab_unlock(page); discard_slab(s, page); - } else - if (n->nr_partial > MAX_PARTIAL) - list_move(&page->lru, + } else { + if (n->nr_partial > MAX_PARTIAL) + list_move(&page->lru, slabs_by_inuse + page->inuse); + } } if (n->nr_partial <= MAX_PARTIAL) @@ -2254,7 +2261,7 @@ int kmem_cache_shrink(struct kmem_cache * Rebuild the partial list with the slabs filled up * most first and the least used slabs at the end. */ - for (i = s->objects - 1; i > 0; i--) + for (i = s->objects - 1; i >= 0; i--) list_splice(slabs_by_inuse + i, n->partial.prev); out: