slab_alloc
简介
分析源码
/* mm/slub.c */
static __always_inline void *slab_alloc(struct kmem_cache *s,
gfp_t gfpflags, int node, unsigned long addr)
{
void **object;
struct kmem_cache_cpu *c;
// 判断object是否存在?如果存在,将freelist指向下一个空闲的object;如果不存在,执行__slab_alloc()
c = __this_cpu_ptr(s->cpu_slab);
object = c->freelist;
if (unlikely(!object || !node_match(c, node)))
object = __slab_alloc(s, gfpflags, node, addr, c);
else
c->freelist = get_freepointer(s, object);
// 判断gfpflags是否有__GFP_ZERO标志?如果有,将object清零;如果没有,不做任何操作;
if (unlikely(gfpflags & __GFP_ZERO) && object)
memset(object, 0, s->objsize);
// 最后返回object
return object;
}
static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
unsigned long addr, struct kmem_cache_cpu *c)
{
void **object;
struct page *new;
// 当page变量无效时,代表第一次分配object,跳转到new_slab
// 当page变量有效时,跳转到another_slab
if (!c->page)
goto new_slab;
if (unlikely(!node_match(c, node)))
goto another_slab;
load_freelist:
// 返回 page->freelist指向第一个空闲object,将freelist指向下一个空闲object
object = c->page->freelist;
if (unlikely(!object))
goto another_slab;
c->freelist = get_freepointer(s, object);
c->page->freelist = NULL;
return object;
another_slab:
// 将page变量指向的slab移动到full链表中
deactivate_slab(s, c);
new_slab:
// 尝试从partial链表获得slab
new = get_partial(s, gfpflags, node);
if (new) {
c->page = new;
goto load_freelist;
}
// 尝试从buddy分配器重新分配新slab
new = new_slab(s, gfpflags, node);
if (new) {
c = __this_cpu_ptr(s->cpu_slab);
if (c->page)
flush_slab(s, c); // 将page变量指向的slab移动到full链表中
c->page = new;
goto load_freelist;
}
// 如果执行到此处,代表内存溢出OOM,如果gfpflags有__GFP_NOWARN标志,打印错误信息;最后返回NULL
if (!(gfpflags & __GFP_NOWARN) && printk_ratelimit())
slab_out_of_memory(s, gfpflags, node);
return NULL;
}Last updated