cache_reap(): avoid free_block for remote notes Currently when we free objects to a remote node we need to run free_block on the remote node which costs a lot of off node accesses. This patch modifies that behavior. Instead of running free_block() we simply transfer the object pointers to the shared array cache on the remote node. The remote node will either use these entries or drain them locally using free_block(). Idea by Kiran. Signed-off-by: Christoph Lameter Signed-off-by: Ravikiran G Thirumalai Index: linux-2.6.16-rc4-mm2/mm/slab.c =================================================================== --- linux-2.6.16-rc4-mm2.orig/mm/slab.c 2006-02-24 10:33:54.000000000 -0800 +++ linux-2.6.16-rc4-mm2/mm/slab.c 2006-02-28 18:40:52.000000000 -0800 @@ -182,6 +182,8 @@ SLAB_DESTROY_BY_RCU | SLAB_MEM_SPREAD) #endif +#define MAX_ALIEN 12 + /* * kmem_bufctl_t: * @@ -911,7 +913,7 @@ static struct array_cache **alloc_alien_ int i; if (limit > 1) - limit = 12; + limit = MAX_ALIEN; ac_ptr = kmalloc_node(memsize, GFP_KERNEL, node); if (ac_ptr) { for_each_node(i) { @@ -960,16 +962,52 @@ static void __drain_alien_cache(struct k */ static void reap_alien(struct kmem_cache *cachep, struct kmem_list3 *l3) { - int node = __get_cpu_var(reap_node); + struct kmem_list3 *rl3; + struct array_cache *ac; + int nr_alien; + int node; + void *aliens[MAX_ALIEN]; - if (l3->alien) { - struct array_cache *ac = l3->alien[node]; - if (ac && ac->avail) { - spin_lock_irq(&ac->lock); - __drain_alien_cache(cachep, ac, node); - spin_unlock_irq(&ac->lock); - } - } + if (!l3->alien) + return; + + ac = l3->alien[node]; + + if (!ac) + return; + + nr_alien = ac->avail; + + if (!nr_alien || !spin_trylock_irq(&ac->lock)) + return; + + /* + * Extract the alien cache so that interrupts can + * be reenabled. We are going to access off node + * items following the unlock and would not want + * those delays with interrupts disabled. + */ + memcpy(aliens, ac->entry, nr_alien * sizeof(void *)); + ac->avail = 0; + spin_unlock_irq(&ac->lock); + + node = __get_cpu_var(reap_node); + rl3 = cachep->nodelists[node]; + if (!spin_trylock(&rl3->list_lock)) + return; + + /* + * Shift alien objects into the shared arraycache + * on the remote node. + */ + while (nr_alien && ac->avail < ac->limit) + ac->entry[ac->avail++] = aliens[--nr_alien]; + + if (nr_alien) + /* Overflow requires direct use of free_block. sigh. */ + free_block(cachep, aliens, nr_alien, node); + + spin_unlock(&rl3->list_lock); } static void drain_alien_cache(struct kmem_cache *cachep,