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
// &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
// 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_alloc | kmem_cache_node | GFP_KERNEL |
kmem_cache_zalloc() | kmem_cache | GFP_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
// 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
// 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
// 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
// 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
// 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값을 반환한다.
맞다면 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
// 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
// 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
// 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의 옵셋)
// 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의 옵셋)
// 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
// 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
// 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의 옵셋)
// 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
// 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
// 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
// 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
// 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
// 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
// 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가 리턴됨
// 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)라고 표기할 것임
// 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
// &(&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
// 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
// &(&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
// 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
// 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)
// 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
// 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
// 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
// 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
// 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)
// 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)
// 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)
// 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)
// 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
// 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
// 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
// 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(-)