--- include/linux/slab.h | 12 ++++++++++++ mm/slub.c | 32 +++++++++++++++++++++----------- 2 files changed, 33 insertions(+), 11 deletions(-) Index: slub/mm/slub.c =================================================================== --- slub.orig/mm/slub.c 2007-05-04 15:52:54.000000000 -0700 +++ slub/mm/slub.c 2007-05-04 15:53:11.000000000 -0700 @@ -2142,42 +2142,46 @@ EXPORT_SYMBOL(kfree); * * Return error code or number of remaining objects */ -static int __kmem_cache_vacate(struct kmem_cache *s, struct page *page) +static int __kmem_cache_vacate(struct kmem_cache *s, + struct page *page, unsigned long flags) { void *p; void *addr = page_address(page); - unsigned long map[BITS_TO_LONGS(s->objects)]; + DECLARE_BITMAP(map, s->objects); int leftover; if (!page->inuse) return 0; /* Determine free objects */ - bitmap_zero(map, s->objects); - for(p = page->freelist; p; p = get_freepointer(s, p)) - set_bit((p - addr) / s->size, map); + bitmap_fill(map, s->objects); + for (p = page->freelist; p; p = get_freepointer(s, p)) + __clear_bit((p - addr) / s->size, map); /* * Get a refcount for all used objects. If that fails then * no KICK callback can be performed. */ - for(p = addr; p < addr + s->objects * s->size; p += s->size) - if (!test_bit((p - addr) / s->size, map)) + for (p = addr; p < addr + s->objects * s->size; p += s->size) + if (test_bit((p - addr) / s->size, map)) if (!s->slab_ops->get_reference(p)) - set_bit((p - addr) / s->size, map); + __clear_bit((p - addr) / s->size, map); /* Got all the references we need. Now we can drop the slab lock */ slab_unlock(page); + local_irq_restore(flags); /* Perform the KICK callbacks to remove the objects */ for(p = addr; p < addr + s->objects * s->size; p += s->size) - if (!test_bit((p - addr) / s->size, map)) + if (test_bit((p - addr) / s->size, map)) s->slab_ops->kick_object(p); + local_irq_save(flags); slab_lock(page); leftover = page->inuse; ClearPageActive(page); putback_slab(s, page); + local_irq_restore(flags); return leftover; } @@ -2197,6 +2201,7 @@ static void remove_from_lists(struct kme */ int kmem_cache_vacate(struct page *page) { + unsigned long flags; struct kmem_cache *s; int rc = 0; @@ -2208,6 +2213,7 @@ int kmem_cache_vacate(struct page *page) if (!PageSlab(page)) goto out; + local_irq_save(flags); slab_lock(page); /* @@ -2221,6 +2227,7 @@ int kmem_cache_vacate(struct page *page) */ if (!PageSlab(page) || PageActive(page) || !page->inuse) { slab_unlock(page); + local_irq_restore(flags); goto out; } @@ -2231,7 +2238,7 @@ int kmem_cache_vacate(struct page *page) s = page->slab; remove_from_lists(s, page); SetPageActive(page); - rc = __kmem_cache_vacate(s, page) == 0; + rc = __kmem_cache_vacate(s, page, flags) == 0; out: put_page(page); return rc; @@ -2336,8 +2343,11 @@ int kmem_cache_shrink(struct kmem_cache /* Now we can free objects in the slabs on the zaplist */ list_for_each_entry_safe(page, page2, &zaplist, lru) { + unsigned long flags; + + local_irq_save(flags); slab_lock(page); - __kmem_cache_vacate(s, page); + __kmem_cache_vacate(s, page, flags); } } Index: slub/include/linux/slab.h =================================================================== --- slub.orig/include/linux/slab.h 2007-05-04 15:53:06.000000000 -0700 +++ slub/include/linux/slab.h 2007-05-04 15:53:17.000000000 -0700 @@ -42,7 +42,19 @@ struct slab_ops { void (*ctor)(void *, struct kmem_cache *, unsigned long); /* FIXME: Remove all destructors ? */ void (*dtor)(void *, struct kmem_cache *, unsigned long); + /* + * Called with slab lock held and interrupts disabled. + * No slab operations may be performed in get_reference + * + * Must return 1 if a reference was obtained. + * 0 if we failed to obtain the reference (f.e. + * the object is concurrently freed). + */ int (*get_reference)(void *); + /* + * Called with no locks held and interrupts enabled. + * Any operation may be performed in kick_object. + */ void (*kick_object)(void *); };