2014년 6월 28일 토요일

[Linux Kernel] 60주차(2014.06.28)

ARM10C 60주차 후기

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

스터디 진도 :

  • mm_init()을 계속 분석합니다.
  • start_kernel()-> mm_init()->kmem_cache_init()->bootstrap()분석중

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()

// ARM10C 20140419
void __init kmem_cache_init(void)
{
...
    // kmem_cache: &boot_kmem_cache,
    // offsetof(struct kmem_cache, node): 128, nr_node_ids: 1
    // sizeof(struct kmem_cache_node *): 4 SLAB_HWCACHE_ALIGN: 0x00002000UL
    // create_boot_cache(&boot_kmem_cache, "kmem_cache", 132, 0x00002000UL)
    create_boot_cache(kmem_cache, "kmem_cache",
            offsetof(struct kmem_cache, node) +
                nr_node_ids * sizeof(struct kmem_cache_node *),
               SLAB_HWCACHE_ALIGN);

create_boot_cache(&boot_kmem_cache) 가 한일:

  • boot_kmem_cache.flags: SLAB_HWCACHE_ALIGN: 0x00002000UL
  • boot_kmem_cache.reserved: 0
  • boot_kmem_cache.min_partial: 5
  • boot_kmem_cache.cpu_partial: 30
  • boot_kmem_cache.refcount: -1
    *
  • 할당 받아 놓은 migratetype이 MIGRATE_UNMOVABLE인 page 를 사용
  • page 맴버를 셋팅함
  • page->counters: 0x80400040
  • page->inuse: 64
  • page->objects: 64
  • page->frozen: 1
  • page->freelist: NULL
  • 할당받은 slab object를 kmem_cache_node 로 사용하고 kmem_cache_node의 멤버 필드를 초기화함
  • 첫번째 object:
  • kmem_cache_node->partial에 연결된 (MIGRATE_UNMOVABLE인 page)->lru 를 삭제
  • kmem_cache_node->nr_partial: 0
  • 두번째 object:
  • kmem_cache_node->nr_partial: 0
  • kmem_cache_node->list_lock: spinlock 초기화 수행
  • kmem_cache_node->slabs: 0, kmem_cache_node->total_objects: 0 로 세팀함
  • kmem_cache_node->full: 리스트 초기화
    *
  • kmem_cache_node 가 boot_kmem_cache.node[0]에 할당됨
    *
  • 할당받은 pcpu 들의 16 byte 공간 (&boot_kmem_cache)->cpu_slab 에
  • 각 cpu에 사용하는 kmem_cache_cpu의 tid 맵버를 설정
    kmem_cache = bootstrap(&boot_kmem_cache);

slub.c::bootstrap()

// ARM10C 20140628
// &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
    struct kmem_cache *s = kmem_cache_zalloc(kmem_cache, GFP_NOWAIT);
struct kmem_cache *s = kmem_cache_zalloc(kmem_cache, GFP_NOWAIT);

slub.c::kmem_cache_zalloc()

// ARM10C 20140628
// kmem_cache: &boot_kmem_cache, GFP_NOWAIT: 0
static inline void *kmem_cache_zalloc(struct kmem_cache *k, gfp_t flags)
{
    // k: &boot_kmem_cache, flags: GFP_NOWAIT: 0, __GFP_ZERO: 0x8000u
    // kmem_cache_alloc(&boot_kmem_cache, __GFP_ZERO: 0x8000u):
    // UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address
    return kmem_cache_alloc(k, flags | __GFP_ZERO);
return kmem_cache_alloc(k, flags | __GFP_ZERO);

slub.c::kmem_cache_alloc()

  • 이전에는 s: &boot_kmem_cache_node, flags: GFP_KERNEL: 0xD0로 실행했었음
    n = kmem_cache_alloc_node(kmem_cache_node, GFP_KERNEL, node); 에서
    return kmem_cache_alloc(s, flags);를 호출했었다.
  • 이번에는 bootstrap()->kmem_cache_zalloc()로 하여
    retrun kmem_cache_alloc(s, flags)으로
    s: k: &boot_kmem_cache, flags: GFP_NOWAIT: 0, __GFP_ZERO: 0x8000 를 호출한다.
호출s값flags값
kmem_cache_allockmem_cache_nodeGFP_KERNEL
kmem_cache_zalloc()kmem_cacheGFP_ZERO
// ARM10C 20140628
// kmem_cache: &boot_kmem_cache, GFP_NOWAIT: 0
static inline void *kmem_cache_zalloc(struct kmem_cache *k, gfp_t flags)
{
    // k: &boot_kmem_cache, flags: GFP_NOWAIT: 0, __GFP_ZERO: 0x8000u
    // kmem_cache_alloc(&boot_kmem_cache, __GFP_ZERO: 0x8000u):
    // UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address
    return kmem_cache_alloc(k, flags | __GFP_ZERO);
return kmem_cache_alloc(k, flags | __GFP_ZERO);

slub.c::kmem_cache_alloc()

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

slub.c::slab_alloc()

// ARM10C 20140628
// s: &bootkmem_cache, 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, gfpflags: __GFP_ZERO: 0x8000, NUMA_NO_NODE: -1, _RET_IP_
    // slab_alloc_node(&boot_kmem_cache, __GFP_ZERO: 0x8000, -1, _RET_IP_):
    // UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address
    return slab_alloc_node(s, gfpflags, NUMA_NO_NODE, addr);

slub.c::slab_alloc_node()

// ARM10C 20140628
// s: &bootkmem_cache, 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, gfpflags: __GFP_ZERO: 0x8000
    // slab_pre_alloc_hook(&boot_kmem_cache, 0x8000): 0
    if (slab_pre_alloc_hook(s, gfpflags))
        return NULL;

slub.c::slab_pre_alloc_hook()

// ARM10C 20140628
// s: &boot_kmem_cache, 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);

kernel.h::might_sleep_if()

flags가 __GFP_WAIT: 0x10이면 sleep한다.
// ARM10C 20140628
#define might_sleep_if(cond) do { if (cond) might_sleep(); } while (0)

slub.c::slab_pre_alloc_hook()

// ARM10C 20140628
// s: &boot_kmem_cache, gfpflags: __GFP_ZERO: 0x8000
static inline int slab_pre_alloc_hook(struct kmem_cache *s, gfp_t flags)
{
...
    // flags: 0x8000, __GFP_WAIT: 0x10u
    might_sleep_if(flags & __GFP_WAIT);

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

fault_inject.h::should_failslab()

// ARM10C 20140628
static inline bool should_failslab(size_t size, gfp_t gfpflags,
                unsigned long flags)
{
    return false;
}
false를 반환하는 null 함수 이다.

slub.c::slab_pre_alloc_hook()

따라서 slab_pre_alloc_hook에서는 flags가 __GPF_WAIT인지 확인하여.
맞다면 sleep하고 아니라면 false값을 반환한다.
    return should_failslab(s->object_size, flags, s->flags);
    // return 0
}

slub.c::slab_alloc_node()

// ARM10C 20140628
// s: &bootkmem_cache, 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;

    if (slab_pre_alloc_hook(s, gfpflags))
        return NULL;

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

memcontrol.h::memcg_kmem_get_cache()

s값을 s값이 대입하기 때문에 memcg_kmem_get_cache()도 의미없는 함수 이다.
// ARM10C 20140628
// s: &boot_kmem_cache, gfpflags: __GFP_ZERO: 0x8000
static inline struct kmem_cache *
memcg_kmem_get_cache(struct kmem_cache *cachep, gfp_t gfp)
{
    // cachep: &boot_kmem_cache
    return cachep;
    // return &boot_kmem_cache
}

slub.c::slab_alloc_node()

// ARM10C 20140628
// s: &bootkmem_cache, 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;

    if (slab_pre_alloc_hook(s, gfpflags))
        return NULL;

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

redo:

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

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

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

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

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

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

    // c->freelist, c->page 의 값을 초기화?:
    // pcpu_populate_chunk에서 초기화 하고 왔음

    // object: 0, page: 0, node: -1, node_match(0, -1): 1
    if (unlikely(!object || !node_match(page, node)))
        // s: &boot_kmem_cache, gfpflags: __GFP_ZERO: 0x8000, node: -1, addr: _RET_IP_,
        // c: (&boot_kmem_cache)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
        // __slab_alloc(&boot_kmem_cache, __GFP_ZERO: 0x8000, -1, _RET_IP_,
        // (&boot_kmem_cache)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)):
        // UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address
        object = __slab_alloc(s, gfpflags, node, addr, c);
   object = __slab_alloc(s, gfpflags, node, addr, c);

slub.c::__slab_alloc()

// ARM10C 20140628
// s: &boot_kmem_cache, gfpflags: __GFP_ZERO: 0x8000, node: -1, addr: _RET_IP_,
// c: (&boot_kmem_cache)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
              unsigned long addr, struct kmem_cache_cpu *c)
{
    void *freelist;
    struct page *page;
    unsigned long flags;

    local_irq_save(flags);
    // cpsr을 flags에 저장

#ifdef CONFIG_PREEMPT // CONFIG_PREEMPT=y
    // s->cpu_slab: (&boot_kmem_cache)->cpu_slab: 0xc0502d10
    // __this_cpu_ptr((&boot_kmem_cache)->cpu_slab: 0xc0502d10):
    // (&boot_kmem_cache)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
    c = this_cpu_ptr(s->cpu_slab);
    // c: (&boot_kmem_cache)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
#endif
    // c->page: ((&boot_kmem_cache)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->page: 0
    page = c->page;
    // page: 0

    // page: 0
    if (!page)
        goto new_slab;
        // new_slab 심볼로 이동
new_slab:

    // c->partial: (&boot_kmem_cache)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)->partial: 0
    if (c->partial) {
        page = c->page = c->partial;
        c->partial = page->next;
        stat(s, CPU_PARTIAL_ALLOC);
        c->freelist = NULL;
        goto redo;
    }

    // s: &boot_kmem_cache, gfpflags: __GFP_ZERO: 0x8000, node: -1,
    // c: (&boot_kmem_cache)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
    // new_slab_objects(&boot_kmem_cache, __GFP_ZERO: 0x8000, -1,
    // (&boot_kmem_cache)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)):
    // UNMOVABLE인 page (boot_kmem_cache)의 virtual address
    freelist = new_slab_objects(s, gfpflags, node, &c);
freelist = new_slab_objects(s, gfpflags, node, &c);

slub.c::new_slab_objects()

// ARM10C 20140628
// s: &boot_kmem_cache, gfpflags: GFP_ZERO: 0x8000, node: -1,
// c: (&boot_kmem_cache)->cpu_slab + (pcpu_unit_offsets[0] + 
per_cpu_start에서의pcpu_base_addr의 옵셋)
static inline void *new_slab_objects(struct kmem_cache *s, gfp_t flags,
            int node, struct kmem_cache_cpu **pc)
{
    void *freelist;

    // *pc: (&boot_kmem_cache)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
    struct kmem_cache_cpu *c = *pc;

    // c: (&boot_kmem_cache)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
    struct page *page;

    // s: &boot_kmem_cache, flags: __GFP_ZERO: 0x8000, node: -1,
    // c: (&boot_kmem_cache)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
    // get_partial(&boot_kmem_cache, __GFP_ZERO: 0x8000, -1,
    // (&boot_kmem_cache)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)):
    // NULL
    freelist = get_partial(s, flags, node, c);
freelist = get_partial(s, flags, node, c);

slub.c::get_partial()

// ARM10C 20140628
// s: &boot_kmem_cache, flags: GFP_ZERO: 0x8000, node: -1,
// c: (&boot_kmem_cache)->cpu_slab + (pcpu_unit_offsets[0] + 
per_cpu_start에서의pcpu_base_addr의 옵셋)
static void *get_partial(struct kmem_cache *s, gfp_t flags, int node,
        struct kmem_cache_cpu *c)
{
    void *object;

    // node: -1, NUMA_NO_NODE: -1, numa_node_id(): 0
    int searchnode = (node == NUMA_NO_NODE) ? numa_node_id() : node;
    // searchnode: 0

    // s: &boot_kmem_cache, searchnode: 0
    // get_node(&boot_kmem_cache, 0): (&boot_kmem_cache)->node[0],
    // c: (&boot_kmem_cache)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋),
    // flags: __GFP_ZERO: 0x8000
    // get_partial_node(&boot_kmem_cache, (&boot_kmem_cache)->node[0],
    // (&boot_kmem_cache)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋), __GFP_ZERO: 0x8000):
    // NULL
    object = get_partial_node(s, get_node(s, searchnode), c, flags);

slub.c::get_partial_node()

// ARM10C 20140628
// s: &boot_kmem_cache, (&boot_kmem_cache)->node[0],
// c: (&boot_kmem_cache)->cpu_slab + (pcpu_unit_offsets[0] + per_cpu_start에서의pcpu_base_addr의 옵셋),
// flags: 
GFP_ZERO: 0x8000
static void *get_partial_node(struct kmem_cache *s, struct kmem_cache_node *n,
                struct kmem_cache_cpu *c, gfp_t flags)
{
    struct page *page, *page2;
    void *object = NULL;
    int available = 0;
    int objects;

    // n: (&boot_kmem_cache)->node[0]: UNMOVABLE인 page 의 object의 시작 virtual address + 64,
    // n->nr_partial: ((&boot_kmem_cache)->node[0])->nr_partial: 0
    if (!n || !n->nr_partial)
        return NULL;
        // return NULL
}
    // return NULL

slub.c::get_partial()

// object = get_partial_node(s, get_node(s, searchnode), c, flags);
// object: NULL
static void *get_partial(struct kmem_cache *s, gfp_t flags, int node,
        struct kmem_cache_cpu *c)
{
...
    object = get_partial_node(s, get_node(s, searchnode), c, flags);
    // object: NULL

    // node: -1, NUMA_NO_NODE: -1
    if (object || node != NUMA_NO_NODE)
        // object: UNMOVABLE인 page 의 object의 시작 virtual address + 64
        return object;

    // s: &boot_kmem_cache, flags: __GFP_ZERO: 0x8000,
    // c: (&boot_kmem_cache)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
    // get_any_partial(&boot_kmem_cache, __GFP_ZERO: 0x8000,
    // (&boot_kmem_cache)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)): NULL
    return get_any_partial(s, flags, c);
    // return NULL
}
get_any_partial()은 NUMA에서 처리가 있으나, 우리는 NUMA가 아니므로 NULL이 리턴된다.

slub.c::get_any_partial()

// s: &boot_kmem_cache, flags: GFP_ZERO: 0x8000,
// c: (&boot_kmem_cache)->cpu_slab + (pcpu_unit_offsets[0] + 
per_cpu_start에서의pcpu_base_addr의 옵셋)
static void *get_any_partial(struct kmem_cache *s, gfp_t flags,
        struct kmem_cache_cpu *c)
{
#ifdef CONFIG_NUMA // CONFIG_NUMA=n
...
#endif
    return NULL;
    // return NULL
}

get_partial(&boot_kmem_cache)이 한일:

// n->nr_partial: 0 이기 때문에 NULL을 리턴

slub.c::new_slab_objects()

// freelist = get_partial(s, flags, node, c);에서
// return NULL
static inline void *new_slab_objects(struct kmem_cache *s, gfp_t flags,
            int node, struct kmem_cache_cpu **pc)
{
...
    freelist = get_partial(s, flags, node, c);
    // freelist: NULL
    // freelist: UNMOVABLE인 page 의 object의 시작 virtual address + 64

    // freelist: NULL
    if (freelist)
        // freelist: UNMOVABLE인 page 의 object의 시작 virtual address + 64
        return freelist;

    // s: &boot_kmem_cache, flags: __GFP_ZERO: 0x8000, node: -1
    page = new_slab(s, flags, node);
page = new_slab(s, flags, node);

slub.c::new_slab()

// ARM10C 20140628
// s: &boot_kmem_cache, flags: __GFP_ZERO: 0x8000, node: -1
static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)
{
    struct page *page;
    void *start;
    void *last;
    void *p;
    int order;

    // flags: __GFP_ZERO: 0x8000, GFP_SLAB_BUG_MASK: 0xfe000005
    BUG_ON(flags & GFP_SLAB_BUG_MASK);

    // s: &boot_kmem_cache, flags: __GFP_ZERO: 0x8000, node: -1
    // GFP_RECLAIM_MASK: 0x13ef0, GFP_CONSTRAINT_MASK: 0x60000
    page = allocate_slab(s,
        flags & (GFP_RECLAIM_MASK | GFP_CONSTRAINT_MASK), node);
page = allocate_slab(s, flags & (GFP_RECLAIM_MASK | GFP_CONSTRAINT_MASK), node);

slub.c::allocate_slab()

// ARM10C 20140628
// s: &boot_kmem_cache, flags: GFP_NOWAIT: 0, node: -1
static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
{
    struct page *page;

    // s->oo: boot_kmem_cache.oo
    struct kmem_cache_order_objects oo = s->oo;
    // oo: boot_kmem_cache.oo

    gfp_t alloc_gfp;

    // flags: GFP_NOWAIT: 0, gfp_allowed_mask: 0x1ffff2f
    flags &= gfp_allowed_mask;
    // flags: GFP_NOWAIT: 0

    // flags: GFP_NOWAIT: 0, __GFP_WAIT: 0x10u
    if (flags & __GFP_WAIT)
        local_irq_enable();

    // s->allocflags: boot_kmem_cache.allocflags: 0
    flags |= s->allocflags;
    // flags: GFP_NOWAIT: 0

    // flags: GFP_NOWAIT: 0, __GFP_NOWARN: 0x200u, __GFP_NORETRY: 0x1000u
    // __GFP_NOFAIL: 0x800u
    alloc_gfp = (flags | __GFP_NOWARN | __GFP_NORETRY) & ~__GFP_NOFAIL;
    // alloc_gfp: 0x1200

    // alloc_gfp: 0x1200, node: -1, oo: boot_kmem_cache.oo
    page = alloc_slab_page(alloc_gfp, node, oo);
page = alloc_slab_page(alloc_gfp, node, oo);

slub.c::alloc_slab_page()

// ARM10C 20140628
// alloc_gfp: 0x1200, node: -1, oo: boot_kmem_cache.oo
static inline struct page *alloc_slab_page(gfp_t flags, int node,
                    struct kmem_cache_order_objects oo)
{
    // oo: boot_kmem_cache.oo
    int order = oo_order(oo);

slub.c::oo_order()

// ARM10C 20140628
// oo: boot_kmem_cache.oo
static inline int oo_order(struct kmem_cache_order_objects x)
{
    // x.x: boot_kmem_cache.oo.x: 32, OO_SHIFT: 16
    return x.x >> OO_SHIFT;
    // return 0
}
return 값이 0이므로 int order = oo_order(oo);에서 order는 0이 된다.

slub.c::alloc_slab_page()

// int order = oo_order(oo);
// order : 0
static inline struct page *alloc_slab_page(gfp_t flags, int node,
                    struct kmem_cache_order_objects oo)
{
    // oo: boot_kmem_cache.oo
    int order = oo_order(oo);
    // order: 0

    // flags: 0x1200, __GFP_NOTRACK: 0x200000u
    flags |= __GFP_NOTRACK;
    // flags: 0x201200

    // node: -1, NUMA_NO_NODE: -1
    if (node == NUMA_NO_NODE)
        // flags: 0x201200, order: 0
        return alloc_pages(flags, order);
        // return migratetype이 MIGRATE_UNMOVABLE인 page
    else
        return alloc_pages_exact_node(node, flags, order);
}
// return alloc_pages(flags, order);
// migratetype이 MIGRATE_UNMOVABLE인 page가 리턴됨

slub.c::allocate_slab()

// page = alloc_slab_page(alloc_gfp, node, oo);에서
// alloca_slab_page에서 migratetype이 MIGRATE_UNMOVABLE인 page가 리턴됨
// 이 page를 migratetype이 MIGRATE_UNMOVABLE인 page (boot_kmem_cache)라고 표기할 것임
static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
{
...
    // alloc_gfp: 0x1200, node: -1, oo: boot_kmem_cache.oo
    page = alloc_slab_page(alloc_gfp, node, oo);
    // page: migratetype이 MIGRATE_UNMOVABLE인 page (boot_kmem_cache)

    if (unlikely(!page)) {
        oo = s->min;
        page = alloc_slab_page(flags, node, oo);
        if (page)
            stat(s, ORDER_FALLBACK);
    }

    // kmemcheck_enabled: 0, page: migratetype이 MIGRATE_UNMOVABLE인 page (boot_kmem_cache)
    // s->flags: (&boot_kmem_cache)->flags: SLAB_HWCACHE_ALIGN: 0x00002000UL
    // SLAB_NOTRACK: 0x00000000UL, DEBUG_DEFAULT_FLAGS: 0x10d00
    if (kmemcheck_enabled && page
        && !(s->flags & (SLAB_NOTRACK | DEBUG_DEFAULT_FLAGS))) {
        int pages = 1 << oo_order(oo);

        kmemcheck_alloc_shadow(page, oo_order(oo), flags, node);
        if (s->ctor)
            kmemcheck_mark_uninitialized_pages(page, pages);
        else
            kmemcheck_mark_unallocated_pages(page, pages);
    }

    // flags: GFP_NOWAIT: 0, __GFP_WAIT: 0x10u
    if (flags & __GFP_WAIT)
        local_irq_disable();

    // page: migratetype이 MIGRATE_UNMOVABLE인 page (boot_kmem_cache)
    if (!page)
        return NULL;

    // oo: boot_kmem_cache.oo, oo_objects(boot_kmem_cache.oo): 32
    page->objects = oo_objects(oo);
    // page->objects: 32, page->_mapcount: 0x00200000

    // page: migratetype이 MIGRATE_UNMOVABLE인 page (boot_kmem_cache)
    // page_zone(migratetype이 MIGRATE_UNMOVABLE인 page (boot_kmem_cache)):
    // &(&contig_page_data)->node_zones[ZONE_NORMAL]
    // s->flags: (&boot_kmem_cache)->flags: SLAB_HWCACHE_ALIGN: 0x00002000UL
    // SLAB_RECLAIM_ACCOUNT: 0x00020000UL, NR_SLAB_RECLAIMABLE: 13, NR_SLAB_UNRECLAIMABLE: 14
    // oo: boot_kmem_cache.oo, oo_order(boot_kmem_cache.oo): 0
    //
    // &(&contig_page_data)->node_zones[ZONE_NORMAL], NR_SLAB_UNRECLAIMABLE: 14, 1

    mod_zone_page_state(page_zone(page),
        (s->flags & SLAB_RECLAIM_ACCOUNT) ?
        NR_SLAB_RECLAIMABLE : NR_SLAB_UNRECLAIMABLE,
        1 << oo_order(oo));
mod_zone_page_state(page_zone(page),
(s->flags & SLAB_RECLAIM_ACCOUNT) ?
NR_SLAB_RECLAIMABLE : NR_SLAB_UNRECLAIMABLE,
1 << oo_order(oo));

vmstat.c::mod_zone_page_state()

// ARM10C 20140628
// &(&contig_page_data)->node_zones[ZONE_NORMAL], NR_SLAB_UNRECLAIMABLE: 14, 1
void mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
                    int delta)
{
    unsigned long flags;

    local_irq_save(flags);
    // zone: &pgdat->node_zones[ZONE_NORMAL], item: 14, delta: 0x1
    __mod_zone_page_state(zone, item, delta);
    local_irq_restore(flags);
}

vmstat.c::__mod_zone_page_state()

// ARM10C 20140628
// zone: contig_page_data->node_zones[0], NR_SLAB_UNRECLAIMABLE: 14, 1
void __mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
                int delta)
{
    // zone->pageset: (&(&contig_page_data)->node_zones[ZONE_NORMAL])->pageset: &boot_pageset
    struct per_cpu_pageset __percpu *pcp = zone->pageset;
    // pcp: &boot_pageset

    s8 __percpu *p = pcp->vm_stat_diff + item;
    // p: &(&boot_pageset)->vm_stat_diff[14]

    long x;
    long t;

    // delta: 1, p: &(&boot_pageset)->vm_stat_diff[14]
    x = delta + __this_cpu_read(*p);

    // # define __this_cpu_read((&boot_pageset)->vm_stat_diff[0]):
    // __pcpu_size_call_return(__this_cpu_read_, ((&boot_pageset)->vm_stat_diff[0]))

    // __this_cpu_read_1(((&boot_pageset)->vm_stat_diff[0])):
    // *({
    //      do {
    //          const void __percpu *__vpp_verify = (typeof((&(((&boot_pageset)->vm_stat_diff[0])))))NULL;
    //          (void)__vpp_verify;
    //      } while (0)
    //      &(((&boot_pageset)->vm_stat_diff[0])) + __my_cpu_offset;
    // })

    // __pcpu_size_call_return(__this_cpu_read_, ((&boot_pageset)->vm_stat_diff[0])):
    // ({    typeof(((&boot_pageset)->vm_stat_diff[0])) pscr_ret__;
    //     __verify_pcpu_ptr(&(((&boot_pageset)->vm_stat_diff[0])));
    //     switch(sizeof(((&boot_pageset)->vm_stat_diff[0]))) {
    //     case 1: pscr_ret__ =
    //          *({
    //               do {
    //                   const void __percpu *__vpp_verify = (typeof((&(((&boot_pageset)->vm_stat_diff[0])))))NULL;
    //                   (void)__vpp_verify;
    //               } while (0)
    //               &(((&boot_pageset)->vm_stat_diff[0])) + __my_cpu_offset;
    //          }); break;
    //     }
    //     pscr_ret__;
    // })

    // __this_cpu_read((&boot_pageset)->vm_stat_diff[14]): 0
    // x: 1

    // pcp->stat_threshold: (&boot_pageset)->stat_threshold
    // __this_cpu_read((&boot_pageset)->stat_threshold): 0
    t = __this_cpu_read(pcp->stat_threshold);
    // t: 0

    // x: 1, t: 0
    if (unlikely(x > t || x < -t)) {
        zone_page_state_add(x, zone, item);
        // zone->vm_stat[14]: (&contig_page_data)->node_zones[ZONE_NORMAL].vm_stat[14]: 2
        // NR_SLAB_UNRECLAIMABLE: 14, vm_stat[14]: 2
        x = 0;
    }

    __this_cpu_write(*p, x);
    // p: &(&boot_pageset)->vm_stat_diff[14]: 0x0

    // __this_cpu_write(pcp, val):
    // __pcpu_size_call(__this_cpu_write_, (&boot_pageset)->vm_stat_diff[0], (x))

    // __this_cpu_write_1((&boot_pageset)->vm_stat_diff[0], x):
    // do {
    //    *({
    //        do {
    //            const void __percpu *__vpp_verify = (typeof(((&boot_pageset)->vm_stat_diff[0]))NULL;
    //            (void)__vpp_verify;
    //        } while (0)
    //        &((&boot_pageset)->vm_stat_diff[0]) + __my_cpu_offset;
    //    }) = x;
    // } while (0)

    // __pcpu_size_call(__this_cpu_write_, (&boot_pageset)->vm_stat_diff[0], x):
    // do {
    //     __verify_pcpu_ptr(&((&boot_pageset)->vm_stat_diff[0]));
    //     switch(sizeof((&boot_pageset)->vm_stat_diff[0])) {
    //         case 1:
    //         do {
    //             *({
    //                 do {
    //                     const void __percpu *__vpp_verify = (typeof(((&boot_pageset)->vm_stat_diff[0]))NULL;
    //                     (void)__vpp_verify;
    //                 } while (0)
    //                 &((&boot_pageset)->vm_stat_diff[0]) + __my_cpu_offset;
    //             }) = x;
    //         } while (0)
    //         break;
    //     }
    // } while (0)
}

vmstat.c::mod_zone_page_state()

// ARM10C 20140628
// &(&contig_page_data)->node_zones[ZONE_NORMAL], NR_SLAB_UNRECLAIMABLE: 14, 1
void mod_zone_page_state(struct zone *zone, enum zone_stat_item item,
                    int delta)
{
    unsigned long flags;

    local_irq_save(flags);
    // zone: &pgdat->node_zones[ZONE_NORMAL], item: 14, delta: 0x1
    __mod_zone_page_state(zone, item, delta);
    local_irq_restore(flags);
}
// zone->vm_stat[14]: (&contig_page_data)->node_zones[ZONE_NORMAL].vm_stat[14]: 2
// NR_SLAB_UNRECLAIMABLE: 14, vm_stat[14]: 2

slub.c::allocate_slab()

mod_zone_page_state(page_zone(page),
(s->flags & SLAB_RECLAIM_ACCOUNT) ?
NR_SLAB_RECLAIMABLE : NR_SLAB_UNRECLAIMABLE,
1 << oo_order(oo));
// zone->vm_stat[14]: (&contig_page_data)->node_zones[ZONE_NORMAL].vm_stat[14]: 2
// NR_SLAB_UNRECLAIMABLE: 14, vm_stat[14]: 2
static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node)
{
...
    mod_zone_page_state(page_zone(page),
        (s->flags & SLAB_RECLAIM_ACCOUNT) ?
        NR_SLAB_RECLAIMABLE : NR_SLAB_UNRECLAIMABLE,
        1 << oo_order(oo));
    // zone->vm_stat[14]: (&contig_page_data)->node_zones[ZONE_NORMAL].vm_stat[14]: 2
    // NR_SLAB_UNRECLAIMABLE: 14, vm_stat[14]: 2

    // page: migratetype이 MIGRATE_UNMOVABLE인 page (boot_kmem_cache)
    return page;
}
// return page: migratetype이 MIGRATE_UNMOVABLE인 page (boot_kmem_cache)

slub.c::new_slab()

// page = allocate_slab(s, flags & (GFP_RECLAIM_MASK | GFP_CONSTRAINT_MASK), node);
// return page: migratetype이 MIGRATE_UNMOVABLE인 page (boot_kmem_cache)
static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)
{
...
    page = allocate_slab(s,
        flags & (GFP_RECLAIM_MASK | GFP_CONSTRAINT_MASK), node);
    // page: migratetype이 MIGRATE_UNMOVABLE인 page (boot_kmem_cache)

    if (!page)
        goto out;

    // page: migratetype이 MIGRATE_UNMOVABLE인 page (boot_kmem_cache)
    // compound_order(page): 0
    order = compound_order(page);
    // free_pages_check에서 page->flags의 NR_PAGEFLAGS 만큼의 하위 비트를 전부 지워줌
    // order: 0

    // s: &boot_kmem_cache, page: migratetype이 MIGRATE_UNMOVABLE인 page (boot_kmem_cache),
    // page_to_nid(migratetype이 MIGRATE_UNMOVABLE인 page (boot_kmem_cache)): 0, page->objects: 32
    inc_slabs_node(s, page_to_nid(page), page->objects);
inc_slabs_node(s, page_to_nid(page), page->objects);

slub.c::inc_slabs_node()

// ARM10C 20140628
// s: &boot_kmem_cache, page: migratetype이 MIGRATE_UNMOVABLE인 page (boot_kmem_cache),
// page_to_nid(migratetype이 MIGRATE_UNMOVABLE인 page (boot_kmem_cache)): 0, page->objects: 32
static inline void inc_slabs_node(struct kmem_cache *s, int node, int objects)
{
    // s: &boot_kmem_cache, node: 0
    // get_node(&boot_kmem_cache, 0): (&boot_kmem_cache)->node[0]:
    // UNMOVABLE인 page 의 object의 시작 virtual address + 64
    struct kmem_cache_node *n = get_node(s, node);
    // n: &(&boot_kmem_cache)->node[0]: UNMOVABLE인 page 의 object의 시작 virtual address + 64

    // n: &(&boot_kmem_cache)->node[0]: UNMOVABLE인 page 의 object의 시작 virtual address + 64
    if (likely(n)) {
        // n->nr_slabs: 0
        atomic_long_inc(&n->nr_slabs);
        // n->nr_slabs: 1

        // objects: 32, n->total_objects: 0
        atomic_long_add(objects, &n->total_objects);
        // n->total_objects: 32
    }
    // kmem_cache_node 가 완성된 이후에 nr_slabs, total_objects 를 증가시킴
}
// kmem_cache_node 가 완성된 이후에 nr_slabs, total_objects 를 증가시킴

inc_slabs_node(&boot_kmem_cache)에서 한일:

// 이전에 할당 받은 MIGRATE_UNMOVABLE인 page의 두번째 object의 맴버 필드값을 변경
// n: &(&boot_kmem_cache)->node[0]: UNMOVABLE인 page 의 object의 시작 virtual address + 64
// n->nr_slabs: 1
// n->total_objects: 32

slub.c::new_slab()

// inc_slabs_node(s, page_to_nid(page), page->objects);
// n: &(&boot_kmem_cache)->node[0]: UNMOVABLE인 page 의 object의 시작 virtual address + 64
// n->nr_slabs: 1
// n->total_objects: 32
static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)
{
...
    inc_slabs_node(s, page_to_nid(page), page->objects);

    // s: &boot_kmem_cache, order: 0
    memcg_bind_pages(s, order); // null function

    // page: migratetype이 MIGRATE_UNMOVABLE인 page (boot_kmem_cache), s: &boot_kmem_cache
    page->slab_cache = s;
    // page->slab_cache: &boot_kmem_cache

    // page: migratetype이 MIGRATE_UNMOVABLE인 page (boot_kmem_cache)
    __SetPageSlab(page);
    // page->flags에 7 (PG_slab) bit를 set

    // page->pfmemalloc: 0
    if (page->pfmemalloc)
        SetPageSlabPfmemalloc(page);

    // page_address(UNMOVABLE인 page (boot_kmem_cache)): UNMOVABLE인 page (boot_kmem_cache)의 virtual address
    start = page_address(page);
start = page_address(page);

highmem.c::page_address()

// ARM10C 20140628
// page: UNMOVABLE인 page (boot_kmem_cache)
void *page_address(const struct page *page)
{
    unsigned long flags;
    void *ret;
    struct page_address_slot *pas;

    // PageHighMem(page): 0
    if (!PageHighMem(page))
        return lowmem_page_address(page);
        // page의 virtual address 값을 리턴
...
}
// page의 virtual address 값을 리턴

slub.c::new_slab()

// inc_slabs_node(s, page_to_nid(page), page->objects);
// n: &(&boot_kmem_cache)->node[0]: UNMOVABLE인 page 의 object의 시작 virtual address + 64
// n->nr_slabs: 1
// n->total_objects: 32
static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)
{
...
    start = page_address(page);
    // start: UNMOVABLE인 page (boot_kmem_cache)의 virtual address

    // s->flags: boot_kmem_cache.flags: SLAB_HWCACHE_ALIGN: 0x00002000UL
    // SLAB_POISON: 0x00000800UL
    if (unlikely(s->flags & SLAB_POISON))
        memset(start, POISON_INUSE, PAGE_SIZE << order);

    // start: UNMOVABLE인 page (boot_kmem_cache)의 virtual address
    last = start;
    // last: UNMOVABLE인 page (boot_kmem_cache)의 virtual address

    // s: &boot_kmem_cache,
    // start: UNMOVABLE인 page (boot_kmem_cache)의 virtual address
    // page->objects: 32
    for_each_object(p, s, start, page->objects) {

    // for (p = (UNMOVABLE인 page (boot_kmem_cache)의 virtual address);
    //      p < (UNMOVABLE인 page (boot_kmem_cache)의 virtual address) + (32) * (&boot_kmem_cache)->size;
    //    p += (&boot_kmem_cache)->size)

        // [loop 1] p: UNMOVABLE인 page (boot_kmem_cache)의 virtual address
        // [loop 1] (&boot_kmem_cache)->size: 128
        // [loop 2] p: UNMOVABLE인 page (boot_kmem_cache)의 virtual address + 128
        // [loop 2] (&boot_kmem_cache)->size: 128
        // [loop 1] s: &boot_kmem_cache, page: UNMOVABLE인 page(boot_kmem_cache),
        // [loop 1] last: UNMOVABLE인 page (boot_kmem_cache)의 virtual address
        // [loop 2] s: &boot_kmem_cache, page: UNMOVABLE인 page(boot_kmem_cache),
        // [loop 2] last: UNMOVABLE인 page (boot_kmem_cache) 의 virtual address
        setup_object(s, page, last);

        // [loop 1] s: &boot_kmem_cache, last: UNMOVABLE인 page (boot_kmem_cache)의 virtual address,
        // [loop 1] p: UNMOVABLE인 page 의 virtual address(boot_kmem_cache)
        // [loop 2] s: &boot_kmem_cache, last: UNMOVABLE인 page (boot_kmem_cache)의 virtual address,
        // [loop 2] p: UNMOVABLE인 page (boot_kmem_cache)의 virtual address + 128
        set_freepointer(s, last, p);
        // [loop 1] last에 p 주소를 mapping 함
        // [loop 2] last에 p 주소를 mapping 함

        // [loop 1] p: UNMOVABLE인 page (boot_kmem_cache)의 virtual address
        // [loop 2] p: UNMOVABLE인 page (boot_kmem_cache)의 virtual address + 128
        last = p;
        // [loop 1] last: UNMOVABLE인 page (boot_kmem_cache)의 virtual addres
        // [loop 2] last: UNMOVABLE인 page (boot_kmem_cache)의 virtual addres + 128

        // [loop 3..32] 수행
    }

    // s: &boot_kmem_cache, page: UNMOVABLE인 page (boot_kmem_cache)
    // last: UNMOVABLE인 page (boot_kmem_cache)의 virtual address + 0x1000 - 128
    setup_object(s, page, last);
setup_object(s, page, last);

slub.c::setup_object()

// ARM10C 20140628
// s: &boot_kmem_cache, page: UNMOVABLE인 page(boot_kmem_cache),
// last: UNMOVABLE인 page 의 virtual address(boot_kmem_cache)
static void setup_object(struct kmem_cache *s, struct page *page,
                void *object)
{
    // s: &boot_kmem_cache, page: UNMOVABLE인 page(boot_kmem_cache)
    // object: UNMOVABLE인 page 의 virtual address(boot_kmem_cache)
    setup_object_debug(s, page, object);

    // s->ctor: boot_kmem_cache.ctor: NULL
    if (unlikely(s->ctor))
        s->ctor(object);
}

slub.c::new_slab()

static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)
{
...
    setup_object(s, page, last);

    // s: &boot_kmem_cache
    // last: UNMOVABLE인 page (boot_kmem_cache)의 virtual address + 0x1000 - 128
    set_freepointer(s, last, NULL);
set_freepointer(s, last, NULL);

slub.c::set_freepointer()

// ARM10C 20140628
// s: &boot_kmem_cache, last: UNMOVABLE인 page 의 virtual address(boot_kmem_cache),
// p: UNMOVABLE인 page 의 virtual address(boot_kmem_cache)
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
    // object: UNMOVABLE인 page 의 virtual address(boot_kmem_cache)
    // s->offset: (&boot_kmem_cache_node)->offset: 0
    // fp: UNMOVABLE인 page 의 virtual address(boot_kmem_cache)
    *(void **)(object + s->offset) = fp;
    // object: UNMOVABLE인 page 의 virtual address(boot_kmem_cache)
}
// object: UNMOVABLE인 page 의 virtual address(boot_kmem_cache)

slub.c::new_slab()

static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)
{
...
    set_freepointer(s, last, NULL);
    // 마지막 object의 내부 freepointer는 null 초기화함

    // start: UNMOVABLE인 page (boot_kmem_cache)의 virtual address
    page->freelist = start;
    // page->freelist: UNMOVABLE인 page (boot_kmem_cache)의 virtual address

    // page의 freelist 맴버는 slab의 object의 시작주소를 가리킴

    // page->objects: 32
    page->inuse = page->objects;
    // page->inuse: 32

    // page의 inuse 맴버는 slab의 free상태인 object의 총 갯수

    page->frozen = 1;
    // page->frozen: 1
out:
    // page: UNMOVABLE인 page (boot_kmem_cache)
    return page;
}
// page = new_slab(s, flags, node);
// page: UNMOVABLE인 page (boot_kmem_cache)

new_slab에서 한일

  • migratetype이 MIGRATE_UNMOVABLE인 page (boot_kmem_cache) 할당 받음
  • 이전에 할당 받은 MIGRATE_UNMOVABLE인 page의 두번째 object의 맴버 필드값을 변경
  • n->nr_slabs: 1
  • n->total_objects: 32
  • page->slab_cache: &boot_kmem_cache주소를 set
  • slab 의 objects 들의 freepointer를 맵핑함
  • 새로 받은 page의 맴버 필드 값 세팅
  • page->freelist: UNMOVABLE인 page (boot_kmem_cache)의 virtual address
  • page->inuse: 32
  • page->frozen: 1
  • page->flags에 7 (PG_slab) bit를 set

slub.c::new_slab_objects()

// page = new_slab(s, flags, node);
// page: UNMOVABLE인 page (boot_kmem_cache)
static inline void *new_slab_objects(struct kmem_cache *s, gfp_t flags,
            int node, struct kmem_cache_cpu **pc)
{
...
    page = new_slab(s, flags, node);
    // page: UNMOVABLE인 page (boot_kmem_cache)


    // page: UNMOVABLE인 page (boot_kmem_cache)
    if (page) {
        // s->cpu_slab: (&boot_kmem_cache)->cpu_slab: 0xc0502d10
        // __this_cpu_ptr(0xc0502d10):
        // (&boot_kmem_cache)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))
        c = __this_cpu_ptr(s->cpu_slab);
        // c: (&boot_kmem_cache)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))

        // pcpu_populate_chunk에서 kmem_cache_cpu의 맵버 필드를 0 으로 초기화함

        // c->page: ((&boot_kmem_cache)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)))->page: 0
        if (c->page)
            flush_slab(s, c);

        // page->freelist: UNMOVABLE인 page (boot_kmem_cache)의 virtual address
        freelist = page->freelist;
        // freelist: UNMOVABLE인 page (boot_kmem_cache)의 virtual address

        // page->freelist: UNMOVABLE인 page (boot_kmem_cache)의 virtual address
        page->freelist = NULL;
        // page->freelist: NULL

        // s: &boot_kmem_cache, ALLOC_SLAB: 8
        stat(s, ALLOC_SLAB); // null function

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

        // *pc: (&boot_kmem_cache)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋),
        // c: (&boot_kmem_cache)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))
        *pc = c;
        // *pc: (&boot_kmem_cache)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
    } else
        freelist = NULL;

    // freelist: UNMOVABLE인 page (boot_kmem_cache)의 virtual address
    return freelist;
    // return UNMOVABLE인 page (boot_kmem_cache)의 virtual address
}
// return freelist
// return UNMOVABLE인 page (boot_kmem_cache)의 virtual address

slub.c::__slab_alloc()

// freelist = new_slab_objects(s, gfpflags, node, &c);
static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node,
              unsigned long addr, struct kmem_cache_cpu *c)
{
...
new_slab:
    freelist = new_slab_objects(s, gfpflags, node, &c);
    // freelist: UNMOVABLE인 page (boot_kmem_cache)의 virtual address

    if (unlikely(!freelist)) {
        if (!(gfpflags & __GFP_NOWARN) && printk_ratelimit())
            slab_out_of_memory(s, gfpflags, node);

        local_irq_restore(flags);
        return NULL;
    }

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

    // s: &boot_kmem_cache, kmem_cache_debug(&boot_kmem_cache): 0
    // page: MIGRATE_UNMOVABLE인 page (boot_kmem_cache), gfpflags: __GFP_ZERO: 0x8000
    // pfmemalloc_match(MIGRATE_UNMOVABLE인 page(boot_kmem_cache), __GFP_ZERO: 0x8000): 1
    if (likely(!kmem_cache_debug(s) && pfmemalloc_match(page, gfpflags)))
        goto load_freelist;
        // load_freelist 심볼로 점프

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

    // (MIGRATE_UNMOVABLE인 page(boot_kmem_cache))->frozen: 1
    VM_BUG_ON(!c->page->frozen);

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

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

    local_irq_restore(flags);
    // flags에 저장된 cpsr 을 복원

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

__slab_alloc(&boot_kmem_cache)이 한일:

  • object를 위한 page 의 사용 하지 않은 다음 object의 시작 virtual address 를 가져옴
  • migratetype이 MIGRATE_UNMOVABLE인 page (boot_kmem_cache) 할당 받음
  • 이전에 할당 받은 MIGRATE_UNMOVABLE인 page의 두번째 object의 맴버 필드값을 변경
  • n->nr_slabs: 1
  • n->total_objects: 32
  • slab 의 objects 들의 freepointer를 맵핑함
  • 새로 받은 page의 맴버 필드 값 세팅
  • page->slab_cache: &boot_kmem_cache주소를 set
  • page->freelist: NULL
  • page->inuse: 32
  • page->frozen: 1
  • page->flags에 7 (PG_slab) bit를 set
  • c->freelist: ((&boot_kmem_cache)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->freelist:
  • UNMOVABLE인 page (boot_kmem_cache)의 시작 object의 virtual address + 128
  • c->tid: ((&boot_kmem_cache)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->tid: 4

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);
        // object: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address
    else {
        void *next_object = get_freepointer_safe(s, object);
        ...
    }

    // gfpflags: __GFP_ZERO: 0x8000, __GFP_ZERO: 0x8000u
    // object: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address
    if (unlikely(gfpflags & __GFP_ZERO) && object)
        memset(object, 0, s->object_size);

    // s: &boot_kmem_cache, gfpflags: __GFP_ZERO: 0x8000,
    // object: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address
    slab_post_alloc_hook(s, gfpflags, object);
slab_post_alloc_hook(s, gfpflags, object);

slub.c::slab_post_alloc_hook()

// ARM10C 20140628
// s: &boot_kmem_cache, gfpflags: __GFP_ZERO: 0x8000,
// object: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address
static inline void slab_post_alloc_hook(struct kmem_cache *s,
                    gfp_t flags, void *object)
{
    // flags: __GFP_ZERO: 0x8000, gfp_allowed_mask: 0x1ffff2f
    flags &= gfp_allowed_mask;
    // flags: 0x8000

    // s: &boot_kmem_cache, flags: 0, object: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address
    // slab_ksize(&boot_kmem_cache): 128
    kmemcheck_slab_alloc(s, flags, object, slab_ksize(s)); // null function

    // object: object: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
    // s->object_size: boot_kmem_cache.object_size: 116,
    // s->flags: boot_kmem_cache.flags: SLAB_HWCACHE_ALIGN: 0x00002000UL, flags: 0
    kmemleak_alloc_recursive(object, s->object_size, 1, s->flags, flags); // null function
}

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:

...
    slab_post_alloc_hook(s, gfpflags, object);

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

slub.c::slab_alloc()

// return UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address
static __always_inline void *slab_alloc(struct kmem_cache *s,
        gfp_t gfpflags, unsigned long addr)
{
    return slab_alloc_node(s, gfpflags, NUMA_NO_NODE, addr);
    // return UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address
}
// return UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address

slub.c::kmem_cache_alloc()

// void *ret = slaballoc(s, gfpflags, _RET_IP);
// ret: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address
void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags)
{
    void *ret = slab_alloc(s, gfpflags, _RET_IP_);
    // ret: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address

    // s->object_size: boot_kmem_cache.object_size: 116,
    // s->size: boot_kmem_cache.size: 128,
    // gfpflags: __GFP_ZERO: 0x8000
    trace_kmem_cache_alloc(_RET_IP_, ret, s->object_size,
                s->size, gfpflags);

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

slab.h::kmem_cache_zalloc()

// return ret: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address
static inline void *kmem_cache_zalloc(struct kmem_cache *k, gfp_t flags)
{
    return kmem_cache_alloc(k, flags | __GFP_ZERO);
    // return UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address
}
// return UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address

slub.c::bootstrap()

static struct kmem_cache * __init bootstrap(struct kmem_cache *static_cache)
{
    int node;

    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 종료

스터디 로그

78add0d..b487a52  master     -> origin/master
Updating 78add0d..b487a52
Fast-forward
include/asm-generic/percpu.h |   2 +
include/linux/fault-inject.h |   1 +
include/linux/gfp.h          |  17 +++-
include/linux/kernel.h       |   1 +
include/linux/kobject.h      |   2 +-
include/linux/lockdep.h      |   1 +
include/linux/memcontrol.h   |   4 +
include/linux/mm.h           |   3 +
include/linux/page-flags.h   |   2 +
include/linux/preempt.h      |   2 +
include/linux/slab.h         |   6 ++
include/linux/slub_def.h     |   5 +-
include/linux/topology.h     |   1 +
mm/highmem.c                 |   2 +
mm/page_alloc.c              |   3 +
mm/slab.h                    |   2 +
mm/slab_common.c             |  47 +++++++++--
mm/slub.c                    | 648 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------
mm/vmstat.c                  |  23 +++++
19 files changed, 675 insertions(+), 97 deletions(-)