Linux内存管理之slab分配器分析(四 申请对象kmalloc)
static void *cache_alloc_refill(struct kmem_cache *cachep, gfp_t flags)
{
int batchcount;
struct kmem_list3 *l3;
struct array_cache *ac;
int node;
retry:
check_irq_off();
/* 获取当前的NUMA节点 */
node = numa_node_id();
/* 获取local cache */
ac = cpu_cache_get(cachep);
/* 批量填充的数目 */
batchcount = ac->batchcount;
/* 如果最近未使用过该local cache,则一次填充的上限为BATCHREFILL_LIMIT个 */
if (!ac->touched && batchcount > BATCHREFILL_LIMIT) {
/*
* If there was little recent activity on this cache, then
* perform only a partial refill. Otherwise we could generate
* refill bouncing.
*/
batchcount = BATCHREFILL_LIMIT;
}
/* 获取本内存节点的kmem_list3的几个slab链表 */
l3 = cachep->nodelists[node];
BUG_ON(ac->avail > 0 || !l3);
spin_lock(&l3->list_lock);
/* See if we can refill from the shared array */
/* shared local cache 用于多核中,所有cpu共享,首先从shared中批量获取slab对象到local */
if (l3->shared && transfer_objects(ac, l3->shared, batchcount))
goto alloc_done;
/* 如果shared为空,或者已无空闲对象,则从slab链表中分配 */
while (batchcount > 0) {
struct list_head *entry;
struct slab *slabp;
/* Get slab alloc is to come from. */
/* 先从部分未满的slab链表中分配 */
entry = l3->slabs_partial.next;
/* 判断是否为空 */
if (entry == &l3->slabs_partial) {
/* 标示刚访问了空链表 */
l3->free_touched = 1;
entry = l3->slabs_free.next;
/* 如果空链表为空,则必须新增slab */
if (entry == &l3->slabs_free)
goto must_grow;
}
/* 从链表上获取到了一个slab */
slabp = list_entry(entry, struct slab, list);
check_slabp(cachep, slabp);
check_spinlock_acquired(cachep);
/*
* The slab was either on partial or free list so
* there must be at least one object available for
* allocation.
*/
BUG_ON(slabp->inuse >= cachep->num);
/* 当前slab的对象活跃数必须小于每个slab的最大对象数 */
while (slabp->inuse < cachep->num && batchcount--) {
STATS_INC_ALLOCED(cachep);
STATS_INC_ACTIVE(cachep);
STATS_SET_HIGH(cachep);
/* 从slab中提取空闲对象,将虚拟地址插入到local cache中 */
ac->entry[ac->avail++] = slab_get_obj(cachep, slabp,
node);
}
check_slabp(cachep, slabp);
/* move slabp to correct slabp list: */
/* 从原链表中删除slab */
list_del(&slabp->list);
if (slabp->free == BUFCTL_END)
/* 此slab中已经没有空闲对象,移动到full链表中 */
list_add(&slabp->list, &l3->slabs_full);
else
/* 此slab中还有空闲对象,移动到partial链表中 */
list_add(&slabp->list, &l3->slabs_partial);
}
must_grow:
/* 从slab链表中添加了avail个空闲对象到local cache中,空闲的对象数量需要更新一下 */
l3->free_objects -= ac->avail;
alloc_done:
spin_unlock(&l3->list_lock);
/* slab链表中也无空闲对象,创建新的slab */
if (unlikely(!ac->avail)) {
int x;
/* 创建空slab */
x = cache_grow(cachep, flags | GFP_THISNODE, node, NULL);
/* cache_grow can reenable interrupts, then ac could change. */
/* 看注释,由于cache_grow开启了中断,local cache指针可能发生裱花,ac需要重新获取 */
ac = cpu_cache_get(cachep);
/* 新的slab创建失败 */
if (!x && ac->avail == 0) /* no objects in sight? abort */
return NULL;
/* 新增slab成功,重新填充local cache */
if (!ac->avail) /* objects refilled by interrupt? */
goto retry;
}
/* 设置近期访问的标志 */
ac->touched = 1;
/* 返回空闲对象的地址 */
return ac->entry[--ac->avail];
}