ARM10C 61주차 후기
일시 : 2014.07.05 (61주차)
모임명 : NAVER개발자커뮤니티지원_IAMROOT.ORG_10차ARM-C
장소 : 토즈 타워점
장소지원 : NAVER 개발자 커뮤니티 지원 프로그램
참여인원 : 5명
스터디 진도 :
- mm_init()을 계속 분석합니다.
- start_kernel()-> mm_init()->kmem_cache_init()->bootstrap()분석중
- bootstrap()은 두번 실행됩니다.
- 1번째는 &boot_kmem_cache 매개변수를 가지고
- 2번째는 &boot_kmem_cache_node 매개변수를 가지고 실행합니다.
main.c::mm_init()
static void __init mm_init(void)
{
page_cgroup_init_flatmem(); // null function
mem_init();
// bootmem으로 관리하던 메모리를 buddy로 이관.
// 각 section 메모리 크기를 출력.
// mm/Makefile 에서 CONFIG_SLUB 설정으로 slub.c 로 jump
kmem_cache_init();
// mm/Makefile 에서 CONFIG_SLUB 설정으로 slub.c 로 jump
kmem_cache_init();
slub.c::kmem_cache_init()
void __init kmem_cache_init(void)
{
...
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
// 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
// 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
// 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의 옵셋)
// 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의 옵셋)
// 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
// 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
// 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]
// 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
// 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
// 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”
// 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
// 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”
// 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
// 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
// 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
// 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
// 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 가 추가됨
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의 옵셋)
// 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의 옵셋)
// 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()으로 이동한다.
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
// &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
// 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
// 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
// slab_alloc(&boot_kmem_cache_node, GFP_ZERO: 0x8000): UNMOVABLE인 page (boot_kmem_cache_node)의 object의 시작 virtual address
void *ret = slaballoc(s, gfpflags, _RET_IP);
slub.c::slab_alloc()
// ARM10C 20140705
// s: &bootkmem_cache_node, gfpflags: __GFP_ZERO: 0x8000, _RET_IP
// s: &bootkmem_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: &bootkmem_cache_node, gfpflags: __GFP_ZERO: 0x8000, NUMA_NO_NODE: -1, _RET_IP
// slaballoc_node(&boot_kmem_cache_node, __GFP_ZERO: 0x8000, -1, _RET_IP):
// UNMOVABLE인 page (boot_kmem_cache_node)의 object의 시작 virtual address
// slaballoc_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: &bootkmem_cache_node, gfpflags: __GFP_ZERO: 0x8000, NUMA_NO_NODE: -1, _RET_IP
// s: &bootkmem_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
// 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
// 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
// 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
// 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
// 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
// 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
// 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(-)
댓글 없음:
댓글 쓰기