2014년 7월 9일 수요일

[Linux Kernel] 61주차(2014.07.05)

ARM10C 61주차 후기

일시 : 2014.07.05 (61주차)
모임명 : NAVER개발자커뮤니티지원_IAMROOT.ORG_10차ARM-C
장소 : 토즈 타워점
장소지원 : NAVER 개발자 커뮤니티 지원 프로그램
참여인원 : 5명

스터디 진도 :

  • mm_init()을 계속 분석합니다.
  • start_kernel()-> mm_init()->kmem_cache_init()->bootstrap()분석중
  • bootstrap()은 두번 실행됩니다.
  • 1번째는 &boot_kmem_cache 매개변수를 가지고
  • 2번째는 &boot_kmem_cache_node 매개변수를 가지고 실행합니다.

main.c::mm_init()

static void __init mm_init(void)
{
    page_cgroup_init_flatmem(); // null function
    mem_init();
    // bootmem으로 관리하던 메모리를 buddy로 이관.
    // 각 section 메모리 크기를 출력.

    // mm/Makefile 에서 CONFIG_SLUB 설정으로 slub.c 로 jump
    kmem_cache_init();
// mm/Makefile 에서 CONFIG_SLUB 설정으로 slub.c 로 jump
kmem_cache_init();

slub.c::kmem_cache_init()

void __init kmem_cache_init(void)
{
...
    kmem_cache = bootstrap(&boot_kmem_cache);
kmem_cache = bootstrap(&boot_kmem_cache);

slub.c::bootstrap()

// ARM10C 20140628
// struct kmem_cache * static_cache: &boot_kmem_cache
static struct kmem_cache * __init bootstrap(struct kmem_cache *static_cache)
{
    int node;

    // kmem_cache: &boot_kmem_cache, GFP_NOWAIT: 0
    // kmem_cache_zalloc(&boot_kmem_cache, GFP_NOWAIT: 0):
    // UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address
    // kmem_cache: &boot_kmem_cache_node, GFP_NOWAIT: 0
    // kmem_cache_zalloc(&boot_kmem_cache_node, GFP_NOWAIT: 0):
    // UNMOVABLE인 page (boot_kmem_cache_node)의 object의 시작 virtual address
    struct kmem_cache *s = kmem_cache_zalloc(kmem_cache, GFP_NOWAIT);
    // s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address

    // s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
    // static_cache: &boot_kmem_cache,
    // kmem_cache->object_size: boot_kmem_cache.object_size: 116
    memcpy(s, static_cache, kmem_cache->object_size);
    // boot_kmem_cache에 세팅된 멤버 필드 값을 전부 할당 받은 object로 복사함

// 2014/06/28 종료
// 2014/07/05 시작
    // s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
    // smp_processor_id(): 0
    __flush_cpu_slab(s, smp_processor_id());
// s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
// smp_processor_id(): 0
__flush_cpu_slab(s, smp_processor_id());

slub.c::__flush_cpu_slab()

// *s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
// cpu: smp_processor_id(): 0
static inline void __flush_cpu_slab(struct kmem_cache *s, int cpu)
{
    // s->cpu_slab: (&boot_kmem_cache 용 object 주소)->cpu_slab: 0xc0502d10, cpu: 0
    // per_cpu_ptr(0xc0502d10, 0):
    // (&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
    struct kmem_cache_cpu *c = per_cpu_ptr(s->cpu_slab, cpu);
    // c: (&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)

    // c: (&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
    if (likely(c)) {
        // c->page: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->page:
        // UNMOVABLE인 page (boot_kmem_cache)
        if (c->page)
            // s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
            // c: (&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
            flush_slab(s, c);
// s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
// c: (&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
flush_slab(s, c);

slub.c::flush_slab()

// s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
// 
c: (&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
static inline void flush_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
{
    // s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
    // CPUSLAB_FLUSH: 13
    stat(s, CPUSLAB_FLUSH);

    // s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
    // c->page: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->page:
    // UNMOVABLE인 page (boot_kmem_cache),
    // c->freelist: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->freelist:
    // UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128
    deactivate_slab(s, c->page, c->freelist);
// s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
// c->page: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + per_cpu_start에서의pcpu_base_addr의 옵셋))->page:
// UNMOVABLE인 page (boot_kmem_cache),
// c->freelist: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + 
per_cpu_start에서의pcpu_base_addr의 옵셋))->freelist:
// UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128
deactivate_slab(s, c->page, c->freelist);

slub.c::deactivate_slab()

// ARM10C 20140705
// s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
// c->page: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + per_cpu_start에서의pcpu_base_addr의 옵셋))->page:
// UNMOVABLE인 page (boot_kmem_cache),
// c->freelist: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + 
per_cpu_start에서의pcpu_base_addr의 옵셋))->freelist:
// UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128
static void deactivate_slab(struct kmem_cache *s, struct page *page,
                void *freelist)
{
    enum slab_modes { M_NONE, M_PARTIAL, M_FULL, M_FREE };
    // M_NONE: 0, M_PARTIAL: 1, M_FULL: 2, M_FREE:3

    struct kmem_cache_node *n = get_node(s, page_to_nid(page));
  • page_to_nid(page)
  • // get_node(UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address, 0):
  • // (&boot_kmem_cache 용 object 주소)->node[0]
// ARM10C 20140705
static inline int page_to_nid(const struct page *page)
{
    // NODES_PGSHIFT: 0, NODES_MASK: 3
    return (page->flags >> NODES_PGSHIFT) & NODES_MASK;
}

slub.c::deactivate_slab()

static void deactivate_slab(struct kmem_cache *s, struct page *page,
                void *freelist)
{
    enum slab_modes { M_NONE, M_PARTIAL, M_FULL, M_FREE };

    struct kmem_cache_node *n = get_node(s, page_to_nid(page));
// s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
// page: UNMOVABLE인 page (boot_kmem_cache)
// page_to_nid(UNMOVABLE인 page (boot_kmem_cache)): 0
// get_node(UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address, 0):
// (&boot_kmem_cache 용 object 주소)->node[0]
struct kmem_cache_node *n = get_node(s, page_to_nid(page));

slub.c::get_node()

// ARM10C 20140705
// s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address, 0
static inline struct kmem_cache_node *get_node(struct kmem_cache *s, int node)
{
    // node: 0, s->node: (&boot_kmem_cache 용 object 주소)->node[0]
    return s->node[node];
    // return (&boot_kmem_cache 용 object 주소)->node[0]
}
get_node(s, page_to_nid(page));
// return (&boot_kmem_cache 용 object 주소)->node[0]

slub.c::deactivate_slab()

get_node(s, page_to_nid(page));
// return (&boot_kmem_cache 용 object 주소)->node[0]
static void deactivate_slab(struct kmem_cache *s, struct page *page,
                void *freelist)
{
...
    struct kmem_cache_node *n = get_node(s, page_to_nid(page));
    // n: (&boot_kmem_cache 용 object 주소)->node[0]

    int lock = 0;
    // lock: 0
    enum slab_modes l = M_NONE, m = M_NONE;
    // l: M_NONE: 0,  m: M_NONE: 0
    void *nextfree;
    int tail = DEACTIVATE_TO_HEAD;
    // tail: DEACTIVATE_TO_HEAD: 15
    struct page new;
    struct page old;

    // page->freelist: (UNMOVABLE인 page (boot_kmem_cache))->freelist: NULL
    if (page->freelist) {
        stat(s, DEACTIVATE_REMOTE_FREES);
        tail = DEACTIVATE_TO_TAIL;
    }
    // s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
    // freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128
    // get_freepointer(UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
    // UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128):
    // UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 256
    // nextfree: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 256
    while (freelist && (nextfree = get_freepointer(s, freelist))) {
        void *prior;
        unsigned long counters;

        // [loop 1] freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128
        // [loop 1] nextfree: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 256

        do {
            // [loop 1] page->freelist: NULL
            prior = page->freelist;
            // [loop 1] prior: NULL

            // [loop 1] page->counters: (UNMOVABLE인 page (boot_kmem_cache))->counters: 0x80200020
            counters = page->counters;
            // [loop 1] counters: 0x80200020

            // [loop 1] s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
            // [loop 1] freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128,
            // [loop 1] prior: NULL
            set_freepointer(s, freelist, prior);
            // [loop 1] freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128: NULL
            // [loop 1] UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128 의 다음 object를 가리키는 주소의 값을
            // [loop 1] NULL로 세팅

            // [loop 1] counters: 0x80200020
            new.counters = counters;
            // [loop 1] new.counters: 0x80200020

            // [loop 1] new.inuse: 32, new.counters: 0x80200020
            new.inuse--;
            // [loop 1] new.inuse: 31, new.counters: 0x8020001f

            // [loop 1] new.frozen: 1
            VM_BUG_ON(!new.frozen);

            // [loop 1] s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
            // [loop 1] page: UNMOVABLE인 page (boot_kmem_cache),
            // [loop 1] prior: NULL, counters: 0x80200020,
            // [loop 1] freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128,
            // [loop 1] new.counters: 0x8020001f,
            // [loop 1] "drain percpu freelist"
            // [loop 1] __cmpxchg_double_slab(UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
            // [loop 1] UNMOVABLE인 page (boot_kmem_cache), NULL, 0x80200020, UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128,
            // [loop 1] 0x8020001f, "drain percpu freelist"): 1
            // [loop 1] UNMOVABLE인 page (boot_kmem_cache)의 필드 맴버 값 변경
            // [loop 1] (UNMOVABLE인 page (boot_kmem_cache))->freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128
            // [loop 1] (UNMOVABLE인 page (boot_kmem_cache))->counters: 0x8020001f
        } while (!__cmpxchg_double_slab(s, page,
            prior, counters,
            freelist, new.counters,
            "drain percpu freelist"));
1번째 루프
// freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128
// get_freepointer(UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address, UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128):
// UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 256
// nextfree: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 256
__cmpxchg_double_slab(s, page,
prior, counters,
freelist, new.counters,
“drain percpu freelist”));

slub.c::__cmpxchg_double_slab()

// ARM10C 20140705
// s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
// page: UNMOVABLE인 page (boot_kmem_cache), prior: NULL, counters: 0x80200020
// freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128
// new.counters: 0x8020001f, “drain percpu freelist”
static inline bool __cmpxchg_double_slab(struct kmem_cache *s, struct page *page,
        void *freelist_old, unsigned long counters_old,
        void *freelist_new, unsigned long counters_new,
        const char *n)
{
    // irqs_disabled(): 1
    VM_BUG_ON(!irqs_disabled());

// CONFIG_HAVE_CMPXCHG_DOUBLE=n, CONFIG_HAVE_ALIGNED_STRUCT_PAGE=n
#if defined(CONFIG_HAVE_CMPXCHG_DOUBLE) && \
    defined(CONFIG_HAVE_ALIGNED_STRUCT_PAGE)
    if (s->flags & __CMPXCHG_DOUBLE) {
        if (cmpxchg_double(&page->freelist, &page->counters,
            freelist_old, counters_old,
            freelist_new, counters_new))
        return 1;
    } else
#endif
    {
        // page: UNMOVABLE인 page (boot_kmem_cache)
        slab_lock(page);
        // preempt count 증가 후 memory barrier 적용

        // page: UNMOVABLE인 page (boot_kmem_cache)
        // page->freelist: (UNMOVABLE인 page (boot_kmem_cache))->freelist: NULL, freelist_old: NULL,
        // page->counters: 0x80200020, counters_old: 0x80200020
        if (page->freelist == freelist_old &&
                    page->counters == counters_old) {
            // freelist_new: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128
            page->freelist = freelist_new;
            // page->freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128

            // page->counters: 0x80200020, counters_new: 0x8020001f
            page->counters = counters_new;
            // page->counters: 0x8020001f

            // page: UNMOVABLE인 page (boot_kmem_cache)
            slab_unlock(page);
            // (MIGRATE_UNMOVABLE인 page(boot_kmem_cache))->flags 의 bit 0을 클리어함
            // dmb(ish)를 사용하여 공유 자원 (MIGRATE_UNMOVABLE인 page)->flags 값을 갱신
            // memory barrier 적용 후 preempt count 감소 시킴

            return 1;
            // return 1
        }
        slab_unlock(page);
    }

    cpu_relax();
    stat(s, CMPXCHG_DOUBLE_FAIL);

#ifdef SLUB_DEBUG_CMPXCHG
    printk(KERN_INFO "%s %s: cmpxchg double redo ", n, s->name);
#endif

    return 0;
}
// return 1

slub.c::deactivate_slab()

1번째 루프
// freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128
// get_freepointer(UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address, UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128):
// UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 256
// nextfree: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 256
// return 1
while (freelist && (nextfree = get_freepointer(s, freelist))) {
2번째 루프
static void deactivate_slab(struct kmem_cache *s, struct page *page,
                void *freelist)
{
...
    while (freelist && (nextfree = get_freepointer(s, freelist))) {
        void *prior;
        unsigned long counters;

        // [loop 2] freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 256
        // [loop 2] nextfree: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 384

        do {
            // [loop 2] page->freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128
            prior = page->freelist;
            // [loop 2] prior: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128

            // [loop 2] page->counters: (UNMOVABLE인 page (boot_kmem_cache))->counters: 0x8020001f
            counters = page->counters;
            // [loop 2] counters: 0x8020001f

            // [loop 2] s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
            // [loop 2] freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 256,
            // [loop 2] prior: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128
            set_freepointer(s, freelist, prior);
            // [loop 2] freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 256:
            // [loop 2] UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128,
            // [loop 2] UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 256 의 다음 object를 가리키는 주소의 값을
            // [loop 2] 이전 object 주소로 세팅

            // [loop 2] counters: 0x8020001f
            new.counters = counters;
            // [loop 2] new.counters: 0x8020001f

            // [loop 2] new.inuse: 31, new.counters: 0x8020001f
            new.inuse--;
            // [loop 2] new.inuse: 30, new.counters: 0x8020001e

            // [loop 2] new.frozen: 1
            VM_BUG_ON(!new.frozen);

            // [loop 2] s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
            // [loop 2] page: UNMOVABLE인 page (boot_kmem_cache),
            // [loop 2] prior: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128, counters: 0x8020001f,
            // [loop 2] freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 256,
            // [loop 2] new.counters: 0x8020001e,
            // [loop 2] "drain percpu freelist"
            // [loop 2] __cmpxchg_double_slab(UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
            // [loop 2] UNMOVABLE인 page (boot_kmem_cache), UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128,
            // [loop 2] 0x8020001f, UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 256, 0x8020001e, "drain percpu freelist"): 1
            // [loop 2] UNMOVABLE인 page (boot_kmem_cache)의 필드 맴버 값 변경
            // [loop 2] (UNMOVABLE인 page (boot_kmem_cache))->freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 256
            // [loop 2] (UNMOVABLE인 page (boot_kmem_cache))->counters: 0x8020001e
        } while (!__cmpxchg_double_slab(s, page,
            prior, counters,
            freelist, new.counters,
            "drain percpu freelist"));
while (!__cmpxchg_double_slab(s, page,
prior, counters,
freelist, new.counters,
“drain percpu freelist”));

slub.c::__cmpxchg_double_slab()

deactivate_slab()에서 while문으로 2번째 루프
// s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
// page: UNMOVABLE인 page (boot_kmem_cache),
// old.freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968,
// old.counters: 0x80200001,
// new.freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968,
// new.counters: 0x00200000,
// “unfreezing slab”
static inline bool __cmpxchg_double_slab(struct kmem_cache *s, struct page *page,
        void *freelist_old, unsigned long counters_old,
        void *freelist_new, unsigned long counters_new,
        const char *n)
{
    // irqs_disabled(): 1
    VM_BUG_ON(!irqs_disabled());

// CONFIG_HAVE_CMPXCHG_DOUBLE=n, CONFIG_HAVE_ALIGNED_STRUCT_PAGE=n
#if defined(CONFIG_HAVE_CMPXCHG_DOUBLE) && \
    defined(CONFIG_HAVE_ALIGNED_STRUCT_PAGE)
    if (s->flags & __CMPXCHG_DOUBLE) {
        if (cmpxchg_double(&page->freelist, &page->counters,
            freelist_old, counters_old,
            freelist_new, counters_new))
        return 1;
    } else
#endif
    {
        // page: UNMOVABLE인 page (boot_kmem_cache)
        slab_lock(page);
        // preempt count 증가 후 memory barrier 적용

        // page: UNMOVABLE인 page (boot_kmem_cache)
        // page->freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968,
        // freelist_old: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968,
        // page->counters: 0x80200001, counters_old: 0x80200001
        if (page->freelist == freelist_old &&
                    page->counters == counters_old) {
            // freelist_new: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968
            page->freelist = freelist_new;
            // page->freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968

            // page->counters: 0x80200001, counters_new: 0x00200000
            page->counters = counters_new;
            // page->counters: 0x00200000

            // page: UNMOVABLE인 page (boot_kmem_cache)
            slab_unlock(page);
            // (MIGRATE_UNMOVABLE인 page(boot_kmem_cache))->flags 의 bit 0을 클리어함
            // dmb(ish)를 사용하여 공유 자원 (MIGRATE_UNMOVABLE인 page)->flags 값을 갱신
            // memory barrier 적용 후 preempt count 감소 시킴

            return 1;
            // return 1
        }
        slab_unlock(page);
    }
...
}
retrun 1

slub.c::deactivate_slab()

  • while문에서는
    • 해당 object를 freelist의 위치를 이동한다.
  • do~while은 해당 object의 다음 위치를 가리키는 값을 null로 만들고,
  • 다른 속성도 초기화 한 후에,
  • __cmpxchg_double_slab()를 통해서 이것이 맞게 되었는지 확인되면 1을 반환하여
    • UNMOVABLE인 page (boot_kmem_cache) 의 사용하지 않는 첫 번째 object의 freepointer 값을 NULL 로 변경,
    • 나머지 object들의 freepointer 값을 이전 object들의 주소로 변경
    • UNMOVABLE인 page (boot_kmem_cache) 이 맴버필드 변경
    • (UNMOVABLE인 page (boot_kmem_cache))->freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968
    • (UNMOVABLE인 page (boot_kmem_cache))->counters: 0x80200001
  • [loop 3 … 30] 번 반복 실행한다.
redo:

    // page->freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968
    old.freelist = page->freelist;
    // old.freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968

    // page->counters: (UNMOVABLE인 page (boot_kmem_cache))->counters: 0x80200001
    old.counters = page->counters;
    // old.counters: 0x80200001

    // old.frozen: 1
    VM_BUG_ON(!old.frozen);

    /* Determine target state of the slab */
    // old.counters: 0x80200001
    new.counters = old.counters;
    // new.counters: 0x80200001

    // freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968
    if (freelist) {
        // new.inuse: 1
        new.inuse--;
        // new.inuse: 0, new.counters: 0x80200000

        // s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
        // freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968
        // old.freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968
        set_freepointer(s, freelist, old.freelist);
// s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
// freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968
// old.freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968
set_freepointer(s, freelist, old.freelist);

slub.c::set_freepointer()

// ARM10C 20140705
// s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
// freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128,
// prior: NULL
static inline void set_freepointer(struct kmem_cache *s, void *object, void *fp)
{
    // object: UNMOVABLE인 page 의 virtual address
    // s->offset: (&boot_kmem_cache_node)->offset: 0
    // fp: UNMOVABLE인 page 의 virtual address
    *(void **)(object + s->offset) = fp;
    // object: UNMOVABLE인 page 의 virtual address(boot_kmem_cache)
}

slub.c::deactivate_slab()

static void deactivate_slab(struct kmem_cache *s, struct page *page,
                void *freelist)
{
...
redo:
...
    if (freelist) {
        // new.inuse: 1
        new.inuse--;
        // new.inuse: 0, new.counters: 0x80200000

        // s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
        // freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968
        // old.freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968
        set_freepointer(s, freelist, old.freelist);
        // UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968 의 다음 object를 가리키는 주소의 값을
        // UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968 로 세팅
        // freepointer의 주소를 자신의 object 주소로 변경

        // freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968
        new.freelist = freelist;
        // new.freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968
    } else
        new.freelist = old.freelist;

    // new.frozen: 1
    new.frozen = 0;
    // new.frozen: 0, new.counters: 0x00200000

    // n: (&boot_kmem_cache 용 object 주소)->node[0]:
    // boot_kmem_cache_node 로 할당 받은 2 번째 object의 주소

    // new.inuse: 0, n->nr_partial: 0, s->min_partial: (&boot_kmem_cache 용 object 주소)->min_partial: 5
    // new.freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968
    if (!new.inuse && n->nr_partial > s->min_partial)
        m = M_FREE;
    else if (new.freelist) {
        // m: M_NONE: 0
        m = M_PARTIAL;
        // m: M_PARTIAL: 1

        // lock: 0
        if (!lock) {
            // lock: 0
            lock = 1;
            // lock: 1
            /*
             * Taking the spinlock removes the possiblity
             * that acquire_slab() will see a slab page that
             * is frozen
             */
            spin_lock(&n->list_lock);
            // n->list_lock 을 이용한 spin_lock 획득
        }
    } else {
        m = M_FULL;
        if (kmem_cache_debug(s) && !lock) {
            lock = 1;
            /*
             * This also ensures that the scanning of full
             * slabs from diagnostic functions will not see
             * any frozen slabs.
             */
            spin_lock(&n->list_lock);
        }
    }

    // l: M_NONE: 0, m: M_PARTIAL: 1
    if (l != m) {

        // l: M_NONE: 0, m: M_PARTIAL: 1
        if (l == M_PARTIAL)

            remove_partial(n, page);

        else if (l == M_FULL)

            remove_full(s, page);

        if (m == M_PARTIAL) {

            // n: (&boot_kmem_cache 용 object 주소)->node[0]:
            // boot_kmem_cache_node 로 할당 받은 2 번째 object의 주소,
            // page: UNMOVABLE인 page (boot_kmem_cache),
            // tail: DEACTIVATE_TO_HEAD: 15
            add_partial(n, page, tail);
// n: (&boot_kmem_cache 용 object 주소)->node[0]:
// boot_kmem_cache_node 로 할당 받은 2 번째 object의 주소,
// page: UNMOVABLE인 page (boot_kmem_cache),
// tail: DEACTIVATE_TO_HEAD: 15
add_partial(n, page, tail);

slub.c::add_partial()

// ARM10C 20140705
// n: (&boot_kmem_cache 용 object 주소)->node[0]:
// boot_kmem_cache_node 로 할당 받은 2 번째 object의 주소,
// page: UNMOVABLE인 page (boot_kmem_cache),
// tail: DEACTIVATE_TO_HEAD: 15
static inline void add_partial(struct kmem_cache_node *n,
                struct page *page, int tail)
{
    // n: UNMOVABLE인 page 의 object의 시작 virtual address,

    // n->nr_partial: 0
    n->nr_partial++;
    // n->nr_partial: 1

    // tail: DEACTIVATE_TO_HEAD: 15, DEACTIVATE_TO_TAIL: 16
    if (tail == DEACTIVATE_TO_TAIL)
        list_add_tail(&page->lru, &n->partial);
    else
        // page->lru: (UNMOVABLE인 page)->lru, n->partial: NULL
        list_add(&page->lru, &n->partial);
        // n->partial에 (UNMOVABLE인 page)->lru 가 추가됨
}

add_partial 한일:

n->nr_partial: 1
n->partial에 (UNMOVABLE인 page (boot_kmem_cache))->lru 가 추가됨

slub.c::deactivate_slab()

static void deactivate_slab(struct kmem_cache *s, struct page *page,
                void *freelist)
{
...
redo:
...
    // l: M_NONE: 0, m: M_PARTIAL: 1
    if (l != m) {

        // l: M_NONE: 0, m: M_PARTIAL: 1
        if (l == M_PARTIAL)

            remove_partial(n, page);

        else if (l == M_FULL)

            remove_full(s, page);

        if (m == M_PARTIAL) {

            // n: (&boot_kmem_cache 용 object 주소)->node[0]:
            // boot_kmem_cache_node 로 할당 받은 2 번째 object의 주소,
            // page: UNMOVABLE인 page (boot_kmem_cache),
            // tail: DEACTIVATE_TO_HEAD: 15
            add_partial(n, page, tail);
            // add_partial 한일:
            // n->nr_partial: 1
            // n->partial에 (UNMOVABLE인 page (boot_kmem_cache))->lru 가 추가됨

            // s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
            // tail: DEACTIVATE_TO_HEAD: 15
            stat(s, tail);

        } else if (m == M_FULL) {

            stat(s, DEACTIVATE_FULL);
            add_full(s, n, page);

        }
    }

    // l: M_NONE: 0, m: M_PARTIAL: 1
    l = m;
    // l: M_PARTIAL: 1

    // s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
    // page: UNMOVABLE인 page (boot_kmem_cache),
    // old.freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968
    // old.counters: 0x80200001
    // new.freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968
    // new.counters: 0x00200000
    // "unfreezing slab"
    // __cmpxchg_double_slab(UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
    // UNMOVABLE인 page (boot_kmem_cache), UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968,
    // 0x80200001, UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968,
    // 0x00200000, "unfreezing slab"): 1
    // UNMOVABLE인 page (boot_kmem_cache)의 필드 맴버 값 변경
    // (UNMOVABLE인 page (boot_kmem_cache))->freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968
    // (UNMOVABLE인 page (boot_kmem_cache))->counters: 0x00200000
    if (!__cmpxchg_double_slab(s, page,
                old.freelist, old.counters,
                new.freelist, new.counters,
                "unfreezing slab"))
        goto redo;

    // lock: 1
    if (lock)
        spin_unlock(&n->list_lock);
        // n->list_lock 을 이용한 spin_lock 해재

    // m: M_PARTIAL: 1
    if (m == M_FREE) {
        stat(s, DEACTIVATE_EMPTY);
        discard_slab(s, page);
        stat(s, FREE_SLAB);
    }
}

deactivate_slab에서 한일:

  • UNMOVABLE인 page (boot_kmem_cache)의 필드 맴버 값 변경
  • (UNMOVABLE인 page (boot_kmem_cache))->counters: 0x00200000
  • (UNMOVABLE인 page (boot_kmem_cache))->freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968
  • (UNMOVABLE인 page (boot_kmem_cache)) 의 object들의 freepointer 값 변경
  • (사용하지 않는 첫 번째 object의 freepointer 값을 NULL 로 변경, 나머지 object들의 freepointer 값을 이전 object들의 주소로 변경)
예시) s->offset이 0이고 slab object 시작 주소가 0x10001000 일 경우
------------------------------------------------------------------------------------------------------------------------------------------
| Slab object 0 (사용중)  | Slab object 1           | Slab object 2           | Slab object 3           | .... | Slab object 31          |
------------------------------------------------------------------------------------------------------------------------------------------
| object start address:   | object start address:   | object start address:   | object start address:   |      | object start address:   |
| 0x10001000              | 0x10001080              | 0x10001100              | 0x10001180              | .... | 0x10001f80              |
------------------------------------------------------------------------------------------------------------------------------------------
| freepointer | data      | freepointer | data      | freepointer | data      | freepointer | data      | .... | freepointer | data      |
------------------------------------------------------------------------------------------------------------------------------------------
| 0x10001080  | 124 Bytes | null        | 124 Bytes | 0x10001080  | 124 Bytes | 0x10001100  | 124 Bytes | .... | 0x10001f80  | 124 Bytes |
------------------------------------------------------------------------------------------------------------------------------------------
  • n: (&boot_kmem_cache 용 object 주소)->node[0]:
  • boot_kmem_cache_node 로 할당 받은 2 번째 object의 주소
  • n->nr_partial: 1
  • n->partial에 (UNMOVABLE인 page (boot_kmem_cache))->lru 가 추가됨

slub.c::flush_slab()

// deactivate_slab(s, c->page, c->freelist);
static inline void flush_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
{
    stat(s, CPUSLAB_FLUSH);

    deactivate_slab(s, c->page, c->freelist);

    // c->tid: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->tid: 4
    // next_tid(4): 8
    c->tid = next_tid(c->tid);
    // c->tid: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->tid: 8

    c->page = NULL;
    // c->page: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->page: NULL

    c->freelist = NULL;
    // c->freelist: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->freelist: NULL
}

flush_slab 이 한일:

  • UNMOVABLE인 page (boot_kmem_cache)의 필드 맴버 값 변경
  • (UNMOVABLE인 page (boot_kmem_cache))->counters: 0x00200000
  • (UNMOVABLE인 page (boot_kmem_cache))->freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968
  • (UNMOVABLE인 page (boot_kmem_cache)) 의 object들의 freepointer 값 변경
  • (사용하지 않는 첫 번째 object의 freepointer 값을 NULL 로 변경, 나머지 object들의 freepointer 값을 이전 object들의 주소로 변경)
에) s->offset이 0이고 slab object 시작 주소가 0x10001000 일 경우
| Slab object 0 (사용중)  | Slab object 1           | Slab object 2           | Slab object 3           | .... | Slab object 31          |
------------------------------------------------------------------------------------------------------------------------------------------
| object start address:   | object start address:   | object start address:   | object start address:   |      | object start address:   |
| 0x10001000              | 0x10001080              | 0x10001100              | 0x10001180              | .... | 0x10001f80              |
------------------------------------------------------------------------------------------------------------------------------------------
| freepointer | data      | freepointer | data      | freepointer | data      | freepointer | data      | .... | freepointer | data      |
------------------------------------------------------------------------------------------------------------------------------------------
| 0x10001080  | 124 Bytes | null        | 124 Bytes | 0x10001080  | 124 Bytes | 0x10001100  | 124 Bytes | .... | 0x10001f80  | 124 Bytes |
------------------------------------------------------------------------------------------------------------------------------------------
  • n: (&boot_kmem_cache 용 object 주소)->node[0]:
  • boot_kmem_cache_node 로 할당 받은 2 번째 object의 주소
  • n->nr_partial: 1
  • n->partial에 (UNMOVABLE인 page (boot_kmem_cache))->lru 가 추가됨
    *
  • c: (&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
  • c->tid: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->tid: 8
  • c->page: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->page: NULL
  • c->freelist: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->freelist: NULL

slub.c::__flush_cpu_slab()

static inline void __flush_cpu_slab(struct kmem_cache *s, int cpu)
{
    struct kmem_cache_cpu *c = per_cpu_ptr(s->cpu_slab, cpu);

    if (likely(c)) {
        // c->page: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->page:
        // UNMOVABLE인 page (boot_kmem_cache)
        if (c->page)
            // s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
            // c: (&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
            flush_slab(s, c);

        // s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
        // c: (&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
        unfreeze_partials(s, c);
    }
}
// s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
// c: (&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
unfreeze_partials(s, c);

slub.c::unfreeze_partials()

// ARM10C 20140705
// s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
// c: (&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
static void unfreeze_partials(struct kmem_cache *s,
        struct kmem_cache_cpu *c)
{
#ifdef CONFIG_SLUB_CPU_PARTIAL // CONFIG_SLUB_CPU_PARTIAL=y
    struct kmem_cache_node *n = NULL, *n2 = NULL;
    struct page *page, *discard_page = NULL;

    // c->partial: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->partial: NULL
    // page: NULL
    while ((page = c->partial)) {
        struct page new;
        struct page old;

        c->partial = page->next;

        n2 = get_node(s, page_to_nid(page));
        if (n != n2) {
            if (n)
                spin_unlock(&n->list_lock);

            n = n2;
            spin_lock(&n->list_lock);
        }

        do {

            old.freelist = page->freelist;
            old.counters = page->counters;
            VM_BUG_ON(!old.frozen);

            new.counters = old.counters;
            new.freelist = old.freelist;

            new.frozen = 0;

        } while (!__cmpxchg_double_slab(s, page,
                old.freelist, old.counters,
                new.freelist, new.counters,
                "unfreezing slab"));

        if (unlikely(!new.inuse && n->nr_partial > s->min_partial)) {
            page->next = discard_page;
            discard_page = page;
        } else {
            add_partial(n, page, DEACTIVATE_TO_TAIL);
            stat(s, FREE_ADD_PARTIAL);
        }
    }

    // n: NULL
    if (n)
        spin_unlock(&n->list_lock);

    // discard_page: NULL
    while (discard_page) {
        page = discard_page;
        discard_page = discard_page->next;

        stat(s, DEACTIVATE_EMPTY);
        discard_slab(s, page);
        stat(s, FREE_SLAB);
    }
#endif
}
동작을 보면 null function이다.
c->partial 에 값이 있을때 이 함수는 실행된다.
따라서 slub.c::__flush_cpu_slab()를 끝내고 bootstrap()으로 이동한다.

__flush_cpu_slab()에서 한일

  • UNMOVABLE인 page (boot_kmem_cache)의 필드 맴버 값 변경
  • (UNMOVABLE인 page (boot_kmem_cache))->counters: 0x00200000
  • (UNMOVABLE인 page (boot_kmem_cache))->freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968
  • (UNMOVABLE인 page (boot_kmem_cache)) 의 object들의 freepointer 값 변경
  • (사용하지 않는 첫 번째 object의 freepointer 값을 NULL 로 변경, 나머지 object들의 freepointer 값을 이전 object들의 주소로 변경)
에) s->offset이 0이고 slab object 시작 주소가 0x10001000 일 경우
------------------------------------------------------------------------------------------------------------------------------------------
| Slab object 0 (사용중)  | Slab object 1           | Slab object 2           | Slab object 3           | .... | Slab object 31          |
------------------------------------------------------------------------------------------------------------------------------------------
| object start address:   | object start address:   | object start address:   | object start address:   |      | object start address:   |
| 0x10001000              | 0x10001080              | 0x10001100              | 0x10001180              | .... | 0x10001f80              |
------------------------------------------------------------------------------------------------------------------------------------------
| freepointer | data      | freepointer | data      | freepointer | data      | freepointer | data      | .... | freepointer | data      |
------------------------------------------------------------------------------------------------------------------------------------------
| 0x10001080  | 124 Bytes | null        | 124 Bytes | 0x10001080  | 124 Bytes | 0x10001100  | 124 Bytes | .... | 0x10001f80  | 124 Bytes |
------------------------------------------------------------------------------------------------------------------------------------------
  • n: (&boot_kmem_cache 용 object 주소)->node[0]:
  • boot_kmem_cache_node 로 할당 받은 page의 2 번째 object의 주소
  • n->nr_partial: 1
  • n->partial에 (UNMOVABLE인 page (boot_kmem_cache))->lru 가 추가됨
  • c: (&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
  • c->tid: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->tid: 8
  • c->page: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->page: NULL
  • c->freelist: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->freelist: NULL

slub.c::bootstrap()

__flush_cpu_slab(s, smp_processor_id());
static struct kmem_cache * __init bootstrap(struct kmem_cache *static_cache)
{
    int node;
    struct kmem_cache *s = kmem_cache_zalloc(kmem_cache, GFP_NOWAIT);
    memcpy(s, static_cache, kmem_cache->object_size);
    __flush_cpu_slab(s, smp_processor_id());

    for_each_node_state(node, N_NORMAL_MEMORY) {
    // for ( (node) = 0; (node) == 0; (node) = 1)

        // s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address, node: 0
        // get_node(UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address, 0):
        // (&boot_kmem_cache 용 object 주소)->node[0]: boot_kmem_cache_node 로 할당 받은 2 번째 object의 주소
        struct kmem_cache_node *n = get_node(s, node);
        // n: boot_kmem_cache_node 로 할당 받은 page의 2 번째 object의 주소
        struct page *p;

        // n: boot_kmem_cache_node 로 할당 받은 page의 2 번째 object의 주소
        if (n) {
            list_for_each_entry(p, &n->partial, lru)
            // for (p = list_first_entry(&n->partial, typeof(*p), lru);
            //      &p->lru != (&n->partial); p = list_next_entry(p, lru))

                // p: UNMOVABLE인 page (boot_kmem_cache)

                // p->slab_cache: (UNMOVABLE인 page (boot_kmem_cache))->slab_cache
                // s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address
                p->slab_cache = s;
                // p->slab_cache: (UNMOVABLE인 page (boot_kmem_cache))->slab_cache:
                // UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address

#ifdef CONFIG_SLUB_DEBUG // CONFIG_SLUB_DEBUG=y
            list_for_each_entry(p, &n->full, lru)
            // for (p = list_first_entry(&n->full, typeof(*p), lru);
            //      &p->lru != (&n->full); p = list_next_entry(p, lru))

                p->slab_cache = s;
#endif
        }
    }

    // s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address
    list_add(&s->list, &slab_caches);
    // slab_caches 의 list에 (UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address)->list를 등록

    // s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address
    return s;
    // return UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address
}
retrun
kmem_cache: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address

bootstrab()이 한 일.

  • UNMOVABLE인 page (boot_kmem_cache)의 필드 맴버 값 변경
  • (UNMOVABLE인 page (boot_kmem_cache))->counters: 0x00200000
  • (UNMOVABLE인 page (boot_kmem_cache))->freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968
  • (UNMOVABLE인 page (boot_kmem_cache)) 의 object들의 freepointer 값 변경
  • (사용하지 않는 첫 번째 object의 freepointer 값을 NULL 로 변경, 나머지 object들의 freepointer 값을 이전 object들의 주소로 변경)
에) s->offset이 0이고 slab object 시작 주소가 0x10001000 일 경우
------------------------------------------------------------------------------------------------------------------------------------------
| Slab object 0 (사용중)  | Slab object 1           | Slab object 2           | Slab object 3           | .... | Slab object 31          |
------------------------------------------------------------------------------------------------------------------------------------------
| object start address:   | object start address:   | object start address:   | object start address:   |      | object start address:   |
| 0x10001000              | 0x10001080              | 0x10001100              | 0x10001180              | .... | 0x10001f80              |
------------------------------------------------------------------------------------------------------------------------------------------
| freepointer | data      | freepointer | data      | freepointer | data      | freepointer | data      | .... | freepointer | data      |
------------------------------------------------------------------------------------------------------------------------------------------
| 0x10001080  | 124 Bytes | null        | 124 Bytes | 0x10001080  | 124 Bytes | 0x10001100  | 124 Bytes | .... | 0x10001f80  | 124 Bytes |
------------------------------------------------------------------------------------------------------------------------------------------
  • n: (&boot_kmem_cache 용 object 주소)->node[0]:
  • boot_kmem_cache_node 로 할당 받은 page의 2 번째 object의 주소
  • n->nr_partial: 1
  • n->partial에 (UNMOVABLE인 page (boot_kmem_cache))->lru 가 추가됨
  • c: (&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
  • c->tid: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->tid: 8
  • c->page: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->page: NULL
  • c->freelist: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->freelist: NULL
  • p->slab_cache: (UNMOVABLE인 page (boot_kmem_cache))->slab_cache:
  • UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address
  • slab_caches 의 list에 (UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address)->list를 등록

slub.c::kmem_cache_init()

kmem_cache = bootstrap(&boot_kmem_cache);
void __init kmem_cache_init(void)
{
...
    create_boot_cache(kmem_cache, "kmem_cache",
            offsetof(struct kmem_cache, node) +
                nr_node_ids * sizeof(struct kmem_cache_node *),
               SLAB_HWCACHE_ALIGN);
    kmem_cache = bootstrap(&boot_kmem_cache);

    kmem_cache_node = bootstrap(&boot_kmem_cache_node);
// &boot_kmem_cache_node
kmem_cache_node = bootstrap(&boot_kmem_cache_node);

slub.c::bootstrap()

// ARM10C 20140705
// &boot_kmem_cache_node
static struct kmem_cache * __init bootstrap(struct kmem_cache *static_cache)
{
    int node;

    // kmem_cache: &boot_kmem_cache_node, GFP_NOWAIT: 0
    // kmem_cache_zalloc(&boot_kmem_cache_node, GFP_NOWAIT: 0):
    // UNMOVABLE인 page (boot_kmem_cache_node)의 object의 시작 virtual address
    struct kmem_cache *s = kmem_cache_zalloc(kmem_cache, GFP_NOWAIT);
// kmem_cache: &boot_kmem_cache_node, GFP_NOWAIT: 0
// kmem_cache_zalloc(&boot_kmem_cache_node, GFP_NOWAIT: 0):
// UNMOVABLE인 page (boot_kmem_cache_node)의 object의 시작 virtual address
struct kmem_cache *s = kmem_cache_zalloc(kmem_cache, GFP_NOWAIT);

slub.c::kmem_cache_zalloc()

// ARM10C 20140705
// k: &boot_kmem_cache_node, flags: __GFP_ZERO: 0x8000u
void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags)
{
    // s: &boot_kmem_cache_node, gfpflags: __GFP_ZERO: 0x8000
    // slab_alloc(&boot_kmem_cache_node, __GFP_ZERO: 0x8000): UNMOVABLE인 page (boot_kmem_cache_node)의 object의 시작 virtual address
    void *ret = slab_alloc(s, gfpflags, _RET_IP_);
// s: &boot_kmem_cache_node, gfpflags: GFP_ZERO: 0x8000
// slab_alloc(&boot_kmem_cache_node, 
GFP_ZERO: 0x8000): UNMOVABLE인 page (boot_kmem_cache_node)의 object의 시작 virtual address
void *ret = slaballoc(s, gfpflags, _RET_IP);

slub.c::slab_alloc()

// ARM10C 20140705
// s: &bootkmem_cache_node, gfpflags: __GFP_ZERO: 0x8000, _RET_IP
static __always_inline void *slab_alloc(struct kmem_cache *s,
        gfp_t gfpflags, unsigned long addr)
{
    // s: &boot_kmem_cache_node, gfpflags: __GFP_ZERO: 0x8000, NUMA_NO_NODE: -1, _RET_IP_
    // slab_alloc_node(&boot_kmem_cache_node, __GFP_ZERO: 0x8000, -1, _RET_IP_):
    // UNMOVABLE인 page (boot_kmem_cache_node)의 object의 시작 virtual address
    return slab_alloc_node(s, gfpflags, NUMA_NO_NODE, addr);
// s: &bootkmem_cache_node, gfpflags: __GFP_ZERO: 0x8000, NUMA_NO_NODE: -1, _RET_IP
// slaballoc_node(&boot_kmem_cache_node, __GFP_ZERO: 0x8000, -1, _RET_IP):
// UNMOVABLE인 page (boot_kmem_cache_node)의 object의 시작 virtual address
return slab_alloc_node(s, gfpflags, NUMA_NO_NODE, addr);

slub.c::slab_alloc_node()

// ARM10C 20140705
// s: &bootkmem_cache_node, gfpflags: __GFP_ZERO: 0x8000, NUMA_NO_NODE: -1, _RET_IP
static __always_inline void *slab_alloc_node(struct kmem_cache *s,
        gfp_t gfpflags, int node, unsigned long addr)
{
    void **object;
    struct kmem_cache_cpu *c;
    struct page *page;
    unsigned long tid;

    // s: &boot_kmem_cache_node, gfpflags: __GFP_ZERO: 0x8000
    // slab_pre_alloc_hook(&boot_kmem_cache_node, 0x8000): 0
    if (slab_pre_alloc_hook(s, gfpflags))
        return NULL;
if (slab_pre_alloc_hook(s, gfpflags))

slub.c::slab_pre_alloc_hook()

// ARM10C 20140705
// s: &boot_kmem_cache_node, gfpflags: __GFP_ZERO: 0x8000
static inline int slab_pre_alloc_hook(struct kmem_cache *s, gfp_t flags)
{
    // flags: __GFP_ZERO: 0x8000, gfp_allowed_mask: 0x1ffff2f
    flags &= gfp_allowed_mask;
    // flags: 0x8000

    // flags: 0x8000
    lockdep_trace_alloc(flags); // null function

    // flags: 0x8000, __GFP_WAIT: 0x10u
    might_sleep_if(flags & __GFP_WAIT);

    // s->object_size: boot_kmem_cache_node.object_size: 44,
    // flags: 0x8000, s->flags: boot_kmem_cache_node.flags: SLAB_HWCACHE_ALIGN: 0x00002000UL
    // should_failslab(44, 0, 0x00002000UL): 0
    return should_failslab(s->object_size, flags, s->flags);
     // return 0
}
// return 0

slub.c::slab_alloc_node()

if (slab_pre_alloc_hook(s, gfpflags))
static __always_inline void *slab_alloc_node(struct kmem_cache *s,
        gfp_t gfpflags, int node, unsigned long addr)
{
...
    if (slab_pre_alloc_hook(s, gfpflags))
    // slab_pre_alloc_hook(s, gfpfags): 0
        return NULL;

    // s: &boot_kmem_cache_node, gfpflags: __GFP_ZERO: 0x8000
    // memcg_kmem_get_cache(&boot_kmem_cache_node, 0x8000): &boot_kmem_cache_node
    s = memcg_kmem_get_cache(s, gfpflags);
// s: &boot_kmem_cache_node, gfpflags: __GFP_ZERO: 0x8000
// memcg_kmem_get_cache(&boot_kmem_cache_node, 0x8000): &boot_kmem_cache_node
s = memcg_kmem_get_cache(s, gfpflags);

memcontrol.h::memcg_kmem_get_cache()

// ARM10C 20140705
// s: &boot_kmem_cache_node, gfpflags: __GFP_ZERO: 0x8000
static inline struct kmem_cache *
memcg_kmem_get_cache(struct kmem_cache *cachep, gfp_t gfp)
{
    // cachep: &boot_kmem_cache_node
    return cachep;
    // return &boot_kmem_cache_node
}
return &boot_kmem_cache_node

slub.c::slab_alloc_node()

s = memcg_kmem_get_cache(s, gfpflags);
static __always_inline void *slab_alloc_node(struct kmem_cache *s,
        gfp_t gfpflags, int node, unsigned long addr)
{
    void **object;
    struct kmem_cache_cpu *c;
    struct page *page;
    unsigned long tid;

    // s: &boot_kmem_cache_node, gfpflags: __GFP_ZERO: 0x8000
    // memcg_kmem_get_cache(&boot_kmem_cache_node, 0x8000): &boot_kmem_cache_node
    s = memcg_kmem_get_cache(s, gfpflags);
    // s: &boot_kmem_cache_node

redo:
    preempt_disable();
    // 선점 카운트 증가, barrier 적용

    // s->cpu_slab: (&boot_kmem_cache_node)->cpu_slab: 0xc0502d00
    // __this_cpu_ptr((&boot_kmem_cache_node)->cpu_slab: 0xc0502d00):
    // (&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
    c = __this_cpu_ptr(s->cpu_slab);
    // c: (&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)

    // c->tid: ((&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->tid: 4
    tid = c->tid;
    // tid: 4

    preempt_enable();
    // barrier 적용, 선점 카운트 감소, should_resched 수행

    // c->freelist: ((&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->freelist:
    // UNMOVABLE인 page 의 object의 시작 virtual address + 128
    object = c->freelist;
    // object: UNMOVABLE인 page 의 object의 시작 virtual address + 128

    // c->page: ((&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->page:
    // MIGRATE_UNMOVABLE인 page
    page = c->page;
    // page: MIGRATE_UNMOVABLE인 page

    // object: UNMOVABLE인 page 의 object의 시작 virtual address + 128
    // page: MIGRATE_UNMOVABLE인 page, node: -1, node_match(MIGRATE_UNMOVABLE인 page, -1): 1
    if (unlikely(!object || !node_match(page, node)))
        object = __slab_alloc(s, gfpflags, node, addr, c);
    else {
        // s: &boot_kmem_cache_node, object: UNMOVABLE인 page 의 object의 시작 virtual address + 128
        // get_freepointer_safe(&boot_kmem_cache_node, UNMOVABLE인 page 의 object의 시작 virtual address + 128):
        // UNMOVABLE인 page 의 object의 시작 virtual address + 192
        void *next_object = get_freepointer_safe(s, object);
// s: &boot_kmem_cache_node, object: UNMOVABLE인 page 의 object의 시작 virtual address + 128
// get_freepointer_safe(&boot_kmem_cache_node, UNMOVABLE인 page 의 object의 시작 virtual address + 128):
// UNMOVABLE인 page 의 object의 시작 virtual address + 192
void *next_object = get_freepointer_safe(s, object);

slub.c::get_freepointer_safe()

// ARM10C 20140705
// s: &boot_kmem_cache_node, object: UNMOVABLE인 page 의 object의 시작 virtual address + 128
static inline void *get_freepointer_safe(struct kmem_cache *s, void *object)
{
    void *p;

#ifdef CONFIG_DEBUG_PAGEALLOC // CONFIG_DEBUG_PAGEALLOC=n
    probe_kernel_read(&p, (void **)(object + s->offset), sizeof(p));
#else
    // s: &boot_kmem_cache_node, object: UNMOVABLE인 page 의 object의 시작 virtual address + 128
    // get_freepointer(&boot_kmem_cache_node, UNMOVABLE인 page 의 object의 시작 virtual address + 128):
    // UNMOVABLE인 page 의 object의 시작 virtual address + 192
    p = get_freepointer(s, object);
// s: &boot_kmem_cache_node, object: UNMOVABLE인 page 의 object의 시작 virtual address + 128
// get_freepointer(&boot_kmem_cache_node, UNMOVABLE인 page 의 object의 시작 virtual address + 128):
// UNMOVABLE인 page 의 object의 시작 virtual address + 192
p = get_freepointer(s, object);

slub.c::get_freepointer()

// ARM10C 20140705
// s: &boot_kmem_cache_node, object: UNMOVABLE인 page 의 object의 시작 virtual address + 128
static inline void *get_freepointer(struct kmem_cache *s, void *object)
{
    // object: UNMOVABLE인 page 의 object의 시작 virtual address
    // s->offset: (&boot_kmem_cache_node)->offset: 0
    return *(void **)(object + s->offset);
    // object: UNMOVABLE인 page 의 object의 시작 virtual address
}
// return
// object: UNMOVABLE인 page 의 object의 시작 virtual address

slub.c::get_freepointer_safe()

static inline void *get_freepointer_safe(struct kmem_cache *s, void *object)
{
    void *p;

#ifdef CONFIG_DEBUG_PAGEALLOC // CONFIG_DEBUG_PAGEALLOC=n
    probe_kernel_read(&p, (void **)(object + s->offset), sizeof(p));
#else
    // s: &boot_kmem_cache_node, object: UNMOVABLE인 page 의 object의 시작 virtual address + 128
    // get_freepointer(&boot_kmem_cache_node, UNMOVABLE인 page 의 object의 시작 virtual address + 128):
    // UNMOVABLE인 page 의 object의 시작 virtual address + 192
    p = get_freepointer(s, object);
    // p: UNMOVABLE인 page 의 object의 시작 virtual address + 192
#endif
    // p: UNMOVABLE인 page 의 object의 시작 virtual address + 192
    return p;
    // return UNMOVABLE인 page 의 object의 시작 virtual address + 192
}
// return
// UNMOVABLE인 page 의 object의 시작 virtual address + 192

slub.c::slab_alloc_node()

static __always_inline void *slab_alloc_node(struct kmem_cache *s,
        gfp_t gfpflags, int node, unsigned long addr)
{
...
redo:
...
    if (unlikely(!object || !node_match(page, node)))
        object = __slab_alloc(s, gfpflags, node, addr, c);
    else {
        // s: &boot_kmem_cache_node, object: UNMOVABLE인 page 의 object의 시작 virtual address + 128
        // get_freepointer_safe(&boot_kmem_cache_node, UNMOVABLE인 page 의 object의 시작 virtual address + 128):
        // UNMOVABLE인 page 의 object의 시작 virtual address + 192
        void *next_object = get_freepointer_safe(s, object);
        // next_object: UNMOVABLE인 page 의 object의 시작 virtual address + 192

        /*
         * The cmpxchg will only match if there was no additional
         * operation and if we are on the right processor.
         *
         * The cmpxchg does the following atomically (without lock
         * semantics!)
         * 1. Relocate first pointer to the current per cpu area.
         * 2. Verify that tid and freelist have not been changed
         * 3. If they were not changed replace tid and freelist
         *
         * Since this is without lock semantics the protection is only
         * against code executing on this cpu *not* from access by
         * other cpus.
         */

// 2014/07/05 종료

스터디 로그

133cada..6d65c2e  master     -> origin/master
Updating 133cada..6d65c2e
Fast-forward
include/linux/fault-inject.h |   1 +
include/linux/kernel.h       |   1 +
include/linux/list.h         |   6 +
include/linux/lockdep.h      |   1 +
include/linux/memcontrol.h   |   4 +
include/linux/mm.h           |   1 +
include/linux/nodemask.h     |   1 +
include/linux/percpu.h       |  91 ++++++++
include/linux/slab.h         |   5 +
include/linux/slub_def.h     |   1 +
include/linux/smp.h          |   1 +
include/linux/spinlock.h     |   1 +
mm/slab.h                    |   1 +
mm/slab_common.c             |   7 +-
mm/slub.c                    | 534 ++++++++++++++++++++++++++++++++++++++++++-
15 files changed, 641 insertions(+), 15 deletions(-)
12edc2f..03f2c9d  master     -> origin/master
Updating 12edc2f..03f2c9d
Fast-forward
 include/linux/percpu-defs.h |   3 +-
 include/linux/percpu.h      |  26 +++++++-
 mm/slub.c                   | 144 ++++++++++++++++++++++++++------------------
 3 files changed, 109 insertions(+), 64 deletions(-)

댓글 없음:

댓글 쓰기