2014년 7월 13일 일요일

[Linux Kernel] 62주차(2014.07.12)

ARM10C 62주차 후기

일시 : 2014.07.12 (62주차)
모임명 : 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)
{
...
    create_boot_cache(kmem_cache_node, "kmem_cache_node",
        sizeof(struct kmem_cache_node), SLAB_HWCACHE_ALIGN);
...
    slab_state = PARTIAL;
...    
    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);
kmem_cache_node = bootstrap(&boot_kmem_cache_node);
boot_kmem_cache_node를 매개변수로 하여 bootstrap()을 재 실행한다.

slub.c::bootstrap()

// struct kmem_cache * static_cache: &&boot_kmem_cache_node
// kmem_cache_node = bootstrap(&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 의 object의 시작 virtual address + 128
    struct kmem_cache *s = kmem_cache_zalloc(kmem_cache, GFP_NOWAIT);
    // s: UNMOVABLE인 page 의 object의 시작 virtual address + 128

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

    // s: UNMOVABLE인 page 의 object의 시작 virtual address + 128,
    // smp_processor_id(): 0
    __flush_cpu_slab(s, smp_processor_id());
__flush_cpu_slab(s, smp_processor_id());

slub.c::__flush_cpu_slab()

// s: UNMOVABLE인 page 의 object의 시작 virtual address + 128,
// smp_processor_id(): 0
// __flush_cpu_slab(s, 0);
static inline void __flush_cpu_slab(struct kmem_cache *s, int cpu)
{
    // s->cpu_slab: (&boot_kmem_cache_node 용 object 주소)->cpu_slab: 0xc0502d00, cpu: 0
    // per_cpu_ptr(0xc0502d00, 0):
    // (&boot_kmem_cache_node 용 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_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)

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

slub.c::flush_slab()

// s: UNMOVABLE인 page 의 object의 시작 virtual address + 128,
// c: (&boot_kmem_cache_node 용 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 의 object의 시작 virtual address + 128,
    // CPUSLAB_FLUSH: 13
    stat(s, CPUSLAB_FLUSH);

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

slub.c::deactivate_slab()

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

    // s: UNMOVABLE인 page 의 object의 시작 virtual address + 128,
    // page: UNMOVABLE인 page
    // page_to_nid(UNMOVABLE인 page): 0
    // get_node(UNMOVABLE인 page 의 object의 시작 virtual address + 128, 0):
    // (&boot_kmem_cache_node 용 object 주소)->node[0]
    struct kmem_cache_node *n = get_node(s, page_to_nid(page));
    // n: (&boot_kmem_cache_node 용 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)->freelist: NULL
    if (page->freelist) {
        stat(s, DEACTIVATE_REMOTE_FREES);
        tail = DEACTIVATE_TO_TAIL;
    }

    // [boot_kmem_cache_node 로 호출]
    // s: UNMOVABLE인 page 의 object의 시작 virtual address + 128,
    // freelist: UNMOVABLE인 page 의 object의 시작 virtual address + 192,
    // get_freepointer(UNMOVABLE인 page 의 object의 시작 virtual address + 128,
    // UNMOVABLE인 page 의 object의 시작 virtual address + 192):
    // 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의 시작 virtual address + 192
        // [loop 1] nextfree: UNMOVABLE인 page의 시작 virtual address + 256
        // [loop 2] freelist: UNMOVABLE인 page의 시작 virtual address + 256
        // [loop 2] nextfree: UNMOVABLE인 page의 시작 virtual address + 320

        do {
            // [loop 1] page->freelist: NULL
            // [loop 2] page->freelist: UNMOVABLE인 page 의 시작 virtual address + 192
            prior = page->freelist;
            // [loop 1] prior: NULL
            // [loop 2] prior: UNMOVABLE인 page 의 시작 virtual address + 192

            // [loop 1] page->counters: (UNMOVABLE인 page)->counters: 0x80400040
            // [loop 2] page->counters: (UNMOVABLE인 page)->counters: 0x8040003f
            counters = page->counters;
            // [loop 1] counters: 0x80400040
            // [loop 2] counters: 0x8040003f

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

            // [loop 1] counters: 0x80400040
            // [loop 2] counters: 0x8040003f
            new.counters = counters;
            // [loop 1] new.counters: 0x80400040
            // [loop 2] new.counters: 0x8040003f

            // [loop 1] new.inuse: 64, new.counters: 0x80400040
            // [loop 2] new.inuse: 63, new.counters: 0x8040003f
            new.inuse--;
            // [loop 1] new.inuse: 63, new.counters: 0x8040003f
            // [loop 2] new.inuse: 62, new.counters: 0x8040003e

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

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

        // [loop 1] nextfree: UNMOVABLE인 page 의 시작 virtual address + 256
        // [loop 2] nextfree: UNMOVABLE인 page 의 시작 virtual address + 320
        freelist = nextfree;
        // [loop 1] freelist: UNMOVABLE인 page 의 시작 virtual address + 256
        // [loop 2] freelist: UNMOVABLE인 page 의 시작 virtual address + 320

        // [loop 3 .. 60] 번 수행
    }

    // [boot_kmem_cache_node 로 호출]
    // 위의 루프에서 한일:
    // UNMOVABLE인 page 의 사용하지 않는 첫 번째 object의 freepointer 값을 NULL 로 변경,
    // 나머지 object들의 freepointer 값을 이전 object들의 주소로 변경
    // UNMOVABLE인 page 의 맴버필드 변경
    // (UNMOVABLE인 page )->freelist: UNMOVABLE인 page 의 시작 virtual address + 3968
    // (UNMOVABLE인 page )->counters: 0x80400004

redo:

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

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

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

    // old.counters: 0x80400004
    new.counters = old.counters;
    // new.counters: 0x80400004

    // freelist: UNMOVABLE인 page 의 시작 virtual address + 4032
    if (freelist) {
        // new.inuse: 4
        new.inuse--;
        // new.inuse: 3, new.counters: 0x80400003

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

        // freelist: UNMOVABLE인 page 의 시작 virtual address + 4032
        new.freelist = freelist;
        // new.freelist: UNMOVABLE인 page 의 시작 virtual address + 4032
    } else
        new.freelist = old.freelist;

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

    // n: (&boot_kmem_cache_node 용 object 주소)->node[0]:
    // UNMOVABLE인 page 의 object의 시작 virtual address

    // new.inuse: 3, n->nr_partial: 1, s->min_partial: (&boot_kmem_cache_node 용 object 주소)->min_partial: 5
    // new.freelist: UNMOVABLE인 page 의 시작 virtual address + 4032
    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

            spin_lock(&n->list_lock);
            // n->list_lock 을 이용한 spin_lock 획득
        }
    } else {
        m = M_FULL;
        if (kmem_cache_debug(s) && !lock) {
            lock = 1;

            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_node 용 object 주소)->node[0]:
            // UNMOVABLE인 page 의 object의 시작 virtual address,
            // page: UNMOVABLE인 page,
            // tail: DEACTIVATE_TO_HEAD: 15
            add_partial(n, page, tail);
            // add_partial 한일:
            // n->nr_partial: 2
            // n->partial에 (UNMOVABLE인 page)->lru 가 추가됨

            // s: UNMOVABLE인 page 의 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 의 object의 시작 virtual address + 128,
    // page: UNMOVABLE인 page,
    // old.freelist: UNMOVABLE인 page 의 시작 virtual address + 3968
    // old.counters: 0x80400004
    // new.freelist: UNMOVABLE인 page 의 시작 virtual address + 4032
    // new.counters: 0x00400003
    // "unfreezing slab"
    // __cmpxchg_double_slab(UNMOVABLE인 page 의 object의 시작 virtual address + 128,
    // UNMOVABLE인 page, UNMOVABLE인 page 의 시작 virtual address + 3968,
    // 0x80400004, UNMOVABLE인 page 의 시작 virtual address + 4032,
    // 0x00400003, "unfreezing slab"): 1
    // UNMOVABLE인 page)의 필드 맴버 값 변경
    // (UNMOVABLE인 page)->freelist: UNMOVABLE인 page 의 시작 virtual address + 4032
    // (UNMOVABLE인 page)->counters: 0x00400003
    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 의 필드 맴버 값 변경
// (UNMOVABLE인 page)->counters: 0x00400003
// (UNMOVABLE인 page)->freelist: UNMOVABLE인 page 의 시작 virtual address + 4032
//
// (UNMOVABLE인 page) 의 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 4           | .... | Slab object 63          |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
| object start address:   | object start address:   | object start address:   | object start address:   | object start address:   |      | object start address:   |
| 0x10001000              | 0x10001040              | 0x10001080              | 0x100010c0              | 0x10001100              | .... | 0x10001fc0              |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
| freepointer | data      | freepointer | data      | freepointer | data      | freepointer | data      | freepointer | data      | .... | freepointer | data      |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 0x10001040  | 64 Bytes  | 0x10001080  | 64 Bytes  | 0x100010c0  | 64 Bytes  | null        | 64 Bytes  | 0x100010c0  | 64 Bytes  | .... | 0x10001f80  | 64 Bytes  |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
// n: (&boot_kmem_cache_node 용 object 주소)->node[0]:
// UNMOVABLE인 page 의 object의 시작 virtual address
// n->nr_partial: 2
// n->partial에 (UNMOVABLE인 page)->lru 가 추가됨

slub.c::flush_slab()

// flush_slab(s,c)
// s: UNMOVABLE인 page 의 object의 시작 virtual address + 128,
// c: (&boot_kmem_cache_node 용 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)
{
    stat(s, CPUSLAB_FLUSH);

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

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

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

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

flush_slab(s,c)가 한일

// UNMOVABLE인 page 의 필드 맴버 값 변경
// (UNMOVABLE인 page)->counters: 0x00400003
// (UNMOVABLE인 page)->freelist: UNMOVABLE인 page 의 시작 virtual address + 4032
//
// (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 4           | .... | Slab object 63          |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
| object start address:   | object start address:   | object start address:   | object start address:   | object start address:   |      | object start address:   |
| 0x10001000              | 0x10001040              | 0x10001080              | 0x100010c0              | 0x10001100              | .... | 0x10001fc0              |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
| freepointer | data      | freepointer | data      | freepointer | data      | freepointer | data      | freepointer | data      | .... | freepointer | data      |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 0x10001040  | 64 Bytes  | 0x10001080  | 64 Bytes  | 0x100010c0  | 64 Bytes  | null        | 64 Bytes  | 0x100010c0  | 64 Bytes  | .... | 0x10001f80  | 64 Bytes  |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
// n: (&boot_kmem_cache_node 용 object 주소)->node[0]:
// UNMOVABLE인 page 의 object의 시작 virtual address
// n->nr_partial: 2
// n->partial에 (UNMOVABLE인 page)->lru 가 추가됨
//
// c: (&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + per_cpu_start에서의pcpu_base_addr의 옵셋)
// c->tid: ((&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + 
per_cpu_start에서의pcpu_base_addr의 옵셋))->tid: 12
// c->page: ((&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + per_cpu_start에서의pcpu_base_addr의 옵셋))->page: NULL
// c->freelist: ((&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + 
per_cpu_start에서의pcpu_base_addr의 옵셋))->freelist: NULL

