Skip to content

Latest commit

 

History

History
2439 lines (2132 loc) · 83.6 KB

a10c_59.md

File metadata and controls

2439 lines (2132 loc) · 83.6 KB

ARM10C 59주차 후기

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

스터디 진도 :

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

list_each_entry_safe를 사용하는 이유

list_each_entry()만을 사용하면 각 list에서 page 주소를 순차적으로 가리키는데, 만약 이 루프에서 list를 변경할 경우 ...safe()를 사용한다.

...safe()는 list_each_entry_safe()를 사용하면 page, page2를 사용하면 page는 지금 순차적으로 검색하는 리스트를 page2는 다음 리스트를 가리키므로 page를 삭제하여도 page2가 다음 리스트를 가리키기 때문에 삭제나 변경 후 page = page2로 사용해서 안전하게 리스트를 검색하게 할 수 있다.

main.c:: mm_init()

// ARM10C 20140329

static void __init mm_init(void)
{
	/*
	 * page_cgroup requires contiguous pages,
	 * bigger than MAX_ORDER unless SPARSEMEM.
	 */
	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()

create_boot_cache()를 2번째 실행한다. 이 함수를 1번째 실행할때는 slab_state: DOWN에서 실행을 했었고. 2번째 실행할 때는 slab_state: PARTIAL로 바꾸어서 실행하는 것이다.

  • slab_state 의미: slab을 초기화한 단계를 나타냄, PARTIAL은 kmem_cache_node 만 사용이 가능함
void __init kmem_cache_init(void)
{
...
	// slab_state: DOWN
	slab_state = PARTIAL;
	// slab_state: PARTIAL
...
// 2014/06/14 시작
	// 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(kmem_cache, "kmem_cache", offsetof(struct kmem_cache, node) + nr_node_ids * sizeof(struct kmem_cache_node *), SLAB_HWCACHE_ALIGN);

slab_common.c::create_boot_cache()

// ARM10C 20140614 // &boot_kmem_cache, "kmem_cache", 132, SLAB_HWCACHE_ALIGN: 0x00002000UL

void __init create_boot_cache(struct kmem_cache *s, const char *name, size_t size,
		unsigned long flags)
{
	int err;

	// s->name: boot_kmem_cache.name: NULL
	s->name = name;
	// s->name: boot_kmem_cache.name: "kmem_cache"

	// s->size: boot_kmem_cache.size: 0
	// s->object_size: boot_kmem_cache.object_size: 0
	s->size = s->object_size = size;
	// s->size: boot_kmem_cache.size: 132
	// s->object_size: boot_kmem_cache.object_size: 132
	
	// flags: SLAB_HWCACHE_ALIGN: 0x00002000UL, ARCH_KMALLOC_MINALIGN: 64, size: 132
	// s->align: boot_kmem_cache.align: 0
	s->align = calculate_alignment(flags, ARCH_KMALLOC_MINALIGN, size);
	// s->align: boot_kmem_cache.align: 64
	
	// s: &boot_kmem_cache, flags: SLAB_HWCACHE_ALIGN: 0x00002000UL
	// __kmem_cache_create(&boot_kmem_cache, 0x00002000UL): 0
	err = __kmem_cache_create(s, flags);

// s: &boot_kmem_cache, flags: SLAB_HWCACHE_ALIGN: 0x00002000UL // __kmem_cache_create(&boot_kmem_cache, 0x00002000UL): 0

err = __kmem_cache_create(s, flags);

slub.c::__kmem_cache_create()

// ARM10C 20140614 // s: &boot_kmem_cache, flags: SLAB_HWCACHE_ALIGN: 0x00002000UL

int __kmem_cache_create(struct kmem_cache *s, unsigned long flags)
{
	int err;

	// s: &boot_kmem_cache, flags: SLAB_HWCACHE_ALIGN: 0x00002000UL
	// kmem_cache_open(&boot_kmem_cache, 0x00002000UL): 0
	err = kmem_cache_open(s, flags);

// kmem_cache_open(&boot_kmem_cache, 0x00002000UL): 0

err = kmem_cache_open(s, flags);

slub.c::kmem_cache_open()

// ARM10C 20140614 // s: &boot_kmem_cache, flags: SLAB_HWCACHE_ALIGN: 0x00002000UL

static int kmem_cache_open(struct kmem_cache *s, unsigned long flags)
{
	// s->size: boot_kmem_cache.size: 132, flags: SLAB_HWCACHE_ALIGN: 0x00002000UL,
	// s->name: boot_kmem_cache.name: "kmem_cache", s->ctor: boot_kmem_cache.ctor: NULL
	s->flags = kmem_cache_flags(s->size, flags, s->name, s->ctor);
	// s->flags: boot_kmem_cache.flags: SLAB_HWCACHE_ALIGN: 0x00002000UL

	// s->reserved: boot_kmem_cache.reserved: 0
	s->reserved = 0;
	// s->reserved: boot_kmem_cache.reserved: 0

	// need_reserve_slab_rcu: 0, s->flags: boot_kmem_cache.flags: SLAB_HWCACHE_ALIGN
	if (need_reserve_slab_rcu && (s->flags & SLAB_DESTROY_BY_RCU))
		s->reserved = sizeof(struct rcu_head);

	// s: &boot_kmem_cache, -1, calculate_sizes(&boot_kmem_cache, -1): 1
	if (!calculate_sizes(s, -1))
		goto error;

// calculate_sizes가 하는일?: // object size 값에 맞게 내부 단편화 문제를 고려하여 최적의 order를 계산함 // kmem_cache의 맴버 inuse, size, allocflags, min, oo, max 값을 초기화해줌

	// disable_higher_order_debug: 0
	if (disable_higher_order_debug) {
		if (get_order(s->size) > get_order(s->object_size)) {
			s->flags &= ~DEBUG_METADATA_FLAGS;
			s->offset = 0;
			if (!calculate_sizes(s, -1))
				goto error;
		}
	}

    // s->size: boot_kmem_cache.size: 192, ilog2(192): 7
	// s: &boot_kmem_cache, 3
	set_min_partial(s, ilog2(s->size) / 2);
	// boot_kmem_cache.min_partial: 5

	// s: &boot_kmem_cache, kmem_cache_has_cpu_partial(&boot_kmem_cache): 1
	// s->size: boot_kmem_cache.size: 192, PAGE_SIZE: 0x1000
	if (!kmem_cache_has_cpu_partial(s))
		s->cpu_partial = 0;
	else if (s->size >= PAGE_SIZE)
		s->cpu_partial = 2;
	else if (s->size >= 1024)
		s->cpu_partial = 6;
	else if (s->size >= 256)
		s->cpu_partial = 13;
	else
		// s->cpu_partial: boot_kmem_cache.cpu_partial: 0
		s->cpu_partial = 30;
		// boot_kmem_cache.cpu_partial: 30

    // s: &boot_kmem_cache, init_kmem_cache_nodes(&boot_kmem_cache): 1
	if (!init_kmem_cache_nodes(s))
		goto error;

// s: &boot_kmem_cache, init_kmem_cache_nodes(&boot_kmem_cache): 1

if (!init_kmem_cache_nodes(s))

slub.c::init_kmem_cache_nodes()

// ARM10C 20140614 // s: &boot_kmem_cache

static int init_kmem_cache_nodes(struct kmem_cache *s)
{
	int node;

	// N_NORMAL_MEMORY: 2
	for_each_node_state(node, N_NORMAL_MEMORY) {
	// for ( (node) = 0; (node) == 0; (node) = 1)

		struct kmem_cache_node *n;

		// slab_state: DOWN: 0
		// slab_state: PARTIAL: 1, DOWN: 0
		if (slab_state == DOWN) {
			// node: 0
			early_kmem_cache_node_alloc(node);
			continue;
		}
			
		// kmem_cache_node: &boot_kmem_cache_node, GFP_KERNEL: 0xD0, node: 0
		// kmem_cache_alloc_node(&boot_kmem_cache_node, GFP_KERNEL: 0xD0, 0):
		// UNMOVABLE인 page 의 object의 시작 virtual address + 64
		n = kmem_cache_alloc_node(kmem_cache_node,
						GFP_KERNEL, node);

// kmem_cache_node: &boot_kmem_cache_node, GFP_KERNEL: 0xD0, node: 0 // kmem_cache_alloc_node(&boot_kmem_cache_node, GFP_KERNEL: 0xD0, 0): // UNMOVABLE인 page 의 object의 시작 virtual address + 64

  n = kmem_cache_alloc_node(kmem_cache_node,
  				GFP_KERNEL, node);

slab.h::kmem_cache_alloc_node()

// ARM10C 20140614 // kmem_cache_node: &boot_kmem_cache_node, GFP_KERNEL: 0xD0, node: 0

static __always_inline void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t flags, int node)
{
	// s: &boot_kmem_cache_node, flags: GFP_KERNEL: 0xD0
	// kmem_cache_alloc(&boot_kmem_cache_node, GFP_KERNEL: 0xD0):
	// UNMOVABLE인 page 의 object의 시작 virtual address + 64
	return kmem_cache_alloc(s, flags);
}

// s: &boot_kmem_cache_node, flags: GFP_KERNEL: 0xD0

return kmem_cache_alloc(s, flags);

slub.c::kmem_cache_alloc()

// ARM10C 20140614 // s: &boot_kmem_cache_node, flags: GFP_KERNEL: 0xD0

void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags)
{
	// s: &boot_kmem_cache_node, gfpflags: GFP_KERNEL: 0xD0
	// slab_alloc(&boot_kmem_cache_node, GFP_KERNEL: 0xD0): UNMOVABLE인 page 의 object의 시작 virtual address + 64
	void *ret = slab_alloc(s, gfpflags, _RET_IP_);

slub.c::slab_alloc()

// ARM10C 20140614 // s: &boot_kmem_cache_node, gfpflags: GFP_KERNEL: 0xD0, RET_IP

static __always_inline void *slab_alloc(struct kmem_cache *s,
		gfp_t gfpflags, unsigned long addr)
{
	// s: &boot_kmem_cache_node, gfpflags: GFP_KERNEL: 0xD0, NUMA_NO_NODE: -1, _RET_IP_
	// slab_alloc_node(&boot_kmem_cache_node, GFP_KERNEL: 0xD0, -1, _RET_IP_):
	// UNMOVABLE인 page 의 object의 시작 virtual address + 64
	return slab_alloc_node(s, gfpflags, NUMA_NO_NODE, addr);
}

// s: &boot_kmem_cache_node, gfpflags: GFP_KERNEL: 0xD0, NUMA_NO_NODE: -1, RET_IP

return slab_alloc_node(s, gfpflags, NUMA_NO_NODE, addr);

slub.c::slab_alloc_node()

// ARM10C 20140614 // s: &boot_kmem_cache_node, gfpflags: GFP_KERNEL: 0xD0, RET_IP

static __always_inline void *slab_alloc(struct kmem_cache *s,
		gfp_t gfpflags, unsigned long addr)
{
	// s: &boot_kmem_cache_node, gfpflags: GFP_KERNEL: 0xD0, NUMA_NO_NODE: -1, _RET_IP_
	// slab_alloc_node(&boot_kmem_cache_node, GFP_KERNEL: 0xD0, -1, _RET_IP_):
	// UNMOVABLE인 page 의 object의 시작 virtual address + 64
	return slab_alloc_node(s, gfpflags, NUMA_NO_NODE, addr);
}

// s: &boot_kmem_cache_node, gfpflags: GFP_KERNEL: 0xD0, NUMA_NO_NODE: -1, RET_IP // slab_alloc_node(&boot_kmem_cache_node, GFP_KERNEL: 0xD0, -1, RET_IP): // UNMOVABLE인 page 의 object의 시작 virtual address + 64

return slab_alloc_node(s, gfpflags, NUMA_NO_NODE, addr);

slub.c::slab_alloc_node()

// ARM10C 20140614 // s: &boot_kmem_cache_node, gfpflags: GFP_KERNEL: 0xD0, 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_node, gfpflags: GFP_KERNEL: 0xD0
	// slab_pre_alloc_hook(&boot_kmem_cache_node, 0xD0): 0
	if (slab_pre_alloc_hook(s, gfpflags))
		return NULL;

	// s: &boot_kmem_cache_node, gfpflags: GFP_KERNEL: 0xD0
	// memcg_kmem_get_cache(&boot_kmem_cache_node, 0xD0): &boot_kmem_cache_node
	s = memcg_kmem_get_cache(s, gfpflags);
	// s: &boot_kmem_cache_node
redo:
	preempt_disable();
	// 선점 카운트 증가, barrier 적용

	// s->cpu_slab: (&boot_kmem_cache_node)->cpu_slab: 0xc0502d00
	// __this_cpu_ptr((&boot_kmem_cache_node)->cpu_slab: 0xc0502d00):
	// (&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
	c = __this_cpu_ptr(s->cpu_slab);
	// c: (&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
	// c->tid: ((&boot_kmem_cache_node)->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_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->freelist: 0
	object = c->freelist;
	// object: 0

	// c->page: ((&boot_kmem_cache_node)->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_node, gfpflags: GFP_KERNEL: 0xD0, node: -1, addr: _RET_IP_,
		// c: (&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
		// __slab_alloc(&boot_kmem_cache_node, GFP_KERNEL: 0xD0, -1, _RET_IP_,
		// (&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)):
		// UNMOVABLE인 page 의 object의 시작 virtual address + 64
		object = __slab_alloc(s, gfpflags, node, addr, c);

// s: &boot_kmem_cache_node, gfpflags: GFP_KERNEL: 0xD0, node: -1, addr: RET_IP, // c: (&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)

object = __slab_alloc(s, gfpflags, node, addr, c);

slub.c::__slab_alloc()

// ARM10C 20140614 // s: &boot_kmem_cache_node, gfpflags: GFP_KERNEL: 0xD0, node: -1, addr: RET_IP, // c: (&boot_kmem_cache_node)->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
	/*
	 * We may have been preempted and rescheduled on a different
	 * cpu before disabling interrupts. Need to reload cpu area
	 * pointer.
	 */
	// s->cpu_slab: (&boot_kmem_cache_node)->cpu_slab: 0xc0502d00
	// __this_cpu_ptr((&boot_kmem_cache_node)->cpu_slab: 0xc0502d00):
	// (&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
	c = this_cpu_ptr(s->cpu_slab);
	// c: (&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
#endif
	// c->page: ((&boot_kmem_cache_node)->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 심볼로 이동
rego:
...
new_slab:

	// c->partial: (&boot_kmem_cache_node)->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_node, gfpflags: GFP_KERNEL: 0xD0, node: -1,
	// c: (&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
	// new_slab_objects(&boot_kmem_cache_node, GFP_KERNEL: 0xD0, -1,
	// (&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)):
	// UNMOVABLE인 page 의 object의 시작 virtual address + 64
	freelist = new_slab_objects(s, gfpflags, node, &c);

// s: &boot_kmem_cache_node, gfpflags: GFP_KERNEL: 0xD0, node: -1, // c: (&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)

freelist = new_slab_objects(s, gfpflags, node, &c);

slub.c::new_slab_objects()

// ARM10C 20140614 // s: &boot_kmem_cache_node, gfpflags: GFP_KERNEL: 0xD0, node: -1, // &c: &(&boot_kmem_cache_node)->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_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
	struct kmem_cache_cpu *c = *pc;
	// c: (&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
	struct page *page;

	// s: &boot_kmem_cache_node, flags: GFP_KERNEL: 0xD0, node: -1,
	// c: (&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
	// get_partial(&boot_kmem_cache_node, GFP_KERNEL: 0xD0, -1,
	// (&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)):
	// UNMOVABLE인 page 의 object의 시작 virtual address + 64
	freelist = get_partial(s, flags, node, c);

// s: &boot_kmem_cache_node, flags: GFP_KERNEL: 0xD0, node: -1, // c: (&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋) // get_partial(&boot_kmem_cache_node, GFP_KERNEL: 0xD0, -1, // (&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)): // UNMOVABLE인 page 의 object의 시작 virtual address + 64

freelist = get_partial(s, flags, node, c);

slub.c::get_partial()

// ARM10C 20140614 // s: &boot_kmem_cache_node, flags: GFP_KERNEL: 0xD0, node: -1, // c: (&boot_kmem_cache_node)->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_node, searchnode: 0
	// get_node(&boot_kmem_cache_node, 0): (&boot_kmem_cache_node)->node[0],
	// c: (&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋),
	// flags: GFP_KERNEL: 0xD0
	// get_partial_node(&boot_kmem_cache_node, (&boot_kmem_cache_node)->node[0],
	// (&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋), GFP_KERNEL: 0xD0):
	// UNMOVABLE인 page 의 object의 시작 virtual address + 64
	object = get_partial_node(s, get_node(s, searchnode), c, flags);

// s: &boot_kmem_cache_node, searchnode: 0 // get_node(&boot_kmem_cache_node, 0): (&boot_kmem_cache_node)->node[0], // c: (&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋), // flags: GFP_KERNEL: 0xD0 // get_partial_node(&boot_kmem_cache_node, (&boot_kmem_cache_node)->node[0], // (&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋), GFP_KERNEL: 0xD0): // UNMOVABLE인 page 의 object의 시작 virtual address + 64

object = get_partial_node(s, get_node(s, searchnode), c, flags);

slub.c::get_partial_node()

// ARM10C 20140614 // s: &boot_kmem_cache_node, (&boot_kmem_cache_node)->node[0], // c: (&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋), // flags: GFP_KERNEL: 0xD0

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;

	/*
	 * Racy check. If we mistakenly see no partial slabs then we
	 * just allocate an empty slab. If we mistakenly try to get a
	 * partial slab and there is none available then get_partials()
	 * will return NULL.
	 */
	// n: (&boot_kmem_cache_node)->node[0]: UNMOVABLE인 page 의 object의 시작 virtual address,
	// n->nr_partial: ((&boot_kmem_cache_node)->node[0])->nr_partial: 1
	if (!n || !n->nr_partial)
		return NULL;

	// early_kmem_cache_node_alloc에서 (&boot_kmem_cache_node)->node[0] 값을 설정함

	// n->list_lock: ((&boot_kmem_cache_node)->node[0])->list_lock
	spin_lock(&n->list_lock);
	// ((&boot_kmem_cache_node)->node[0])->list_lock의 spinlock 획득

// 2014/06/14 종료
// 2014/06/21 시작

	list_for_each_entry_safe(page, page2, &n->partial, lru) {
	// for (page = list_first_entry(&n->partial, typeof(*page), lru),
	//      page2 = list_next_entry(page, lru);
	//      &page->lru != (&n->partial);
	//      page = page2, page2 = list_next_entry(page2, lru))

		// page: MIGRATE_UNMOVABLE인 page, page2: page lru의 offset 만큼 계산된 주소

		void *t;

		// page: MIGRATE_UNMOVABLE인 page, flags: GFP_KERNEL: 0xD0
		// pfmemalloc_match(MIGRATE_UNMOVABLE인 page, GFP_KERNEL: 0xD0): 1
		if (!pfmemalloc_match(page, flags))
			continue;

// page: MIGRATE_UNMOVABLE인 page, flags: GFP_KERNEL: 0xD0 // pfmemalloc_match(MIGRATE_UNMOVABLE인 page, GFP_KERNEL: 0xD0): 1

if (!pfmemalloc_match(page, flags))

slub.c::pfmemalloc_match()

// ARM10C 20140621 // page: MIGRATE_UNMOVABLE인 page, flags: GFP_KERNEL: 0xD0

static inline bool pfmemalloc_match(struct page *page, gfp_t gfpflags)
{
	// page: MIGRATE_UNMOVABLE인 page,
	// PageSlabPfmemalloc(MIGRATE_UNMOVABLE인 page): 0
	if (unlikely(PageSlabPfmemalloc(page)))
		return gfp_pfmemalloc_allowed(gfpflags);

	return true;
	// return true
}

page-flags.h::PageSlabPfmemalloc()

// ARM10C 20140621 // page: MIGRATE_UNMOVABLE인 page

static inline int PageSlabPfmemalloc(struct page *page)
{
	// page: MIGRATE_UNMOVABLE인 page,
	// PageSlab(MIGRATE_UNMOVABLE인 page): 1
	VM_BUG_ON(!PageSlab(page));

	// page: MIGRATE_UNMOVABLE인 page,
	// PageActive(MIGRATE_UNMOVABLE인 page): 0
	return PageActive(page);
	// return 0
}

// page: MIGRATE_UNMOVABLE인 page, // PageActive(MIGRATE_UNMOVABLE인 page): 0

return PageActive(page);

page-flags.h::PageActive()

// ARM10C 20140621

PAGEFLAG(Active, active) __CLEARPAGEFLAG(Active, active)
// ARM10C 20140621
// __CLEARPAGEFLAG(Active, active)
// static inline void __ClearPageActive(struct page *page)
// { __clear_bit(PG_active, &page->flags); }
#define __CLEARPAGEFLAG(uname, lname)					\
// ARM10C 20140621
// TESTCLEARFLAG(Active, active):
// static inline int TestClearPageActive(struct page *page)
// { return test_and_clear_bit(PG_active, &page->flags); }
#define TESTCLEARFLAG(uname, lname)					\
static inline int TestClearPage##uname(struct page *page)		\
		{ return test_and_clear_bit(PG_##lname, &page->flags); }

slub.c::get_partial_node()

static void *get_partial_node(struct kmem_cache *s, struct kmem_cache_node *n,
				struct kmem_cache_cpu *c, gfp_t flags)
{
...
	list_for_each_entry_safe(page, page2, &n->partial, lru) {
		void *t;

        if (!pfmemalloc_match(page, flags))
			continue;

		// s: &boot_kmem_cache_node, n: (&boot_kmem_cache_node)->node[0],
		// page: MIGRATE_UNMOVABLE인 page, object: NULL
		// acquire_slab(&boot_kmem_cache_node, (&boot_kmem_cache_node)->node[0], MIGRATE_UNMOVABLE인 page, 1, objects):
		// UNMOVABLE인 page 의 object의 시작 virtual address + 64
		t = acquire_slab(s, n, page, object == NULL, &objects);

// s: &boot_kmem_cache_node, n: (&boot_kmem_cache_node)->node[0], // page: MIGRATE_UNMOVABLE인 page, object: NULL // acquire_slab(&boot_kmem_cache_node, (&boot_kmem_cache_node)->node[0], MIGRATE_UNMOVABLE인 page, 1, objects): // UNMOVABLE인 page 의 object의 시작 virtual address + 64

t = acquire_slab(s, n, page, object == NULL, &objects);

slub.c::acquire_slab()

// ARM10C 20140621 // s: &boot_kmem_cache_node, n: (&boot_kmem_cache_node)->node[0], // page: MIGRATE_UNMOVABLE인 page, 1, objects

static inline void *acquire_slab(struct kmem_cache *s,
		struct kmem_cache_node *n, struct page *page,
		int mode, int *objects)
{
	void *freelist;
	unsigned long counters;
	struct page new;

	/*
	 * Zap the freelist and set the frozen bit.
	 * The old freelist is the list of objects for the
	 * per cpu allocation list.
	 */
	// page->freelist: UNMOVABLE인 page 의 object의 시작 virtual address + 64
	freelist = page->freelist;
	// freelist: UNMOVABLE인 page 의 object의 시작 virtual address + 64

	// page->objects: 64, page->inuse: 1, page->frozen: 0 값에 의해
	// page->counters: 0x400001 값으로 해석됨
	counters = page->counters;
	// counters: 0x400001
	new.counters = counters;
	// new.counters: 0x400001

	// new.objects: 64, new.inuse: 1
	*objects = new.objects - new.inuse;
	// *objects: 63

	// mode: 1
	if (mode) {
		// new.inuse: 1, page->objects: 64
		new.inuse = page->objects;
		// new.inuse: 64
		// new.counters: 0x400040
		new.freelist = NULL;
		// new.freelist: NULL
	} else {
		new.freelist = freelist;
	}

	// new.frozen: 0
	VM_BUG_ON(new.frozen);

	// new.frozen: 0
	new.frozen = 1;
	// new.frozen: 1
	// new.counters: 0x80400040

	// s: &boot_kmem_cache_node, page: MIGRATE_UNMOVABLE인 page,
	// freelist: UNMOVABLE인 page 의 object의 시작 virtual address + 64
	// counters: 0x400001, new.freelist: NULL, new.counters: 0x80400040, "acquire_slab"
	// __cmpxchg_double_slab(&boot_kmem_cache_node, MIGRATE_UNMOVABLE인 page,
	// UNMOVABLE인 page 의 object의 시작 virtual address + 64, 0x400001, NULL, 0x80400040
	// "acquire_slab"): 1
	if (!__cmpxchg_double_slab(s, page,
			freelist, counters,
			new.freelist, new.counters,
			"acquire_slab"))
		return NULL;

// s: &boot_kmem_cache_node, page: MIGRATE_UNMOVABLE인 page, // freelist: UNMOVABLE인 page 의 object의 시작 virtual address + 64 // counters: 0x400001, new.freelist: NULL, new.counters: 0x80400040, "acquire_slab" // __cmpxchg_double_slab(&boot_kmem_cache_node, MIGRATE_UNMOVABLE인 page, // UNMOVABLE인 page 의 object의 시작 virtual address + 64, 0x400001, NULL, 0x80400040 // "acquire_slab"): 1

if (!__cmpxchg_double_slab(s, page, freelist, counters, new.freelist, new.counters, "acquire_slab"))

slub.c::__cmpxchg_double_slab()

// ARM10C 20140621 // s: &boot_kmem_cache_node, page: MIGRATE_UNMOVABLE인 page, // freelist: UNMOVABLE인 page 의 object의 시작 virtual address + 64 // counters: 0x400001, new.freelist: NULL, new.counters: 0x80400040, "acquire_slab"

static inline bool __cmpxchg_double_slab(struct kmem_cache *s, struct page *page,
		void *freelist_old, unsigned long counters_old,
		void *freelist_new, unsigned long counters_new,
		const char *n)
{
	// irqs_disabled(): 1
	VM_BUG_ON(!irqs_disabled());

// CONFIG_HAVE_CMPXCHG_DOUBLE=n, CONFIG_HAVE_ALIGNED_STRUCT_PAGE=n
#if defined(CONFIG_HAVE_CMPXCHG_DOUBLE) && \
    defined(CONFIG_HAVE_ALIGNED_STRUCT_PAGE)
	if (s->flags & __CMPXCHG_DOUBLE) {
		if (cmpxchg_double(&page->freelist, &page->counters,
			freelist_old, counters_old,
			freelist_new, counters_new))
		return 1;
	} else
#endif
	{
		// page: MIGRATE_UNMOVABLE인 page
		slab_lock(page);

// page: MIGRATE_UNMOVABLE인 page

slab_lock(page);

slub.c::slab_lock()

// ARM10C 20140621 // page: MIGRATE_UNMOVABLE인 page

static __always_inline void slab_lock(struct page *page)
{
	// PG_locked: 0, page->flags: (MIGRATE_UNMOVABLE인 page)->flags
	bit_spin_lock(PG_locked, &page->flags);
}

// PG_locked: 0, page->flags: (MIGRATE_UNMOVABLE인 page)->flags

bit_spin_lock(PG_locked, &page->flags);

bit_spinlock.h::bit_spin_lock()

// ARM10C 20140621 // PG_locked: 0, page->flags: (MIGRATE_UNMOVABLE인 page)->flags

static inline void bit_spin_lock(int bitnum, unsigned long *addr)
{
	/*
	 * Assuming the lock is uncontended, this never enters
	 * the body of the outer loop. If it is contended, then
	 * within the inner loop a non-atomic test is used to
	 * busywait with less bus contention for a good time to
	 * attempt to acquire the lock bit.
	 */
	preempt_disable();
	// preempt count 증가 후 memory barrier 적용

#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) // CONFIG_SMP=y, CONFIG_DEBUG_SPINLOCK=y
	// bitnum: 0, addr: &(MIGRATE_UNMOVABLE인 page)->flags
	// test_and_set_bit_lock(0, &(MIGRATE_UNMOVABLE인 page)->flags): 0
	while (unlikely(test_and_set_bit_lock(bitnum, addr))) {
		preempt_enable();
		do {
			cpu_relax();
		} while (test_bit(bitnum, addr));
		preempt_disable();
	}
#endif
	// __acquire(bitlock): 0
	__acquire(bitlock);
}

preempt.h::preempt_disable()

// ARM10C 20140621

#define preempt_disable()/*ARM10C this*/	\
do { \
	preempt_count_inc(); \
	barrier(); \
} while (0)

bit_spinlock.h::bit_spin_lock()

static inline void bit_spin_lock(int bitnum, unsigned long *addr)
{
	preempt_disable();
	// preempt count 증가 후 memory barrier 적용

#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) // CONFIG_SMP=y, CONFIG_DEBUG_SPINLOCK=y
	// bitnum: 0, addr: &(MIGRATE_UNMOVABLE인 page)->flags
	// test_and_set_bit_lock(0, &(MIGRATE_UNMOVABLE인 page)->flags): 0
	while (unlikely(test_and_set_bit_lock(bitnum, addr))) {

// bitnum: 0, addr: &(MIGRATE_UNMOVABLE인 page)->flags // test_and_set_bit_lock(0, &(MIGRATE_UNMOVABLE인 page)->flags): 0

while (unlikely(test_and_set_bit_lock(bitnum, addr))) {

lock.h::test_adn_set_bit_lock()

// ARM10C 20140621
// bitnum: 0, addr: &(MIGRATE_UNMOVABLE인 page)->flags
#define test_and_set_bit_lock(nr, addr)	test_and_set_bit(nr, addr)

bitops.h:: test_and_set_bit()

// ARM10C 20140621 // bitnum: 0, addr: &(MIGRATE_UNMOVABLE인 page)->flags

#define test_and_set_bit(nr,p)		ATOMIC_BITOP(test_and_set_bit,nr,p)

bit_spinlock.h::bit_spin_lock()

// ARM10C 20140621 // PG_locked: 0, page->flags: (MIGRATE_UNMOVABLE인 page)->flags

static inline void bit_spin_lock(int bitnum, unsigned long *addr)
{
	/*
	 * Assuming the lock is uncontended, this never enters
	 * the body of the outer loop. If it is contended, then
	 * within the inner loop a non-atomic test is used to
	 * busywait with less bus contention for a good time to
	 * attempt to acquire the lock bit.
	 */
	preempt_disable();
	// preempt count 증가 후 memory barrier 적용

#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) // CONFIG_SMP=y, CONFIG_DEBUG_SPINLOCK=y
	// bitnum: 0, addr: &(MIGRATE_UNMOVABLE인 page)->flags
	// test_and_set_bit_lock(0, &(MIGRATE_UNMOVABLE인 page)->flags): 0
	while (unlikely(test_and_set_bit_lock(bitnum, addr))) {
		preempt_enable();
		do {
			cpu_relax();
		} while (test_bit(bitnum, addr));
		preempt_disable();
	}
#endif
	// __acquire(bitlock): 0
	__acquire(bitlock);
}

// __acquire(bitlock): 0

__acquire(bitlock);

compiler.h::__acquire()

// ARM10C 20140621
# define __acquire(x) (void)0

slub.c::__cmpxchg_double_slab()

static inline bool __cmpxchg_double_slab(struct kmem_cache *s, struct page *page,
		void *freelist_old, unsigned long counters_old,
		void *freelist_new, unsigned long counters_new,
		const char *n)
{
	// irqs_disabled(): 1
	VM_BUG_ON(!irqs_disabled());

// CONFIG_HAVE_CMPXCHG_DOUBLE=n, CONFIG_HAVE_ALIGNED_STRUCT_PAGE=n
#if defined(CONFIG_HAVE_CMPXCHG_DOUBLE) && \
    defined(CONFIG_HAVE_ALIGNED_STRUCT_PAGE)
	if (s->flags & __CMPXCHG_DOUBLE) {
		if (cmpxchg_double(&page->freelist, &page->counters,
			freelist_old, counters_old,
			freelist_new, counters_new))
		return 1;
	} else
#endif
	{
		// page: MIGRATE_UNMOVABLE인 page
		slab_lock(page);
		// preempt count 증가 후 memory barrier 적용

		// page->freelist: UNMOVABLE인 page 의 object의 시작 virtual address + 64,
		// freelist_old: UNMOVABLE인 page 의 object의 시작 virtual address + 64
		// page->counters: 0x400001, counters_old: 0x400001
		if (page->freelist == freelist_old &&
					page->counters == counters_old) {
			// freelist_new: NULL
			page->freelist = freelist_new;
			// page->freelist: NULL

			// page->counters: 0x400001, counters_new: 0x80400040
			page->counters = counters_new;
			// page->counters: 0x80400040

			// page: MIGRATE_UNMOVABLE인 page
			slab_unlock(page);

// page: MIGRATE_UNMOVABLE인 page

slab_unlock(page);

slub.c::slab_unlock()

// ARM10C 20140621
// page: MIGRATE_UNMOVABLE인 page
static __always_inline void slab_unlock(struct page *page)
{
	// PG_locked: 0, page->flags: (MIGRATE_UNMOVABLE인 page)->flags
	__bit_spin_unlock(PG_locked, &page->flags);
}

bit_spinlock.h::__bit_spin_unlock()

// ARM10C 20140621 // PG_locked: 0, page->flags: &(MIGRATE_UNMOVABLE인 page)->flags

static inline void __bit_spin_unlock(int bitnum, unsigned long *addr)
{
#ifdef CONFIG_DEBUG_SPINLOCK // CONFIG_DEBUG_SPINLOCK=y
	// bitnum: 0, addr: &(MIGRATE_UNMOVABLE인 page)->flags
	// test_bit(0, &(MIGRATE_UNMOVABLE인 page)->flags): 1
	BUG_ON(!test_bit(bitnum, addr));
#endif
#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) // CONFIG_SMP=y, CONFIG_DEBUG_SPINLOCK=y
	// bitnum: 0, addr: &(MIGRATE_UNMOVABLE인 page)->flags
	__clear_bit_unlock(bitnum, addr);

// bitnum: 0, addr: &(MIGRATE_UNMOVABLE인 page)->flags

__clear_bit_unlock(bitnum, addr);

lock.h::__clear_bit_unlock()

// ARM10C 20140621 // bitnum: 0, addr: &(MIGRATE_UNMOVABLE인 page)->flags

#define __clear_bit_unlock(nr, addr)	\
do {					\
	smp_mb();			\
	__clear_bit(nr, addr);		\
} while (0)

smp_mb();
__clear_bit(nr, addr); \

barrier.h::smb_mb()

// ARM10C 20140621 // A.R.M: A8.8.43 DMB // ISH option: // ISH Inner Shareable is the required shareability domain, reads and writes are the required // access types. Encoded as option = 0b1011. // 공유자원을 다른 cpu core가 사용할수 있게 해주는 옵션

#define smp_mb()	dmb(ish)

barrier.h::dmb()

// ARM10C 20140621 // A.R.M: A8.8.43 DMB // ISH option: // ISH Inner Shareable is the required shareability domain, reads and writes are the required // access types. Encoded as option = 0b1011.

#define dmb(option) __asm__ __volatile__ ("dmb " #option : : : "memory")

non-atomic.h::__clear_bit()

// ARM10C 20140621

static inline void __clear_bit(int nr, volatile unsigned long *addr)
{
	// mask : 0x1
	unsigned long mask = BIT_MASK(nr);
	unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);

	// nr 값을 이용해서 해당 bit를 클리어
	*p &= ~mask;
}

bit_spinlock.h::__bit_spin_unlock()

static inline void __bit_spin_unlock(int bitnum, unsigned long *addr)
{
	// bitnum: 0, addr: &(MIGRATE_UNMOVABLE인 page)->flags
	// test_bit(0, &(MIGRATE_UNMOVABLE인 page)->flags): 1
	BUG_ON(!test_bit(bitnum, addr));

	// bitnum: 0, addr: &(MIGRATE_UNMOVABLE인 page)->flags
	__clear_bit_unlock(bitnum, addr);
	// (MIGRATE_UNMOVABLE인 page)->flags 의 bit 0을 클리어함
	// dmb(ish)를 사용하여 공유 자원 (MIGRATE_UNMOVABLE인 page)->flags 값을 갱신

    preempt_enable();
	// memory barrier 적용 후 preempt count 감소 시킴

	// __release(bitlock): 0
	__release(bitlock);
}

compiler.h::__release()

// ARM10C 20140621

# define __release(x) (void)0

slub.c::__cmpxchg_double_slab()

static inline bool __cmpxchg_double_slab(struct kmem_cache *s, struct page *page,
		void *freelist_old, unsigned long counters_old,
		void *freelist_new, unsigned long counters_new,
		const char *n)
{
	// irqs_disabled(): 1
	VM_BUG_ON(!irqs_disabled());

// CONFIG_HAVE_CMPXCHG_DOUBLE=n, CONFIG_HAVE_ALIGNED_STRUCT_PAGE=n
#if defined(CONFIG_HAVE_CMPXCHG_DOUBLE) && \
    defined(CONFIG_HAVE_ALIGNED_STRUCT_PAGE)
	if (s->flags & __CMPXCHG_DOUBLE) {
		if (cmpxchg_double(&page->freelist, &page->counters,
			freelist_old, counters_old,
			freelist_new, counters_new))
		return 1;
	} else
#endif
	{
		// page: MIGRATE_UNMOVABLE인 page
		slab_lock(page);
		// preempt count 증가 후 memory barrier 적용

		// page->freelist: UNMOVABLE인 page 의 object의 시작 virtual address + 64,
		// freelist_old: UNMOVABLE인 page 의 object의 시작 virtual address + 64
		// page->counters: 0x400001, counters_old: 0x400001
		if (page->freelist == freelist_old &&
					page->counters == counters_old) {
			// freelist_new: NULL
			page->freelist = freelist_new;
			// page->freelist: NULL

			// page->counters: 0x400001, counters_new: 0x80400040
			page->counters = counters_new;
			// page->counters: 0x80400040

			// page: MIGRATE_UNMOVABLE인 page
			slab_unlock(page);
			// (MIGRATE_UNMOVABLE인 page)->flags 의 bit 0을 클리어함
			// dmb(ish)를 사용하여 공유 자원 (MIGRATE_UNMOVABLE인 page)->flags 값을 갱신
			// memory barrier 적용 후 preempt count 감소 시킴

			return 1;
			// return 1
		}
		slab_unlock(page);
	}

	cpu_relax();
	stat(s, CMPXCHG_DOUBLE_FAIL);

#ifdef SLUB_DEBUG_CMPXCHG
	printk(KERN_INFO "%s %s: cmpxchg double redo ", n, s->name);
#endif

	return 0;
}

// return 1;

slub.c::acquire_slab()

static inline void *acquire_slab(struct kmem_cache *s,
		struct kmem_cache_node *n, struct page *page,
		int mode, int *objects)
{
	void *freelist;
	unsigned long counters;
	struct page new;

	// page->freelist: UNMOVABLE인 page 의 object의 시작 virtual address + 64
	freelist = page->freelist;
	// freelist: UNMOVABLE인 page 의 object의 시작 virtual address + 64

	// page->objects: 64, page->inuse: 1, page->frozen: 0 값에 의해
	// page->counters: 0x400001 값으로 해석됨
	counters = page->counters;
	// counters: 0x400001
	new.counters = counters;
	// new.counters: 0x400001

	// new.objects: 64, new.inuse: 1
	*objects = new.objects - new.inuse;
	// *objects: 63

	// mode: 1
	if (mode) {
		// new.inuse: 1, page->objects: 64
		new.inuse = page->objects;
		// new.inuse: 64
		// new.counters: 0x400040
		new.freelist = NULL;
		// new.freelist: NULL
	} else {
		new.freelist = freelist;
	}

	// new.frozen: 0
	VM_BUG_ON(new.frozen);

	// new.frozen: 0
	new.frozen = 1;
	// new.frozen: 1
	// new.counters: 0x80400040

	// s: &boot_kmem_cache_node, page: MIGRATE_UNMOVABLE인 page,
	// freelist: UNMOVABLE인 page 의 object의 시작 virtual address + 64
	// counters: 0x400001, new.freelist: NULL, new.counters: 0x80400040, "acquire_slab"
	// __cmpxchg_double_slab(&boot_kmem_cache_node, MIGRATE_UNMOVABLE인 page,
	// UNMOVABLE인 page 의 object의 시작 virtual address + 64, 0x400001, NULL, 0x80400040
	// "acquire_slab"): 1
	if (!__cmpxchg_double_slab(s, page,
			freelist, counters,
			new.freelist, new.counters,
			"acquire_slab"))
		return NULL;
	// __cmpxchg_double_slab에서 한일:
	// MIGRATE_UNMOVABLE인 page의 멤버 필드 값
	// page->freelist: NULL
	// page->counters: 0x80400040
	// 로 변경함

	// n: (&boot_kmem_cache_node)->node[0], page: MIGRATE_UNMOVABLE인 page
	remove_partial(n, page);

slub.c::remove_partial()

// ARM10C 20140621 // n: (&boot_kmem_cache_node)->node[0], page: MIGRATE_UNMOVABLE인 page

static inline void remove_partial(struct kmem_cache_node *n,
					struct page *page)
{
	// page->lru: (MIGRATE_UNMOVABLE인 page)->lru
	list_del(&page->lru);
	// n->partial에 연결된 (MIGRATE_UNMOVABLE인 page)->lru 를 삭제

	// n: UNMOVABLE인 page 의 object의 시작 virtual address

	// n->nr_partial: 1
	n->nr_partial--;
	// n->nr_partial: 0
}

list.h::list_del()

// ARM10C 20140517

static inline void list_del(struct list_head *entry)
{
	__list_del(entry->prev, entry->next);

	// LIST_POISON1: ((void *) 0x00100100)
	entry->next = LIST_POISON1;

	// LIST_POISON2: ((void *) 0x00200200)
	entry->prev = LIST_POISON2;
}

slub.c::acquire_slab()

static inline void *acquire_slab(struct kmem_cache *s,
		struct kmem_cache_node *n, struct page *page,
		int mode, int *objects)
{
	void *freelist;
	unsigned long counters;
	struct page new;

	// page->freelist: UNMOVABLE인 page 의 object의 시작 virtual address + 64
	freelist = page->freelist;
	// freelist: UNMOVABLE인 page 의 object의 시작 virtual address + 64

	// page->objects: 64, page->inuse: 1, page->frozen: 0 값에 의해
	// page->counters: 0x400001 값으로 해석됨
	counters = page->counters;
	// counters: 0x400001
	new.counters = counters;
	// new.counters: 0x400001

	// new.objects: 64, new.inuse: 1
	*objects = new.objects - new.inuse;
	// *objects: 63

	// mode: 1
	if (mode) {
		// new.inuse: 1, page->objects: 64
		new.inuse = page->objects;
		// new.inuse: 64
		// new.counters: 0x400040
		new.freelist = NULL;
		// new.freelist: NULL
	} else {
		new.freelist = freelist;
	}

	// new.frozen: 0
	VM_BUG_ON(new.frozen);

	// new.frozen: 0
	new.frozen = 1;
	// new.frozen: 1
	// new.counters: 0x80400040

	// s: &boot_kmem_cache_node, page: MIGRATE_UNMOVABLE인 page,
	// freelist: UNMOVABLE인 page 의 object의 시작 virtual address + 64
	// counters: 0x400001, new.freelist: NULL, new.counters: 0x80400040, "acquire_slab"
	// __cmpxchg_double_slab(&boot_kmem_cache_node, MIGRATE_UNMOVABLE인 page,
	// UNMOVABLE인 page 의 object의 시작 virtual address + 64, 0x400001, NULL, 0x80400040
	// "acquire_slab"): 1
	if (!__cmpxchg_double_slab(s, page,
			freelist, counters,
			new.freelist, new.counters,
			"acquire_slab"))
		return NULL;
	// __cmpxchg_double_slab에서 한일:
	// MIGRATE_UNMOVABLE인 page의 멤버 필드 값
	// page->freelist: NULL
	// page->counters: 0x80400040
	// 로 변경함

	// n: (&boot_kmem_cache_node)->node[0], page: MIGRATE_UNMOVABLE인 page
	remove_partial(n, page);
	// n->partial에 연결된 (MIGRATE_UNMOVABLE인 page)->lru 를 삭제
	// n->nr_partial: 0

	// freelist: UNMOVABLE인 page 의 object의 시작 virtual address + 64
	WARN_ON(!freelist);

	// freelist: UNMOVABLE인 page 의 object의 시작 virtual address + 64
	return freelist;
	// return UNMOVABLE인 page 의 object의 시작 virtual address + 64
}

// return freelist; // return UNMOVABLE인 page 의 object의 시작 virtual address + 64

slub.c::get_partial_node()

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)->node[0]: UNMOVABLE인 page 의 object의 시작 virtual address,
	// n->nr_partial: ((&boot_kmem_cache_node)->node[0])->nr_partial: 1
	if (!n || !n->nr_partial)
		return NULL;

	// early_kmem_cache_node_alloc에서 (&boot_kmem_cache_node)->node[0] 값을 설정함

	// n->list_lock: ((&boot_kmem_cache_node)->node[0])->list_lock
	spin_lock(&n->list_lock);
	// ((&boot_kmem_cache_node)->node[0])->list_lock의 spinlock 획득

// 2014/06/14 종료
// 2014/06/21 시작

	list_for_each_entry_safe(page, page2, &n->partial, lru) {
	// for (page = list_first_entry(&n->partial, typeof(*page), lru),
	//      page2 = list_next_entry(page, lru);
	//      &page->lru != (&n->partial);
	//      page = page2, page2 = list_next_entry(page2, lru))

		// page: MIGRATE_UNMOVABLE인 page, page2: page lru의 offset 만큼 계산된 주소

		void *t;

		// page: MIGRATE_UNMOVABLE인 page, flags: GFP_KERNEL: 0xD0
		// pfmemalloc_match(MIGRATE_UNMOVABLE인 page, GFP_KERNEL: 0xD0): 1
		if (!pfmemalloc_match(page, flags))
			continue;

        // s: &boot_kmem_cache_node, n: (&boot_kmem_cache_node)->node[0],
		// page: MIGRATE_UNMOVABLE인 page, object: NULL
		// acquire_slab(&boot_kmem_cache_node, (&boot_kmem_cache_node)->node[0], MIGRATE_UNMOVABLE인 page, 1, objects):
		// UNMOVABLE인 page 의 object의 시작 virtual address + 64
		t = acquire_slab(s, n, page, object == NULL, &objects);
		// t: UNMOVABLE인 page 의 object의 시작 virtual address + 64, objects: 63


		// t: UNMOVABLE인 page 의 object의 시작 virtual address + 64
		if (!t)
			break;
			
		// available: 0, objects: 63
		available += objects;
		// available: 63

		// object: NULL
		if (!object) {
			// c->page: ((&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->page,
			// page: MIGRATE_UNMOVABLE인 page
			c->page = page;
			// c->page: ((&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->page:
			// MIGRATE_UNMOVABLE인 page

			// s: &boot_kmem_cache_node, ALLOC_FROM_PARTIAL: 7
			stat(s, ALLOC_FROM_PARTIAL); // null function

			// object: NULL, t: UNMOVABLE인 page 의 object의 시작 virtual address + 64
			object = t;
			// object: UNMOVABLE인 page 의 object의 시작 virtual address + 64
		} else {
			put_cpu_partial(s, page, 0);
			stat(s, CPU_PARTIAL_NODE);
		}

		// s: &boot_kmem_cache_node,
		// kmem_cache_has_cpu_partial(&boot_kmem_cache_node): 1,
		// available: 63, s->cpu_partial: boot_kmem_cache_node.cpu_partial: 30
		if (!kmem_cache_has_cpu_partial(s)
			|| available > s->cpu_partial / 2)
			break;
			// break 로 loop 탈출
	}

// acquire_slab 이 한일?: // 다음 object의 주소를 받아옴 // UNMOVABLE인 page 의 object의 시작 virtual address + 64 // MIGRATE_UNMOVABLE인 page의 멤버 필드 값 변경 // page->freelist: NULL // page->counters: 0x80400040 // n->partial에 연결된 (MIGRATE_UNMOVABLE인 page)->lru 를 삭제 // n->nr_partial: 0

// s: &boot_kmem_cache_node, // kmem_cache_has_cpu_partial(&boot_kmem_cache_node): 1, // available: 63, s->cpu_partial: boot_kmem_cache_node.cpu_partial: 30

if (!kmem_cache_has_cpu_partial(s)

slub.c::kmem_cache_has_cpu_partial()

// ARM10C 20140621 // s: &boot_kmem_cache

static inline bool kmem_cache_has_cpu_partial(struct kmem_cache *s)
{
#ifdef CONFIG_SLUB_CPU_PARTIAL // CONFIG_SLUB_CPU_PARTIAL=y
	// s: &boot_kmem_cache_node, kmem_cache_debug(&boot_kmem_cache_node): 0
	// s: &boot_kmem_cache, kmem_cache_debug(&boot_kmem_cache): 0
	return !kmem_cache_debug(s);
	// return 1
	// return 1
#else
	return false;
#endif
}

slub.c::get_partial_node()

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)->node[0]: UNMOVABLE인 page 의 object의 시작 virtual address,
	// n->nr_partial: ((&boot_kmem_cache_node)->node[0])->nr_partial: 1
	if (!n || !n->nr_partial)
		return NULL;

	// early_kmem_cache_node_alloc에서 (&boot_kmem_cache_node)->node[0] 값을 설정함

	// n->list_lock: ((&boot_kmem_cache_node)->node[0])->list_lock
	spin_lock(&n->list_lock);
	// ((&boot_kmem_cache_node)->node[0])->list_lock의 spinlock 획득

// 2014/06/14 종료
// 2014/06/21 시작

	list_for_each_entry_safe(page, page2, &n->partial, lru) {
	// for (page = list_first_entry(&n->partial, typeof(*page), lru),
	//      page2 = list_next_entry(page, lru);
	//      &page->lru != (&n->partial);
	//      page = page2, page2 = list_next_entry(page2, lru))

		// page: MIGRATE_UNMOVABLE인 page, page2: page lru의 offset 만큼 계산된 주소

		void *t;

		// page: MIGRATE_UNMOVABLE인 page, flags: GFP_KERNEL: 0xD0
		// pfmemalloc_match(MIGRATE_UNMOVABLE인 page, GFP_KERNEL: 0xD0): 1
		if (!pfmemalloc_match(page, flags))
			continue;

        // s: &boot_kmem_cache_node, n: (&boot_kmem_cache_node)->node[0],
		// page: MIGRATE_UNMOVABLE인 page, object: NULL
		// acquire_slab(&boot_kmem_cache_node, (&boot_kmem_cache_node)->node[0], MIGRATE_UNMOVABLE인 page, 1, objects):
		// UNMOVABLE인 page 의 object의 시작 virtual address + 64
		t = acquire_slab(s, n, page, object == NULL, &objects);
		// t: UNMOVABLE인 page 의 object의 시작 virtual address + 64, objects: 63


		// t: UNMOVABLE인 page 의 object의 시작 virtual address + 64
		if (!t)
			break;
			
		// available: 0, objects: 63
		available += objects;
		// available: 63

		// object: NULL
		if (!object) {
			// c->page: ((&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->page,
			// page: MIGRATE_UNMOVABLE인 page
			c->page = page;
			// c->page: ((&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->page:
			// MIGRATE_UNMOVABLE인 page

			// s: &boot_kmem_cache_node, ALLOC_FROM_PARTIAL: 7
			stat(s, ALLOC_FROM_PARTIAL); // null function

			// object: NULL, t: UNMOVABLE인 page 의 object의 시작 virtual address + 64
			object = t;
			// object: UNMOVABLE인 page 의 object의 시작 virtual address + 64
		} else {
			put_cpu_partial(s, page, 0);
			stat(s, CPU_PARTIAL_NODE);
		}

		// s: &boot_kmem_cache_node,
		// kmem_cache_has_cpu_partial(&boot_kmem_cache_node): 1,
		// available: 63, s->cpu_partial: boot_kmem_cache_node.cpu_partial: 30
		if (!kmem_cache_has_cpu_partial(s)
			|| available > s->cpu_partial / 2)
			break;
			// break 로 loop 탈출
	}

	// n->list_lock: ((&boot_kmem_cache_node)->node[0])->list_lock
	spin_unlock(&n->list_lock);
	// ((&boot_kmem_cache_node)->node[0])->list_lock의 spinlock 해제

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

slub.c::get_partial()

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_node, searchnode: 0
	// get_node(&boot_kmem_cache_node, 0): (&boot_kmem_cache_node)->node[0],
	// c: (&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋),
	// flags: GFP_KERNEL: 0xD0
	// get_partial_node(&boot_kmem_cache_node, (&boot_kmem_cache_node)->node[0],
	// (&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋), GFP_KERNEL: 0xD0):
	// UNMOVABLE인 page 의 object의 시작 virtual address + 64
	object = get_partial_node(s, get_node(s, searchnode), c, flags);
	// object: UNMOVABLE인 page 의 object의 시작 virtual address + 64

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

	return get_any_partial(s, flags, c);
}

// return UNMOVABLE인 page 의 object의 시작 virtual address + 64

get_partial()이 한일

  • object를 위한 page 의 사용 하지 않은 다음 object의 시작 virtual address 를 가져옴
  • page->counters: 0x80400040
  • page->inuse: 64
  • page->objects: 64
  • page->frozen: 1
  • page->freelist: NULL
  • n->partial에 연결된 (MIGRATE_UNMOVABLE인 page)->lru 를 삭제
  • n->nr_partial: 0

slub.c::new_slab_objects()

// ARM10C 20140614 // s: &boot_kmem_cache_node, gfpflags: GFP_KERNEL: 0xD0, node: -1, // &c: &(&boot_kmem_cache_node)->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_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
	struct kmem_cache_cpu *c = *pc;
	// c: (&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
	struct page *page;

	// s: &boot_kmem_cache_node, flags: GFP_KERNEL: 0xD0, node: -1,
	// c: (&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
	// get_partial(&boot_kmem_cache_node, GFP_KERNEL: 0xD0, -1,
	// (&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)):
	// UNMOVABLE인 page 의 object의 시작 virtual address + 64
	freelist = get_partial(s, flags, node, c);
	// freelist: UNMOVABLE인 page 의 object의 시작 virtual address + 64


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

	page = new_slab(s, flags, node);
	if (page) {
		c = __this_cpu_ptr(s->cpu_slab);
		if (c->page)
			flush_slab(s, c);

		freelist = page->freelist;
		page->freelist = NULL;

		stat(s, ALLOC_SLAB);
		c->page = page;
		*pc = c;
	} else
		freelist = NULL;

	return freelist;
}

// retrun freelist

slub.c::__slab_alloc()

// ARM10C 20140614 // s: &boot_kmem_cache_node, gfpflags: GFP_KERNEL: 0xD0, node: -1, addr: RET_IP, // c: (&boot_kmem_cache_node)->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)
{
...
    goto new_slab;
		// new_slab 심볼로 이동
...
new_slab:

	// c->partial: (&boot_kmem_cache_node)->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_node, gfpflags: GFP_KERNEL: 0xD0, node: -1,
	// c: (&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
	// new_slab_objects(&boot_kmem_cache_node, GFP_KERNEL: 0xD0, -1,
	// (&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)):
	// UNMOVABLE인 page 의 object의 시작 virtual address + 64
	freelist = new_slab_objects(s, gfpflags, node, &c);
	// freelist: UNMOVABLE인 page 의 object의 시작 virtual address + 64
	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_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->page:
	// MIGRATE_UNMOVABLE인 page
	page = c->page;
	// page: MIGRATE_UNMOVABLE인 page

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

// load_freelist 심볼로 점프

goto load_freelist;

load_freelist:
	/*
	 * freelist is pointing to the list of objects to be used.
	 * page is pointing to the page from which the objects are obtained.
	 * That page must be frozen for per cpu allocations to work.
	 */
	// c->page: ((&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->page:
	// MIGRATE_UNMOVABLE인 page

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

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

slub.c::get_freepointer()

// ARM10C 20140621 // s: &boot_kmem_cache_node, freelist: UNMOVABLE인 page 의 object의 시작 virtual address + 64

static inline void *get_freepointer(struct kmem_cache *s, void *object)
{
	// object: UNMOVABLE인 page 의 object의 시작 virtual address
	// s->offset: (&boot_kmem_cache_node)->offset: 0
	return *(void **)(object + s->offset);
	// object: UNMOVABLE인 page 의 object의 시작 virtual address
}

slub.c::__slab_alloc()

// ARM10C 20140614 // s: &boot_kmem_cache_node, gfpflags: GFP_KERNEL: 0xD0, node: -1, addr: RET_IP, // c: (&boot_kmem_cache_node)->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)
{
...
load_freelist:
	// c->page: ((&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->page:
	// MIGRATE_UNMOVABLE인 page

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

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

	// c->tid: ((&boot_kmem_cache_node)->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_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->tid: 0 // next_tid(0): 4

c->tid = next_tid(c->tid);

slub.c::next_tid()

// ARM10C 20140621 // c->tid: ((&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->tid: 0

static inline unsigned long next_tid(unsigned long tid)
{
	// tid: 0, TID_STEP: 4
	return tid + TID_STEP;
	// return 4
}

slub.c::__slab_alloc()

// ARM10C 20140614 // s: &boot_kmem_cache_node, gfpflags: GFP_KERNEL: 0xD0, node: -1, addr: RET_IP, // c: (&boot_kmem_cache_node)->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)
{
...
load_freelist:
	// c->page: ((&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->page:
	// MIGRATE_UNMOVABLE인 page

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

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

	// c->tid: ((&boot_kmem_cache_node)->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_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->tid: 4

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

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

new_slab_objects이 한일:

  • object를 위한 page 의 사용 하지 않은 다음 object의 시작 virtual address 를 가져옴
  • page->counters: 0x80400040
  • page->inuse: 64
  • page->objects: 64
  • page->frozen: 1
  • page->freelist: NULL
  • n->partial에 연결된 (MIGRATE_UNMOVABLE인 page)->lru 를 삭제
  • n->nr_partial: 0

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:
...
	// object: 0, page: 0, node: -1, node_match(0, -1): 1
	if (unlikely(!object || !node_match(page, node)))
		// s: &boot_kmem_cache_node, gfpflags: GFP_KERNEL: 0xD0, node: -1, addr: _RET_IP_,
		// c: (&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
		// __slab_alloc(&boot_kmem_cache_node, GFP_KERNEL: 0xD0, -1, _RET_IP_,
		// (&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)):
		// UNMOVABLE인 page 의 object의 시작 virtual address + 64
		object = __slab_alloc(s, gfpflags, node, addr, c);
		// object: UNMOVABLE인 page 의 object의 시작 virtual address + 64
	else {
	...
	}

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

	// s: &boot_kmem_cache_node, gfpflags: GFP_KERNEL: 0xD0,
	// object: UNMOVABLE인 page 의 object의 시작 virtual address + 64
	slab_post_alloc_hook(s, gfpflags, object);
}

// s: &boot_kmem_cache_node, gfpflags: GFP_KERNEL: 0xD0, // object: UNMOVABLE인 page 의 object의 시작 virtual address + 64

slab_post_alloc_hook(s, gfpflags, object);

slub.c::slab_post_alloc_hook()

// ARM10C 20140621 // s: &boot_kmem_cache_node, gfpflags: GFP_KERNEL: 0xD0, // object: UNMOVABLE인 page 의 object의 시작 virtual address + 64

static inline void slab_post_alloc_hook(struct kmem_cache *s,
					gfp_t flags, void *object)
{
	// flags: GFP_KERNEL: 0xD0, gfp_allowed_mask: 0x1ffff2f
	flags &= gfp_allowed_mask;
	// flags: 0

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

	// object: UNMOVABLE인 page 의 object의 시작 virtual address + 64,
	// s->object_size: boot_kmem_cache_node.object_size: 64,
	// s->flags: boot_kmem_cache_node.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:
...
	// s: &boot_kmem_cache_node, gfpflags: GFP_KERNEL: 0xD0,
	// object: UNMOVABLE인 page 의 object의 시작 virtual address + 64
	slab_post_alloc_hook(s, gfpflags, object);

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

// return UNMOVABLE인 page 의 object의 시작 virtual address + 64

return object;

slub.c::slab_alloc()

// ARM10C 20140614 // s: &boot_kmem_cache_node, gfpflags: GFP_KERNEL: 0xD0, RET_IP

static __always_inline void *slab_alloc(struct kmem_cache *s,
		gfp_t gfpflags, unsigned long addr)
{
	// s: &boot_kmem_cache_node, gfpflags: GFP_KERNEL: 0xD0, NUMA_NO_NODE: -1, _RET_IP_
	// slab_alloc_node(&boot_kmem_cache_node, GFP_KERNEL: 0xD0, -1, _RET_IP_):
	// UNMOVABLE인 page 의 object의 시작 virtual address + 64
	return slab_alloc_node(s, gfpflags, NUMA_NO_NODE, addr);
}

// return UNMOVABLE인 page 의 object의 시작 virtual address + 64

return slab_alloc_node(s, gfpflags, NUMA_NO_NODE, addr);

slub.c::kmem_cache_alloc()

// ARM10C 20140614 // s: &boot_kmem_cache_node, flags: GFP_KERNEL: 0xD0

void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags)
{
	// s: &boot_kmem_cache_node, gfpflags: GFP_KERNEL: 0xD0
	// slab_alloc(&boot_kmem_cache_node, GFP_KERNEL: 0xD0): UNMOVABLE인 page 의 object의 시작 virtual address + 64
	void *ret = slab_alloc(s, gfpflags, _RET_IP_);
	// ret: UNMOVABLE인 page 의 object의 시작 virtual address + 64

	// ret: UNMOVABLE인 page 의 object의 시작 virtual address + 64
	// s->object_size: boot_kmem_cache_node.object_size: 64,
	// s->size: boot_kmem_cache_node.size: 64,
	// gfpflags: GFP_KERNEL: 0xD0
	trace_kmem_cache_alloc(_RET_IP_, ret, s->object_size,
				s->size, gfpflags);

	// ret: UNMOVABLE인 page 의 object의 시작 virtual address + 64
	return ret;
	// return UNMOVABLE인 page 의 object의 시작 virtual address + 64
}

// return UNMOVABLE인 page 의 object의 시작 virtual address + 64

return ret;

slab.h::kmem_cache_alloc_node()

// ARM10C 20140614 // kmem_cache_node: &boot_kmem_cache_node, GFP_KERNEL: 0xD0, node: 0

static __always_inline void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t flags, int node)
{
	// s: &boot_kmem_cache_node, flags: GFP_KERNEL: 0xD0
	// kmem_cache_alloc(&boot_kmem_cache_node, GFP_KERNEL: 0xD0):
	// UNMOVABLE인 page 의 object의 시작 virtual address + 64
	return kmem_cache_alloc(s, flags);
	// return UNMOVABLE인 page 의 object의 시작 virtual address + 64
}

// return UNMOVABLE인 page 의 object의 시작 virtual address + 64 return kmem_cache_alloc(s, flags);

kmem_cache_alloc_node 한일?

  • MIGRATE_UNMOVABLE인 page 할당 받아 쪼개놓은 object들에서 object를 1개 할당받음
  • page->counters: 0x80400040
  • page->inuse: 64
  • page->objects: 64
  • page->frozen: 1
  • page->freelist: NULL
  • c->freelist: ((&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->freelist:
  • UNMOVABLE인 page 의 object의 시작 virtual address + 128
  • c->tid: ((&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->tid: 4
  • object를 위한 page 의 사용 하지 않은 다음 object의 시작 virtual address 를 가져옴
  • n->partial에 연결된 (MIGRATE_UNMOVABLE인 page)->lru 를 삭제
  • n->nr_partial: 0

slub.c::init_kmem_cache_nodes()

// ARM10C 20140614 // s: &boot_kmem_cache

static int init_kmem_cache_nodes(struct kmem_cache *s)
{
	int node;

	// N_NORMAL_MEMORY: 2
	for_each_node_state(node, N_NORMAL_MEMORY) {
	// for ( (node) = 0; (node) == 0; (node) = 1)

		struct kmem_cache_node *n;

		// slab_state: DOWN: 0
		// slab_state: PARTIAL: 1, DOWN: 0
		if (slab_state == DOWN) {
		    ...
		    continue;
	    }
		// kmem_cache_node: &boot_kmem_cache_node, GFP_KERNEL: 0xD0, node: 0
		// kmem_cache_alloc_node(&boot_kmem_cache_node, GFP_KERNEL: 0xD0, 0):
		// UNMOVABLE인 page 의 object의 시작 virtual address + 64
		n = kmem_cache_alloc_node(kmem_cache_node,
						GFP_KERNEL, node);
		// n: UNMOVABLE인 page 의 object의 시작 virtual address + 64

		if (!n) {
			free_kmem_cache_nodes(s);
			return 0;
		}

		// node: 0, s->node[0]: boot_kmem_cache.node[0]
		// n: UNMOVABLE인 page 의 object의 시작 virtual address + 64
		s->node[node] = n;
		// s->node[0]: boot_kmem_cache.node[0]: UNMOVABLE인 page 의 object의 시작 virtual address + 64

		// n: UNMOVABLE인 page 의 object의 시작 virtual address + 64
		init_kmem_cache_node(n);

// n: UNMOVABLE인 page 의 object의 시작 virtual address + 64

init_kmem_cache_node(n);

slub.c::init_kmem_cache_node()

// ARM10C 20140621 // n: UNMOVABLE인 page 의 object의 시작 virtual address + 64

static void
init_kmem_cache_node(struct kmem_cache_node *n)
{
	// n: UNMOVABLE인 page 의 object의 시작 virtual address
	// n: UNMOVABLE인 page 의 object의 시작 virtual address + 64

	n->nr_partial = 0;
	// n->nr_partial: 0

	spin_lock_init(&n->list_lock);
	// n->list_lock: spinlock 초기화 수행

	INIT_LIST_HEAD(&n->partial);
	// n->partial: 리스트 초기화

#ifdef CONFIG_SLUB_DEBUG // CONFIG_SLUB_DEBUG=y
	atomic_long_set(&n->nr_slabs, 0);
	// n->nr_slabs: 0

	atomic_long_set(&n->total_objects, 0);
	// n->total_objects: 0

	INIT_LIST_HEAD(&n->full);
	// n->full: 리스트 초기화
#endif
}
  • n->nr_partial: 0
  • n->list_lock: spinlock 초기화 수행
  • n->partial: 리스트 초기화
  • n->nr_slabs: 0
  • n->total_objects: 0
  • n->full: 리스트 초기화
  • 할당받은 slab object를 kmem_cache_node 로 사용하고
  • kmem_cache_node의 멤버 필드를 초기화함

slub.c::init_kmem_cache_nodes()

// ARM10C 20140614 // s: &boot_kmem_cache

static int init_kmem_cache_nodes(struct kmem_cache *s)
{
	int node;

	// N_NORMAL_MEMORY: 2
	for_each_node_state(node, N_NORMAL_MEMORY) {
	// for ( (node) = 0; (node) == 0; (node) = 1)

		struct kmem_cache_node *n;

		// slab_state: DOWN: 0
		// slab_state: PARTIAL: 1, DOWN: 0
		if (slab_state == DOWN) {
		    ...
		    continue;
	    }
		// kmem_cache_node: &boot_kmem_cache_node, GFP_KERNEL: 0xD0, node: 0
		// kmem_cache_alloc_node(&boot_kmem_cache_node, GFP_KERNEL: 0xD0, 0):
		// UNMOVABLE인 page 의 object의 시작 virtual address + 64
		n = kmem_cache_alloc_node(kmem_cache_node,
						GFP_KERNEL, node);
		// n: UNMOVABLE인 page 의 object의 시작 virtual address + 64

		if (!n) {
			free_kmem_cache_nodes(s);
			return 0;
		}

		// node: 0, s->node[0]: boot_kmem_cache.node[0]
		// n: UNMOVABLE인 page 의 object의 시작 virtual address + 64
		s->node[node] = n;
		// s->node[0]: boot_kmem_cache.node[0]: UNMOVABLE인 page 의 object의 시작 virtual address + 64

		// n: UNMOVABLE인 page 의 object의 시작 virtual address + 64
		init_kmem_cache_node(n);
	}
	return 1;
	// return 1 수행

init_kmem_cache_nodes(&boot_kmem_cache_node) 가 한일:

  • migratetype이 MIGRATE_UNMOVABLE인 page 할당 받음
  • page 맴버를 셋팅함
  • page->slab_cache: &boot_kmem_cache_node 주소를 set
  • page->flags에 7 (PG_slab) bit를 set
  • page->freelist: UNMOVABLE인 page 의 object의 시작 virtual address + 64
  • page->inuse: 1, page->frozen: 0 page 맴버를 셋팅함
  • slab 의 objects 들의 freepointer를 맵핑함
  • 할당받은 slab object를 kmem_cache_node 로 사용하고 kmem_cache_node의 멤버 필드를 초기화함
  • kmem_cache_node->nr_partial: 1
  • kmem_cache_node->list_lock: spinlock 초기화 수행
  • kmem_cache_node->slabs: 1, kmem_cache_node->total_objects: 64 로 세팀함
  • kmem_cache_node->full: 리스트 초기화
  • kmem_cache_node의 partial 맴버에 현재 page의 lru 리스트를 추가함

init_kmem_cache_nodes(&boot_kmem_cache) 가 한일:

MIGRATE_UNMOVABLE인 page 할당 받아 쪼개놓은 object들에서 object를 1개 할당받음 page->counters: 0x80400040 page->inuse: 64 page->objects: 64 page->frozen: 1 page->freelist: NULL c->freelist: ((&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->freelist: UNMOVABLE인 page 의 object의 시작 virtual address + 128 c->tid: ((&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->tid: 4 첫번째 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: 리스트 초기화

slub.c::kmem_cache_open()

// ARM10C 20140614 // s: &boot_kmem_cache, flags: SLAB_HWCACHE_ALIGN: 0x00002000UL

static int kmem_cache_open(struct kmem_cache *s, unsigned long flags)
{
...
    // s: &boot_kmem_cache_node, init_kmem_cache_nodes(&boot_kmem_cache_node): 1
	// s: &boot_kmem_cache, init_kmem_cache_nodes(&boot_kmem_cache): 1
	if (!init_kmem_cache_nodes(s))
		goto error;

	// s: &boot_kmem_cache_node, alloc_kmem_cache_cpus(&boot_kmem_cache_node): 1
	// s: &boot_kmem_cache, alloc_kmem_cache_cpus(&boot_kmem_cache): 1
	if (alloc_kmem_cache_cpus(s))

// s: &boot_kmem_cache, alloc_kmem_cache_cpus(&boot_kmem_cache): 1

if (alloc_kmem_cache_cpus(s))

slub.c::alloc_kmem_cache_cpus()

// ARM10C 20140621 // s: &boot_kmem_cache

static inline int alloc_kmem_cache_cpus(struct kmem_cache *s)
{
	// PERCPU_DYNAMIC_EARLY_SIZE: 0x3000, KMALLOC_SHIFT_HIGH: 13
	// sizeof(struct kmem_cache_cpu): 16 bytes
	BUILD_BUG_ON(PERCPU_DYNAMIC_EARLY_SIZE <
			KMALLOC_SHIFT_HIGH * sizeof(struct kmem_cache_cpu));

	/*
	 * Must align to double word boundary for the double cmpxchg
	 * instructions to work; see __pcpu_double_call_return_bool().
	 */
	// s->cpu_slab: (&boot_kmem_cache_node)->cpu_slab
	// sizeof(struct kmem_cache_cpu): 16 bytes, sizeof(void *): 8 bytes
	// __alloc_percpu(16, 8): 0xc0502d00
	// s->cpu_slab: (&boot_kmem_cache)->cpu_slab
	// sizeof(struct kmem_cache_cpu): 16 bytes, sizeof(void *): 8 bytes
	// __alloc_percpu(16, 8): 0xc0502d10
	s->cpu_slab = __alloc_percpu(sizeof(struct kmem_cache_cpu),
				     2 * sizeof(void *));

// __alloc_percpu(16, 8): 0xc0502d10

s->cpu_slab = __alloc_percpu(sizeof(struct kmem_cache_cpu), 2 * sizeof(void *));

percpu.c::__alloc_percpu()

// ARM10C 20140621 // __alloc_percpu(16, 8)

void __percpu *__alloc_percpu(size_t size, size_t align)
{
	// size: 16, align: 8
	return pcpu_alloc(size, align, false);

percpu.c::pcpu_alloc()

// ARM10C 20140621 // size: 16, align: 8, false

static void __percpu *pcpu_alloc(size_t size, size_t align, bool reserved)
{
	static int warn_limit = 10;
	// warn_limit: 10
	struct pcpu_chunk *chunk;
	const char *err;
	int slot, off, new_alloc;
	unsigned long flags;
	void __percpu *ptr;

	// size: 16, align: 8, PCPU_MIN_UNIT_SIZE: 0x8000, PAGE_SIZE: 0x1000
	// size: 16, align: 8, PCPU_MIN_UNIT_SIZE: 0x8000, PAGE_SIZE: 0x1000
	if (unlikely(!size || size > PCPU_MIN_UNIT_SIZE || align > PAGE_SIZE)) {
		WARN(true, "illegal size (%zu) or align (%zu) for "
		     "percpu allocation\n", size, align);
		return NULL;
	}

	mutex_lock(&pcpu_alloc_mutex);
	// pcpu_alloc_mutex의 mutex lock을 수행
	// pcpu_alloc_mutex의 mutex lock을 수행

	spin_lock_irqsave(&pcpu_lock, flags);
	// pcpu_lock의 spin lock 을 수행하고 cpsr을 flags에 저장
	// pcpu_lock의 spin lock 을 수행하고 cpsr을 flags에 저장

	/* serve reserved allocations from the reserved chunk if available */
	// reserved: false, pcpu_reserved_chunk: pcpu_setup_first_chunk()함수에서 할당한 schunk
	// reserved: false, pcpu_reserved_chunk: pcpu_setup_first_chunk()함수에서 할당한 schunk
	if (reserved && pcpu_reserved_chunk) {
		chunk = pcpu_reserved_chunk;

		if (size > chunk->contig_hint) {
			err = "alloc from reserved chunk failed";
			goto fail_unlock;
		}

		while ((new_alloc = pcpu_need_to_extend(chunk))) {
			spin_unlock_irqrestore(&pcpu_lock, flags);
			if (pcpu_extend_area_map(chunk, new_alloc) < 0) {
				err = "failed to extend area map of reserved chunk";
				goto fail_unlock_mutex;
			}
			spin_lock_irqsave(&pcpu_lock, flags);
		}

		off = pcpu_alloc_area(chunk, size, align);
		if (off >= 0)
			goto area_found;

		err = "alloc from reserved chunk failed";
		goto fail_unlock;
	}

restart:
	/* search through normal chunks */
	// size: 16, pcpu_size_to_slot(16): 1, pcpu_nr_slots: 15
	// size: 16, pcpu_size_to_slot(16): 1, pcpu_nr_slots: 15
	for (slot = pcpu_size_to_slot(size); slot < pcpu_nr_slots; slot++) {

		// slot: 1~10
		// list_for_each_entry 의 &chunk->list != (&pcpu_slot[slot]) 조건에 의해
		// 수행 되지 않음

		list_for_each_entry(chunk, &pcpu_slot[slot], list) {
		// for (chunk = list_first_entry(&pcpu_slot[slot], typeof(*chunk), list);
		//      &chunk->list != (&pcpu_slot[slot]); chunk = list_next_entry(chunk, list))

			// chuck: &pcpu_slot[11]

			// size: 16, chunk->contig_hint: (&pcpu_slot[11])->contig_hint: 0x3000
			// size: 16, chunk->contig_hint: (&pcpu_slot[11])->contig_hint: 0x3000
			if (size > chunk->contig_hint)
				continue;

			// chuck: &pcpu_slot[11]: dchunk: 4K만큼 할당 받은 주소
			// chuck: &pcpu_slot[11]: dchunk: 4K만큼 할당 받은 주소
			new_alloc = pcpu_need_to_extend(chunk);
			// new_alloc: 0
			// new_alloc: 0

			if (new_alloc) {
				spin_unlock_irqrestore(&pcpu_lock, flags);
				if (pcpu_extend_area_map(chunk,
							 new_alloc) < 0) {
					err = "failed to extend area map";
					goto fail_unlock_mutex;
				}
				spin_lock_irqsave(&pcpu_lock, flags);
				/*
				 * pcpu_lock has been dropped, need to
				 * restart cpu_slot list walking.
				 */
				goto restart;
			}

			// chuck: &pcpu_slot[11]: dchunk: 4K만큼 할당 받은 주소, size: 16, align: 8
			// pcpu_alloc_area(&pcpu_slot[11], 16, 8): 0x1d00 + 0x2000
			// chuck: &pcpu_slot[11]: dchunk: 4K만큼 할당 받은 주소, size: 16, align: 8
			// pcpu_alloc_area(&pcpu_slot[11], 16, 8): 0x1d00 + 0x2000 + 16
			off = pcpu_alloc_area(chunk, size, align);
			// off: 0x1d00 + 0x2000
			// off: 0x1d00 + 0x2000 + 16

			// off: 0x1d00 + 0x2000
			// off: 0x1d00 + 0x2000 + 16
			if (off >= 0)
				goto area_found;
				// area_found 위치로 이동
				// area_found 위치로 이동
		}
	}

	/* hmmm... no space left, create a new chunk */
	spin_unlock_irqrestore(&pcpu_lock, flags);

	chunk = pcpu_create_chunk();
	if (!chunk) {
		err = "failed to allocate new chunk";
		goto fail_unlock_mutex;
	}

	spin_lock_irqsave(&pcpu_lock, flags);
	pcpu_chunk_relocate(chunk, -1);
	goto restart;

area_found:
	spin_unlock_irqrestore(&pcpu_lock, flags);
	// pcpu_lock의 spin unlock 을 수행하고 flags에 저장되어있던 cpsr 복원
	// pcpu_lock의 spin unlock 을 수행하고 flags에 저장되어있던 cpsr 복원

	/* populate, map and clear the area */
	// chuck: &pcpu_slot[11]: dchunk: 4K만큼 할당 받은 주소,
	// off: 0x1d00 + 0x2000, size: 16
	// pcpu_populate_chunk(&pcpu_slot[11], 0x3d00, 16): 0
	// chuck: &pcpu_slot[11]: dchunk: 4K만큼 할당 받은 주소,
	// off: 0x1d00 + 0x2000 + 16, size: 16
	// pcpu_populate_chunk(&pcpu_slot[11], 0x3d10, 16): 0
	if (pcpu_populate_chunk(chunk, off, size)) {
		spin_lock_irqsave(&pcpu_lock, flags);
		pcpu_free_area(chunk, off);
		err = "failed to populate";
		goto fail_unlock;
	}

	mutex_unlock(&pcpu_alloc_mutex);
	// pcpu_alloc_mutex의 mutex unlock을 수행
	// pcpu_alloc_mutex의 mutex unlock을 수행

	/* return address relative to base address */
	// chunk->base_addr: dchunk->base_addr: 128K 만큼 물리주소 0x5FFFFFFF 근처에 할당받은 주소
	// off: 0x3d00
	// __addr_to_pcpu_ptr(128K 만큼 물리주소 0x5FFFFFFF 근처에 할당받은 주소+0x3d00): 0xc0502d00
	// chunk->base_addr: dchunk->base_addr: 128K 만큼 물리주소 0x5FFFFFFF 근처에 할당받은 주소
	// off: 0x3d10
	// __addr_to_pcpu_ptr(128K 만큼 물리주소 0x5FFFFFFF 근처에 할당받은 주소+0x3d10): 0xc0502d00
	ptr = __addr_to_pcpu_ptr(chunk->base_addr + off);
	// ptr: 0xc0502d00
	// ptr: 0xc0502d10

	// ptr: 0xc0502d00, size: 16
	// ptr: 0xc0502d10, size: 16
	kmemleak_alloc_percpu(ptr, size); // null function

	// ptr: 0xc0502d00
	// ptr: 0xc0502d10
	return ptr;
	// return 0xc0502d00
	// return 0xc0502d10

fail_unlock:
	spin_unlock_irqrestore(&pcpu_lock, flags);
fail_unlock_mutex:
	mutex_unlock(&pcpu_alloc_mutex);
	if (warn_limit) {
		pr_warning("PERCPU: allocation failed, size=%zu align=%zu, "
			   "%s\n", size, align, err);
		dump_stack();
		if (!--warn_limit)
			pr_info("PERCPU: limit reached, disable warning\n");
	}
	return NULL;
}

percpu.c::__alloc_percpu()

// ARM10C 20140621 // __alloc_percpu(16, 8)

void __percpu *__alloc_percpu(size_t size, size_t align)
{
	// size: 16, align: 8
	return pcpu_alloc(size, align, false);
	// return 0xc0502d10

slub.c::alloc_kmem_cache_cpus()

static inline int alloc_kmem_cache_cpus(struct kmem_cache *s)
{
	BUILD_BUG_ON(PERCPU_DYNAMIC_EARLY_SIZE <
			KMALLOC_SHIFT_HIGH * sizeof(struct kmem_cache_cpu));
	// s->cpu_slab: (&boot_kmem_cache_node)->cpu_slab
	// sizeof(struct kmem_cache_cpu): 16 bytes, sizeof(void *): 8 bytes
	// __alloc_percpu(16, 8): 0xc0502d00
	// s->cpu_slab: (&boot_kmem_cache)->cpu_slab
	// sizeof(struct kmem_cache_cpu): 16 bytes, sizeof(void *): 8 bytes
	// __alloc_percpu(16, 8): 0xc0502d10
	s->cpu_slab = __alloc_percpu(sizeof(struct kmem_cache_cpu),
				     2 * sizeof(void *));
	// s->cpu_slab: (&boot_kmem_cache_node)->cpu_slab: 0xc0502d00
	// s->cpu_slab: (&boot_kmem_cache)->cpu_slab: 0xc0502d10

	// s->cpu_slab: (&boot_kmem_cache_node)->cpu_slab: 0xc0502d00
	// s->cpu_slab: (&boot_kmem_cache)->cpu_slab: 0xc0502d10
	if (!s->cpu_slab)
		return 0;

	// s: &boot_kmem_cache_node
	// s: &boot_kmem_cache
	init_kmem_cache_cpus(s);

slub.c::init_kmem_cache_cpus()

// ARM10C 20140621 // s: &boot_kmem_cache

static void init_kmem_cache_cpus(struct kmem_cache *s)
{
	int cpu;

	// nr_cpu_ids: 4, cpu_possible_mask: cpu_possible_bits[1]
	// cpumask_next((-1), cpu_possible_bits[1]): 0
	for_each_possible_cpu(cpu)
	// for ((cpu) = -1; (cpu) = cpumask_next((cpu), (cpu_possible_mask)), (cpu) < nr_cpu_ids; )
		// s->cpu_slab: (&boot_kmem_cache_node)->cpu_slab: 0xc0502d00, cpu: 0
		// per_cpu_ptr((&boot_kmem_cache_node)->cpu_slab, 0):
		// (&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의 pcpu_base_addr의 옵셋)
		// init_tid(0): 0
		// s->cpu_slab: (&boot_kmem_cache)->cpu_slab: 0xc0502d10, cpu: 0
		// per_cpu_ptr((&boot_kmem_cache)->cpu_slab, 0):
		// (&boot_kmem_cache)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의 pcpu_base_addr의 옵셋)
		// init_tid(0): 0
		per_cpu_ptr(s->cpu_slab, cpu)->tid = init_tid(cpu);
		// ((&boot_kmem_cache_node)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->tid: 0
		// ((&boot_kmem_cache)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->tid: 0

		// 할당받은 pcpu 들의 16 byte 공간에 각 cpu에 사용하는 kmem_cache_cpu의 tid 맵버를 설정
}

slub.c::alloc_kmem_cache_cpus()

static inline int alloc_kmem_cache_cpus(struct kmem_cache *s)
{
	BUILD_BUG_ON(PERCPU_DYNAMIC_EARLY_SIZE <
			KMALLOC_SHIFT_HIGH * sizeof(struct kmem_cache_cpu));
	// s->cpu_slab: (&boot_kmem_cache_node)->cpu_slab
	// sizeof(struct kmem_cache_cpu): 16 bytes, sizeof(void *): 8 bytes
	// __alloc_percpu(16, 8): 0xc0502d00
	// s->cpu_slab: (&boot_kmem_cache)->cpu_slab
	// sizeof(struct kmem_cache_cpu): 16 bytes, sizeof(void *): 8 bytes
	// __alloc_percpu(16, 8): 0xc0502d10
	s->cpu_slab = __alloc_percpu(sizeof(struct kmem_cache_cpu),
				     2 * sizeof(void *));
	// s->cpu_slab: (&boot_kmem_cache_node)->cpu_slab: 0xc0502d00
	// s->cpu_slab: (&boot_kmem_cache)->cpu_slab: 0xc0502d10

	// s->cpu_slab: (&boot_kmem_cache_node)->cpu_slab: 0xc0502d00
	// s->cpu_slab: (&boot_kmem_cache)->cpu_slab: 0xc0502d10
	if (!s->cpu_slab)
		return 0;

	// s: &boot_kmem_cache_node
	// s: &boot_kmem_cache
	init_kmem_cache_cpus(s);
	// 할당받은 pcpu 들의 16 byte 공간에 각 cpu에 사용하는 kmem_cache_cpu의 tid 맵버를 설정
	// 할당받은 pcpu 들의 16 byte 공간에 각 cpu에 사용하는 kmem_cache_cpu의 tid 맵버를 설정

	return 1;
	// return 1
	// return 1
}

kmem_cache_open 가 한일:

  • boot_kmem_cache_node.flags: SLAB_HWCACHE_ALIGN: 0x00002000UL
  • boot_kmem_cache_node.reserved: 0
  • boot_kmem_cache_node.min_partial: 5
  • boot_kmem_cache_node.cpu_partial: 30
  • migratetype이 MIGRATE_UNMOVABLE인 page 할당 받음
  • page 맴버를 셋팅함
  • page->slab_cache: &boot_kmem_cache_node 주소를 set
  • page->flags에 7 (PG_slab) bit를 set
  • page->freelist: UNMOVABLE인 page 의 object의 시작 virtual address + 64
  • page->inuse: 1, page->frozen: 0 page 맴버를 셋팅함
  • slab 의 objects 들의 freepointer를 맵핑함
  • 할당받은 slab object를 kmem_cache_node 로 사용하고 kmem_cache_node의 멤버 필드를 초기화함
  • kmem_cache_node->nr_partial: 1
  • kmem_cache_node->list_lock: spinlock 초기화 수행
  • kmem_cache_node->slabs: 1, kmem_cache_node->total_objects: 64 로 세팀함
  • kmem_cache_node->full: 리스트 초기화
  • kmem_cache_node의 partial 맴버에 현재 page의 lru 리스트를 추가함
  • kmem_cache_node 가 boot_kmem_cache_node.node[0]에 할당됨
  • 할당받은 pcpu 들의 16 byte 공간 (&boot_kmem_cache_node)->cpu_slab 에
  • 각 cpu에 사용하는 kmem_cache_cpu의 tid 맵버를 설정

slub.c::__kmem_cache_create()

// ARM10C 20140614 // s: &boot_kmem_cache, flags: SLAB_HWCACHE_ALIGN: 0x00002000UL

int __kmem_cache_create(struct kmem_cache *s, unsigned long flags)
{
	int err;

	// s: &boot_kmem_cache_node, flags: SLAB_HWCACHE_ALIGN: 0x00002000UL
	// kmem_cache_open(&boot_kmem_cache_node, 0x00002000UL): 0
	// s: &boot_kmem_cache, flags: SLAB_HWCACHE_ALIGN: 0x00002000UL
	// kmem_cache_open(&boot_kmem_cache, 0x00002000UL): 0
	err = kmem_cache_open(s, flags);
	// err: 0
	// err: 0

// 2014/06/21 종료

git log

From github.com:arm10c/linux-stable
   5ec2e72..e2b578f  master     -> origin/master
Updating 5ec2e72..e2b578f
Fast-forward
 arch/arm/include/asm/barrier.h          |  13 ++++-
 arch/arm/include/asm/bitops.h           |   9 ++--
 arch/arm/lib/bitops.h                   |   1 +
 arch/arm/lib/testsetbit.S               |   1 +
 include/asm-generic/bitops/lock.h       |   4 ++
 include/asm-generic/bitops/non-atomic.h |   1 +
 include/linux/bit_spinlock.h            |  23 +++++++--
 include/linux/compiler.h                |   2 +
 include/linux/gfp.h                     |   1 +
 include/linux/irqflags.h                |   1 +
 include/linux/kmemcheck.h               |   3 ++
 include/linux/kmemleak.h                |   4 ++
 include/linux/log2.h                    |   2 +
 include/linux/mm_types.h                |  14 ++++--
 include/linux/page-flags-layout.h       |   2 +-
 include/linux/page-flags.h              |  47 ++++++++++++++++++
 include/linux/preempt.h                 |   2 +
 include/linux/slab.h                    |   5 ++
 include/linux/slub_def.h                |   2 +
 include/trace/events/kmem.h             |   7 +++
 lib/string.c                            |   1 +
 mm/page_alloc.c                         |   1 +
 mm/percpu-vm.c                          |  22 +++++++++
 mm/percpu.c                             | 209 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
 mm/slub.c                               | 341 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
e2b578f..78add0d  master     -> origin/master
Updating e2b578f..78add0d
Fast-forward
 include/linux/mm_types.h    | 16 +++++++++++++++-
 include/linux/page-flags.h  |  6 +++++-
 include/linux/slab.h        |  2 ++
 include/trace/events/kmem.h |  3 +--
 mm/percpu-vm.c              |  4 ++--
 mm/percpu.c                 | 51 +++++++++++++++++++++++++++++----------------------
 mm/slub.c                   | 61 +++++++++++++++++++++++++++++++++++++++++++++++--------------