The multiprocessor case

kmem_cache_alloc( ) first disables the local interrupts; it then looks for a free object in the cache's local array associated with the running CPU:

local_irq_save(save_flags);

cc = cachep->cpudata[smp_processor_id( )]; if (cc->avail)

objp = kmem_cache_alloc_batch(cachep, flags); if (!objp)

goto alloc_new_slab;

local_irq_restore(save_flags); return objp;

The cc local variable contains the address of the local array descriptor; thus, (cc+1) yields the address of the first local array element. If the avail field of the local array descriptor is positive, the function loads the address of the corresponding object into the objp local variable and decrements the counter. Otherwise, it invokes kmem_cache_alloc_batch( ) to repopulate the local array.

The kmem_cache_alloc_batch( ) function gets the cache spin lock and then allocates a predefined number of objects from the cache and inserts them into the local array:

count = cachep->batchcount;

spin_lock(&cachep->spinlock);

entry = cachep->slabs_partial.next; if (entry == &cachep->slabs_partial) { entry = cachep->slabs_free.next; if (entry == slabs_free)

break; list_del(entry);

list_add(entry, &cachep->slabs_partial);

slabp = list_entry(entry, slab_t, list); slabp->inuse++;

objp = & slabp->s_mem[slabp->free * cachep->objsize]; slabp->free = ((kmem_bufctl_*)(((slab_t *)slabp)+1))[slabp->free]; if (slabp->free == BUFCTL_END) { list_del(&slabp->list);

list_add(&slabp->list, &cachep->slabs_full);

spin_unlock(&cachep->spinlock); if (cc->avail)

return ((void *)(cc+1))[--cc->avail]; return NULL;

The number of pre-allocated objects is stored in the batchcount field of the cache descriptor; by default, it is half of the local array size, but the system administrator can modify it by writing into the /proc/slabinfo file. The code that gets the objects from the slabs is identical to that of the uniprocessor case, so we won't discuss it further.

The kmem_cache_alloc_batch( ) function returns NULL if the cache does not have free objects. In this case, kmem_cache_alloc( ) invokes kmem_cache_grow( ) and then repeats the whole procedure, (as in the uniprocessor case).

Was this article helpful?

0 0

Post a comment