2017-01-14

主要介绍partial和cpu partial的产生.
内核未定义 CONFIG_NUMA

partial没有指明是node partial还是cpu partial时, 则指的是node partial.

1. node partial的产生

在cpu0上执行newslabobjects -> new_slab, 由于可能睡眠, 之后可能运行在cpu1上. 这时若cpu1的c->page非空, 则根据情况, 可能将其放入node partial中.

linux-3.10.86/mm/slub.c

__slab_alloc
|--local_irq_save(flags);
|--freelist =new_slab_objects //buddy的page的首个obj
|    |--page = new_slab(s, flags, node); //在cpu0上
|    |--c = __this_cpu_ptr(s->cpu_slab) //进程可能迁移到cpu1上
|    |--if (c->page) flush_slab(s, c);

flush_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
|-- deactivate_slab(s, c->page, c->freelist)


static void deactivate_slab(struct kmem_cache *s, struct page *page, void *freelist)
{

    /*
     while循环前:
     obj_t2 -> obj_t1 -> NULL
     ^
     @page->freelist

     obj_03 -> obj_02 -> obj_01 -> NULL
     ^
     @freelist


     循环单次后:   
     obj_03   ->  obj_t2  -> obj_t1 -> NULL
     ^
     page->freelist 


     obj_02 -> obj_01 -> NULL
     ^
     freelist

     再来一回:
     obj_02 -> obj_03   ->  obj_t2  -> obj_t1 -> NULL
     ^
     page->freelist


     obj_01 -> NULL
     ^
     freelist

     问题:为何不直接修改指针把两个链表串起来, 而是要一个一个object的放到链表中?
     答:因为要修改counters, 所以要一个一个数.
    */
    while (freelist && (nextfree = get_freepointer(s, freelist))) {
        ...
    }

    ....

    /*
    如果这里freelist为NULL, 说明@freelist传入时就为NULL
    */
    /*把the last one也接上*/
    if (freelist) {
        new.inuse--;
        /* 
        new->freelist
        v
        obj_01 -> obj_02 -> obj_03   ->  obj_t2  -> obj_t1 -> NULL
        ^
        freelist
        */
        set_freepointer(s, freelist, old.freelist);
        new.freelist = freelist;
    } else
        ...

    new.frozen = 0;

    //有M_FREE, M_PARTIAL等情况, 这里只看M_PARTIAL
    ...

    if (m == M_PARTIAL) {
        /*问题:为何不是put_cpu_partial()?*/
        add_partial(n, page, tail);

    }

}

2. cpu partial的产生

kmem_cache_free -> slab_free(s, virt_to_head_page(x), x, ...)
|-- if (page != c->page) __slab_free
|   |--n = NULL
|   |-- 原先obj链表为: -> NULL , 释放obj_t3后为: -> obj_t3 -> NULL
|   |-- new.inuse--; 
|   |--if (!prior) && !was_frozen)new.frozen = 1;//obj_t3所属的page, 除obj_t3外, 没有其他obj可供分配了.
|   |--if (!new.inuse)&& !was_frozen) n = get_node //obj放回page后, page就是完整的, 打算把page放到node partial中
|--if (likely(!n)) //不放回node 
|   |--if (new.frozen && !was_frozen) put_cpu_partial(s, page, 1)//当前page没人接管, 则放回cpu partial

什么情况下wasfrozen会是0?
答: c->page把obj分配光了, c->page就处于unforzen状态, 接下来其他page作为c->page. 这时的page处于比较有趣的一种状态, struct kmem
cache没有字段管理这个page, struct kmemcachecpu也没有链表管理这个page. 我们只能通过obj来找到该page. 现在释放obj, 我们就有机会把这些特殊状态的page收集起来, 将其放入cpu partial.

__slab_alloc
|--page = c->page;
|--freelist = c->freelist;
|-- if freelist 为空
|   |--freelist = get_freelist(s, page);
|   |   |--/*if NULL, then unfreeze 解冻. if !NULL, then 维持frozen */
|   |   |--new.frozen = freelist != NULL;

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

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


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


blog comments powered by Disqus