kernel_review/a10c_61.md at master · hephaex/kernel_review

ARM10C 61주차 후기

일시 : 2014.07.05 (61주차)

모임명 : NAVER개발자커뮤니티지원_10차ARM-C

장소 : 토즈 타워점

장소지원 : NAVER 개발자 커뮤니티 지원 프로그램

참여인원 : 5명

스터디 진도 :

  • mm_init()을 계속 분석합니다.
  • start_kernel()-> mm_init()->kmem_cache_init()->bootstrap()분석중
  • bootstrap()은 두번 실행됩니다.
  • 1번째는 &boot_kmem_cache 매개변수를 가지고
  • 2번째는 &boot_kmem_cache_node 매개변수를 가지고 실행합니다.

main.c::mm_init()

static void __init mm_init(void)
{
	page_cgroup_init_flatmem(); // null function
	mem_init();
	// bootmem으로 관리하던 메모리를 buddy로 이관.
	// 각 section 메모리 크기를 출력.
	
	// mm/Makefile 에서 CONFIG_SLUB 설정으로 slub.c 로 jump
	kmem_cache_init();

// mm/Makefile 에서 CONFIG_SLUB 설정으로 slub.c 로 jump

kmem_cache_init();

slub.c::kmem_cache_init()

void __init kmem_cache_init(void)
{
...
	kmem_cache = bootstrap(&boot_kmem_cache);

kmem_cache = bootstrap(&boot_kmem_cache);

slub.c::bootstrap()

// ARM10C 20140628 // struct kmem_cache * static_cache: &boot_kmem_cache

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

	// kmem_cache: &boot_kmem_cache, GFP_NOWAIT: 0
	// kmem_cache_zalloc(&boot_kmem_cache, GFP_NOWAIT: 0):
	// UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address
	// kmem_cache: &boot_kmem_cache_node, GFP_NOWAIT: 0
	// kmem_cache_zalloc(&boot_kmem_cache_node, GFP_NOWAIT: 0):
	// UNMOVABLE인 page (boot_kmem_cache_node)의 object의 시작 virtual address
	struct kmem_cache *s = kmem_cache_zalloc(kmem_cache, GFP_NOWAIT);
	// s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address

	// s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
	// static_cache: &boot_kmem_cache,
	// kmem_cache->object_size: boot_kmem_cache.object_size: 116
	memcpy(s, static_cache, kmem_cache->object_size);
	// boot_kmem_cache에 세팅된 멤버 필드 값을 전부 할당 받은 object로 복사함

// 2014/06/28 종료
// 2014/07/05 시작
    // s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
	// smp_processor_id(): 0
	__flush_cpu_slab(s, smp_processor_id());

// s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address, // smp_processor_id(): 0

__flush_cpu_slab(s, smp_processor_id());

slub.c::__flush_cpu_slab()

// *s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address, // cpu: smp_processor_id(): 0

static inline void __flush_cpu_slab(struct kmem_cache *s, int cpu)
{
	// s->cpu_slab: (&boot_kmem_cache 용 object 주소)->cpu_slab: 0xc0502d10, cpu: 0
	// per_cpu_ptr(0xc0502d10, 0):
	// (&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
	struct kmem_cache_cpu *c = per_cpu_ptr(s->cpu_slab, cpu);
	// c: (&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
	
	// c: (&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
	if (likely(c)) {
		// c->page: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->page:
		// UNMOVABLE인 page (boot_kmem_cache)
		if (c->page)
			// s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
			// c: (&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
			flush_slab(s, c);

// s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address, // c: (&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)

flush_slab(s, c);

slub.c::flush_slab()

// *s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address, // *c: (&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)

static inline void flush_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
{
	// s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
	// CPUSLAB_FLUSH: 13
	stat(s, CPUSLAB_FLUSH);

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

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

deactivate_slab(s, c->page, c->freelist);

slub.c::deactivate_slab()

// ARM10C 20140705 // s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address, // c->page: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->page: // UNMOVABLE인 page (boot_kmem_cache), // c->freelist: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->freelist: // UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128

static void deactivate_slab(struct kmem_cache *s, struct page *page,
				void *freelist)
{
	enum slab_modes { M_NONE, M_PARTIAL, M_FULL, M_FREE };
	// M_NONE: 0, M_PARTIAL: 1, M_FULL: 2, M_FREE:3

	struct kmem_cache_node *n = get_node(s, page_to_nid(page));
  • page_to_nid(page)
  • // get_node(UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address, 0):
  • // (&boot_kmem_cache 용 object 주소)->node[0]
// ARM10C 20140705
static inline int page_to_nid(const struct page *page)
{
	// NODES_PGSHIFT: 0, NODES_MASK: 3
	return (page->flags >> NODES_PGSHIFT) & NODES_MASK;
}

slub.c::deactivate_slab()

static void deactivate_slab(struct kmem_cache *s, struct page *page,
				void *freelist)
{
	enum slab_modes { M_NONE, M_PARTIAL, M_FULL, M_FREE };
	
    struct kmem_cache_node *n = get_node(s, page_to_nid(page));

// s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address, // page: UNMOVABLE인 page (boot_kmem_cache) // page_to_nid(UNMOVABLE인 page (boot_kmem_cache)): 0 // get_node(UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address, 0): // (&boot_kmem_cache 용 object 주소)->node[0]

struct kmem_cache_node *n = get_node(s, page_to_nid(page));

slub.c::get_node()

// ARM10C 20140705 // s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address, 0

static inline struct kmem_cache_node *get_node(struct kmem_cache *s, int node)
{
	// node: 0, s->node: (&boot_kmem_cache 용 object 주소)->node[0]
	return s->node[node];
	// return (&boot_kmem_cache 용 object 주소)->node[0]
}

get_node(s, page_to_nid(page)); // return (&boot_kmem_cache 용 object 주소)->node[0]

slub.c::deactivate_slab()

get_node(s, page_to_nid(page)); // return (&boot_kmem_cache 용 object 주소)->node[0]

static void deactivate_slab(struct kmem_cache *s, struct page *page,
				void *freelist)
{
...
    struct kmem_cache_node *n = get_node(s, page_to_nid(page));
	// n: (&boot_kmem_cache 용 object 주소)->node[0]

	int lock = 0;
	// lock: 0
	enum slab_modes l = M_NONE, m = M_NONE;
	// l: M_NONE: 0,  m: M_NONE: 0
	void *nextfree;
	int tail = DEACTIVATE_TO_HEAD;
	// tail: DEACTIVATE_TO_HEAD: 15
	struct page new;
	struct page old;

	// page->freelist: (UNMOVABLE인 page (boot_kmem_cache))->freelist: NULL
	if (page->freelist) {
		stat(s, DEACTIVATE_REMOTE_FREES);
		tail = DEACTIVATE_TO_TAIL;
	}
	// s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
	// freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128
	// get_freepointer(UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
	// UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128):
	// UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 256
	// nextfree: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 256
	while (freelist && (nextfree = get_freepointer(s, freelist))) {
		void *prior;
		unsigned long counters;

		// [loop 1] freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128
		// [loop 1] nextfree: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 256

		do {
			// [loop 1] page->freelist: NULL
			prior = page->freelist;
			// [loop 1] prior: NULL

			// [loop 1] page->counters: (UNMOVABLE인 page (boot_kmem_cache))->counters: 0x80200020
			counters = page->counters;
			// [loop 1] counters: 0x80200020

			// [loop 1] s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
			// [loop 1] freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128,
			// [loop 1] prior: NULL
			set_freepointer(s, freelist, prior);
			// [loop 1] freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128: NULL
			// [loop 1] UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128 의 다음 object를 가리키는 주소의 값을
			// [loop 1] NULL로 세팅

			// [loop 1] counters: 0x80200020
			new.counters = counters;
			// [loop 1] new.counters: 0x80200020

			// [loop 1] new.inuse: 32, new.counters: 0x80200020
			new.inuse--;
			// [loop 1] new.inuse: 31, new.counters: 0x8020001f

			// [loop 1] new.frozen: 1
			VM_BUG_ON(!new.frozen);

			// [loop 1] s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
			// [loop 1] page: UNMOVABLE인 page (boot_kmem_cache),
			// [loop 1] prior: NULL, counters: 0x80200020,
			// [loop 1] freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128,
			// [loop 1] new.counters: 0x8020001f,
			// [loop 1] "drain percpu freelist"
			// [loop 1] __cmpxchg_double_slab(UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
			// [loop 1] UNMOVABLE인 page (boot_kmem_cache), NULL, 0x80200020, UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128,
			// [loop 1] 0x8020001f, "drain percpu freelist"): 1
			// [loop 1] UNMOVABLE인 page (boot_kmem_cache)의 필드 맴버 값 변경
			// [loop 1] (UNMOVABLE인 page (boot_kmem_cache))->freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128
			// [loop 1] (UNMOVABLE인 page (boot_kmem_cache))->counters: 0x8020001f
		} while (!__cmpxchg_double_slab(s, page,
			prior, counters,
			freelist, new.counters,
			"drain percpu freelist"));

1번째 루프 // freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128 // get_freepointer(UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address, UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128): // UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 256 // nextfree: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 256

__cmpxchg_double_slab(s, page, prior, counters, freelist, new.counters, "drain percpu freelist"));

slub.c::__cmpxchg_double_slab()

// ARM10C 20140705 // s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address, // page: UNMOVABLE인 page (boot_kmem_cache), prior: NULL, counters: 0x80200020 // freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128 // new.counters: 0x8020001f, "drain percpu freelist"

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: UNMOVABLE인 page (boot_kmem_cache)
		slab_lock(page);
		// preempt count 증가 후 memory barrier 적용

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

			// page->counters: 0x80200020, counters_new: 0x8020001f
			page->counters = counters_new;
			// page->counters: 0x8020001f

			// page: UNMOVABLE인 page (boot_kmem_cache)
			slab_unlock(page);
			// (MIGRATE_UNMOVABLE인 page(boot_kmem_cache))->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::deactivate_slab()

1번째 루프 // freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128 // get_freepointer(UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address, UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128): // UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 256 // nextfree: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 256

// return 1

while (freelist && (nextfree = get_freepointer(s, freelist))) {

2번째 루프

static void deactivate_slab(struct kmem_cache *s, struct page *page,
				void *freelist)
{
...
	while (freelist && (nextfree = get_freepointer(s, freelist))) {
		void *prior;
		unsigned long counters;

		// [loop 2] freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 256
		// [loop 2] nextfree: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 384

		do {
			// [loop 2] page->freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128
			prior = page->freelist;
			// [loop 2] prior: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128

			// [loop 2] page->counters: (UNMOVABLE인 page (boot_kmem_cache))->counters: 0x8020001f
			counters = page->counters;
			// [loop 2] counters: 0x8020001f

			// [loop 2] s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
			// [loop 2] freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 256,
			// [loop 2] prior: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128
			set_freepointer(s, freelist, prior);
			// [loop 2] freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 256:
			// [loop 2] UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128,
			// [loop 2] UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 256 의 다음 object를 가리키는 주소의 값을
			// [loop 2] 이전 object 주소로 세팅

			// [loop 2] counters: 0x8020001f
			new.counters = counters;
			// [loop 2] new.counters: 0x8020001f

			// [loop 2] new.inuse: 31, new.counters: 0x8020001f
			new.inuse--;
			// [loop 2] new.inuse: 30, new.counters: 0x8020001e

			// [loop 2] new.frozen: 1
			VM_BUG_ON(!new.frozen);

			// [loop 2] s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
			// [loop 2] page: UNMOVABLE인 page (boot_kmem_cache),
			// [loop 2] prior: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128, counters: 0x8020001f,
			// [loop 2] freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 256,
			// [loop 2] new.counters: 0x8020001e,
			// [loop 2] "drain percpu freelist"
			// [loop 2] __cmpxchg_double_slab(UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
			// [loop 2] UNMOVABLE인 page (boot_kmem_cache), UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128,
			// [loop 2] 0x8020001f, UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 256, 0x8020001e, "drain percpu freelist"): 1
			// [loop 2] UNMOVABLE인 page (boot_kmem_cache)의 필드 맴버 값 변경
			// [loop 2] (UNMOVABLE인 page (boot_kmem_cache))->freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 256
			// [loop 2] (UNMOVABLE인 page (boot_kmem_cache))->counters: 0x8020001e
		} while (!__cmpxchg_double_slab(s, page,
			prior, counters,
			freelist, new.counters,
			"drain percpu freelist"));

while (!__cmpxchg_double_slab(s, page, prior, counters, freelist, new.counters, "drain percpu freelist"));

slub.c::__cmpxchg_double_slab()

deactivate_slab()에서 while문으로 2번째 루프 // s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address, // page: UNMOVABLE인 page (boot_kmem_cache), // old.freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968, // old.counters: 0x80200001, // new.freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968, // new.counters: 0x00200000, // "unfreezing 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: UNMOVABLE인 page (boot_kmem_cache)
		slab_lock(page);
		// preempt count 증가 후 memory barrier 적용

		// page: UNMOVABLE인 page (boot_kmem_cache)
		// page->freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968,
		// freelist_old: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968,
		// page->counters: 0x80200001, counters_old: 0x80200001
		if (page->freelist == freelist_old &&
					page->counters == counters_old) {
			// freelist_new: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968
			page->freelist = freelist_new;
			// page->freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968

			// page->counters: 0x80200001, counters_new: 0x00200000
			page->counters = counters_new;
			// page->counters: 0x00200000

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

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

retrun 1

slub.c::deactivate_slab()

  • while문에서는
    • 해당 object를 freelist의 위치를 이동한다.
  • do~while은 해당 object의 다음 위치를 가리키는 값을 null로 만들고,
  • 다른 속성도 초기화 한 후에,
  • __cmpxchg_double_slab()를 통해서 이것이 맞게 되었는지 확인되면 1을 반환하여
    • UNMOVABLE인 page (boot_kmem_cache) 의 사용하지 않는 첫 번째 object의 freepointer 값을 NULL 로 변경,
    • 나머지 object들의 freepointer 값을 이전 object들의 주소로 변경
    • UNMOVABLE인 page (boot_kmem_cache) 이 맴버필드 변경
    • (UNMOVABLE인 page (boot_kmem_cache))->freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968
    • (UNMOVABLE인 page (boot_kmem_cache))->counters: 0x80200001
  • [loop 3 ... 30] 번 반복 실행한다.
redo:

	// page->freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968
	old.freelist = page->freelist;
	// old.freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968

	// page->counters: (UNMOVABLE인 page (boot_kmem_cache))->counters: 0x80200001
	old.counters = page->counters;
	// old.counters: 0x80200001

	// old.frozen: 1
	VM_BUG_ON(!old.frozen);

	/* Determine target state of the slab */
	// old.counters: 0x80200001
	new.counters = old.counters;
	// new.counters: 0x80200001

	// freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968
	if (freelist) {
		// new.inuse: 1
		new.inuse--;
		// new.inuse: 0, new.counters: 0x80200000

		// s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
		// freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968
		// old.freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968
		set_freepointer(s, freelist, old.freelist);

// s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address, // freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968 // old.freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968

set_freepointer(s, freelist, old.freelist);

slub.c::set_freepointer()

// ARM10C 20140705 // s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address, // freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 128, // prior: NULL

static inline void set_freepointer(struct kmem_cache *s, void *object, void *fp)
{
	// object: UNMOVABLE인 page 의 virtual address
	// s->offset: (&boot_kmem_cache_node)->offset: 0
	// fp: UNMOVABLE인 page 의 virtual address
	*(void **)(object + s->offset) = fp;
	// object: UNMOVABLE인 page 의 virtual address(boot_kmem_cache)
}

slub.c::deactivate_slab()

static void deactivate_slab(struct kmem_cache *s, struct page *page,
				void *freelist)
{
...
redo:
...
	if (freelist) {
		// new.inuse: 1
		new.inuse--;
		// new.inuse: 0, new.counters: 0x80200000

		// s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
		// freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968
		// old.freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968
		set_freepointer(s, freelist, old.freelist);
		// UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968 의 다음 object를 가리키는 주소의 값을
		// UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968 로 세팅
		// freepointer의 주소를 자신의 object 주소로 변경

		// freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968
		new.freelist = freelist;
		// new.freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968
	} else
		new.freelist = old.freelist;

	// new.frozen: 1
	new.frozen = 0;
	// new.frozen: 0, new.counters: 0x00200000

	// n: (&boot_kmem_cache 용 object 주소)->node[0]:
	// boot_kmem_cache_node 로 할당 받은 2 번째 object의 주소

	// new.inuse: 0, n->nr_partial: 0, s->min_partial: (&boot_kmem_cache 용 object 주소)->min_partial: 5
	// new.freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968
	if (!new.inuse && n->nr_partial > s->min_partial)
		m = M_FREE;
	else if (new.freelist) {
		// m: M_NONE: 0
		m = M_PARTIAL;
		// m: M_PARTIAL: 1

		// lock: 0
		if (!lock) {
			// lock: 0
			lock = 1;
			// lock: 1
			/*
			 * Taking the spinlock removes the possiblity
			 * that acquire_slab() will see a slab page that
			 * is frozen
			 */
			spin_lock(&n->list_lock);
			// n->list_lock 을 이용한 spin_lock 획득
		}
	} else {
		m = M_FULL;
		if (kmem_cache_debug(s) && !lock) {
			lock = 1;
			/*
			 * This also ensures that the scanning of full
			 * slabs from diagnostic functions will not see
			 * any frozen slabs.
			 */
			spin_lock(&n->list_lock);
		}
	}

	// l: M_NONE: 0, m: M_PARTIAL: 1
	if (l != m) {

		// l: M_NONE: 0, m: M_PARTIAL: 1
		if (l == M_PARTIAL)

			remove_partial(n, page);

		else if (l == M_FULL)

			remove_full(s, page);

		if (m == M_PARTIAL) {

			// n: (&boot_kmem_cache 용 object 주소)->node[0]:
			// boot_kmem_cache_node 로 할당 받은 2 번째 object의 주소,
			// page: UNMOVABLE인 page (boot_kmem_cache),
			// tail: DEACTIVATE_TO_HEAD: 15
			add_partial(n, page, tail);

// n: (&boot_kmem_cache 용 object 주소)->node[0]: // boot_kmem_cache_node 로 할당 받은 2 번째 object의 주소, // page: UNMOVABLE인 page (boot_kmem_cache), // tail: DEACTIVATE_TO_HEAD: 15

add_partial(n, page, tail);

slub.c::add_partial()

// ARM10C 20140705 // n: (&boot_kmem_cache 용 object 주소)->node[0]: // boot_kmem_cache_node 로 할당 받은 2 번째 object의 주소, // page: UNMOVABLE인 page (boot_kmem_cache), // tail: DEACTIVATE_TO_HEAD: 15

static inline void add_partial(struct kmem_cache_node *n,
				struct page *page, int tail)
{
	// n: UNMOVABLE인 page 의 object의 시작 virtual address,

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

	// tail: DEACTIVATE_TO_HEAD: 15, DEACTIVATE_TO_TAIL: 16
	if (tail == DEACTIVATE_TO_TAIL)
		list_add_tail(&page->lru, &n->partial);
	else
		// page->lru: (UNMOVABLE인 page)->lru, n->partial: NULL
		list_add(&page->lru, &n->partial);
		// n->partial에 (UNMOVABLE인 page)->lru 가 추가됨
}

add_partial 한일:

n->nr_partial: 1 n->partial에 (UNMOVABLE인 page (boot_kmem_cache))->lru 가 추가됨

slub.c::deactivate_slab()

static void deactivate_slab(struct kmem_cache *s, struct page *page,
				void *freelist)
{
...
redo:
...
    // l: M_NONE: 0, m: M_PARTIAL: 1
	if (l != m) {

		// l: M_NONE: 0, m: M_PARTIAL: 1
		if (l == M_PARTIAL)

			remove_partial(n, page);

		else if (l == M_FULL)

			remove_full(s, page);

		if (m == M_PARTIAL) {

			// n: (&boot_kmem_cache 용 object 주소)->node[0]:
			// boot_kmem_cache_node 로 할당 받은 2 번째 object의 주소,
			// page: UNMOVABLE인 page (boot_kmem_cache),
			// tail: DEACTIVATE_TO_HEAD: 15
			add_partial(n, page, tail);
			// add_partial 한일:
			// n->nr_partial: 1
			// n->partial에 (UNMOVABLE인 page (boot_kmem_cache))->lru 가 추가됨

			// s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
			// tail: DEACTIVATE_TO_HEAD: 15
			stat(s, tail);

		} else if (m == M_FULL) {

			stat(s, DEACTIVATE_FULL);
			add_full(s, n, page);

		}
	}

	// l: M_NONE: 0, m: M_PARTIAL: 1
	l = m;
	// l: M_PARTIAL: 1

	// s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
	// page: UNMOVABLE인 page (boot_kmem_cache),
	// old.freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968
	// old.counters: 0x80200001
	// new.freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968
	// new.counters: 0x00200000
	// "unfreezing slab"
	// __cmpxchg_double_slab(UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
	// UNMOVABLE인 page (boot_kmem_cache), UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968,
	// 0x80200001, UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968,
	// 0x00200000, "unfreezing slab"): 1
	// UNMOVABLE인 page (boot_kmem_cache)의 필드 맴버 값 변경
	// (UNMOVABLE인 page (boot_kmem_cache))->freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968
	// (UNMOVABLE인 page (boot_kmem_cache))->counters: 0x00200000
	if (!__cmpxchg_double_slab(s, page,
				old.freelist, old.counters,
				new.freelist, new.counters,
				"unfreezing slab"))
		goto redo;

	// lock: 1
	if (lock)
		spin_unlock(&n->list_lock);
		// n->list_lock 을 이용한 spin_lock 해재

	// m: M_PARTIAL: 1
	if (m == M_FREE) {
		stat(s, DEACTIVATE_EMPTY);
		discard_slab(s, page);
		stat(s, FREE_SLAB);
	}
}

deactivate_slab에서 한일:

  • UNMOVABLE인 page (boot_kmem_cache)의 필드 맴버 값 변경

  • (UNMOVABLE인 page (boot_kmem_cache))->counters: 0x00200000

  • (UNMOVABLE인 page (boot_kmem_cache))->freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968

  • (UNMOVABLE인 page (boot_kmem_cache)) 의 object들의 freepointer 값 변경

  • (사용하지 않는 첫 번째 object의 freepointer 값을 NULL 로 변경, 나머지 object들의 freepointer 값을 이전 object들의 주소로 변경)

예시) s->offset이 0이고 slab object 시작 주소가 0x10001000 일 경우

------------------------------------------------------------------------------------------------------------------------------------------
| Slab object 0 (사용중)  | Slab object 1           | Slab object 2           | Slab object 3           | .... | Slab object 31          |
------------------------------------------------------------------------------------------------------------------------------------------
| object start address:   | object start address:   | object start address:   | object start address:   |      | object start address:   |
| 0x10001000              | 0x10001080              | 0x10001100              | 0x10001180              | .... | 0x10001f80              |
------------------------------------------------------------------------------------------------------------------------------------------
| freepointer | data      | freepointer | data      | freepointer | data      | freepointer | data      | .... | freepointer | data      |
------------------------------------------------------------------------------------------------------------------------------------------
| 0x10001080  | 124 Bytes | null        | 124 Bytes | 0x10001080  | 124 Bytes | 0x10001100  | 124 Bytes | .... | 0x10001f80  | 124 Bytes |
------------------------------------------------------------------------------------------------------------------------------------------
  • n: (&boot_kmem_cache 용 object 주소)->node[0]:
  • boot_kmem_cache_node 로 할당 받은 2 번째 object의 주소
  • n->nr_partial: 1
  • n->partial에 (UNMOVABLE인 page (boot_kmem_cache))->lru 가 추가됨

slub.c::flush_slab()

// deactivate_slab(s, c->page, c->freelist);

static inline void flush_slab(struct kmem_cache *s, struct kmem_cache_cpu *c)
{
	stat(s, CPUSLAB_FLUSH);

	deactivate_slab(s, c->page, c->freelist);
	
	// c->tid: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->tid: 4
	// next_tid(4): 8
	c->tid = next_tid(c->tid);
	// c->tid: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->tid: 8

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

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

flush_slab 이 한일:

  • UNMOVABLE인 page (boot_kmem_cache)의 필드 맴버 값 변경

  • (UNMOVABLE인 page (boot_kmem_cache))->counters: 0x00200000

  • (UNMOVABLE인 page (boot_kmem_cache))->freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968

  • (UNMOVABLE인 page (boot_kmem_cache)) 의 object들의 freepointer 값 변경

  • (사용하지 않는 첫 번째 object의 freepointer 값을 NULL 로 변경, 나머지 object들의 freepointer 값을 이전 object들의 주소로 변경)

에) s->offset이 0이고 slab object 시작 주소가 0x10001000 일 경우

| Slab object 0 (사용중)  | Slab object 1           | Slab object 2           | Slab object 3           | .... | Slab object 31          |
------------------------------------------------------------------------------------------------------------------------------------------
| object start address:   | object start address:   | object start address:   | object start address:   |      | object start address:   |
| 0x10001000              | 0x10001080              | 0x10001100              | 0x10001180              | .... | 0x10001f80              |
------------------------------------------------------------------------------------------------------------------------------------------
| freepointer | data      | freepointer | data      | freepointer | data      | freepointer | data      | .... | freepointer | data      |
------------------------------------------------------------------------------------------------------------------------------------------
| 0x10001080  | 124 Bytes | null        | 124 Bytes | 0x10001080  | 124 Bytes | 0x10001100  | 124 Bytes | .... | 0x10001f80  | 124 Bytes |
------------------------------------------------------------------------------------------------------------------------------------------
  • n: (&boot_kmem_cache 용 object 주소)->node[0]:
  • boot_kmem_cache_node 로 할당 받은 2 번째 object의 주소
  • n->nr_partial: 1
  • n->partial에 (UNMOVABLE인 page (boot_kmem_cache))->lru 가 추가됨
  • c: (&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
  • c->tid: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->tid: 8
  • c->page: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->page: NULL
  • c->freelist: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->freelist: NULL

slub.c::__flush_cpu_slab()

static inline void __flush_cpu_slab(struct kmem_cache *s, int cpu)
{
	struct kmem_cache_cpu *c = per_cpu_ptr(s->cpu_slab, cpu);

	if (likely(c)) {
		// c->page: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->page:
		// UNMOVABLE인 page (boot_kmem_cache)
		if (c->page)
			// s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
			// c: (&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
			flush_slab(s, c);

		// s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address,
		// c: (&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)
		unfreeze_partials(s, c);
	}
}

// s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address, // c: (&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)

unfreeze_partials(s, c);

slub.c::unfreeze_partials()

// ARM10C 20140705 // s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address, // c: (&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)

static void unfreeze_partials(struct kmem_cache *s,
		struct kmem_cache_cpu *c)
{
#ifdef CONFIG_SLUB_CPU_PARTIAL // CONFIG_SLUB_CPU_PARTIAL=y
	struct kmem_cache_node *n = NULL, *n2 = NULL;
	struct page *page, *discard_page = NULL;

	// c->partial: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->partial: NULL
	// page: NULL
	while ((page = c->partial)) {
		struct page new;
		struct page old;

		c->partial = page->next;

		n2 = get_node(s, page_to_nid(page));
		if (n != n2) {
			if (n)
				spin_unlock(&n->list_lock);

			n = n2;
			spin_lock(&n->list_lock);
		}

		do {

			old.freelist = page->freelist;
			old.counters = page->counters;
			VM_BUG_ON(!old.frozen);

			new.counters = old.counters;
			new.freelist = old.freelist;

			new.frozen = 0;

		} while (!__cmpxchg_double_slab(s, page,
				old.freelist, old.counters,
				new.freelist, new.counters,
				"unfreezing slab"));

		if (unlikely(!new.inuse && n->nr_partial > s->min_partial)) {
			page->next = discard_page;
			discard_page = page;
		} else {
			add_partial(n, page, DEACTIVATE_TO_TAIL);
			stat(s, FREE_ADD_PARTIAL);
		}
	}

	// n: NULL
	if (n)
		spin_unlock(&n->list_lock);
				
	// discard_page: NULL
	while (discard_page) {
		page = discard_page;
		discard_page = discard_page->next;

		stat(s, DEACTIVATE_EMPTY);
		discard_slab(s, page);
		stat(s, FREE_SLAB);
	}
#endif
}

동작을 보면 null function이다. c->partial 에 값이 있을때 이 함수는 실행된다. 따라서 slub.c::__flush_cpu_slab()를 끝내고 bootstrap()으로 이동한다.

__flush_cpu_slab()에서 한일

  • UNMOVABLE인 page (boot_kmem_cache)의 필드 맴버 값 변경

  • (UNMOVABLE인 page (boot_kmem_cache))->counters: 0x00200000

  • (UNMOVABLE인 page (boot_kmem_cache))->freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968

  • (UNMOVABLE인 page (boot_kmem_cache)) 의 object들의 freepointer 값 변경

  • (사용하지 않는 첫 번째 object의 freepointer 값을 NULL 로 변경, 나머지 object들의 freepointer 값을 이전 object들의 주소로 변경)

에) s->offset이 0이고 slab object 시작 주소가 0x10001000 일 경우

------------------------------------------------------------------------------------------------------------------------------------------
| Slab object 0 (사용중)  | Slab object 1           | Slab object 2           | Slab object 3           | .... | Slab object 31          |
------------------------------------------------------------------------------------------------------------------------------------------
| object start address:   | object start address:   | object start address:   | object start address:   |      | object start address:   |
| 0x10001000              | 0x10001080              | 0x10001100              | 0x10001180              | .... | 0x10001f80              |
------------------------------------------------------------------------------------------------------------------------------------------
| freepointer | data      | freepointer | data      | freepointer | data      | freepointer | data      | .... | freepointer | data      |
------------------------------------------------------------------------------------------------------------------------------------------
| 0x10001080  | 124 Bytes | null        | 124 Bytes | 0x10001080  | 124 Bytes | 0x10001100  | 124 Bytes | .... | 0x10001f80  | 124 Bytes |
------------------------------------------------------------------------------------------------------------------------------------------
  • n: (&boot_kmem_cache 용 object 주소)->node[0]:

  • boot_kmem_cache_node 로 할당 받은 page의 2 번째 object의 주소

  • n->nr_partial: 1

  • n->partial에 (UNMOVABLE인 page (boot_kmem_cache))->lru 가 추가됨

  • c: (&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)

  • c->tid: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->tid: 8

  • c->page: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->page: NULL

  • c->freelist: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->freelist: NULL

slub.c::bootstrap()

__flush_cpu_slab(s, smp_processor_id());

static struct kmem_cache * __init bootstrap(struct kmem_cache *static_cache)
{
	int node;
	struct kmem_cache *s = kmem_cache_zalloc(kmem_cache, GFP_NOWAIT);
	memcpy(s, static_cache, kmem_cache->object_size);
	__flush_cpu_slab(s, smp_processor_id());

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

		// s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address, node: 0
		// get_node(UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address, 0):
		// (&boot_kmem_cache 용 object 주소)->node[0]: boot_kmem_cache_node 로 할당 받은 2 번째 object의 주소
		struct kmem_cache_node *n = get_node(s, node);
		// n: boot_kmem_cache_node 로 할당 받은 page의 2 번째 object의 주소
		struct page *p;

		// n: boot_kmem_cache_node 로 할당 받은 page의 2 번째 object의 주소
		if (n) {
			list_for_each_entry(p, &n->partial, lru)
			// for (p = list_first_entry(&n->partial, typeof(*p), lru);
			//      &p->lru != (&n->partial); p = list_next_entry(p, lru))

				// p: UNMOVABLE인 page (boot_kmem_cache)

				// p->slab_cache: (UNMOVABLE인 page (boot_kmem_cache))->slab_cache
				// s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address
				p->slab_cache = s;
				// p->slab_cache: (UNMOVABLE인 page (boot_kmem_cache))->slab_cache:
				// UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address

#ifdef CONFIG_SLUB_DEBUG // CONFIG_SLUB_DEBUG=y
			list_for_each_entry(p, &n->full, lru)
			// for (p = list_first_entry(&n->full, typeof(*p), lru);
			//      &p->lru != (&n->full); p = list_next_entry(p, lru))

				p->slab_cache = s;
#endif
		}
	}

	// s: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address
	list_add(&s->list, &slab_caches);
	// slab_caches 의 list에 (UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address)->list를 등록

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

retrun

kmem_cache: UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address

bootstrab()이 한 일.

  • UNMOVABLE인 page (boot_kmem_cache)의 필드 맴버 값 변경

  • (UNMOVABLE인 page (boot_kmem_cache))->counters: 0x00200000

  • (UNMOVABLE인 page (boot_kmem_cache))->freelist: UNMOVABLE인 page (boot_kmem_cache)의 시작 virtual address + 3968

  • (UNMOVABLE인 page (boot_kmem_cache)) 의 object들의 freepointer 값 변경

  • (사용하지 않는 첫 번째 object의 freepointer 값을 NULL 로 변경, 나머지 object들의 freepointer 값을 이전 object들의 주소로 변경)

에) s->offset이 0이고 slab object 시작 주소가 0x10001000 일 경우

------------------------------------------------------------------------------------------------------------------------------------------
| Slab object 0 (사용중)  | Slab object 1           | Slab object 2           | Slab object 3           | .... | Slab object 31          |
------------------------------------------------------------------------------------------------------------------------------------------
| object start address:   | object start address:   | object start address:   | object start address:   |      | object start address:   |
| 0x10001000              | 0x10001080              | 0x10001100              | 0x10001180              | .... | 0x10001f80              |
------------------------------------------------------------------------------------------------------------------------------------------
| freepointer | data      | freepointer | data      | freepointer | data      | freepointer | data      | .... | freepointer | data      |
------------------------------------------------------------------------------------------------------------------------------------------
| 0x10001080  | 124 Bytes | null        | 124 Bytes | 0x10001080  | 124 Bytes | 0x10001100  | 124 Bytes | .... | 0x10001f80  | 124 Bytes |
------------------------------------------------------------------------------------------------------------------------------------------
  • n: (&boot_kmem_cache 용 object 주소)->node[0]:

  • boot_kmem_cache_node 로 할당 받은 page의 2 번째 object의 주소

  • n->nr_partial: 1

  • n->partial에 (UNMOVABLE인 page (boot_kmem_cache))->lru 가 추가됨

  • c: (&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋)

  • c->tid: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->tid: 8

  • c->page: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->page: NULL

  • c->freelist: ((&boot_kmem_cache 용 object 주소)->cpu_slab + (pcpu_unit_offsets[0] + __per_cpu_start에서의pcpu_base_addr의 옵셋))->freelist: NULL

  • p->slab_cache: (UNMOVABLE인 page (boot_kmem_cache))->slab_cache:

  • UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address

  • slab_caches 의 list에 (UNMOVABLE인 page (boot_kmem_cache)의 object의 시작 virtual address)->list를 등록

slub.c::kmem_cache_init()

kmem_cache = bootstrap(&boot_kmem_cache);

void __init kmem_cache_init(void)
{
...
	create_boot_cache(kmem_cache, "kmem_cache",
			offsetof(struct kmem_cache, node) +
				nr_node_ids * sizeof(struct kmem_cache_node *),
		       SLAB_HWCACHE_ALIGN);
	kmem_cache = bootstrap(&boot_kmem_cache);
	
	kmem_cache_node = bootstrap(&boot_kmem_cache_node);

// &boot_kmem_cache_node

kmem_cache_node = bootstrap(&boot_kmem_cache_node);

slub.c::bootstrap()

// ARM10C 20140705 // &boot_kmem_cache_node

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

	// kmem_cache: &boot_kmem_cache_node, GFP_NOWAIT: 0
	// kmem_cache_zalloc(&boot_kmem_cache_node, GFP_NOWAIT: 0):
	// UNMOVABLE인 page (boot_kmem_cache_node)의 object의 시작 virtual address
	struct kmem_cache *s = kmem_cache_zalloc(kmem_cache, GFP_NOWAIT);

// kmem_cache: &boot_kmem_cache_node, GFP_NOWAIT: 0 // kmem_cache_zalloc(&boot_kmem_cache_node, GFP_NOWAIT: 0): // UNMOVABLE인 page (boot_kmem_cache_node)의 object의 시작 virtual address

struct kmem_cache *s = kmem_cache_zalloc(kmem_cache, GFP_NOWAIT);

slub.c::kmem_cache_zalloc()

// ARM10C 20140705 // k: &boot_kmem_cache_node, flags: __GFP_ZERO: 0x8000u

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

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

void *ret = slab_alloc(s, gfpflags, RET_IP);

slub.c::slab_alloc()

// ARM10C 20140705 // s: &boot_kmem_cache_node, gfpflags: __GFP_ZERO: 0x8000, RET_IP

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

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

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

slub.c::slab_alloc_node()

// ARM10C 20140705 // s: &boot_kmem_cache_node, gfpflags: __GFP_ZERO: 0x8000, NUMA_NO_NODE: -1, RET_IP

static __always_inline void *slab_alloc_node(struct kmem_cache *s,
		gfp_t gfpflags, int node, unsigned long addr)
{
	void **object;
	struct kmem_cache_cpu *c;
	struct page *page;
	unsigned long tid;

	// s: &boot_kmem_cache_node, gfpflags: __GFP_ZERO: 0x8000
	// slab_pre_alloc_hook(&boot_kmem_cache_node, 0x8000): 0
	if (slab_pre_alloc_hook(s, gfpflags))
		return NULL;

if (slab_pre_alloc_hook(s, gfpflags))

slub.c::slab_pre_alloc_hook()

// ARM10C 20140705
// s: &boot_kmem_cache_node, gfpflags: __GFP_ZERO: 0x8000
static inline int slab_pre_alloc_hook(struct kmem_cache *s, gfp_t flags)
{
	// flags: __GFP_ZERO: 0x8000, gfp_allowed_mask: 0x1ffff2f
	flags &= gfp_allowed_mask;
	// flags: 0x8000

	// flags: 0x8000
	lockdep_trace_alloc(flags); // null function

	// flags: 0x8000, __GFP_WAIT: 0x10u
	might_sleep_if(flags & __GFP_WAIT);

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

// return 0

slub.c::slab_alloc_node()

if (slab_pre_alloc_hook(s, gfpflags))

static __always_inline void *slab_alloc_node(struct kmem_cache *s,
		gfp_t gfpflags, int node, unsigned long addr)
{
...
	if (slab_pre_alloc_hook(s, gfpflags))
	// slab_pre_alloc_hook(s, gfpfags): 0
		return NULL;

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

// s: &boot_kmem_cache_node, gfpflags: __GFP_ZERO: 0x8000 // memcg_kmem_get_cache(&boot_kmem_cache_node, 0x8000): &boot_kmem_cache_node

s = memcg_kmem_get_cache(s, gfpflags);

memcontrol.h::memcg_kmem_get_cache()

// ARM10C 20140705 // s: &boot_kmem_cache_node, gfpflags: __GFP_ZERO: 0x8000

static inline struct kmem_cache *
memcg_kmem_get_cache(struct kmem_cache *cachep, gfp_t gfp)
{
	// cachep: &boot_kmem_cache_node
	return cachep;
	// return &boot_kmem_cache_node
}

return &boot_kmem_cache_node

slub.c::slab_alloc_node()

s = memcg_kmem_get_cache(s, gfpflags);

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_ZERO: 0x8000
	// memcg_kmem_get_cache(&boot_kmem_cache_node, 0x8000): &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: 4
	tid = c->tid;
	// tid: 4

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

	// 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
	object = c->freelist;
	// object: UNMOVABLE인 page 의 object의 시작 virtual address + 128

	// 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

	// object: UNMOVABLE인 page 의 object의 시작 virtual address + 128
	// page: MIGRATE_UNMOVABLE인 page, node: -1, node_match(MIGRATE_UNMOVABLE인 page, -1): 1
	if (unlikely(!object || !node_match(page, node)))
		object = __slab_alloc(s, gfpflags, node, addr, c);
	else {
		// s: &boot_kmem_cache_node, object: UNMOVABLE인 page 의 object의 시작 virtual address + 128
		// get_freepointer_safe(&boot_kmem_cache_node, UNMOVABLE인 page 의 object의 시작 virtual address + 128):
		// UNMOVABLE인 page 의 object의 시작 virtual address + 192
		void *next_object = get_freepointer_safe(s, object);

// s: &boot_kmem_cache_node, object: UNMOVABLE인 page 의 object의 시작 virtual address + 128 // get_freepointer_safe(&boot_kmem_cache_node, UNMOVABLE인 page 의 object의 시작 virtual address + 128): // UNMOVABLE인 page 의 object의 시작 virtual address + 192

void *next_object = get_freepointer_safe(s, object);

slub.c::get_freepointer_safe()

// ARM10C 20140705
// s: &boot_kmem_cache_node, object: UNMOVABLE인 page 의 object의 시작 virtual address + 128
static inline void *get_freepointer_safe(struct kmem_cache *s, void *object)
{
	void *p;

#ifdef CONFIG_DEBUG_PAGEALLOC // CONFIG_DEBUG_PAGEALLOC=n
	probe_kernel_read(&p, (void **)(object + s->offset), sizeof(p));
#else
	// s: &boot_kmem_cache_node, object: UNMOVABLE인 page 의 object의 시작 virtual address + 128
	// get_freepointer(&boot_kmem_cache_node, UNMOVABLE인 page 의 object의 시작 virtual address + 128):
	// UNMOVABLE인 page 의 object의 시작 virtual address + 192
	p = get_freepointer(s, object);

// s: &boot_kmem_cache_node, object: UNMOVABLE인 page 의 object의 시작 virtual address + 128 // get_freepointer(&boot_kmem_cache_node, UNMOVABLE인 page 의 object의 시작 virtual address + 128): // UNMOVABLE인 page 의 object의 시작 virtual address + 192

p = get_freepointer(s, object);

slub.c::get_freepointer()

// ARM10C 20140705 // s: &boot_kmem_cache_node, object: UNMOVABLE인 page 의 object의 시작 virtual address + 128

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
}

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

slub.c::get_freepointer_safe()

static inline void *get_freepointer_safe(struct kmem_cache *s, void *object)
{
	void *p;

#ifdef CONFIG_DEBUG_PAGEALLOC // CONFIG_DEBUG_PAGEALLOC=n
	probe_kernel_read(&p, (void **)(object + s->offset), sizeof(p));
#else
	// s: &boot_kmem_cache_node, object: UNMOVABLE인 page 의 object의 시작 virtual address + 128
	// get_freepointer(&boot_kmem_cache_node, UNMOVABLE인 page 의 object의 시작 virtual address + 128):
	// UNMOVABLE인 page 의 object의 시작 virtual address + 192
	p = get_freepointer(s, object);
	// p: UNMOVABLE인 page 의 object의 시작 virtual address + 192
#endif
	// p: UNMOVABLE인 page 의 object의 시작 virtual address + 192
	return p;
	// return UNMOVABLE인 page 의 object의 시작 virtual address + 192
}

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

slub.c::slab_alloc_node()

static __always_inline void *slab_alloc_node(struct kmem_cache *s,
		gfp_t gfpflags, int node, unsigned long addr)
{
...
redo:
...
	if (unlikely(!object || !node_match(page, node)))
		object = __slab_alloc(s, gfpflags, node, addr, c);
	else {
		// s: &boot_kmem_cache_node, object: UNMOVABLE인 page 의 object의 시작 virtual address + 128
		// get_freepointer_safe(&boot_kmem_cache_node, UNMOVABLE인 page 의 object의 시작 virtual address + 128):
		// UNMOVABLE인 page 의 object의 시작 virtual address + 192
		void *next_object = get_freepointer_safe(s, object);
		// next_object: UNMOVABLE인 page 의 object의 시작 virtual address + 192

		/*
		 * The cmpxchg will only match if there was no additional
		 * operation and if we are on the right processor.
		 *
		 * The cmpxchg does the following atomically (without lock
		 * semantics!)
		 * 1. Relocate first pointer to the current per cpu area.
		 * 2. Verify that tid and freelist have not been changed
		 * 3. If they were not changed replace tid and freelist
		 *
		 * Since this is without lock semantics the protection is only
		 * against code executing on this cpu *not* from access by
		 * other cpus.
		 */

// 2014/07/05 종료

스터디 로그

133cada..6d65c2e  master     -> origin/master
Updating 133cada..6d65c2e
Fast-forward
include/linux/fault-inject.h |   1 +
include/linux/kernel.h       |   1 +
include/linux/list.h         |   6 +
include/linux/lockdep.h      |   1 +
include/linux/memcontrol.h   |   4 +
include/linux/mm.h           |   1 +
include/linux/nodemask.h     |   1 +
include/linux/percpu.h       |  91 ++++++++
include/linux/slab.h         |   5 +
include/linux/slub_def.h     |   1 +
include/linux/smp.h          |   1 +
include/linux/spinlock.h     |   1 +
mm/slab.h                    |   1 +
mm/slab_common.c             |   7 +-
mm/slub.c                    | 534 ++++++++++++++++++++++++++++++++++++++++++-
15 files changed, 641 insertions(+), 15 deletions(-)
12edc2f..03f2c9d  master     -> origin/master
Updating 12edc2f..03f2c9d
Fast-forward
 include/linux/percpu-defs.h |   3 +-
 include/linux/percpu.h      |  26 +++++++-
 mm/slub.c                   | 144 ++++++++++++++++++++++++++------------------
 3 files changed, 109 insertions(+), 64 deletions(-)