ARM10C 62주차 후기
일시 : 2014.07.12 (62주차)
모임명 : NAVER개발자커뮤니티지원_IAMROOT.ORG_10차ARM-C
장소 : 토즈 타워점
장소지원 : NAVER 개발자 커뮤니티 지원 프로그램
참여인원 : 5명
스터디 진도 :
- mm_init()을 계속 분석합니다.
- start_kernel()-> mm_init()->kmem_cache_init()->bootstrap()분석중
- bootstrap()은 두번 실행됩니다.
- 1번째는 &boot_kmem_cache 매개변수를 가지고
- 2번째는 &boot_kmem_cache_node 매개변수를 가지고 실행합니다.
main.c::mm_init()
static void __init mm_init(void)
{
page_cgroup_init_flatmem(); // null function
mem_init();
// bootmem으로 관리하던 메모리를 buddy로 이관.
// 각 section 메모리 크기를 출력.
// mm/Makefile 에서 CONFIG_SLUB 설정으로 slub.c 로 jump
kmem_cache_init();
// mm/Makefile 에서 CONFIG_SLUB 설정으로 slub.c 로 jump
kmem_cache_init();
slub.c::kmem_cache_init()
void __init kmem_cache_init(void)
{
...
create_boot_cache(kmem_cache_node, "kmem_cache_node",
sizeof(struct kmem_cache_node), SLAB_HWCACHE_ALIGN);
...
slab_state = PARTIAL;
...
create_boot_cache(kmem_cache, "kmem_cache",
offsetof(struct kmem_cache, node) +
nr_node_ids * sizeof(struct kmem_cache_node *),
SLAB_HWCACHE_ALIGN);
kmem_cache = bootstrap(&boot_kmem_cache);
kmem_cache_node = bootstrap(&boot_kmem_cache_node);
kmem_cache_node = bootstrap(&boot_kmem_cache_node);
boot_kmem_cache_node를 매개변수로 하여 bootstrap()을 재 실행한다.
slub.c::bootstrap()
// struct kmem_cache * static_cache: &&boot_kmem_cache_node
// kmem_cache_node = bootstrap(&boot_kmem_cache_node);
// kmem_cache_node = bootstrap(&boot_kmem_cache_node);
static struct kmem_cache * __init bootstrap(struct kmem_cache *static_cache)
{
int node;
// kmem_cache: &boot_kmem_cache_node, GFP_NOWAIT: 0
// kmem_cache_zalloc(&boot_kmem_cache_node, GFP_NOWAIT: 0):
// UNMOVABLE인 page 의 object의 시작 virtual address + 128
struct kmem_cache *s = kmem_cache_zalloc(kmem_cache, GFP_NOWAIT);
// s: UNMOVABLE인 page 의 object의 시작 virtual address + 128
// s: UNMOVABLE인 page 의 object의 시작 virtual address + 128
// static_cache: &boot_kmem_cache_node,
// kmem_cache->object_size: boot_kmem_cache_node.object_size: 44
memcpy(s, static_cache, kmem_cache->object_size);
// boot_kmem_cache_node에 세팅된 멤버 필드 값을 전부 할당 받은 object로 복사함
// s: UNMOVABLE인 page 의 object의 시작 virtual address + 128,
// smp_processor_id(): 0
__flush_cpu_slab(s, smp_processor_id());
__flush_cpu_slab(s, smp_processor_id());
slub.c::__flush_cpu_slab()
// s: UNMOVABLE인 page 의 object의 시작 virtual address + 128,
// smp_processor_id(): 0
// __flush_cpu_slab(s, 0);
// smp_processor_id(): 0
// __flush_cpu_slab(s, 0);
static inline void __flush_cpu_slab(struct kmem_cache *s, int cpu)
{
// s->cpu_slab: (&boot_kmem_cache_node 용 object 주소)->cpu_slab: 0xc0502d00, cpu: 0
// per_cpu_ptr(0xc0502d00, 0):
// (&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
struct kmem_cache_cpu *c = per_cpu_ptr(s->cpu_slab, cpu);
// c: (&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
// c: (&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
if (likely(c)) {
// c->page: ((&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->page:
// UNMOVABLE인 page
if (c->page)
// s: UNMOVABLE인 page 의 object의 시작 virtual address + 128,
// c: (&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
flush_slab(s, c);
flush_slab(s, c);
slub.c::flush_slab()
// s: UNMOVABLE인 page 의 object의 시작 virtual address + 128,
// c: (&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
// c: (&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
static inline void flush_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
{
// s: UNMOVABLE인 page 의 object의 시작 virtual address + 128,
// CPUSLAB_FLUSH: 13
stat(s, CPUSLAB_FLUSH);
// s: UNMOVABLE인 page 의 object의 시작 virtual address + 128,
// c->page: ((&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->page:
// UNMOVABLE인 page,
// c->freelist: ((&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->freelist:
// UNMOVABLE인 page 의 object의 시작 virtual address + 192
deactivate_slab(s, c->page, c->freelist);
deactivate_slab(s, c->page, c->freelist);
slub.c::deactivate_slab()
// s: UNMOVABLE인 page 의 object의 시작 virtual address + 128,
// c->page: ((&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + per_cpu_start에서의pcpu_base_addr의 옵셋))->page:
// UNMOVABLE인 page,
// c->freelist: ((&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + per_cpu_start에서의pcpu_base_addr의 옵셋))->freelist:
// UNMOVABLE인 page 의 object의 시작 virtual address + 192
// c->page: ((&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + per_cpu_start에서의pcpu_base_addr의 옵셋))->page:
// UNMOVABLE인 page,
// c->freelist: ((&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + per_cpu_start에서의pcpu_base_addr의 옵셋))->freelist:
// UNMOVABLE인 page 의 object의 시작 virtual address + 192
static void deactivate_slab(struct kmem_cache *s, struct page *page,
void *freelist)
{
enum slab_modes { M_NONE, M_PARTIAL, M_FULL, M_FREE };
// s: UNMOVABLE인 page 의 object의 시작 virtual address + 128,
// page: UNMOVABLE인 page
// page_to_nid(UNMOVABLE인 page): 0
// get_node(UNMOVABLE인 page 의 object의 시작 virtual address + 128, 0):
// (&boot_kmem_cache_node 용 object 주소)->node[0]
struct kmem_cache_node *n = get_node(s, page_to_nid(page));
// n: (&boot_kmem_cache_node 용 object 주소)->node[0]
int lock = 0;
// lock: 0
enum slab_modes l = M_NONE, m = M_NONE;
// l: M_NONE: 0, m: M_NONE: 0
void *nextfree;
int tail = DEACTIVATE_TO_HEAD;
// tail: DEACTIVATE_TO_HEAD: 15
struct page new;
struct page old;
// page->freelist: (UNMOVABLE인 page)->freelist: NULL
if (page->freelist) {
stat(s, DEACTIVATE_REMOTE_FREES);
tail = DEACTIVATE_TO_TAIL;
}
// [boot_kmem_cache_node 로 호출]
// s: UNMOVABLE인 page 의 object의 시작 virtual address + 128,
// freelist: UNMOVABLE인 page 의 object의 시작 virtual address + 192,
// get_freepointer(UNMOVABLE인 page 의 object의 시작 virtual address + 128,
// UNMOVABLE인 page 의 object의 시작 virtual address + 192):
// UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 256
// nextfree: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 256
while (freelist && (nextfree = get_freepointer(s, freelist))) {
void *prior;
unsigned long counters;
// [loop 1] freelist: UNMOVABLE인 page의 시작 virtual address + 192
// [loop 1] nextfree: UNMOVABLE인 page의 시작 virtual address + 256
// [loop 2] freelist: UNMOVABLE인 page의 시작 virtual address + 256
// [loop 2] nextfree: UNMOVABLE인 page의 시작 virtual address + 320
do {
// [loop 1] page->freelist: NULL
// [loop 2] page->freelist: UNMOVABLE인 page 의 시작 virtual address + 192
prior = page->freelist;
// [loop 1] prior: NULL
// [loop 2] prior: UNMOVABLE인 page 의 시작 virtual address + 192
// [loop 1] page->counters: (UNMOVABLE인 page)->counters: 0x80400040
// [loop 2] page->counters: (UNMOVABLE인 page)->counters: 0x8040003f
counters = page->counters;
// [loop 1] counters: 0x80400040
// [loop 2] counters: 0x8040003f
// [loop 1] s: UNMOVABLE인 page 의 object의 시작 virtual address + 128,
// [loop 1] freelist: UNMOVABLE인 page 의 object의 시작 virtual address + 192,
// [loop 1] prior: NULL
// [loop 2] s: UNMOVABLE인 page 의 object의 시작 virtual address + 128,
// [loop 2] freelist: UNMOVABLE인 page 의 시작 virtual address + 256,
// [loop 2] prior: UNMOVABLE인 page 의 시작 virtual address + 192
set_freepointer(s, freelist, prior);
// [loop 1] freelist: UNMOVABLE인 page 의 시작 virtual address + 192: NULL
// [loop 1] UNMOVABLE인 page 의 시작 virtual address + 192 의 다음 object를 가리키는 주소의 값을
// [loop 1] NULL로 세팅
// [loop 2] freelist: UNMOVABLE인 page 의 시작 virtual address + 256:
// [loop 2] UNMOVABLE인 page 의 시작 virtual address + 192,
// [loop 2] UNMOVABLE인 page 의 시작 virtual address + 256 의 다음 object를 가리키는 주소의 값을
// [loop 2] 이전 object 주소로 세팅
// [loop 1] counters: 0x80400040
// [loop 2] counters: 0x8040003f
new.counters = counters;
// [loop 1] new.counters: 0x80400040
// [loop 2] new.counters: 0x8040003f
// [loop 1] new.inuse: 64, new.counters: 0x80400040
// [loop 2] new.inuse: 63, new.counters: 0x8040003f
new.inuse--;
// [loop 1] new.inuse: 63, new.counters: 0x8040003f
// [loop 2] new.inuse: 62, new.counters: 0x8040003e
// [loop 1] new.frozen: 1
// [loop 2] new.frozen: 1
VM_BUG_ON(!new.frozen);
// [loop 1] s: UNMOVABLE인 page 의 object의 시작 virtual address + 128,
// [loop 1] page: UNMOVABLE인 page,
// [loop 1] prior: NULL, counters: 0x80400040,
// [loop 1] freelist: UNMOVABLE인 page 의 시작 virtual address + 192,
// [loop 1] new.counters: 0x8040003f,
// [loop 1] "drain percpu freelist"
// [loop 1] __cmpxchg_double_slab(UNMOVABLE인 page 의 object의 시작 virtual address + 128,
// [loop 1] UNMOVABLE인 page, NULL, 0x80400040, UNMOVABLE인 page 의 시작 virtual address + 192,
// [loop 1] 0x8040003f, "drain percpu freelist"): 1
// [loop 1] UNMOVABLE인 page 의 필드 맴버 값 변경
// [loop 1] (UNMOVABLE인 page)->freelist: UNMOVABLE인 page 의 시작 virtual address + 192
// [loop 1] (UNMOVABLE인 page)->counters: 0x8040003f
//
// [loop 2] s: UNMOVABLE인 page 의 object의 시작 virtual address + 128,
// [loop 2] page: UNMOVABLE인 page,
// [loop 2] prior: UNMOVABLE인 page 의 시작 virtual address + 192, counters: 0x8040003f,
// [loop 2] freelist: UNMOVABLE인 page 의 시작 virtual address + 256,
// [loop 2] new.counters: 0x8040003e,
// [loop 2] "drain percpu freelist"
// [loop 2] __cmpxchg_double_slab(UNMOVABLE인 page 의 object의 시작 virtual address + 128,
// [loop 2] UNMOVABLE인 page, UNMOVABLE인 page 의 시작 virtual address + 192,
// [loop 2] 0x8040003f, UNMOVABLE인 page 의 시작 virtual address + 256, 0x8040003e, "drain percpu freelist"): 1
// [loop 2] UNMOVABLE인 page 의 필드 맴버 값 변경
// [loop 2] (UNMOVABLE인 page)->freelist: UNMOVABLE인 page 의 시작 virtual address + 256
// [loop 2] (UNMOVABLE인 page))->counters: 0x8040003e
} while (!__cmpxchg_double_slab(s, page,
prior, counters,
freelist, new.counters,
"drain percpu freelist"));
// [loop 1] nextfree: UNMOVABLE인 page 의 시작 virtual address + 256
// [loop 2] nextfree: UNMOVABLE인 page 의 시작 virtual address + 320
freelist = nextfree;
// [loop 1] freelist: UNMOVABLE인 page 의 시작 virtual address + 256
// [loop 2] freelist: UNMOVABLE인 page 의 시작 virtual address + 320
// [loop 3 .. 60] 번 수행
}
// [boot_kmem_cache_node 로 호출]
// 위의 루프에서 한일:
// UNMOVABLE인 page 의 사용하지 않는 첫 번째 object의 freepointer 값을 NULL 로 변경,
// 나머지 object들의 freepointer 값을 이전 object들의 주소로 변경
// UNMOVABLE인 page 의 맴버필드 변경
// (UNMOVABLE인 page )->freelist: UNMOVABLE인 page 의 시작 virtual address + 3968
// (UNMOVABLE인 page )->counters: 0x80400004
redo:
// page->freelist: UNMOVABLE인 page 의 시작 virtual address + 3968
old.freelist = page->freelist;
// old.freelist: UNMOVABLE인 page 의 시작 virtual address + 3968
// page->counters: (UNMOVABLE인 page)->counters: 0x80400004
old.counters = page->counters;
// old.counters: 0x80400004
// old.frozen: 1
VM_BUG_ON(!old.frozen);
// old.counters: 0x80400004
new.counters = old.counters;
// new.counters: 0x80400004
// freelist: UNMOVABLE인 page 의 시작 virtual address + 4032
if (freelist) {
// new.inuse: 4
new.inuse--;
// new.inuse: 3, new.counters: 0x80400003
// s: UNMOVABLE인 page 의 object의 시작 virtual address + 128,
// freelist: UNMOVABLE인 page 의 시작 virtual address + 4032
// old.freelist: UNMOVABLE인 page 의 시작 virtual address + 3968
set_freepointer(s, freelist, old.freelist);
// UNMOVABLE인 page 의 시작 virtual address + 4032 의 다음 object를 가리키는 주소의 값을
// UNMOVABLE인 page 의 시작 virtual address + 3968 로 세팅
// freepointer의 주소를 이전 object 주소로 변경
// freelist: UNMOVABLE인 page 의 시작 virtual address + 4032
new.freelist = freelist;
// new.freelist: UNMOVABLE인 page 의 시작 virtual address + 4032
} else
new.freelist = old.freelist;
// new.frozen: 1
new.frozen = 0;
// new.frozen: 0, new.counters: 0x00400003
// n: (&boot_kmem_cache_node 용 object 주소)->node[0]:
// UNMOVABLE인 page 의 object의 시작 virtual address
// new.inuse: 3, n->nr_partial: 1, s->min_partial: (&boot_kmem_cache_node 용 object 주소)->min_partial: 5
// new.freelist: UNMOVABLE인 page 의 시작 virtual address + 4032
if (!new.inuse && n->nr_partial > s->min_partial)
m = M_FREE;
else if (new.freelist) {
// m: M_NONE: 0
m = M_PARTIAL;
// m: M_PARTIAL: 1
// lock: 0
if (!lock) {
// lock: 0
lock = 1;
// lock: 1
spin_lock(&n->list_lock);
// n->list_lock 을 이용한 spin_lock 획득
}
} else {
m = M_FULL;
if (kmem_cache_debug(s) && !lock) {
lock = 1;
spin_lock(&n->list_lock);
}
}
// l: M_NONE: 0, m: M_PARTIAL: 1
if (l != m) {
// l: M_NONE: 0, m: M_PARTIAL: 1
if (l == M_PARTIAL)
remove_partial(n, page);
else if (l == M_FULL)
remove_full(s, page);
if (m == M_PARTIAL) {
// n: (&boot_kmem_cache_node 용 object 주소)->node[0]:
// UNMOVABLE인 page 의 object의 시작 virtual address,
// page: UNMOVABLE인 page,
// tail: DEACTIVATE_TO_HEAD: 15
add_partial(n, page, tail);
// add_partial 한일:
// n->nr_partial: 2
// n->partial에 (UNMOVABLE인 page)->lru 가 추가됨
// s: UNMOVABLE인 page 의 object의 시작 virtual address,
// tail: DEACTIVATE_TO_HEAD: 15
stat(s, tail);
} else if (m == M_FULL) {
stat(s, DEACTIVATE_FULL);
add_full(s, n, page);
}
}
// l: M_NONE: 0, m: M_PARTIAL: 1
l = m;
// l: M_PARTIAL: 1
// s: UNMOVABLE인 page 의 object의 시작 virtual address + 128,
// page: UNMOVABLE인 page,
// old.freelist: UNMOVABLE인 page 의 시작 virtual address + 3968
// old.counters: 0x80400004
// new.freelist: UNMOVABLE인 page 의 시작 virtual address + 4032
// new.counters: 0x00400003
// "unfreezing slab"
// __cmpxchg_double_slab(UNMOVABLE인 page 의 object의 시작 virtual address + 128,
// UNMOVABLE인 page, UNMOVABLE인 page 의 시작 virtual address + 3968,
// 0x80400004, UNMOVABLE인 page 의 시작 virtual address + 4032,
// 0x00400003, "unfreezing slab"): 1
// UNMOVABLE인 page)의 필드 맴버 값 변경
// (UNMOVABLE인 page)->freelist: UNMOVABLE인 page 의 시작 virtual address + 4032
// (UNMOVABLE인 page)->counters: 0x00400003
if (!__cmpxchg_double_slab(s, page,
old.freelist, old.counters,
new.freelist, new.counters,
"unfreezing slab"))
goto redo;
// lock: 1
if (lock)
spin_unlock(&n->list_lock);
// n->list_lock 을 이용한 spin_lock 해재
// m: M_PARTIAL: 1
if (m == M_FREE) {
stat(s, DEACTIVATE_EMPTY);
discard_slab(s, page);
stat(s, FREE_SLAB);
}
}
deactivate_slab에서 한일:
// UNMOVABLE인 page 의 필드 맴버 값 변경
// (UNMOVABLE인 page)->counters: 0x00400003
// (UNMOVABLE인 page)->freelist: UNMOVABLE인 page 의 시작 virtual address + 4032
//
// (UNMOVABLE인 page) 의 object들의 freepointer 값 변경
// (사용하지 않는 첫 번째 object의 freepointer 값을 NULL 로 변경, 나머지 object들의 freepointer 값을 이전 object들의 주소로 변경)
//
// 에) s->offset이 0이고 slab object 시작 주소가 0x10001000 일 경우
// (UNMOVABLE인 page)->counters: 0x00400003
// (UNMOVABLE인 page)->freelist: UNMOVABLE인 page 의 시작 virtual address + 4032
//
// (UNMOVABLE인 page) 의 object들의 freepointer 값 변경
// (사용하지 않는 첫 번째 object의 freepointer 값을 NULL 로 변경, 나머지 object들의 freepointer 값을 이전 object들의 주소로 변경)
//
// 에) s->offset이 0이고 slab object 시작 주소가 0x10001000 일 경우
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Slab object 0 (사용중) | Slab object 1 (사용중) | Slab object 2 (사용중) | Slab object 3 | Slab object 4 | .... | Slab object 63 |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
| object start address: | object start address: | object start address: | object start address: | object start address: | | object start address: |
| 0x10001000 | 0x10001040 | 0x10001080 | 0x100010c0 | 0x10001100 | .... | 0x10001fc0 |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
| freepointer | data | freepointer | data | freepointer | data | freepointer | data | freepointer | data | .... | freepointer | data |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 0x10001040 | 64 Bytes | 0x10001080 | 64 Bytes | 0x100010c0 | 64 Bytes | null | 64 Bytes | 0x100010c0 | 64 Bytes | .... | 0x10001f80 | 64 Bytes |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
// n: (&boot_kmem_cache_node 용 object 주소)->node[0]:
// UNMOVABLE인 page 의 object의 시작 virtual address
// n->nr_partial: 2
// n->partial에 (UNMOVABLE인 page)->lru 가 추가됨
// UNMOVABLE인 page 의 object의 시작 virtual address
// n->nr_partial: 2
// n->partial에 (UNMOVABLE인 page)->lru 가 추가됨
slub.c::flush_slab()
// flush_slab(s,c)
// s: UNMOVABLE인 page 의 object의 시작 virtual address + 128,
// c: (&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
// s: UNMOVABLE인 page 의 object의 시작 virtual address + 128,
// c: (&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
static inline void flush_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
{
stat(s, CPUSLAB_FLUSH);
deactivate_slab(s, c->page, c->freelist);
// c->tid: ((&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->tid: 8
// next_tid(8): 12
c->tid = next_tid(c->tid);
// c->tid: ((&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->tid: 12
c->page = NULL;
// c->page: ((&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->page: NULL
c->freelist = NULL;
// c->freelist: ((&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->freelist: NULL
}
flush_slab(s,c)가 한일
// UNMOVABLE인 page 의 필드 맴버 값 변경
// (UNMOVABLE인 page)->counters: 0x00400003
// (UNMOVABLE인 page)->freelist: UNMOVABLE인 page 의 시작 virtual address + 4032
//
// (UNMOVABLE인 page (boot_kmem_cache)) 의 object들의 freepointer 값 변경
// (사용하지 않는 첫 번째 object의 freepointer 값을 NULL 로 변경, 나머지 object들의 freepointer 값을 이전 object들의 주소로 변경)
//
// 에) s->offset이 0이고 slab object 시작 주소가 0x10001000 일 경우
// (UNMOVABLE인 page)->counters: 0x00400003
// (UNMOVABLE인 page)->freelist: UNMOVABLE인 page 의 시작 virtual address + 4032
//
// (UNMOVABLE인 page (boot_kmem_cache)) 의 object들의 freepointer 값 변경
// (사용하지 않는 첫 번째 object의 freepointer 값을 NULL 로 변경, 나머지 object들의 freepointer 값을 이전 object들의 주소로 변경)
//
// 에) s->offset이 0이고 slab object 시작 주소가 0x10001000 일 경우
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Slab object 0 (사용중) | Slab object 1 (사용중) | Slab object 2 (사용중) | Slab object 3 | Slab object 4 | .... | Slab object 63 |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
| object start address: | object start address: | object start address: | object start address: | object start address: | | object start address: |
| 0x10001000 | 0x10001040 | 0x10001080 | 0x100010c0 | 0x10001100 | .... | 0x10001fc0 |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
| freepointer | data | freepointer | data | freepointer | data | freepointer | data | freepointer | data | .... | freepointer | data |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 0x10001040 | 64 Bytes | 0x10001080 | 64 Bytes | 0x100010c0 | 64 Bytes | null | 64 Bytes | 0x100010c0 | 64 Bytes | .... | 0x10001f80 | 64 Bytes |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
// n: (&boot_kmem_cache_node 용 object 주소)->node[0]:
// UNMOVABLE인 page 의 object의 시작 virtual address
// n->nr_partial: 2
// n->partial에 (UNMOVABLE인 page)->lru 가 추가됨
//
// c: (&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + per_cpu_start에서의pcpu_base_addr의 옵셋)
// c->tid: ((&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + per_cpu_start에서의pcpu_base_addr의 옵셋))->tid: 12
// c->page: ((&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + per_cpu_start에서의pcpu_base_addr의 옵셋))->page: NULL
// c->freelist: ((&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + per_cpu_start에서의pcpu_base_addr의 옵셋))->freelist: NULL
// UNMOVABLE인 page 의 object의 시작 virtual address
// n->nr_partial: 2
// n->partial에 (UNMOVABLE인 page)->lru 가 추가됨
//
// c: (&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + per_cpu_start에서의pcpu_base_addr의 옵셋)
// c->tid: ((&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + per_cpu_start에서의pcpu_base_addr의 옵셋))->tid: 12
// c->page: ((&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + per_cpu_start에서의pcpu_base_addr의 옵셋))->page: NULL
// c->freelist: ((&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + per_cpu_start에서의pcpu_base_addr의 옵셋))->freelist: NULL
slub.c::__flush_cpu_slab()
// s: UNMOVABLE인 page 의 object의 시작 virtual address + 128,
// smp_processor_id(): 0
// smp_processor_id(): 0
static inline void __flush_cpu_slab(struct kmem_cache *s, int cpu)
{
struct kmem_cache_cpu *c = per_cpu_ptr(s->cpu_slab, cpu);
if (likely(c)) {
if (c->page)
flush_slab(s, c);
// s: UNMOVABLE인 page 의 object의 시작 virtual address + 128,
// c: (&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
unfreeze_partials(s, c);
}
}
__flush_cpu_slab 한일:
// UNMOVABLE인 page 의 필드 맴버 값 변경
// (UNMOVABLE인 page)->counters: 0x00400003
// (UNMOVABLE인 page)->freelist: UNMOVABLE인 page 의 시작 virtual address + 4032
//
// (UNMOVABLE인 page) 의 object들의 freepointer 값 변경
// (사용하지 않는 첫 번째 object의 freepointer 값을 NULL 로 변경, 나머지 object들의 freepointer 값을 이전 object들의 주소로 변경)
//
// 에) s->offset이 0이고 slab object 시작 주소가 0x10001000 일 경우
// (UNMOVABLE인 page)->counters: 0x00400003
// (UNMOVABLE인 page)->freelist: UNMOVABLE인 page 의 시작 virtual address + 4032
//
// (UNMOVABLE인 page) 의 object들의 freepointer 값 변경
// (사용하지 않는 첫 번째 object의 freepointer 값을 NULL 로 변경, 나머지 object들의 freepointer 값을 이전 object들의 주소로 변경)
//
// 에) s->offset이 0이고 slab object 시작 주소가 0x10001000 일 경우
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Slab object 0 (사용중) | Slab object 1 (사용중) | Slab object 2 (사용중) | Slab object 3 | Slab object 4 | .... | Slab object 63 |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
| object start address: | object start address: | object start address: | object start address: | object start address: | | object start address: |
| 0x10001000 | 0x10001040 | 0x10001080 | 0x100010c0 | 0x10001100 | .... | 0x10001fc0 |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
| freepointer | data | freepointer | data | freepointer | data | freepointer | data | freepointer | data | .... | freepointer | data |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 0x10001040 | 64 Bytes | 0x10001080 | 64 Bytes | 0x100010c0 | 64 Bytes | null | 64 Bytes | 0x100010c0 | 64 Bytes | .... | 0x10001f80 | 64 Bytes |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
// n: (&boot_kmem_cache_node 용 object 주소)->node[0]:
// UNMOVABLE인 page 의 object의 시작 virtual address
// n->nr_partial: 2
// n->partial에 (UNMOVABLE인 page)->lru 가 추가됨
//
// c: (&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + per_cpu_start에서의pcpu_base_addr의 옵셋)
// c->tid: ((&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + per_cpu_start에서의pcpu_base_addr의 옵셋))->tid: 12
// c->page: ((&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + per_cpu_start에서의pcpu_base_addr의 옵셋))->page: NULL
// c->freelist: ((&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + per_cpu_start에서의pcpu_base_addr의 옵셋))->freelist: NULL
// UNMOVABLE인 page 의 object의 시작 virtual address
// n->nr_partial: 2
// n->partial에 (UNMOVABLE인 page)->lru 가 추가됨
//
// c: (&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + per_cpu_start에서의pcpu_base_addr의 옵셋)
// c->tid: ((&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + per_cpu_start에서의pcpu_base_addr의 옵셋))->tid: 12
// c->page: ((&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + per_cpu_start에서의pcpu_base_addr의 옵셋))->page: NULL
// c->freelist: ((&boot_kmem_cache_node 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + per_cpu_start에서의pcpu_base_addr의 옵셋))->freelist: NULL
slub.c::bootstrap()
// &boot_kmem_cache_node
static struct kmem_cache * __init bootstrap(struct kmem_cache *static_cache)
{
int node;
struct kmem_cache *s = kmem_cache_zalloc(kmem_cache, GFP_NOWAIT);
memcpy(s, static_cache, kmem_cache->object_size);
__flush_cpu_slab(s, smp_processor_id());
for_each_node_state(node, N_NORMAL_MEMORY) {
// for ( (node) = 0; (node) == 0; (node) = 1)
// s: UNMOVABLE인 page 의 object의 시작 virtual address + 128, node: 0
// get_node(UNMOVABLE인 page 의 object의 시작 virtual address + 128, 0):
// (&boot_kmem_cache_node 용 object 주소)->node[0]: UNMOVABLE인 page 의 object의 시작 virtual address
struct kmem_cache_node *n = get_node(s, node);
// n: UNMOVABLE인 page 의 object의 시작 virtual address
struct page *p;
// n: UNMOVABLE인 page 의 object의 시작 virtual address
if (n) {
list_for_each_entry(p, &n->partial, lru)
// for (p = list_first_entry(&n->partial, typeof(*p), lru);
// &p->lru != (&n->partial); p = list_next_entry(p, lru))
// p: UNMOVABLE인 page
// p->slab_cache: (UNMOVABLE인 page)->slab_cache
// s: UNMOVABLE인 page 의 object의 시작 virtual address + 128
p->slab_cache = s;
// p->slab_cache: (UNMOVABLE인 page)->slab_cache:
// UNMOVABLE인 page 의 object의 시작 virtual address + 128
#ifdef CONFIG_SLUB_DEBUG // CONFIG_SLUB_DEBUG=y
list_for_each_entry(p, &n->full, lru)
// for (p = list_first_entry(&n->full, typeof(*p), lru);
// &p->lru != (&n->full); p = list_next_entry(p, lru))
p->slab_cache = s;
#endif
}
}
// s: UNMOVABLE인 page 의 object의 시작 virtual address + 128
list_add(&s->list, &slab_caches);
// slab_caches 의 list에 (UNMOVABLE인 page 의 object의 시작 virtual address + 128)->list를 등록
// s: UNMOVABLE인 page 의 object의 시작 virtual address + 128
return s;
// return UNMOVABLE인 page 의 object의 시작 virtual address + 128
}
// return UNMOVABLE인 page 의 object의 시작 virtual address + 128
slub.c::kmem_cache_init()
void __init kmem_cache_init(void)
{
static __initdata struct kmem_cache boot_kmem_cache,boot_kmem_cache_node;
if (debug_guardpage_minorder())
slub_max_order = 0;
kmem_cache_node = &boot_kmem_cache_node;
kmem_cache = &boot_kmem_cache;
create_boot_cache(kmem_cache_node, "kmem_cache_node", sizeof(struct kmem_cache_node), SLAB_HWCACHE_ALIGN);
register_hotmemory_notifier(&slab_memory_callback_nb); // null function
slab_state = PARTIAL;
create_boot_cache(kmem_cache, "kmem_cache",
offsetof(struct kmem_cache, node) +
nr_node_ids * sizeof(struct kmem_cache_node *),
SLAB_HWCACHE_ALIGN);
kmem_cache = bootstrap(&boot_kmem_cache);
kmem_cache_node = bootstrap(&boot_kmem_cache_node);
// slab_caches 의 list에 (UNMOVABLE인 page 의 object의 시작 virtual address + 128)->list를 등록
// 2014/07/12 종료
study log
boot_kmem_cache_node를 가지고 bootstrap()을 분석했습니다.
다음 시간에는 create_kmalloc_caches(0)에서 slab: UP으로 활성화와
slub정보를 출력하는 부분을 분석합니다.
다음 시간에는 create_kmalloc_caches(0)에서 slab: UP으로 활성화와
slub정보를 출력하는 부분을 분석합니다.
10996da..fea5705 master -> origin/master
Merge made by the 'recursive' strategy.
arch/arm/include/asm/processor.h | 2 +
include/linux/kmemcheck.h | 1 +
include/linux/kmemleak.h | 1 +
include/linux/mm.h | 1 +
include/linux/percpu.h | 63 +++--
include/linux/slab.h | 3 +-
include/linux/slub_def.h | 2 +
include/trace/events/kmem.h | 1 +
mm/slab_common.c | 1 +
mm/slub.c | 532 ++++++++++++++++++++++++++++++++++++++-
10 files changed, 571 insertions(+), 36 deletions(-)
댓글 없음:
댓글 쓰기