当向Slab缓存中提出对象申请的请求时,首先是找到相应的kmem_cache,然后从相应的
array cache中分配slab对象。当array cache中没有对象可以分配的时候,会批量向slab
缓存中提出对象申请来填满array cache,然后再从array cache中取出一个对象分配出去。
如果从slab缓存中分配对象的时候,发现kmem_list3中半满和空闲链表中都没有节点可以供
分配:entry == &l3->slabs_partial && entry == &l3->slabs_free,表示slab对象缓存需要
增长。下面就对slab对象缓存增长的函数进行分析。
static int cache_grow(struct kmem_cache *cachep, gfp_t flags, int nodeid)
{
struct slab *slabp;
void *objp;
size_t offset;
gfp_t local_flags;
unsigned long ctor_flags;
struct kmem_list3 *l3;
标志位检查
if (flags & ~(SLAB_DMA | SLAB_LEVEL_MASK | SLAB_NO_GROW))
BUG();
if (flags & SLAB_NO_GROW)
return 0;
ctor_flags = SLAB_CTOR_CONSTRUCTOR;
local_flags = (flags & SLAB_LEVEL_MASK);
if (!(local_flags & __GFP_WAIT))
ctor_flags |= SLAB_CTOR_ATOMIC;
check_irq_off();
l3 = cachep->nodelists[nodeid];
对kmem_list3进行加锁
spin_lock(&l3->list_lock);
取当前slab的颜色
offset = l3->colour_next;
计算下一个slab的颜色
l3->colour_next++;
if (l3->colour_next >= cachep->colour)
l3->colour_next = 0;
spin_unlock(&l3->list_lock);
计算slab的着色偏移区
offset *= cachep->colour_off;
if (local_flags & __GFP_WAIT)
local_irq_enable();
kmem_flagcheck(cachep, flags);
从伙伴系统中申请页面,返回页面的虚拟地址
if (!(objp = kmem_getpages(cachep, flags, nodeid)))
goto failed;
为slab对象分配对象管理区
if (!(slabp = alloc_slabmgmt(cachep, objp, offset, local_flags)))
goto opps1;
slabp->nodeid = nodeid;
将该对象、slab缓存同页面建立联系:
【page->lru.prev 指向引用该页面的slab的指针 page->lru.prev = (struct list_head *)slab】
【page->lru.next 指向引用该页面的cache的指针 page->lru.next = (struct list_head *)cache】
set_slab_attr(cachep, slabp, objp);
对slab对象调用构造函数,并且初始化bufferctl数组。
cache_init_objs(cachep, slabp, ctor_flags);
if (local_flags & __GFP_WAIT)
local_irq_disable();
check_irq_off();
spin_lock(&l3->list_lock);
将slab管理区链入kmem_list3的空闲链表中。
list_add_tail(&slabp->list, &(l3->slabs_free));
STATS_INC_GROWN(cachep);
调整空闲对象的数量
l3->free_objects += cachep->num;
spin_unlock(&l3->list_lock);
return 1;
opps1:
kmem_freepages(cachep, objp);
failed:
if (local_flags & __GFP_WAIT)
local_irq_disable();
return 0;
}