slub.c::__flush_cpu_slab()

// s: UNMOVABLE인 page 의 object의 시작 virtual address + 128,
// smp_processor_id(): 0
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)) {
        if (c->page)
            flush_slab(s, c);

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

__flush_cpu_slab 한일:

// UNMOVABLE인 page 의 필드 맴버 값 변경
// (UNMOVABLE인 page)->counters: 0x00400003
// (UNMOVABLE인 page)->freelist: UNMOVABLE인 page 의 시작 virtual address + 4032
//
// (UNMOVABLE인 page) 의 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 4           | .... | Slab object 63          |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
| object start address:   | object start address:   | object start address:   | object start address:   | object start address:   |      | object start address:   |
| 0x10001000              | 0x10001040              | 0x10001080              | 0x100010c0              | 0x10001100              | .... | 0x10001fc0              |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
| freepointer | data      | freepointer | data      | freepointer | data      | freepointer | data      | freepointer | data      | .... | freepointer | data      |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 0x10001040  | 64 Bytes  | 0x10001080  | 64 Bytes  | 0x100010c0  | 64 Bytes  | null        | 64 Bytes  | 0x100010c0  | 64 Bytes  | .... | 0x10001f80  | 64 Bytes  |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
// n: (&boot_kmem_cache_node 용 object 주소)->node[0]:
// UNMOVABLE인 page 의 object의 시작 virtual address
// n->nr_partial: 2
// n->partial에 (UNMOVABLE인 page)->lru 가 추가됨
//
// c: (&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + per_cpu_start에서의pcpu_base_addr의 옵셋)
// c->tid: ((&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + 
per_cpu_start에서의pcpu_base_addr의 옵셋))->tid: 12
// c->page: ((&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + per_cpu_start에서의pcpu_base_addr의 옵셋))->page: NULL
// c->freelist: ((&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + 
per_cpu_start에서의pcpu_base_addr의 옵셋))->freelist: NULL

