static void __always_inline *slab_alloc(struct kmem_cache *s,
gfp_t gfpflags, int node, void *addr)
{
void **object;
unsigned long flags;
struct kmem_cache_cpu *c;
local_irq_save(flags);
c = get_cpu_slab(s, smp_processor_id());
if (unlikely(!c->freelist || !node_match(c, node)))
object = __slab_alloc(s, gfpflags, node, addr, c);
else {
object = c->freelist;/* 如果当前的 SLAB 里的对象没有用完,就从里面取 */
c->freelist = object[c->offset]; /* 注意每个对象后面会多一块区域,指向下一个空闲对象,最后一个空闲对象的后面为 NULL ,表明此 SLAB 已经用完了 */
}
local_irq_restore(flags);
if (unlikely((gfpflags & __GFP_ZERO) && object))
memset(object, 0, c->objsize);
return object;
}
static void *__slab_alloc(struct kmem_cache *s,
gfp_t gfpflags, int node, void *addr, struct kmem_cache_cpu *c)
{
void **object;
struct page *new;
if (!c->page)
goto new_slab;
slab_lock(c->page);
if (unlikely(!node_match(c, node)))
goto another_slab;
load_freelist:
object = c->page->freelist;/* 因为有可能从下面 new_slab 标号处的分支跳转到这里,故而 freelist 可能不为空, new slab 会把 partial 或新的 slab 返回给这里 */
if (unlikely(!object))/* 当前的 SLAB 用完了就会产生这个情况,那么就要把当前的 SLAB deactivate ,然后寻找一个新的 SLAB*/
goto another_slab;
if (unlikely(SlabDebug(c->page)))
goto debug;
object = c->page->freelist;/* 下面这一段取下当前的 SLAB 的 freelist ,不管是新的还是 partial 的,将它放到 kmem_cache-> cpu_slab 上,请注意第一个空闲对象用于此次的分配,于是就被跳过去了 */
c->freelist = object[c->offset];
c->page->inuse = s->objects;
c->page->freelist = NULL;
c->node = page_to_nid(c->page);
slab_unlock(c->page);
return object;
another_slab:
deactivate_slab(s, c);
new_slab:
new = get_partial(s, gfpflags, node);/* 所有的 partial 都是放在 s->local_node 上的,即所有的 SLAB ,假设是一个 partial 的 SLAB ,即该 SLAB 不是当前的 SLAB ,但上面有部分对象在用,都是放在 kmem_cache->local_node-> partial 上的,通过该 SLAB 的首页 (Page 数据结构 ) 的 lru( 如果全部用完了,则被 deactivate 了,那么不在此 partial 链上 )*/
if (new) {
c->page = new;
goto load_freelist;/* Partial SLAB 的情况 */
}
if (gfpflags & __GFP_WAIT)
local_irq_enable();
new = new_slab(s, gfpflags, node);/* 执行到这里, partial 也用完了,所以只能申请一个新的 SLAB 了 */
if (gfpflags & __GFP_WAIT)
local_irq_disable();
if (new) {
c = get_cpu_slab(s, smp_processor_id());
if (c->page)
flush_slab(s, c);
slab_lock(new);
SetSlabFrozen(new);
c->page = new;
goto load_freelist; /* New SLAB 的情况 */
}
return NULL;
debug:
object = c->page->freelist;
if (!alloc_debug_processing(s, c->page, object, addr))
goto another_slab;
c->page->inuse++;
c->page->freelist = object[c->offset];
c->node = -1;
slab_unlock(c->page);
return object;
}
static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)
{
struct page *page;
struct kmem_cache_node *n;
void *start;
void *last;
void *p;
BUG_ON(flags & GFP_SLAB_BUG_MASK);
page = allocate_slab(s,
flags & (GFP_RECLAIM_MASK | GFP_CONSTRAINT_MASK), node);/* 此函数只是 alloc_pages 的封装,在 NUMA 的情况下,及 node 不为 -1 的情况下,在 node 对应的内存上分配内存页,这是因为 NUMA 结构下买个内存的访问速度不一定一样,所以 CPU 都倾向于访问本地内存,这样最高效 */
if (!page)
goto out;
n = get_node(s, page_to_nid(page));
if (n)
atomic_long_inc(&n->nr_slabs);
page->slab = s;
page->flags |= 1 << PG_slab;
if (s->flags & (SLAB_DEBUG_FREE | SLAB_RED_ZONE | SLAB_POISON |
SLAB_STORE_USER | SLAB_TRACE))
SetSlabDebug(page);
start = page_address(page);
if (unlikely(s->flags & SLAB_POISON))
memset(start, POISON_INUSE, PAGE_SIZE << s->order);
last = start;
for_each_object(p, s, start) {/* 这一段代码将整个 free list 构建出来,每个 object 后面都有一个指针,指向下一个 object ,第一个 object 就是首 page 的起始地址;要注意的是,第一个 object 后面的指针,被赋值了两次,第一个指向自己,第二次才指向第二个 object ,这一点写的很恶心,让我不明白了一会儿 */
setup_object(s, page, last);
set_freepointer(s, last, p);
last = p;
}
setup_object(s, page, last);
set_freepointer(s, last, NULL);/* 将最后一个 object 后面的指针置为 NULL ,这也是函数 slab_alloc 中 c->freelist 会最后为 NULL 的原因 */
page->freelist = start;
page->inuse = 0;
out:
return page;
}