ARM10C 64주차 후기
일시 : 2014.07.26 (64주차)
모임명 : NAVER개발자커뮤니티지원_IAMROOT.ORG_10차ARM-C
장소 : 토즈 타워점
장소지원 : NAVER 개발자 커뮤니티 지원 프로그램
참여인원 : 5명
스터디 진도 :
- mm_init()을 계속 분석합니다.
- start_kernel()-> mm_init()-> kmem_cache_init() 완료
- start_kernel()-> mm_init()-> percpu_init_late() 완료
- start_kernel()-> mm_init()-> pgtable_cache_init() 완료
- slub이 partial에서 up으로 활성화 되었습니다.
- 다음 주 (8월 3일)은 여름휴가 입니다.
- 8월 9일에 65주차 분석 스터디를 계속합니다.
- 다음 스터디는 vmalloc_init(); 부터 시작합니다.
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)
{
static __initdata struct kmem_cache boot_kmem_cache,
boot_kmem_cache_node;
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);
// 할당받은 pcpu 들의 16 byte 공간 (&boot_kmem_cache_node)->cpu_slab 에
// 각 cpu에 사용하는 kmem_cache_cpu의 tid 맵버를 설정
...
slab_state = PARTIAL;
// slab_state 의미:
// slab을 초기화한 단계를 나타냄, PARTIAL은 kmem_cache_node 만 사용이 가능함
create_boot_cache(kmem_cache, "kmem_cache",
offsetof(struct kmem_cache, node) +
nr_node_ids * sizeof(struct kmem_cache_node *),
SLAB_HWCACHE_ALIGN);
// 할당받은 pcpu 들의 16 byte 공간 (&boot_kmem_cache)->cpu_slab 에
// 각 cpu에 사용하는 kmem_cache_cpu의 tid 맵버를 설정
kmem_cache = bootstrap(&boot_kmem_cache);
// slab_caches 의 list에 (UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address)->list를 등록
kmem_cache_node = bootstrap(&boot_kmem_cache_node);
// slab_caches 의 list에 (UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968)->list를 등록
create_kmalloc_caches(0);
create_kmalloc_caches(0);
slab_common.c::create_kmalloc_caches()
// ARM10C 20140719
// flags: 0
void __init create_kmalloc_caches(unsigned long flags)
{
int i;
/*
* Patch up the size_index table if we have strange large alignment
* requirements for the kmalloc array. This is only the case for
* MIPS it seems. The standard arches will not generate any code here.
*
* Largest permitted alignment is 256 bytes due to the way we
* handle the index determination for the smaller caches.
*
* Make sure that nothing crazy happens if someone starts tinkering
* around with ARCH_KMALLOC_MINALIGN
*/
// KMALLOC_MIN_SIZE: 64
BUILD_BUG_ON(KMALLOC_MIN_SIZE > 256 ||
(KMALLOC_MIN_SIZE & (KMALLOC_MIN_SIZE - 1)));
// KMALLOC_MIN_SIZE: 64
for (i = 8; i < KMALLOC_MIN_SIZE; i += 8) {
// i: 8, size_index_elem(8): 0
int elem = size_index_elem(i);
// elem: 0
// elem: 0, ARRAY_SIZE(size_index): 24
if (elem >= ARRAY_SIZE(size_index))
break;
// elem: 0, KMALLOC_SHIFT_LOW: 6
size_index[elem] = KMALLOC_SHIFT_LOW;
// size_index[0]: 6
}
// 루프 수행 결과
// size_index[0 .. 6]: 6
// KMALLOC_MIN_SIZE: 64
if (KMALLOC_MIN_SIZE >= 64) {
/*
* The 96 byte size cache is not used if the alignment
* is 64 byte.
*/
for (i = 64 + 8; i <= 96; i += 8)
// i: 72, size_index_elem(72): 8
size_index[size_index_elem(i)] = 7;
// size_index[8]: 7
// 루프 수행 결과
// size_index[8 .. 11]: 7
}
// KMALLOC_MIN_SIZE: 64
if (KMALLOC_MIN_SIZE >= 128) {
/*
* The 192 byte sized cache is not used if the alignment
* is 128 byte. Redirect kmalloc to use the 256 byte cache
* instead.
*/
for (i = 128 + 8; i <= 192; i += 8)
size_index[size_index_elem(i)] = 8;
}
// KMALLOC_SHIFT_LOW: 6, KMALLOC_SHIFT_HIGH: 13
for (i = KMALLOC_SHIFT_LOW; i <= KMALLOC_SHIFT_HIGH; i++) {
// i: 6, kmalloc_caches[6]: NULL
// i: 7, kmalloc_caches[7]: NULL
// i: 12, kmalloc_caches[12]: NULL
if (!kmalloc_caches[i]) {
// i: 6, flags: 0, create_kmalloc_cache(NULL, 64, 0): kmem_cache#2
// i: 7, flags: 0, create_kmalloc_cache(NULL, 128, 0): kmem_cache#3
// i: 12, flags: 0, create_kmalloc_cache(NULL, 4096, 0): kmem_cache#9
kmalloc_caches[i] = create_kmalloc_cache(NULL,
1 << i, flags);
// kmalloc_caches[6]: kmem_cache#2
// kmalloc_caches[7]: kmem_cache#3
// kmalloc_caches[12]: kmem_cache#9
}
/*
* Caches that are not of the two-to-the-power-of size.
* These have to be created immediately after the
* earlier power of two caches
*/
// KMALLOC_MIN_SIZE: 64, i: 6, kmalloc_caches[1]: NULL
// KMALLOC_MIN_SIZE: 64, i: 7, kmalloc_caches[1]: NULL
// KMALLOC_MIN_SIZE: 64, i: 12, kmalloc_caches[1]: NULL
if (KMALLOC_MIN_SIZE <= 32 && !kmalloc_caches[1] && i == 6)
kmalloc_caches[1] = create_kmalloc_cache(NULL, 96, flags);
// KMALLOC_MIN_SIZE: 64, i: 6, kmalloc_caches[1]: NULL
// KMALLOC_MIN_SIZE: 64, i: 7, kmalloc_caches[2]: NULL
// KMALLOC_MIN_SIZE: 64, i: 12, kmalloc_caches[2]: NULL
if (KMALLOC_MIN_SIZE <= 64 && !kmalloc_caches[2] && i == 7)
// i: 7, flags: 0, create_kmalloc_cache(NULL, 192, 0): kmem_cache#4
kmalloc_caches[2] = create_kmalloc_cache(NULL, 192, flags);
// kmalloc_caches[2]: kmem_cache#4
// loop i = 8 9 10 11 13 수행 (skip)
}
// 위 loop 에서 한일:
// kmem_cache object를 1개 할당받음
// kmem_cache_node object를 1개 할당받음
// kmem_cache 의 refcount 가 1로 set
// slab_caches에 kmem_cache의 list 추가
/* Kmalloc array is now usable */
// slab_state: PARTIAL
slab_state = UP;
// slab_state: UP
// KMALLOC_SHIFT_HIGH: 13
for (i = 0; i <= KMALLOC_SHIFT_HIGH; i++) {
// i: 0, kmalloc_caches[0]: NULL
// i: 2, kmalloc_caches[2]: kmem_cache#4
struct kmem_cache *s = kmalloc_caches[i];
// i: 0, s: NULL
// i: 2, s: kmem_cache#4
char *n;
// i: 0, s: NULL
// i: 2, s: kmem_cache#4
if (s) {
// GFP_NOWAIT: 0, i: 2, kmalloc_size(2): 192
n = kasprintf(GFP_NOWAIT, "kmalloc-%d", kmalloc_size(i));
// n: kmem_cache#2-o1
// n: kmem_cache#2-o1
BUG_ON(!n);
// s->name: kmem_cache#2->name: NULL, n: kmem_cache#2-o1
s->name = n;
// s->name: kmem_cache#2->name: kmem_cache#2-o1: "kmalloc-192"
}
// loop i = 1 3 .. 13 수행 (skip)
}
// kmalloc_caches[0] kmalloc_caches[1], kmalloc_caches[3], kmalloc_caches[4], kmalloc_caches[5]
// 는 값이 null 이므로 skip
// kmalloc_caches[6]: kmem_cache#2->name: "kmalloc-64"
// kmalloc_caches[7]: kmem_cache#3->name: "kmalloc-128"
// kmalloc_caches[2]: kmem_cache#4->name: "kmalloc-192"
// kmalloc_caches[8]: kmem_cache#5->name: "kmalloc-256"
// kmalloc_caches[9]: kmem_cache#6->name: "kmalloc-512"
// kmalloc_caches[10]: kmem_cache#7->name: "kmalloc-1024"
// kmalloc_caches[11]: kmem_cache#8->name: "kmalloc-2048"
// kmalloc_caches[12]: kmem_cache#9->name: "kmalloc-4096"
// kmalloc_caches[13]: kmem_cache#10->name: "kmalloc-8192"
#ifdef CONFIG_ZONE_DMA // CONFIG_ZONE_DMA=n
for (i = 0; i <= KMALLOC_SHIFT_HIGH; i++) {
struct kmem_cache *s = kmalloc_caches[i];
if (s) {
int size = kmalloc_size(i);
char *n = kasprintf(GFP_NOWAIT,
"dma-kmalloc-%d", size);
BUG_ON(!n);
kmalloc_dma_caches[i] = create_kmalloc_cache(n,
size, SLAB_CACHE_DMA | flags);
}
}
#endif
}
create_kmalloc_caches()가 한일
// create_kmalloc_caches 가 한일:
// 배열 size_index[] 값을 변경, kmalloc_caches[] 값을 채워줌
//
// size_index[0 .. 6]: 6
// size_index[8 .. 11]: 7
//
// kmem_cache object를 1개 할당받음
// kmem_cache_node object를 1개 할당받음
// kmem_cache 의 refcount 가 1로 set
// slab_caches에 kmem_cache의 list 추가
//
// kmalloc_caches[6]:
// # order: 0, object size: 64
// kmem_cache#2
// - kmem_cache#2->allocflags: 0
// - kmem_cache#2->oo.x: 0x40
// - kmem_cache#2->min.x: 0x40
// - kmem_cache#2->max.x: 0x40
// - kmem_cache#2->min_partial: 5
// - kmem_cache#2->cpu_partial: 30
// - kmem_cache#2->name: "kmalloc-64"
// kmem_cache_node#3
//
// kmalloc_caches[7]:
// # order: 0, object size: 128
// kmem_cache#3
// - kmem_cache#3->allocflags: 0
// - kmem_cache#3->oo.x: 0x20
// - kmem_cache#3->min.x: 0x20
// - kmem_cache#3->max.x: 0x20
// - kmem_cache#3->min_partial: 5
// - kmem_cache#3->cpu_partial: 30
// - kmem_cache#3->name: "kmalloc-128"
// kmem_cache_node#4
//
// kmalloc_caches[2]:
// # order: 0, object size: 192
// kmem_cache#4
// - kmem_cache#4->allocflags: 0
// - kmem_cache#4->oo.x: 0x15
// - kmem_cache#4->min.x: 0x15
// - kmem_cache#4->max.x: 0x15
// - kmem_cache#4->min_partial: 5
// - kmem_cache#4->cpu_partial: 30
// - kmem_cache#4->name: "kmalloc-192"
// kmem_cache_node#5
//
// kmalloc_caches[8]:
// # order: 0, object size: 256
// kmem_cache#5
// - kmem_cache#5->allocflags: 0
// - kmem_cache#5->oo.x: 0x10
// - kmem_cache#5->min.x: 0x10
// - kmem_cache#5->max.x: 0x10
// - kmem_cache#5->min_partial: 5
// - kmem_cache#5->cpu_partial: 13
// - kmem_cache#5->name: "kmalloc-256"
// kmem_cache_node#6
//
// kmalloc_caches[9]:
// # order: 1, object size: 512
// kmem_cache#6
// - kmem_cache#6->allocflags: __GFP_COMP (0x4000)
// - kmem_cache#6->oo.x: 0x10010
// - kmem_cache#6->min.x: 0x8
// - kmem_cache#6->max.x: 0x10010
// - kmem_cache#6->min_partial: 5
// - kmem_cache#6->cpu_partial: 13
// - kmem_cache#6->name: "kmalloc-512"
// kmem_cache_node#7
//
// kmalloc_caches[10]:
// # order: 2, object size: 1024
// kmem_cache#7
// - kmem_cache#7->allocflags: __GFP_COMP (0x4000)
// - kmem_cache#7->oo.x: 0x20020
// - kmem_cache#7->min.x: 0x4
// - kmem_cache#7->max.x: 0x20020
// - kmem_cache#7->min_partial: 5
// - kmem_cache#7->cpu_partial: 6
// - kmem_cache#7->name: "kmalloc-1024"
// kmem_cache_node#8
//
// kmalloc_caches[11]:
// # order: 3, object size: 2048
// kmem_cache#8
// - kmem_cache#8->allocflags: __GFP_COMP (0x4000)
// - kmem_cache#8->oo.x: 0x30010
// - kmem_cache#8->min.x: 0x2
// - kmem_cache#8->max.x: 0x30010
// - kmem_cache#8->min_partial: 5
// - kmem_cache#8->cpu_partial: 6
// - kmem_cache#8->name: "kmalloc-2048"
// kmem_cache_node#9
//
// kmalloc_caches[12]:
// # order: 3, object size: 4096
// kmem_cache#9
// - kmem_cache#9->allocflags: __GFP_COMP (0x4000)
// - kmem_cache#9->oo.x: 0x30008
// - kmem_cache#9->min.x: 0x10002
// - kmem_cache#9->max.x: 0x30008
// - kmem_cache#9->min_partial: 6
// - kmem_cache#9->cpu_partial: 2
// - kmem_cache#9->name: "kmalloc-4096"
// kmem_cache_node#10
//
// kmalloc_caches[13]:
// # order: 3, object size: 8192
// kmem_cache#10
// - kmem_cache#10->allocflags: __GFP_COMP (0x4000)
// - kmem_cache#10->oo.x: 0x30004
// - kmem_cache#10->min.x: 0x10001
// - kmem_cache#10->max.x: 0x30004
// - kmem_cache#10->min_partial: 6
// - kmem_cache#10->cpu_partial: 2
// - kmem_cache#10->name: "kmalloc-8192"
// kmem_cache_node#11
//
// slab_state: UP
slub.c::kmem_cache_init()
void __init kmem_cache_init(void)
{
...
create_kmalloc_caches(0);
#ifdef CONFIG_SMP // CONFIG_SMP=y
register_cpu_notifier(&slab_notifier);
// (&cpu_chain)->head: slab_notifier 포인터 대입
// (&slab_notifier)->next은 (&page_alloc_cpu_notify_nb)->next로 대입
#endif
// KERN_INFO: "\001" "6", cache_line_size(): 64
// slub_min_order: 0, slub_max_order: 3, slub_min_objects: 0
// nr_cpu_ids: 4, nr_node_ids: 1
printk(KERN_INFO
"SLUB: HWalign=%d, Order=%d-%d, MinObjects=%d,"
" CPUs=%d, Nodes=%d\n",
cache_line_size(),
slub_min_order, slub_max_order, slub_min_objects,
nr_cpu_ids, nr_node_ids);
// "SLUB: HWalign=64, Order=0-3, MinObjects=0," " CPUs=4, Nodes=1"
}
main.c::mm_init()
static void __init mm_init(void)
{
...
kmem_cache_init();
// slub 을 활성화 시킴
percpu_init_late();
percpu_init_late();
percpu.c::percpu_init_late()
// ARM10C 20140726
void __init percpu_init_late(void)
{
// pcpu_first_chunk: pcpu_setup_first_chunk()함수에서 할당한 dchunk,
// pcpu_reserved_chunk: pcpu_setup_first_chunk()함수에서 할당한 schunk
struct pcpu_chunk *target_chunks[] =
{ pcpu_first_chunk, pcpu_reserved_chunk, NULL };
struct pcpu_chunk *chunk;
unsigned long flags;
int i;
for (i = 0; (chunk = target_chunks[i]); i++) {
int *map;
// PERCPU_DYNAMIC_EARLY_SLOTS: 128, sizeof(map[0]): 4
const size_t size = PERCPU_DYNAMIC_EARLY_SLOTS * sizeof(map[0]);
// size: 512
// size: 512, PAGE_SIZE: 4096
BUILD_BUG_ON(size > PAGE_SIZE);
// size: 512
map = pcpu_mem_zalloc(size);
// map: kmem_cache#6-o1
// map: kmem_cache#6-o1
BUG_ON(!map);
spin_lock_irqsave(&pcpu_lock, flags);
// flags에 cpsr 저장 후 pcpu_lock 를 사용한 spinlock 획득
// map: kmem_cache#6-o1, chunk->map: dchunk->map, size: 512
memcpy(map, chunk->map, size);
// dchunk로 할당 받은 pcpu 메모리 값들을 slab으로 카피하여 이관
// map: kmem_cache#6-o1
chunk->map = map;
// chunk->map: dchunk->map: kmem_cache#6-o1
spin_unlock_irqrestore(&pcpu_lock, flags);
// flags에 저장된 cpsr을 원복하고 pcpu_lock 를 사용한 spinlock 해제
}
}
main.c::mm_init()
static void __init mm_init(void)
{
...
kmem_cache_init();
// slub 을 활성화 시킴
percpu_init_late();
// dchunk로 할당 받은 pcpu 메모리 값들을 slab으로 카피하여 이관
pgtable_cache_init(); // null function