slub.c::bootstrap()

// &boot_kmem_cache_node
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 의 object의 시작 virtual address + 128, node: 0
        // get_node(UNMOVABLE인 page 의 object의 시작 virtual address + 128, 0):
        // (&boot_kmem_cache_node 용 object 주소)->node[0]: UNMOVABLE인 page 의 object의 시작 virtual address
        struct kmem_cache_node *n = get_node(s, node);
        // n: UNMOVABLE인 page 의 object의 시작 virtual address

        struct page *p;

        // n: UNMOVABLE인 page 의 object의 시작 virtual address
        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

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

#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 의 object의 시작 virtual address + 128
    list_add(&s->list, &slab_caches);
    // slab_caches 의 list에 (UNMOVABLE인 page 의 object의 시작 virtual address + 128)->list를 등록

    // s: UNMOVABLE인 page 의 object의 시작 virtual address + 128
    return s;
    // return UNMOVABLE인 page 의 object의 시작 virtual address + 128
}
// return UNMOVABLE인 page 의 object의 시작 virtual address + 128

slub.c::kmem_cache_init()

void __init kmem_cache_init(void)
{
    static __initdata struct kmem_cache boot_kmem_cache,boot_kmem_cache_node;

    if (debug_guardpage_minorder())
        slub_max_order = 0;

    kmem_cache_node = &boot_kmem_cache_node;
    kmem_cache = &boot_kmem_cache;

    create_boot_cache(kmem_cache_node, "kmem_cache_node", sizeof(struct kmem_cache_node), SLAB_HWCACHE_ALIGN);

    register_hotmemory_notifier(&slab_memory_callback_nb); // null function

    slab_state = PARTIAL;

    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);
    // slab_caches 의 list에 (UNMOVABLE인 page 의 object의 시작 virtual address + 128)->list를 등록

// 2014/07/12 종료

study log

boot_kmem_cache_node를 가지고 bootstrap()을 분석했습니다.
다음 시간에는 create_kmalloc_caches(0)에서 slab: UP으로 활성화와
slub정보를 출력하는 부분을 분석합니다.
10996da..fea5705  master     -> origin/master
Merge made by the 'recursive' strategy.
arch/arm/include/asm/processor.h |   2 +
include/linux/kmemcheck.h        |   1 +
include/linux/kmemleak.h         |   1 +
include/linux/mm.h               |   1 +
include/linux/percpu.h           |  63 +++--
include/linux/slab.h             |   3 +-
include/linux/slub_def.h         |   2 +
include/trace/events/kmem.h      |   1 +
mm/slab_common.c                 |   1 +
mm/slub.c                        | 532 ++++++++++++++++++++++++++++++++++++++-
10 files changed, 571 insertions(+), 36 deletions(-)

댓글 없음:

댓글 쓰기