2017-01-14

本文假定没有打开CONFIGSLUBDEBUG, 没有配置CONFIG_NUMA.

1. 什么是frozen

linux-3.10.86/mm/slub.c

 *   If a slab is frozen then it is exempt(免除) from list management. It is not
 *   on any list. It is not on any list. The processor that froze the slab is the one who can
 *   perform list operations on the page. Other processors may put objects
 *   onto the freelist but the processor that froze the slab is the only
 *   one that can retrieve the objects from the page's freelist.

cpu01的c->page是frozen, 那么cpu01可以从该page中取出或放回obj, cpu02不能从该page中取obj, 只能把obj还给该page.

2. cpu partial上的page都是frozen状态

linux-3.10.86/include/linux/slub_def.h

struct kmem_cache_cpu {
...
    struct page *partial;   /* Partially allocated frozen slabs */
    ...
};

c->partial 都是 冻住的?
答:是的:

__slab_alloc
|--new_slab:
|   |--if (c->partial) 
|   |   |--page = c->page = c->partial;
|   |   |--c->partial = page->next;
|   |   |--c->freelist = NULL;
|--redo:
|   |--freelist = c->freelist;
|--freelist = get_freelist(s, page); //obj01 -> obj02 -> obj03 -> NULL, get_freelist返回obj01
|   |--...
|   |--page->freelist = NULL;  //为后续归还obj到该page做好准备.
|   |--return page_bk->freelist;
|--load_freelist:
|   |--VM_BUG_ON(!c->page->frozen);   //c->partial上的page都是frozen的. page只有frozen的才可作为c->page
|   |-- c->freelist = get_freepointer(s, freelist);//c->freelist指向obj02
|   |-- c->tid = next_tid(c->tid);
|   |-- return freelist; //freelist指向obj01

3. node partial上的page都是unfrozen

get_partial_node
{
    list_for_each_entry_safe(page, page2, &n->partial, lru) {
        acquire_slab
        {
            VM_BUG_ON(new.frozen); //n->partial上的page都是 没有冻 的.
            new.frozen = 1;
            remove_partial(n, page);
        }
        ...
        c->page = page  or  put_cpu_partial 两相宜. page都是frozen的.
    }
}

4. c->page要求frozen

__slab_alloc
|--local_irq_save(flags);
|--freelist =new_slab_objects //buddy的page的首个obj
|   |--page = new_slab(s, flags, node); //假定在cpu0上
|   |   |--page->frozen = 1;
|   |--c = __this_cpu_ptr(s->cpu_slab) //new_slab()比较慢, 现在进程可能迁移到cpu1上
|   |--freelist = page->freelist;
|   |--page->freelist = NULL;
|   |--c->page = page; //c->page的page  其freelist 为 NULL, 且frozen 为 1.
|--goto load_freelist
|   |--That page must be frozen for per cpu allocations to work.
|   |--VM_BUG_ON(!c->page->frozen); 
|   |--修改c->freelist  c->tid
|   |--local_irq_restore(flags);
|   |--return freelist

这个设计牛逼了, 允许同时从同一个page 一端取出 , 而在另一端放回. 取出通过c->freelist;
把某obj放回, 比如把objt2放回, 通过objt2找到其所属的page, 然后放回page->freepointer, 形成链表:
objt2 -> objt1 -> NULL.

5. 耗尽c->page的obj后解冻page

static inline void *get_freelist(struct kmem_cache *s, struct page *page)
{
    VM_BUG_ON(!new.frozen);
    ... 
    /*
    if NULL, then unfreeze. 解冻
    if !NULL, then 维持frozen
    */
    new.frozen = freelist != NULL;
}

如果c->page没有obj供分配了, 那么就解冻了.

本文地址: https://awakening-fong.github.io/posts/mm/slub_frozen

转载请注明出处: https://awakening-fong.github.io


若无法评论, 请打开JavaScript, 并通过proxy.


blog comments powered by Disqus