当array cache中没有可用的object的时候,需要批量从slab缓存中申请对象,这个时候
该函数被调用。下面分析一下这个函数。
static void *cache_alloc_refill(struct kmem_cache *cachep, gfp_t flags)
{
int batchcount;
struct kmem_list3 *l3;
struct array_cache *ac;
check_irq_off();
取得当前CPU对应的array cache.
ac = cpu_cache_get(cachep);
retry:
batchcount = ac->batchcount;
对批量申请的slab对象数进行重新调整
if (!ac->touched && batchcount > BATCHREFILL_LIMIT) {
batchcount = BATCHREFILL_LIMIT;
}
取得本节点对应的kmem_list3缓存。
l3 = cachep->nodelists[numa_node_id()];
BUG_ON(ac->avail > 0 || !l3);
对kmem_list3加锁
spin_lock(&l3->list_lock);
看看是不是在多节点环境下,并且同其他节点共享的l3缓存是不是为空,
如果不为空,则首先从同其他节点共享的array cache中进行对象分配。
if (l3->shared) {
struct array_cache *shared_array = l3->shared;
if (shared_array->avail) {
if (batchcount > shared_array->avail)
batchcount = shared_array->avail;
shared_array->avail -= batchcount;
ac->avail = batchcount;
对象拷贝
memcpy(ac->entry,
&(shared_array->entry[shared_array->avail]),
sizeof(void *) * batchcount);
shared_array->touched = 1;
goto alloc_done;
}
}
如果是单节点,或者共享节点的对象已经分配完,则从slab缓存中进行分配
while (batchcount > 0) {
struct list_head *entry;
struct slab *slabp;
分配规则:
1. 先从半满的缓存中进行分配
2. 如果半满缓存分配完。再从全部空闲的缓存中进行对象分配
entry = l3->slabs_partial.next;
if (entry == &l3->slabs_partial) {
l3->free_touched = 1;
entry = l3->slabs_free.next;
if (entry == &l3->slabs_free)
goto must_grow;
}
slabp = list_entry(entry, struct slab, list);
check_slabp(cachep, slabp);
check_spinlock_acquired(cachep);
检查slab缓存中的对象有没有被全部暂用,如果被暂用则退出这个
while循环。
while (slabp->inuse < cachep->num && batchcount--) {
STATS_INC_ALLOCED(cachep);
STATS_INC_ACTIVE(cachep);
STATS_SET_HIGH(cachep);
对象分配
ac->entry[ac->avail++] = slab_get_obj(cachep, slabp,
numa_node_id());
}
check_slabp(cachep, slabp);
将该slab从之前的链表中游离出来
list_del(&slabp->list);
如果该slab的对象全部被分配出去,则把它放到全满的链表中
否则放入半满的链表中。
if (slabp->free == BUFCTL_END)
list_add(&slabp->list, &l3->slabs_full);
else
list_add(&slabp->list, &l3->slabs_partial);
}
must_grow:
l3->free_objects -= ac->avail;
alloc_done:
spin_unlock(&l3->list_lock);
if (unlikely(!ac->avail)) {
int x;
表示slab缓存中没有足够的对象可以供分配,需要grow一下slab的大小。
x = cache_grow(cachep, flags, numa_node_id());
ac = cpu_cache_get(cachep);
如果缓存增长失败,则返回空。表示对象分配失败
if (!x && ac->avail == 0)
return NULL;
分配完之后,需要从新执行之前的操作,把缓存填满。
if (!ac->avail)
goto retry;
}
ac->touched = 1;
对象分配。
return ac->entry[--ac->avail];
}