ARM10C 56주차 후기
일시 : 2014.05.31 (56주차)
모임명 : NAVER개발자커뮤니티지원_IAMROOT.ORG_10차ARM-C
장소 : 토즈 타워점
장소지원 : NAVER 개발자 커뮤니티 지원 프로그램
참여인원 : 4명
스터디 진도 :
- 지난 스터디에 이어서 mem_init()을 계속 분석합니다.
- start_kernel()-> mm_init()->kmem_cache_init()->create_boot_cache() 분석중
slub.c::kmem_cache_init()
// ARM10C 20140419
// &boot_kmem_cache_node, “kmem_cache_node”, sizeof(struct kmem_cache_node): 44 byte,
// SLAB_HWCACHE_ALIGN: 0x00002000UL
create_boot_cache(kmem_cache_node, "kmem_cache_node", \
sizeof(struct kmem_cache_node), SLAB_HWCACHE_ALIGN);
// &boot_kmem_cache_node, “kmem_cache_node”, sizeof(struct kmem_cache_node): 44 byte,
// SLAB_HWCACHE_ALIGN: 0x00002000UL
create_boot_cache(kmem_cache_node, "kmem_cache_node", \
sizeof(struct kmem_cache_node), SLAB_HWCACHE_ALIGN);
slab_common.c::create_boot_cache()
// ARM10C 20140419
// &boot_kmem_cache_node, “kmem_cache_node”, sizeof(struct kmem_cache_node): 44 byte,
// SLAB_HWCACHE_ALIGN: 0x00002000UL
void __init create_boot_cache(struct kmem_cache *s, const char *name, size_t size,
unsigned long flags)
{
int err;
// s->name: boot_kmem_cache_node.name: NULL
s->name = name;
// s->name: boot_kmem_cache_node.name: "kmem_cache_node"
// s->size: boot_kmem_cache_node.size: 0
// s->object_size: boot_kmem_cache_node.object_size: 0
s->size = s->object_size = size;
// s->size: boot_kmem_cache_node.size: 44
// s->object_size: boot_kmem_cache_node.object_size: 44
// flags: SLAB_HWCACHE_ALIGN: 0x00002000UL, ARCH_KMALLOC_MINALIGN: 64, size: 44
// s->align: boot_kmem_cache_node.align: 0
s->align = calculate_alignment(flags, ARCH_KMALLOC_MINALIGN, size);
// s->align: boot_kmem_cache_node.align: 64
// s: &boot_kmem_cache_node, flags: SLAB_HWCACHE_ALIGN: 0x00002000UL
err = __kmem_cache_create(s, flags);
// &boot_kmem_cache_node, “kmem_cache_node”, sizeof(struct kmem_cache_node): 44 byte,
// SLAB_HWCACHE_ALIGN: 0x00002000UL
void __init create_boot_cache(struct kmem_cache *s, const char *name, size_t size,
unsigned long flags)
{
int err;
// s->name: boot_kmem_cache_node.name: NULL
s->name = name;
// s->name: boot_kmem_cache_node.name: "kmem_cache_node"
// s->size: boot_kmem_cache_node.size: 0
// s->object_size: boot_kmem_cache_node.object_size: 0
s->size = s->object_size = size;
// s->size: boot_kmem_cache_node.size: 44
// s->object_size: boot_kmem_cache_node.object_size: 44
// flags: SLAB_HWCACHE_ALIGN: 0x00002000UL, ARCH_KMALLOC_MINALIGN: 64, size: 44
// s->align: boot_kmem_cache_node.align: 0
s->align = calculate_alignment(flags, ARCH_KMALLOC_MINALIGN, size);
// s->align: boot_kmem_cache_node.align: 64
// s: &boot_kmem_cache_node, flags: SLAB_HWCACHE_ALIGN: 0x00002000UL
err = __kmem_cache_create(s, flags);
slub.c::__kmem_cache_create()
// ARM10C 20140419
// s: &boot_kmem_cache_node,
// flags: SLAB_HWCACHE_ALIGN: 0x00002000UL
int __kmem_cache_create(struct kmem_cache *s, unsigned long flags)
{
int err;
// s: &boot_kmem_cache_node, flags: SLAB_HWCACHE_ALIGN: 0x00002000UL
err = kmem_cache_open(s, flags);
// s: &boot_kmem_cache_node,
// flags: SLAB_HWCACHE_ALIGN: 0x00002000UL
int __kmem_cache_create(struct kmem_cache *s, unsigned long flags)
{
int err;
// s: &boot_kmem_cache_node, flags: SLAB_HWCACHE_ALIGN: 0x00002000UL
err = kmem_cache_open(s, flags);
slub.c::kmem_cache_open()
// ARM10C 20140419
// s: &boot_kmem_cache_node,
// flags: SLAB_HWCACHE_ALIGN: 0x00002000UL
static int kmem_cache_open(struct kmem_cache *s, unsigned long flags)
{
// s->size: boot_kmem_cache_node.size: 44, flags: SLAB_HWCACHE_ALIGN: 0x00002000UL,
// s->name: boot_kmem_cache_node.name: "kmem_cache_node, s->ctor: boot_kmem_cache_node.ctor: NULL
s->flags = kmem_cache_flags(s->size, flags, s->name, s->ctor);
// s->flags: boot_kmem_cache_node.flags: SLAB_HWCACHE_ALIGN: 0x00002000UL
// s->reserved: boot_kmem_cache_node.reserved: 0
s->reserved = 0;
// s->reserved: boot_kmem_cache_node.reserved: 0
// need_reserve_slab_rcu: 0 , s->flags: boot_kmem_cache_node.flags: SLAB_HWCACHE_ALIGN
if (need_reserve_slab_rcu && (s->flags & SLAB_DESTROY_BY_RCU))
s->reserved = sizeof(struct rcu_head);
// s: &boot_kmem_cache_node, -1, calculate_sizes(&boot_kmem_cache_node, -1): 1
if (!calculate_sizes(s, -1))
goto error;
// disable_higher_order_debug: 0
if (disable_higher_order_debug) {
/*
* Disable debugging flags that store metadata if the min slab
* order increased.
*/
if (get_order(s->size) > get_order(s->object_size)) {
s->flags &= ~DEBUG_METADATA_FLAGS;
s->offset = 0;
if (!calculate_sizes(s, -1))
goto error;
}
}
// CONFIG_HAVE_CMPXCHG_DOUBLE=n, CONFIG_HAVE_ALIGNED_STRUCT_PAGE=n
#if defined(CONFIG_HAVE_CMPXCHG_DOUBLE) && \
defined(CONFIG_HAVE_ALIGNED_STRUCT_PAGE)
if (system_has_cmpxchg_double() && (s->flags & SLAB_DEBUG_FLAGS) == 0)
/* Enable fast mode */
s->flags |= __CMPXCHG_DOUBLE;
#endif
/*
* The larger the object size is, the more pages we want on the partial
* list to avoid pounding the page allocator excessively.
*/
// s->size: boot_kmem_cache_node.size: 64, ilog2(64): 6
// s: &boot_kmem_cache_node, 3
set_min_partial(s, ilog2(s->size) / 2);
// boot_kmem_cache_node.min_partial: 5
/*
* cpu_partial determined the maximum number of objects kept in the
* per cpu partial lists of a processor.
*
* Per cpu partial lists mainly contain slabs that just have one
* object freed. If they are used for allocation then they can be
* filled up again with minimal effort. The slab will never hit the
* per node partial lists and therefore no locking will be required.
*
* This setting also determines
*
* A) The number of objects from per cpu partial slabs dumped to the
* per node list when we reach the limit.
* B) The number of objects in cpu partial slabs to extract from the
* per node list when we run out of per cpu objects. We only fetch
* 50% to keep some capacity around for frees.
*/
// s: &boot_kmem_cache_node, kmem_cache_has_cpu_partial(&boot_kmem_cache_node): 1
// s->size: boot_kmem_cache_node.size: 64, PAGE_SIZE: 0x1000
if (!kmem_cache_has_cpu_partial(s))
s->cpu_partial = 0;
else if (s->size >= PAGE_SIZE)
s->cpu_partial = 2;
else if (s->size >= 1024)
s->cpu_partial = 6;
else if (s->size >= 256)
s->cpu_partial = 13;
else
// s->cpu_partial: boot_kmem_cache_node.cpu_partial: 0
s->cpu_partial = 30;
// boot_kmem_cache_node.cpu_partial: 30
#ifdef CONFIG_NUMA // CONFIG_NUMA=n
s->remote_node_defrag_ratio = 1000;
#endif
// s: &boot_kmem_cache_node, init_kmem_cache_nodes(&boot_kmem_cache_node): 1
if (!init_kmem_cache_nodes(s))
goto error;
// s: &boot_kmem_cache_node,
// flags: SLAB_HWCACHE_ALIGN: 0x00002000UL
static int kmem_cache_open(struct kmem_cache *s, unsigned long flags)
{
// s->size: boot_kmem_cache_node.size: 44, flags: SLAB_HWCACHE_ALIGN: 0x00002000UL,
// s->name: boot_kmem_cache_node.name: "kmem_cache_node, s->ctor: boot_kmem_cache_node.ctor: NULL
s->flags = kmem_cache_flags(s->size, flags, s->name, s->ctor);
// s->flags: boot_kmem_cache_node.flags: SLAB_HWCACHE_ALIGN: 0x00002000UL
// s->reserved: boot_kmem_cache_node.reserved: 0
s->reserved = 0;
// s->reserved: boot_kmem_cache_node.reserved: 0
// need_reserve_slab_rcu: 0 , s->flags: boot_kmem_cache_node.flags: SLAB_HWCACHE_ALIGN
if (need_reserve_slab_rcu && (s->flags & SLAB_DESTROY_BY_RCU))
s->reserved = sizeof(struct rcu_head);
// s: &boot_kmem_cache_node, -1, calculate_sizes(&boot_kmem_cache_node, -1): 1
if (!calculate_sizes(s, -1))
goto error;
// disable_higher_order_debug: 0
if (disable_higher_order_debug) {
/*
* Disable debugging flags that store metadata if the min slab
* order increased.
*/
if (get_order(s->size) > get_order(s->object_size)) {
s->flags &= ~DEBUG_METADATA_FLAGS;
s->offset = 0;
if (!calculate_sizes(s, -1))
goto error;
}
}
// CONFIG_HAVE_CMPXCHG_DOUBLE=n, CONFIG_HAVE_ALIGNED_STRUCT_PAGE=n
#if defined(CONFIG_HAVE_CMPXCHG_DOUBLE) && \
defined(CONFIG_HAVE_ALIGNED_STRUCT_PAGE)
if (system_has_cmpxchg_double() && (s->flags & SLAB_DEBUG_FLAGS) == 0)
/* Enable fast mode */
s->flags |= __CMPXCHG_DOUBLE;
#endif
/*
* The larger the object size is, the more pages we want on the partial
* list to avoid pounding the page allocator excessively.
*/
// s->size: boot_kmem_cache_node.size: 64, ilog2(64): 6
// s: &boot_kmem_cache_node, 3
set_min_partial(s, ilog2(s->size) / 2);
// boot_kmem_cache_node.min_partial: 5
/*
* cpu_partial determined the maximum number of objects kept in the
* per cpu partial lists of a processor.
*
* Per cpu partial lists mainly contain slabs that just have one
* object freed. If they are used for allocation then they can be
* filled up again with minimal effort. The slab will never hit the
* per node partial lists and therefore no locking will be required.
*
* This setting also determines
*
* A) The number of objects from per cpu partial slabs dumped to the
* per node list when we reach the limit.
* B) The number of objects in cpu partial slabs to extract from the
* per node list when we run out of per cpu objects. We only fetch
* 50% to keep some capacity around for frees.
*/
// s: &boot_kmem_cache_node, kmem_cache_has_cpu_partial(&boot_kmem_cache_node): 1
// s->size: boot_kmem_cache_node.size: 64, PAGE_SIZE: 0x1000
if (!kmem_cache_has_cpu_partial(s))
s->cpu_partial = 0;
else if (s->size >= PAGE_SIZE)
s->cpu_partial = 2;
else if (s->size >= 1024)
s->cpu_partial = 6;
else if (s->size >= 256)
s->cpu_partial = 13;
else
// s->cpu_partial: boot_kmem_cache_node.cpu_partial: 0
s->cpu_partial = 30;
// boot_kmem_cache_node.cpu_partial: 30
#ifdef CONFIG_NUMA // CONFIG_NUMA=n
s->remote_node_defrag_ratio = 1000;
#endif
// s: &boot_kmem_cache_node, init_kmem_cache_nodes(&boot_kmem_cache_node): 1
if (!init_kmem_cache_nodes(s))
goto error;
slub.c::init_kmem_cache_nodes()
// s: &boot_kmem_cache_node,
// return: init_kmem_cache_nodes(&boot_kmem_cache_node): 1
static int init_kmem_cache_nodes(struct kmem_cache *s)
{
int node;
// N_NORMAL_MEMORY: 2
for_each_node_state(node, N_NORMAL_MEMORY) {
// for ( (node) = 0; (node) == 0; (node) = 1)
struct kmem_cache_node *n;
// slab_state: DOWN: 1
if (slab_state == DOWN) {
// node: 0
early_kmem_cache_node_alloc(node);
continue;
}
// return: init_kmem_cache_nodes(&boot_kmem_cache_node): 1
static int init_kmem_cache_nodes(struct kmem_cache *s)
{
int node;
// N_NORMAL_MEMORY: 2
for_each_node_state(node, N_NORMAL_MEMORY) {
// for ( (node) = 0; (node) == 0; (node) = 1)
struct kmem_cache_node *n;
// slab_state: DOWN: 1
if (slab_state == DOWN) {
// node: 0
early_kmem_cache_node_alloc(node);
continue;
}
slub.c::early_kmem_cache_node_alloc()
// ARM10C 20140426
// node: 0
static void early_kmem_cache_node_alloc(int node)
{
struct page *page;
struct kmem_cache_node *n;
// kmem_cache_node->size: boot_kmem_cache_node.size: 64, sizeof(struct kmem_cache_node): 44 bytes
BUG_ON(kmem_cache_node->size < sizeof(struct kmem_cache_node));
// kmem_cache_node: &boot_kmem_cache_node, GFP_NOWAIT: 0, node: 0
page = new_slab(kmem_cache_node, GFP_NOWAIT, node);
// node: 0
static void early_kmem_cache_node_alloc(int node)
{
struct page *page;
struct kmem_cache_node *n;
// kmem_cache_node->size: boot_kmem_cache_node.size: 64, sizeof(struct kmem_cache_node): 44 bytes
BUG_ON(kmem_cache_node->size < sizeof(struct kmem_cache_node));
// kmem_cache_node: &boot_kmem_cache_node, GFP_NOWAIT: 0, node: 0
page = new_slab(kmem_cache_node, GFP_NOWAIT, node);
slub.c::new_slab()
// ARM10C 20140426
// kmem_cache_node: &boot_kmem_cache_node, GFP_NOWAIT: 0, node: 0
static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)
{
struct page *page;
void *start;
void *last;
void *p;
int order;
// flags: GFP_NOWAIT: 0, GFP_SLAB_BUG_MASK: 0xfe000005
BUG_ON(flags & GFP_SLAB_BUG_MASK);
// s: &boot_kmem_cache_node, flags: GFP_NOWAIT: 0, node: 0
// GFP_RECLAIM_MASK: 0x13ef0, GFP_CONSTRAINT_MASK: 0x60000
page = allocate_slab(s,
flags & (GFP_RECLAIM_MASK | GFP_CONSTRAINT_MASK), node);
// page: migratetype이 MIGRATE_UNMOVABLE인 page
if (!page)
goto out;
// page: migratetype이 MIGRATE_UNMOVABLE인 page
// compound_order(page): 0
order = compound_order(page);
// free_pages_check에서 page->flags의 NR_PAGEFLAGS 만큼의 하위 비트를 전부 지워줌
// order: 0
// kmem_cache_node: &boot_kmem_cache_node, GFP_NOWAIT: 0, node: 0
static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)
{
struct page *page;
void *start;
void *last;
void *p;
int order;
// flags: GFP_NOWAIT: 0, GFP_SLAB_BUG_MASK: 0xfe000005
BUG_ON(flags & GFP_SLAB_BUG_MASK);
// s: &boot_kmem_cache_node, flags: GFP_NOWAIT: 0, node: 0
// GFP_RECLAIM_MASK: 0x13ef0, GFP_CONSTRAINT_MASK: 0x60000
page = allocate_slab(s,
flags & (GFP_RECLAIM_MASK | GFP_CONSTRAINT_MASK), node);
// page: migratetype이 MIGRATE_UNMOVABLE인 page
if (!page)
goto out;
// page: migratetype이 MIGRATE_UNMOVABLE인 page
// compound_order(page): 0
order = compound_order(page);
// free_pages_check에서 page->flags의 NR_PAGEFLAGS 만큼의 하위 비트를 전부 지워줌
// order: 0
mm.h::compound_order()
// ARM10C 20140524
// page: migratetype이 MIGRATE_UNMOVABLE인 page
static inline int compound_order(struct page *page)
{
// PageHead(page): 0
if (!PageHead(page))
return 0;
return (unsigned long)page[1].lru.prev;
}
order = compound_order(page);
// order: 0
// free_pages_check에서 page->flags의 NR_PAGEFLAGS 만큼의 하위 비트를 전부 지워줌
- compound가 접착이라는 의미이므로 page가 붙여서 할당 받았는지 여부를 나타내는 것으로 추정된다.
- 우리는 작은 것을 받았으므로 0일것이다. 하지만 의미는 분명하게 확인해 보자.
- free_pages_check에서 버디를 활성화하기 전에 모두 0으로 초기화 하고 왔다
- page->flags의 NR_PAGEFLAGS 만큼의 하위 비트를 전부 지워줌.
// page: migratetype이 MIGRATE_UNMOVABLE인 page
static inline int compound_order(struct page *page)
{
// PageHead(page): 0
if (!PageHead(page))
return 0;
return (unsigned long)page[1].lru.prev;
}
// order: 0
// free_pages_check에서 page->flags의 NR_PAGEFLAGS 만큼의 하위 비트를 전부 지워줌
slub.c::new_slab()
// 2014/05/31 시작
// s: &boot_kmem_cache_node, page: migratetype이 MIGRATE_UNMOVABLE인 page
// page_to_nid(migratetype이 MIGRATE_UNMOVABLE인 page): 0, page->objects: 64
inc_slabs_node(s, page_to_nid(page), page->objects);
// s: &boot_kmem_cache_node, page: migratetype이 MIGRATE_UNMOVABLE인 page
// page_to_nid(migratetype이 MIGRATE_UNMOVABLE인 page): 0, page->objects: 64
inc_slabs_node(s, page_to_nid(page), page->objects);
slub.c::inc_slabs_node()
// ARM10C 20140531
// s: &boot_kmem_cache_node, page: migratetype이 MIGRATE_UNMOVABLE인 page
// page_to_nid(migratetype이 MIGRATE_UNMOVABLE인 page): 0, page->objects: 64
// kmem_cache_node: &boot_kmem_cache_node, node: 0, page->objects: 64
static inline void inc_slabs_node(struct kmem_cache *s, int node, int objects)
{
// s: &boot_kmem_cache_node, node:0
// get_node(&boot_kmem_cache_node,0) : (&boot_kmem_cache_node)->node[0]
struct kmem_cache_node *n = get_node(s, node);
// s: &boot_kmem_cache_node, page: migratetype이 MIGRATE_UNMOVABLE인 page
// page_to_nid(migratetype이 MIGRATE_UNMOVABLE인 page): 0, page->objects: 64
// kmem_cache_node: &boot_kmem_cache_node, node: 0, page->objects: 64
static inline void inc_slabs_node(struct kmem_cache *s, int node, int objects)
{
// s: &boot_kmem_cache_node, node:0
// get_node(&boot_kmem_cache_node,0) : (&boot_kmem_cache_node)->node[0]
struct kmem_cache_node *n = get_node(s, node);
slub.c::get_node(s,node)
// ARM10C 20140531
// s: &boot_kmem_cache_node, node: 0
static inline struct kmem_cache_node *get_node(struct kmem_cache *s, int node)
{
// node: 0, s->node: (&boot_kmem_cache_node)->node[0]
return s->node[node];
// return (&boot_kmem_cache_node)->node[0]
}
// return (&boot_kmem_cache_node)->node[0]
// s: &boot_kmem_cache_node, node: 0
static inline struct kmem_cache_node *get_node(struct kmem_cache *s, int node)
{
// node: 0, s->node: (&boot_kmem_cache_node)->node[0]
return s->node[node];
// return (&boot_kmem_cache_node)->node[0]
}
slub.c::inc_slabs_node()
// get_node에서 (&boot_kmem_cache_node)->node[0]를 리턴받아 n에 할당함
struct kmem_cache_node *n = get_node(s, node);
// n: &(&boot_kmem_cache_node)->node[0]: NULL
// n: &(&boot_kmem_cache_node)->node[0]: UNMOVABLE인 page 의 object의 시작 virtual address
/*
* May be called early in order to allocate a slab for the
* kmem_cache_node structure. Solve the chicken-egg
* dilemma by deferring the increment of the count during
* bootstrap (see early_kmem_cache_node_alloc).
*/
// n: &(&boot_kmem_cache_node)->node[0]: NULL
if (likely(n)) {
// n->slabs: 0
atomic_long_inc(&n->nr_slabs);
// n->slabs: 1
// objects: 64, n->total_objects: 0
atomic_long_add(objects, &n->total_objects);
// n->total_objects: 64
}
// kmem_cache_node 가 완성된 이후에 nr_slabs, total_objects 가 증가될 것으로 예상됨
}
여기서 if(likely(n))에서 n의 값을 확인해 보자.
n은 n : &(&boot_kmem_cache_node)->node[0]이므로NULL이다.
아직 kmem_cache_node를 한번 들어왔고, 초기화만 한것이므로
inc_slabs_node 는 나중에 kmem_cache_node가 완성된 이후면 증가하는 것으로 예상한다.
struct kmem_cache_node *n = get_node(s, node);
// n: &(&boot_kmem_cache_node)->node[0]: NULL
// n: &(&boot_kmem_cache_node)->node[0]: UNMOVABLE인 page 의 object의 시작 virtual address
/*
* May be called early in order to allocate a slab for the
* kmem_cache_node structure. Solve the chicken-egg
* dilemma by deferring the increment of the count during
* bootstrap (see early_kmem_cache_node_alloc).
*/
// n: &(&boot_kmem_cache_node)->node[0]: NULL
if (likely(n)) {
// n->slabs: 0
atomic_long_inc(&n->nr_slabs);
// n->slabs: 1
// objects: 64, n->total_objects: 0
atomic_long_add(objects, &n->total_objects);
// n->total_objects: 64
}
// kmem_cache_node 가 완성된 이후에 nr_slabs, total_objects 가 증가될 것으로 예상됨
}
n은 n : &(&boot_kmem_cache_node)->node[0]이므로NULL이다.
아직 kmem_cache_node를 한번 들어왔고, 초기화만 한것이므로
inc_slabs_node 는 나중에 kmem_cache_node가 완성된 이후면 증가하는 것으로 예상한다.
slub.c::new_slab()
// inc_slabs_node에서 n은 &(&boot_kmem_cache_node)->node[0]이므로NULL이다.
// 초기화만 했고, kmem_cache_node가 완성된 이후 증가한다.
inc_slabs_node(s, page_to_nid(page), page->objects);
// s: &boot_kmem_cache_node
// order: 0
memcg_bind_pages(s, order);
// null function
// page : migratetype이 MIGRATE_UNMOVEABLE인 page
// s : &boot_kmem_cache_node
page->slab_cache = s;
// page->slab_cache : &boot_kmem_cache_node
// page: migratetype이 MIGRATE_UNMOVABLE인 page
__SetPageSlab(page);
// 초기화만 했고, kmem_cache_node가 완성된 이후 증가한다.
inc_slabs_node(s, page_to_nid(page), page->objects);
// s: &boot_kmem_cache_node
// order: 0
memcg_bind_pages(s, order);
// null function
// page : migratetype이 MIGRATE_UNMOVEABLE인 page
// s : &boot_kmem_cache_node
page->slab_cache = s;
// page->slab_cache : &boot_kmem_cache_node
// page: migratetype이 MIGRATE_UNMOVABLE인 page
__SetPageSlab(page);
page-flags.h::__SetPageSlab(page)
__SetPageSlab은 매크로이다.
__PAGEFLAG(Slab, slab)
__SetPageSlab(strunct page *page) \
{__set_bits(PG_slab, &page->flags);}
# define __SETPAGEFLAG(Slab,slab); \
static inline void _SetPageSlab(struct page *page) \
{ __set_bits(PG_slab, &page->flags);
// PG_slab : enum 7
page->flags의 7번째 bit를 set한다.
__PAGEFLAG(Slab, slab)
__SetPageSlab(strunct page *page) \
{__set_bits(PG_slab, &page->flags);}
# define __SETPAGEFLAG(Slab,slab); \
static inline void _SetPageSlab(struct page *page) \
{ __set_bits(PG_slab, &page->flags);
page->flags의 7번째 bit를 set한다.
slub.c::new_slab()
__SetPageSlab(page) 는 page->flags의 7번째 bit를 set한다.
여기서 page는 migratetype이 MIGRATE_UNMOVABLE인 page이다.
__SetPageSlab(page);
// page->flags에 7 (PG_slab) bit를 set
// page->pfmemalloc: 0
if (page->pfmemalloc)
SetPageSlabPfmemalloc(page);
// page: migratetype이 MIGRATE_UNMOVABLE인 page
// 이 코드 이후 부터는 UNMOVABLE인 page로 표기
start = page_address(page);
if (page->pfmemalloc)
// page->pfmemalloc : 0
SetPageSlabPfmemalloc(page);
// page : &boot_kmem_cache_node
start = page_address(page);
- page->pfmemalloc : page_alloc.c : 2887에서 0으로 초기화 했다.
- page를 migratetype이 MI GRATE_UNMOVEABLE 에서
- UNMOVEABLE인 page로 쓰기로 하자.
여기서 page는 migratetype이 MIGRATE_UNMOVABLE인 page이다.
__SetPageSlab(page);
// page->flags에 7 (PG_slab) bit를 set
// page->pfmemalloc: 0
if (page->pfmemalloc)
SetPageSlabPfmemalloc(page);
// page: migratetype이 MIGRATE_UNMOVABLE인 page
// 이 코드 이후 부터는 UNMOVABLE인 page로 표기
start = page_address(page);
if (page->pfmemalloc)
// page->pfmemalloc : 0
SetPageSlabPfmemalloc(page);
// page : &boot_kmem_cache_node
start = page_address(page);
highmem.c::page_address(page)
// ARM10C 20140531
// page: migratetype이 MIGRATE_UNMOVABLE인 page
void *page_address(const struct page *page)
{
unsigned long flags;
void *ret;
struct page_address_slot *pas;
// PageHighMem(page): 0
if (!PageHighMem(page))
return lowmem_page_address(page);
// page의 virtual address 값을 리턴
pas = page_slot(page);
ret = NULL;
spin_lock_irqsave(&pas->lock, flags);
if (!list_empty(&pas->lh)) {
struct page_address_map *pam;
list_for_each_entry(pam, &pas->lh, list) {
if (pam->page == page) {
ret = pam->virtual;
goto done;
}
}
}
done:
spin_unlock_irqrestore(&pas->lock, flags);
return ret;
}
// start: UNMOVABLE인 page 의 virtual address
// ARM10C 20140531
// page: migratetype이 MIGRATE_UNMOVABLE인 page
void *page_address(const struct page *page)
{
unsigned long flags;
void *ret;
struct page_address_slot *pas;
// PageHighMem(page): 0
if (!PageHighMem(page))
return lowmem_page_address(page);
// page의 virtual address 값을 리턴
pas = page_slot(page);
ret = NULL;
spin_lock_irqsave(&pas->lock, flags);
if (!list_empty(&pas->lh)) {
struct page_address_map *pam;
list_for_each_entry(pam, &pas->lh, list) {
if (pam->page == page) {
ret = pam->virtual;
goto done;
}
}
}
done:
spin_unlock_irqrestore(&pas->lock, flags);
return ret;
}
slub.c::new_slab()
start = page_address(page);
// start: UNMOVABLE인 page 의 virtual address
// s->flags: boot_kmem_cache_node.flags: SLAB_HWCACHE_ALIGN: 0x00002000UL
// SLAB_POISON: 0x00000800UL
if (unlikely(s->flags & SLAB_POISON))
memset(start, POISON_INUSE, PAGE_SIZE << order);
// start: UNMOVABLE인 page 의 virtual address
last = start;
// last: UNMOVABLE인 page 의 virtual address
// s: &boot_kmem_cache_node,
// start: UNMOVABLE인 page 의 virtual address
// page->objects: 64
for_each_object(p, s, start, page->objects) {
// for (p = (UNMOVABLE인 page 의 virtual address);
// p < (UNMOVABLE인 page 의 virtual address) + (64) * (&boot_kmem_cache_node)->size;
// p += (&boot_kmem_cache_node)->size)
// p: UNMOVABLE인 page 의 virtual address
// (&boot_kmem_cache_node)->size: 64
// s: &boot_kmem_cache_node, page: UNMOVABLE인 page
// last: UNMOVABLE인 page 의 virtual address
setup_object(s, page, last);
// s: &boot_kmem_cache_node, last: UNMOVABLE인 page 의 virtual address
// p: UNMOVABLE인 page 의 virtual address
set_freepointer(s, last, p);
// last에 p 주소를 mapping 함
last = p;
}
start = page_address(page);
// start: UNMOVABLE인 page 의 virtual address
// s->flags: boot_kmem_cache_node.flags: SLAB_HWCACHE_ALIGN: 0x00002000UL
// SLAB_POISON: 0x00000800UL
if (unlikely(s->flags & SLAB_POISON))
memset(start, POISON_INUSE, PAGE_SIZE << order);
// start: UNMOVABLE인 page 의 virtual address
last = start;
// last: UNMOVABLE인 page 의 virtual address
// s: &boot_kmem_cache_node,
// start: UNMOVABLE인 page 의 virtual address
// page->objects: 64
for_each_object(p, s, start, page->objects) {
// for (p = (UNMOVABLE인 page 의 virtual address);
// p < (UNMOVABLE인 page 의 virtual address) + (64) * (&boot_kmem_cache_node)->size;
// p += (&boot_kmem_cache_node)->size)
// p: UNMOVABLE인 page 의 virtual address
// (&boot_kmem_cache_node)->size: 64
// s: &boot_kmem_cache_node, page: UNMOVABLE인 page
// last: UNMOVABLE인 page 의 virtual address
setup_object(s, page, last);
// s: &boot_kmem_cache_node, last: UNMOVABLE인 page 의 virtual address
// p: UNMOVABLE인 page 의 virtual address
set_freepointer(s, last, p);
// last에 p 주소를 mapping 함
last = p;
}
slub.c::setup_objects(s page last)
// s: &boot_kmem_cache_node, page: UNMOVABLE인 page
// last: UNMOVABLE인 page 의 virtual address
// setup_object(s, page, last);
static void setup_object(struct kmem_cache *s, struct page *page,
void *object)
{
// s: &boot_kmem_cache_node, page: UNMOVABLE인 page
// object: UNMOVABLE인 page 의 virtual address
setup_object_debug(s, page, object);
// last: UNMOVABLE인 page 의 virtual address
// setup_object(s, page, last);
static void setup_object(struct kmem_cache *s, struct page *page,
void *object)
{
// s: &boot_kmem_cache_node, page: UNMOVABLE인 page
// object: UNMOVABLE인 page 의 virtual address
setup_object_debug(s, page, object);
slub.c::setup_object_debug()
// ARM10C 20140531
// s: &boot_kmem_cache_node, page: UNMOVABLE인 page
// object: UNMOVABLE인 page 의 virtual address
static void setup_object_debug(struct kmem_cache *s, struct page *page,
void *object)
{
// s->flags: boot_kmem_cache_node.flags: SLAB_HWCACHE_ALIGN: 0x00002000UL
// SLAB_STORE_USER: 0x00010000UL,
// SLAB_RED_ZONE: 0x00000400UL,
// __OBJECT_POISON: 0x80000000UL
// 0x00010000 | 0x00000400 | 0x80000000: 0x80010400
// s->flags & 0x80010400
if (!(s->flags & (SLAB_STORE_USER|SLAB_RED_ZONE|__OBJECT_POISON)))
return;
// return 수행
if문에서 참값으로 return한다.
// s: &boot_kmem_cache_node, page: UNMOVABLE인 page
// object: UNMOVABLE인 page 의 virtual address
static void setup_object_debug(struct kmem_cache *s, struct page *page,
void *object)
{
// s->flags: boot_kmem_cache_node.flags: SLAB_HWCACHE_ALIGN: 0x00002000UL
// SLAB_STORE_USER: 0x00010000UL,
// SLAB_RED_ZONE: 0x00000400UL,
// __OBJECT_POISON: 0x80000000UL
// 0x00010000 | 0x00000400 | 0x80000000: 0x80010400
// s->flags & 0x80010400
if (!(s->flags & (SLAB_STORE_USER|SLAB_RED_ZONE|__OBJECT_POISON)))
return;
// return 수행
slub.c::setup_objects(s page last)
setup_object_debug(s, page, object);
// s->ctor: boot_kmem_cache_node.ctor: NULL
if (unlikely(s->ctor))
s->ctor(object);
}
setup_object_debug(s, page, object);
// s->ctor: boot_kmem_cache_node.ctor: NULL
if (unlikely(s->ctor))
s->ctor(object);
}
slub.c::newslab()
for_each_object(p, s, start, page->objects) {
setup_object(s, page, last);
// s: &boot_kmem_cache_node,
// last : UNMOVERABLE인 page의 가상 주소
// p: UNMOVERABLE인 page의 가상 주소
set_freepointer(s, last, p);
for_each_object(p, s, start, page->objects) {
setup_object(s, page, last);
// s: &boot_kmem_cache_node,
// last : UNMOVERABLE인 page의 가상 주소
// p: UNMOVERABLE인 page의 가상 주소
set_freepointer(s, last, p);
slub.c::set_freepoint(s,page,last)
// s: &boot_kmem_cache_node,
// last : UNMOVERABLE인 page의 가상 주소
// p: UNMOVERABLE인 page의 가상 주소
static inline void set_freepointer(struct kmem_cache *s, void *object, void *fp)
{
// object : last : UNMOVERABLE인 page의 가상 주소
// s->offset : &boot_kmem_cache_node->offset : 0
// fp : UNMOVABLE인 page 의 virtual address
*(void **)(object + s->offset) = fp;
// object: UNMOVERABLE인 page의 가상 주소
}
- (void *)(object + s->offset) = fp
- object + s->offset를 더한 주소에 fp를 넣는다.
- 즉 next를 가리키는 구조가 된다.
- |0x10001000|data|0x10001040|data|0x10000080|data|…|null|data|화
- 한 페이지당 60Byte * 60 = 3840 Byte, 사용가능.
-
last에 p주소를 매핑함.
-
for_each_object가 하는일:
- 다음 object의 시작주소를 이전 object의 내부에 저장을 하는데.
- 그 위치는 s->offset에 의해 결정되어 저장됨.
// last : UNMOVERABLE인 page의 가상 주소
// p: UNMOVERABLE인 page의 가상 주소
static inline void set_freepointer(struct kmem_cache *s, void *object, void *fp)
{
// object : last : UNMOVERABLE인 page의 가상 주소
// s->offset : &boot_kmem_cache_node->offset : 0
// fp : UNMOVABLE인 page 의 virtual address
*(void **)(object + s->offset) = fp;
// object: UNMOVERABLE인 page의 가상 주소
}
last에 p주소를 매핑함.
for_each_object가 하는일:
- 다음 object의 시작주소를 이전 object의 내부에 저장을 하는데.
- 그 위치는 s->offset에 의해 결정되어 저장됨.
slub.c::new_slab()
for_each_object(p, s, start, page->objects) {...}
// for_each_object가 하는일:
// 다음 object의 시작주소를 이전 object의 내부(freepointer) 에 저장을 하는데
// 그 위치는 s->offset에 의해 결정되어 저장됨
// 예시:
// |0x10001000|data 60Byte |0x10001040|data 60Byte |0x10000080|data 0x60Byte |...|null|data|
// s: &boot_kmem_cache_node
// page : UNMOVEABLE인 page
// last: UNMOVEABLE인 page의 가상 주소 + 0x1000 - 64
setup_object(s, page, last);
set_freepointer(s, last, NULL);
// 마지막 object의 freepoint는 null 로 초기화
// page->freelist: UNMOVEABLE인 page의 가상 주소.
// page의 freelist멤버는 slab의 oject의 시작 주소를 가리킴.
page->freelist = start;
// page->objects : 64
page->inuse = page->objects;
// page->inuse : 64
//
// page의 object 멤버는 slab의 object의 총 갯수
// page의 inuse 멤버는 slab의 free상태인 object의 총 갯수
page->frozen = 1;
// page->frozen : 1
out:
return page;
}
- net_slab()이 한일
- migratype이 MIGRATE_UNMOVEABLE인 page 를 할당 받았고,
- page->flags의 NR_PAGEFLAGS를 지우고 (PG_slab) bit를 set
- slab 의 object들의 freepoint를 매핑 함.
- kmem_cache_node가 완성된 이후에 nr_slabs, total_objects가 증가
- page->freelist : UNMOVEABLE인 page의 가상주소,
- page->inuse: 64로 설정함
- page->frozen : 1로 설정함
for_each_object(p, s, start, page->objects) {...}
// for_each_object가 하는일:
// 다음 object의 시작주소를 이전 object의 내부(freepointer) 에 저장을 하는데
// 그 위치는 s->offset에 의해 결정되어 저장됨
// 예시:
// |0x10001000|data 60Byte |0x10001040|data 60Byte |0x10000080|data 0x60Byte |...|null|data|
// s: &boot_kmem_cache_node
// page : UNMOVEABLE인 page
// last: UNMOVEABLE인 page의 가상 주소 + 0x1000 - 64
setup_object(s, page, last);
set_freepointer(s, last, NULL);
// 마지막 object의 freepoint는 null 로 초기화
// page->freelist: UNMOVEABLE인 page의 가상 주소.
// page의 freelist멤버는 slab의 oject의 시작 주소를 가리킴.
page->freelist = start;
// page->objects : 64
page->inuse = page->objects;
// page->inuse : 64
//
// page의 object 멤버는 slab의 object의 총 갯수
// page의 inuse 멤버는 slab의 free상태인 object의 총 갯수
page->frozen = 1;
// page->frozen : 1
out:
return page;
}
slub.c::early_kmem_cache_node_alloc()
// node: 0
static void early_kmem_cache_node_alloc(int node)
{
...
page = new_slab(kmem_cache_node, GFP_NOWAIT, node);
// page: UNMOVABLE인 page
BUG_ON(!page);
// page: UNMOVABLE인 page, page_to_nid(UNMOVABLE인 page): 0, node: 0
// if: false
if (page_to_nid(page) != node) {
printk(KERN_ERR "SLUB: Unable to allocate memory from "
"node %d\n", node);
printk(KERN_ERR "SLUB: Allocating a useless per node structure "
"in order to be able to continue\n");
}
// page->freelist: UNMOVABLE인 page 의 object시작 가상주소
n = page->freelist;
// n: page->freelist: UNMOVABLE인 page 의 object시작 가상주소
BUG_ON(!n);
// kmem_cache_node : &boot_kmem_cache_node
// n: page->freelist: UNMOVABLE인 page 의 object시작 가상주소
page->freelist = get_freepointer(kmem_cache_node, n);
// node: 0
static void early_kmem_cache_node_alloc(int node)
{
...
page = new_slab(kmem_cache_node, GFP_NOWAIT, node);
// page: UNMOVABLE인 page
BUG_ON(!page);
// page: UNMOVABLE인 page, page_to_nid(UNMOVABLE인 page): 0, node: 0
// if: false
if (page_to_nid(page) != node) {
printk(KERN_ERR "SLUB: Unable to allocate memory from "
"node %d\n", node);
printk(KERN_ERR "SLUB: Allocating a useless per node structure "
"in order to be able to continue\n");
}
// page->freelist: UNMOVABLE인 page 의 object시작 가상주소
n = page->freelist;
// n: page->freelist: UNMOVABLE인 page 의 object시작 가상주소
BUG_ON(!n);
// kmem_cache_node : &boot_kmem_cache_node
// n: page->freelist: UNMOVABLE인 page 의 object시작 가상주소
page->freelist = get_freepointer(kmem_cache_node, n);
slub.c::get_freepointer()
// ARM10C 20140531
// kmem_cache_node: &boot_kmem_cache_node,
// n: UNMOVABLE인 page 의 object의 시작 virtual address
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
}
gett_freepointer가 하는일
- 다음 object의 주소를 가져옴.
- // 할당받았던 slub_object을 처음 주소에 값을 가지고 오기 때문에.
- // 다음 위치(next)주고가 된다.
- 다음 freepointer를 가리킨다.
// kmem_cache_node: &boot_kmem_cache_node,
// n: UNMOVABLE인 page 의 object의 시작 virtual address
static inline void *get_freepointer(struct kmem_cache *s, void *object)
{
// object: UNMOVABLE인 page 의 object의 시작 virtual address
// s->offset: (&boot_kmem_cache_node)->offset: 0
return *(void **)(object + s->offset);
// object: UNMOVABLE인 page 의 object의 시작 virtual address
}
slub.c::early_kmem_cache_node_alloc()
...
page->freelist = get_freepointer(kmem_cache_node, n);
// page->freelist: UNMOVABLE인 page 의 object의 시작 virtual address + 64
// get_freepointer 하는일:
// 다음 object의 주소를 가져옴
// page->inuse : 64
page->inuse = 1;
// page의 inuse맴버는 현재 사용하고 있는 object수를 의미함
// (64)에서 1로 바뀜. (사용중인 slab 수)
// page->frozen : 1
page->frozen = 0;
// page->frozen : 0
// kmem_cache_node->node : (&boot_kmem_cache_node)->node[0]: NULL
// n: UNMOVEABLE인 page의 시작 object의 가상 주소
kmem_cache_node->node[node] = n;
// kmem_cache_node->node: (&boot_kmem_cache_node)->node[0]:
// UNMOVABLE인 page 의 object의 시작 virtual address
#ifdef CONFIG_SLUB_DEBUG // y
// kmem_cache_node->node[0]:
// #define SLUB_RED_ACTIVE 0xcc
init_object(kmem_cache_node, n, SLUB_RED_ACTIVE);
...
page->freelist = get_freepointer(kmem_cache_node, n);
// page->freelist: UNMOVABLE인 page 의 object의 시작 virtual address + 64
// get_freepointer 하는일:
// 다음 object의 주소를 가져옴
// page->inuse : 64
page->inuse = 1;
// page의 inuse맴버는 현재 사용하고 있는 object수를 의미함
// (64)에서 1로 바뀜. (사용중인 slab 수)
// page->frozen : 1
page->frozen = 0;
// page->frozen : 0
// kmem_cache_node->node : (&boot_kmem_cache_node)->node[0]: NULL
// n: UNMOVEABLE인 page의 시작 object의 가상 주소
kmem_cache_node->node[node] = n;
// kmem_cache_node->node: (&boot_kmem_cache_node)->node[0]:
// UNMOVABLE인 page 의 object의 시작 virtual address
#ifdef CONFIG_SLUB_DEBUG // y
// kmem_cache_node->node[0]:
// #define SLUB_RED_ACTIVE 0xcc
init_object(kmem_cache_node, n, SLUB_RED_ACTIVE);
slub.c::init_object()
// ARM10C 20140531
// kmem_cache_node: &boot_kmem_cache_node,
// n: UNMOVABLE인 page 의 object의 시작 virtual address,
// SLUB_RED_ACTIVE: 0xcc
static void init_object(struct kmem_cache *s, void *object, u8 val)
{
// object: UNMOVABLE인 page 의 object의 시작 virtual address
u8 *p = object;
// p: UNMOVABLE인 page 의 object의 시작 virtual address
// s->flags: (&boot_kmem_cache_node)->flags: SLAB_HWCACHE_ALIGN: 0x00002000UL
// __OBJECT_POISON: 0x80000000UL
if (s->flags & __OBJECT_POISON) {
memset(p, POISON_FREE, s->object_size - 1);
p[s->object_size - 1] = POISON_END;
}
// s->flags: (&boot_kmem_cache_node)->flags: SLAB_HWCACHE_ALIGN: 0x00002000UL
// SLAB_RED_ZONE: 0x00000400UL
if (s->flags & SLAB_RED_ZONE)
memset(p + s->object_size, val, s->inuse - s->object_size);
}
// kmem_cache_node: &boot_kmem_cache_node,
// n: UNMOVABLE인 page 의 object의 시작 virtual address,
// SLUB_RED_ACTIVE: 0xcc
static void init_object(struct kmem_cache *s, void *object, u8 val)
{
// object: UNMOVABLE인 page 의 object의 시작 virtual address
u8 *p = object;
// p: UNMOVABLE인 page 의 object의 시작 virtual address
// s->flags: (&boot_kmem_cache_node)->flags: SLAB_HWCACHE_ALIGN: 0x00002000UL
// __OBJECT_POISON: 0x80000000UL
if (s->flags & __OBJECT_POISON) {
memset(p, POISON_FREE, s->object_size - 1);
p[s->object_size - 1] = POISON_END;
}
// s->flags: (&boot_kmem_cache_node)->flags: SLAB_HWCACHE_ALIGN: 0x00002000UL
// SLAB_RED_ZONE: 0x00000400UL
if (s->flags & SLAB_RED_ZONE)
memset(p + s->object_size, val, s->inuse - s->object_size);
}
slub.c::early_kmem_cache_node_alloc()
init_object(kmem_cache_node, n, SLUB_RED_ACTIVE);
// kmem_cache_node: &boot_kmem_cache_node,
// n: UNMOVABLE인 page 의 object의 시작 virtual address
init_tracking(kmem_cache_node, n);
init_object(kmem_cache_node, n, SLUB_RED_ACTIVE);
// kmem_cache_node: &boot_kmem_cache_node,
// n: UNMOVABLE인 page 의 object의 시작 virtual address
init_tracking(kmem_cache_node, n);
slub.c::init_tracking()
// ARM10C 20140531
// kmem_cache_node: &boot_kmem_cache_node,
// n: UNMOVABLE인 page 의 object의 시작 virtual address
static void init_tracking(struct kmem_cache *s, void *object)
{
// s->flags: (&boot_kmem_cache_node)->flags: SLAB_HWCACHE_ALIGN: 0x00002000UL
// SLAB_STORE_USER: 0x00010000UL
if (!(s->flags & SLAB_STORE_USER))
return;
// return 수행
set_track(s, object, TRACK_FREE, 0UL);
set_track(s, object, TRACK_ALLOC, 0UL);
}
if문에서 리턴함
// kmem_cache_node: &boot_kmem_cache_node,
// n: UNMOVABLE인 page 의 object의 시작 virtual address
static void init_tracking(struct kmem_cache *s, void *object)
{
// s->flags: (&boot_kmem_cache_node)->flags: SLAB_HWCACHE_ALIGN: 0x00002000UL
// SLAB_STORE_USER: 0x00010000UL
if (!(s->flags & SLAB_STORE_USER))
return;
// return 수행
set_track(s, object, TRACK_FREE, 0UL);
set_track(s, object, TRACK_ALLOC, 0UL);
}
slub.c::early_kmem_cache_node_alloc()
init_tracking(kmem_cache_node, n);
// n: UNMOVABLE인 page 의 object의 시작 virtual address
init_kmem_cache_node(n);
init_tracking(kmem_cache_node, n);
// n: UNMOVABLE인 page 의 object의 시작 virtual address
init_kmem_cache_node(n);
slub.c::init_kmem_cache_node()
// ARM10C 20140531
// n: UNMOVEABLE의 page의 object의 시작 virtual address
여기서 할당 받았던 slab을 kmem_cache_node로 초기화를 여기서 하는 과정이다.
static void
init_kmem_cache_node(struct kmem_cache_node *n)
{
// n: UNMOVABLE인 page 의 object의 시작 virtual address
n->nr_partial = 0;
// n->nr_partial: 0
spin_lock_init(&n->list_lock);
// kmem_cache_node에 spinlock 맴버 변수를 초기화
// n->partial: 0
INIT_LIST_HEAD(&n->partial);
// n->partial: 리스트 초기화
#ifdef CONFIG_SLUB_DEBUG // CONFIG_SLUB_DEBUG=y
atomic_long_set(&n->nr_slabs, 0);
// n->nr_slabs: 0
atomic_long_set(&n->total_objects, 0);
// n->total_objects: 0
INIT_LIST_HEAD(&n->full);
// n->full: 리스트 초기화
#endif
}
참조 kmem_cache_node의 자료구조
struct kmem_cache_node {
spinlock_t list_lock;
unsigned long nr_partial;
struct list_head partial;
atomic_long_t nr_slabs;
atomic_long_t total_objects;
struct list_head full;
};
// n: UNMOVEABLE의 page의 object의 시작 virtual address
여기서 할당 받았던 slab을 kmem_cache_node로 초기화를 여기서 하는 과정이다.
static void
init_kmem_cache_node(struct kmem_cache_node *n)
{
// n: UNMOVABLE인 page 의 object의 시작 virtual address
n->nr_partial = 0;
// n->nr_partial: 0
spin_lock_init(&n->list_lock);
// kmem_cache_node에 spinlock 맴버 변수를 초기화
// n->partial: 0
INIT_LIST_HEAD(&n->partial);
// n->partial: 리스트 초기화
#ifdef CONFIG_SLUB_DEBUG // CONFIG_SLUB_DEBUG=y
atomic_long_set(&n->nr_slabs, 0);
// n->nr_slabs: 0
atomic_long_set(&n->total_objects, 0);
// n->total_objects: 0
INIT_LIST_HEAD(&n->full);
// n->full: 리스트 초기화
#endif
}
struct kmem_cache_node {
spinlock_t list_lock;
unsigned long nr_partial;
struct list_head partial;
atomic_long_t nr_slabs;
atomic_long_t total_objects;
struct list_head full;
};
slub.c::early_kmem_cache_node_alloc()
init_kmem_cache_node(n);
// 할당받은 slab object를 kmem_cache_node로 사용하고,
// kmem_cache_node의 맴버 필들를 초기화함.
// n->nr_partial: 0
// n->list_lock: spinlock 초기화 수행
// n->partial: 리스트 초기화
// n->nr_slabs: 0
// n->total_objects: 0
// n->full: 리스트 초기화
// 할당받은 slab object를 kmem_cache_node 로 사용하고
// kmem_cache_node의 멤버 필드를 초기화함
// page: UNMOVABLE인 page
// kmem_cache_node: &boot_kmem_cache_node, node: 0, page->objects: 64
inc_slabs_node(kmem_cache_node, node, page->objects);
init_kmem_cache_node(n);
// kmem_cache_node: &boot_kmem_cache_node, node: 0, page->object:64
inc_slabs_node(kmem_cache_node, node, page->objects);a
init_kmem_cache_node(n);
// 할당받은 slab object를 kmem_cache_node로 사용하고,
// kmem_cache_node의 맴버 필들를 초기화함.
// n->nr_partial: 0
// n->list_lock: spinlock 초기화 수행
// n->partial: 리스트 초기화
// n->nr_slabs: 0
// n->total_objects: 0
// n->full: 리스트 초기화
// 할당받은 slab object를 kmem_cache_node 로 사용하고
// kmem_cache_node의 멤버 필드를 초기화함
// page: UNMOVABLE인 page
// kmem_cache_node: &boot_kmem_cache_node, node: 0, page->objects: 64
inc_slabs_node(kmem_cache_node, node, page->objects);
init_kmem_cache_node(n);
// kmem_cache_node: &boot_kmem_cache_node, node: 0, page->object:64
inc_slabs_node(kmem_cache_node, node, page->objects);a
slub.c::inc_slabs_node()
이번에는 n이 값이 있으므로 likely를 실햄함.
// ARM10C 20140531
// s: &boot_kmem_cache_node, page: migratetype이 MIGRATE_UNMOVABLE인 page
// page_to_nid(migratetype이 MIGRATE_UNMOVABLE인 page): 0, page->objects: 64
// ARM10C 20140531
// kmem_cache_node: &boot_kmem_cache_node, node: 0, page->objects: 64
static inline void inc_slabs_node(struct kmem_cache *s, int node, int objects)
{
// s: &boot_kmem_cache_node, node: 0
// get_node(&boot_kmem_cache_node, 0): (&boot_kmem_cache_node)->node[0]: NULL
// s: &boot_kmem_cache_node, node: 0
// get_node(&boot_kmem_cache_node, 0): (&boot_kmem_cache_node)->node[0]:
// UNMOVABLE인 page 의 object의 시작 virtual address
struct kmem_cache_node *n = get_node(s, node);
// n: &(&boot_kmem_cache_node)->node[0]: NULL
// n: &(&boot_kmem_cache_node)->node[0]: UNMOVABLE인 page 의 object의 시작 virtual address
/*
* May be called early in order to allocate a slab for the
* kmem_cache_node structure. Solve the chicken-egg
* dilemma by deferring the increment of the count during
* bootstrap (see early_kmem_cache_node_alloc).
*/
// n: &(&boot_kmem_cache_node)->node[0]: NULL
// n: &(&boot_kmem_cache_node)->node[0]: UNMOVABLE인 page 의 object의 시작 virtual address
if (likely(n)) {
// n->slabs: 0
atomic_long_inc(&n->nr_slabs);
// n->slabs: 1
// objects: 64, n->total_objects: 0
atomic_long_add(objects, &n->total_objects);
// n->total_objects: 64
}
// kmem_cache_node 가 완성된 이후에 nr_slabs, total_objects 가 증가될 것으로 예상됨
// kmem_cache_node가 완성되었기 때문에 예상대로 증가했음.
}
// ARM10C 20140531
// s: &boot_kmem_cache_node, page: migratetype이 MIGRATE_UNMOVABLE인 page
// page_to_nid(migratetype이 MIGRATE_UNMOVABLE인 page): 0, page->objects: 64
// ARM10C 20140531
// kmem_cache_node: &boot_kmem_cache_node, node: 0, page->objects: 64
static inline void inc_slabs_node(struct kmem_cache *s, int node, int objects)
{
// s: &boot_kmem_cache_node, node: 0
// get_node(&boot_kmem_cache_node, 0): (&boot_kmem_cache_node)->node[0]: NULL
// s: &boot_kmem_cache_node, node: 0
// get_node(&boot_kmem_cache_node, 0): (&boot_kmem_cache_node)->node[0]:
// UNMOVABLE인 page 의 object의 시작 virtual address
struct kmem_cache_node *n = get_node(s, node);
// n: &(&boot_kmem_cache_node)->node[0]: NULL
// n: &(&boot_kmem_cache_node)->node[0]: UNMOVABLE인 page 의 object의 시작 virtual address
/*
* May be called early in order to allocate a slab for the
* kmem_cache_node structure. Solve the chicken-egg
* dilemma by deferring the increment of the count during
* bootstrap (see early_kmem_cache_node_alloc).
*/
// n: &(&boot_kmem_cache_node)->node[0]: NULL
// n: &(&boot_kmem_cache_node)->node[0]: UNMOVABLE인 page 의 object의 시작 virtual address
if (likely(n)) {
// n->slabs: 0
atomic_long_inc(&n->nr_slabs);
// n->slabs: 1
// objects: 64, n->total_objects: 0
atomic_long_add(objects, &n->total_objects);
// n->total_objects: 64
}
// kmem_cache_node 가 완성된 이후에 nr_slabs, total_objects 가 증가될 것으로 예상됨
// kmem_cache_node가 완성되었기 때문에 예상대로 증가했음.
}
slub.c::early_kmem_cache_node_alloc()
// kmem_cache_node: &boot_kmem_cache_node, node: 0, page->object:64
inc_slabs_node(kmem_cache_node, node, page->objects);a
// n->slabs: 1, n->total_objects: 64 로 설정함
// n: UNMOVABLE인 page 의 object의 시작 virtual address,
// page: UNMOVABLE인 page, DEACTIVATE_TO_HEAD: 15
// 15: enum DEACTIVATE_TO_HEAD, Cpu slab was moved to the head of partials
add_partial(n, page, DEACTIVATE_TO_HEAD);
}
// kmem_cache_node: &boot_kmem_cache_node, node: 0, page->object:64
inc_slabs_node(kmem_cache_node, node, page->objects);a
// n->slabs: 1, n->total_objects: 64 로 설정함
// n: UNMOVABLE인 page 의 object의 시작 virtual address,
// page: UNMOVABLE인 page, DEACTIVATE_TO_HEAD: 15
// 15: enum DEACTIVATE_TO_HEAD, Cpu slab was moved to the head of partials
add_partial(n, page, DEACTIVATE_TO_HEAD);
}
slub.c::add_partial()
// ARM10C 20140531
// n: UNMOVABLE인 page 의 object의 시작 virtual address,
// page: UNMOVABLE인 page, 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 가 추가됨
}
// n: UNMOVABLE인 page 의 object의 시작 virtual address,
// page: UNMOVABLE인 page, 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 가 추가됨
}
slub.c::early_kmem_cache_node_alloc()
add_partial(n, page, DEACTIVATE_TO_HEAD);
// kmem_cache_node의 partial 맴버의 현재 page의 lru 리스트를 추가함
}
add_partial(n, page, DEACTIVATE_TO_HEAD);
// kmem_cache_node의 partial 맴버의 현재 page의 lru 리스트를 추가함
}
slub.c::init_kmem_cache_node()
// s: &boot_kmem_cache_node
static int init_kmem_cache_nodes(struct kmem_cache *s)
{
int node;
// N_NORMAL_MEMORY: 2
for_each_node_state(node, N_NORMAL_MEMORY) {
// for ( (node) = 0; (node) == 0; (node) = 1)
struct kmem_cache_node *n;
// slab_state: DOWN: 1
if (slab_state == DOWN) {
// node: 0
early_kmem_cache_node_alloc(node);
//
continue;
}
...
}
return 1;
// return 수행
}
- early_kmem_cache_node_alloc이 한일
- new_slab()
- migratetype이 MIGRATE_UNMOVEABLE인 page를 할당 받음.
- page->flags에 7(PG_slab) bit를 초기화
- slab의 objects들을 freepointer를 맵핑함.
- page->freelist: UNMOVEABLE인 page의 object의 시작 가상 주소 + 64
- init_kmem_cache_node()
- n->nr_partial : 1
- n->list_lock : spinglock 초기화함
- kmem_cache_node->slabs: 1, kmem_cache_node->total_objects: 64 로 세팀함
- n->partial : 리스트 초기화
- n->nr_slabs: 0
- n->slabs: 1,
- kmem_cache_node->total_objects: 64
- kmem_cache_node->full: 리스트 초기화
- kmem_cache_node의 partial 맴버에 현재 page의 lru 리스트를 추가함
- init_kmem_cache_nodes가 한일.
- kmem_cache_alloc_node로 할당 받고,
- free_kmem_cache_nodes로 프리시킨다.
static int init_kmem_cache_nodes(struct kmem_cache *s)
{
int node;
// N_NORMAL_MEMORY: 2
for_each_node_state(node, N_NORMAL_MEMORY) {
// for ( (node) = 0; (node) == 0; (node) = 1)
struct kmem_cache_node *n;
// slab_state: DOWN: 1
if (slab_state == DOWN) {
// node: 0
early_kmem_cache_node_alloc(node);
//
continue;
}
...
}
return 1;
// return 수행
}
- new_slab()
- migratetype이 MIGRATE_UNMOVEABLE인 page를 할당 받음.
- page->flags에 7(PG_slab) bit를 초기화
- slab의 objects들을 freepointer를 맵핑함.
- page->freelist: UNMOVEABLE인 page의 object의 시작 가상 주소 + 64
- init_kmem_cache_node()
- n->nr_partial : 1
- n->list_lock : spinglock 초기화함
- kmem_cache_node->slabs: 1, kmem_cache_node->total_objects: 64 로 세팀함
- n->partial : 리스트 초기화
- n->nr_slabs: 0
- n->slabs: 1,
- kmem_cache_node->total_objects: 64
- kmem_cache_node->full: 리스트 초기화
- kmem_cache_node의 partial 맴버에 현재 page의 lru 리스트를 추가함
- kmem_cache_alloc_node로 할당 받고,
- free_kmem_cache_nodes로 프리시킨다.
slub.c::kmem_cache_open()
// s: &boot_kmem_cache_node, init_kmem_cache_nodes(&boot_kmem_cache_node): 1
if (!init_kmem_cache_nodes(s))
goto error;
// s: &boot_kmem_cache_node
if (alloc_kmem_cache_cpus(s))
return 0;
// s: &boot_kmem_cache_node, init_kmem_cache_nodes(&boot_kmem_cache_node): 1
if (!init_kmem_cache_nodes(s))
goto error;
// s: &boot_kmem_cache_node
if (alloc_kmem_cache_cpus(s))
return 0;
slub.c::alloc_kmem_cache_cpus()
// s: &boot_kmem_cache_node
static inline int alloc_kmem_cache_cpus(struct kmem_cache *s)
{
// PERCPU_DYNAMIC_EARLY_SIZE: 0x3000, KMALLOC_SHIFT_HIGH: 13
// sizeof(struct kmem_cache_cpu): 16 bytes
BUILD_BUG_ON(PERCPU_DYNAMIC_EARLY_SIZE <
KMALLOC_SHIFT_HIGH * sizeof(struct kmem_cache_cpu));
/*
* Must align to double word boundary for the double cmpxchg
* instructions to work; see __pcpu_double_call_return_bool().
*/
// s->cpu_slab: (&boot_kmem_cache_node)->cpu_slab
// sizeof(struct kmem_cache_cpu): 16 bytes
// __alloc_percpu(16, 8)
s->cpu_slab = __alloc_percpu(sizeof(struct kmem_cache_cpu),
2 * sizeof(void *));
static inline int alloc_kmem_cache_cpus(struct kmem_cache *s)
{
// PERCPU_DYNAMIC_EARLY_SIZE: 0x3000, KMALLOC_SHIFT_HIGH: 13
// sizeof(struct kmem_cache_cpu): 16 bytes
BUILD_BUG_ON(PERCPU_DYNAMIC_EARLY_SIZE <
KMALLOC_SHIFT_HIGH * sizeof(struct kmem_cache_cpu));
/*
* Must align to double word boundary for the double cmpxchg
* instructions to work; see __pcpu_double_call_return_bool().
*/
// s->cpu_slab: (&boot_kmem_cache_node)->cpu_slab
// sizeof(struct kmem_cache_cpu): 16 bytes
// __alloc_percpu(16, 8)
s->cpu_slab = __alloc_percpu(sizeof(struct kmem_cache_cpu),
2 * sizeof(void *));
percpu.c:__alloc_percpu()
// ARM10C 20140531
// __alloc_percpu(16, 8)
void __percpu *__alloc_percpu(size_t size, size_t align)
{
// size: 16, align: 8
return pcpu_alloc(size, align, false);
}
// __alloc_percpu(16, 8)
void __percpu *__alloc_percpu(size_t size, size_t align)
{
// size: 16, align: 8
return pcpu_alloc(size, align, false);
}
percpu.c::*pcpu_alloc()
// ARM10C 20140531
// size: 16, align: 8, false
static void __percpu *pcpu_alloc(size_t size, size_t align, bool reserved)
{
static int warn_limit = 10;
// warn_limit: 10
struct pcpu_chunk *chunk;
const char *err;
int slot, off, new_alloc;
unsigned long flags;
void __percpu *ptr;
// size: 16, align: 8, PCPU_MIN_UNIT_SIZE: 0x8000, PAGE_SIZE: 0x1000
// if: false
if (unlikely(!size || size > PCPU_MIN_UNIT_SIZE || align > PAGE_SIZE)) {
WARN(true, "illegal size (%zu) or align (%zu) for "
"percpu allocation\n", size, align);
return NULL;
}
mutex_lock(&pcpu_alloc_mutex);
// pcpu_alloc_mutex의 mutex lock을 수행
spin_lock_irqsave(&pcpu_lock, flags);
// pcpu_lock의 spiclock 을 수행하고 cpsr을 flags에 저장
/* serve reserved allocations from the reserved chunk if available */
// reserved: false, pcpu_reserved_chunk: pcpu_setup_first_chunk()함수에서 할당한 schunk
// if: false
if (reserved && pcpu_reserved_chunk) {
...
}
...
restart:
/* search through normal chunks */
// size: 16, pcpu_size_to_slot(16): 1, pcpu_nr_slots: 15
for (slot = pcpu_size_to_slot(size); slot < pcpu_nr_slots; slot++) {
// size: 16, align: 8, false
static void __percpu *pcpu_alloc(size_t size, size_t align, bool reserved)
{
static int warn_limit = 10;
// warn_limit: 10
struct pcpu_chunk *chunk;
const char *err;
int slot, off, new_alloc;
unsigned long flags;
void __percpu *ptr;
// size: 16, align: 8, PCPU_MIN_UNIT_SIZE: 0x8000, PAGE_SIZE: 0x1000
// if: false
if (unlikely(!size || size > PCPU_MIN_UNIT_SIZE || align > PAGE_SIZE)) {
WARN(true, "illegal size (%zu) or align (%zu) for "
"percpu allocation\n", size, align);
return NULL;
}
mutex_lock(&pcpu_alloc_mutex);
// pcpu_alloc_mutex의 mutex lock을 수행
spin_lock_irqsave(&pcpu_lock, flags);
// pcpu_lock의 spiclock 을 수행하고 cpsr을 flags에 저장
/* serve reserved allocations from the reserved chunk if available */
// reserved: false, pcpu_reserved_chunk: pcpu_setup_first_chunk()함수에서 할당한 schunk
// if: false
if (reserved && pcpu_reserved_chunk) {
...
}
...
restart:
/* search through normal chunks */
// size: 16, pcpu_size_to_slot(16): 1, pcpu_nr_slots: 15
for (slot = pcpu_size_to_slot(size); slot < pcpu_nr_slots; slot++) {
percpu.c::pcpu_size_to_slot()
// ARM10C 20140301
// pcpu_size_to_slot(size: 0x3000)
// ARM10C 20140531
// size: 16
static int pcpu_size_to_slot(int size)
{
// size: 0x3000, pcpu_unit_size : 0x8000
// size: 16, pcpu_unit_size : 0x8000
if (size == pcpu_unit_size)
return pcpu_nr_slots - 1;
// size: 0x3000
// size: 16
return __pcpu_size_to_slot(size);
// __pcpu_size_to_slot(0x3000): 11
// __pcpu_size_to_slot(16): 1
}
// pcpu_size_to_slot(size: 0x3000)
// ARM10C 20140531
// size: 16
static int pcpu_size_to_slot(int size)
{
// size: 0x3000, pcpu_unit_size : 0x8000
// size: 16, pcpu_unit_size : 0x8000
if (size == pcpu_unit_size)
return pcpu_nr_slots - 1;
// size: 0x3000
// size: 16
return __pcpu_size_to_slot(size);
// __pcpu_size_to_slot(0x3000): 11
// __pcpu_size_to_slot(16): 1
}
percpu.c::__pcpu_size_to_slot()
// pcpu_size_to_slot(size: 0x8000)
// pcpu_size_to_slot(size: 0x3000)
static int __pcpu_size_to_slot(int size)
{
// size: 0x8000
// size: 0x3000
int highbit = fls(size); /* size is in bytes */
// highbit = 16
// highbit = 14
// PCPU_SLOT_BASE_SHIFT: 5
return max(highbit - PCPU_SLOT_BASE_SHIFT + 2, 1);
// max(13, 1) = 13
// max(11, 1) = 11
}
// pcpu_size_to_slot(size: 0x3000)
static int __pcpu_size_to_slot(int size)
{
// size: 0x8000
// size: 0x3000
int highbit = fls(size); /* size is in bytes */
// highbit = 16
// highbit = 14
// PCPU_SLOT_BASE_SHIFT: 5
return max(highbit - PCPU_SLOT_BASE_SHIFT + 2, 1);
// max(13, 1) = 13
// max(11, 1) = 11
}
percpu.c::*pcpu_alloc()
restart:
/* search through normal chunks */
// size: 16, pcpu_size_to_slot(16): 1, pcpu_nr_slots: 15
for (slot = pcpu_size_to_slot(size); slot < pcpu_nr_slots; slot++) {
// slot: 1~10
// list_for_each_entry 의 &chunk->list != (&pcpu_slot[slot]) 조건에 의해
// 수행 되지 않음
list_for_each_entry(chunk, &pcpu_slot[slot], list) {
-
list_for_each_entry(chunk, &pcpu_slot[slot], list) 를 정의를 풀어보자.
// #define list_for_each_entry(pos, head, member) \
// for (pos = list_first_entry(head, typeof(pos), member); \
// &pos->member != (head); \
// pos = list_next_entry(pos, member))
//
// for (chunk = list_first_entry(&pcpu_slot[1], typeof(chunk), list);
// &chunk->list != (&pcpu_slot[1]); chunk = list_next_entry(chunk, list))
//
// list_first_entry(&pcpu_slot[1])
//
// #define list_first_entry(ptr, type, member) \
// list_entry((ptr)->next, type, member)
//
// list_first_entry(&pcpu_slot[1], typeof(chunk), list):
// list_entry(&pcpu_slot[1]->next, typeof(chunk), list)
//
// #define list_entry(ptr, type, member) \
// container_of(ptr, type, member)
//
// container_of(&pcpu_slot[1]->next, typeof(*chunk), list)
-
list_for_each_entry(chunk, &pcpu_slot[slot], list) {
// for (chunk = list_first_entry(&pcpu_slot[1], typeof(*chunk), list);
// &chunk->list != (&pcpu_slot[1]); chunk = list_next_entry(chunk, list))
slot 1~10까지 list_for_each_entry는
&chunk->list != (&pcpu_slot[1])의 조건에 의해서
수행되지 않는다.
slot이 11일때 (dchunk로 값을 넣었음)
for (slot = pcpu_size_to_slot(size); slot < pcpu_nr_slots; slot++) {
// pcpu_size_to_slot: size:16
// slot: 1
list_for_each_entry(chunk, &pcpu_slot[slot], list) {
// for (chunk = list_first_entry(&pcpu_slot[1], typeof(*chunk), list);
// &chunk->list != (&pcpu_slot[1]); chunk = list_next_entry(chunk, list))
// chunk: &pcpu_slot[11]
// size: 16, chunk->contig_hint: &pcpu_slot[11]->contig_hint : 0x3000
//
if (size > chunk->contig_hint)
continue;
new_alloc = pcpu_need_to_extend(chunk);
restart:
/* search through normal chunks */
// size: 16, pcpu_size_to_slot(16): 1, pcpu_nr_slots: 15
for (slot = pcpu_size_to_slot(size); slot < pcpu_nr_slots; slot++) {
// slot: 1~10
// list_for_each_entry 의 &chunk->list != (&pcpu_slot[slot]) 조건에 의해
// 수행 되지 않음
list_for_each_entry(chunk, &pcpu_slot[slot], list) {
list_for_each_entry(chunk, &pcpu_slot[slot], list) 를 정의를 풀어보자.
// #define list_for_each_entry(pos, head, member) \
// for (pos = list_first_entry(head, typeof(pos), member); \
// &pos->member != (head); \
// pos = list_next_entry(pos, member))
//
// for (chunk = list_first_entry(&pcpu_slot[1], typeof(chunk), list);
// &chunk->list != (&pcpu_slot[1]); chunk = list_next_entry(chunk, list))
//
// list_first_entry(&pcpu_slot[1])
//
// #define list_first_entry(ptr, type, member) \
// list_entry((ptr)->next, type, member)
//
// list_first_entry(&pcpu_slot[1], typeof(chunk), list):
// list_entry(&pcpu_slot[1]->next, typeof(chunk), list)
//
// #define list_entry(ptr, type, member) \
// container_of(ptr, type, member)
//
// container_of(&pcpu_slot[1]->next, typeof(*chunk), list)
// #define list_for_each_entry(pos, head, member) \
// for (pos = list_first_entry(head, typeof(pos), member); \
// &pos->member != (head); \
// pos = list_next_entry(pos, member))
//
// for (chunk = list_first_entry(&pcpu_slot[1], typeof(chunk), list);
// &chunk->list != (&pcpu_slot[1]); chunk = list_next_entry(chunk, list))
//
// list_first_entry(&pcpu_slot[1])
//
// #define list_first_entry(ptr, type, member) \
// list_entry((ptr)->next, type, member)
//
// list_first_entry(&pcpu_slot[1], typeof(chunk), list):
// list_entry(&pcpu_slot[1]->next, typeof(chunk), list)
//
// #define list_entry(ptr, type, member) \
// container_of(ptr, type, member)
//
// container_of(&pcpu_slot[1]->next, typeof(*chunk), list)
list_for_each_entry(chunk, &pcpu_slot[slot], list) {
// for (chunk = list_first_entry(&pcpu_slot[1], typeof(*chunk), list);
// &chunk->list != (&pcpu_slot[1]); chunk = list_next_entry(chunk, list))
// for (chunk = list_first_entry(&pcpu_slot[1], typeof(*chunk), list);
// &chunk->list != (&pcpu_slot[1]); chunk = list_next_entry(chunk, list))
&chunk->list != (&pcpu_slot[1])의 조건에 의해서
수행되지 않는다.
slot이 11일때 (dchunk로 값을 넣었음)
for (slot = pcpu_size_to_slot(size); slot < pcpu_nr_slots; slot++) {
// pcpu_size_to_slot: size:16
// slot: 1
list_for_each_entry(chunk, &pcpu_slot[slot], list) {
// for (chunk = list_first_entry(&pcpu_slot[1], typeof(*chunk), list);
// &chunk->list != (&pcpu_slot[1]); chunk = list_next_entry(chunk, list))
// chunk: &pcpu_slot[11]
// size: 16, chunk->contig_hint: &pcpu_slot[11]->contig_hint : 0x3000
//
if (size > chunk->contig_hint)
continue;
new_alloc = pcpu_need_to_extend(chunk);
percpu.c::pcpu_need_to_extend()
// ARM10C 20140531
// chuck: &pcpu_slot[11]: dchunk: 4K만큼 할당 받은 주소
static int pcpu_need_to_extend(struct pcpu_chunk *chunk)
{
int new_alloc;
// chunk->map_alloc: dchunk->map_alloc: 128,
// chunk->map_used: dchunk->map_used: 2
if (chunk->map_alloc >= chunk->map_used + 2)
return 0;
// return 0 수행
new_alloc = PCPU_DFL_MAP_ALLOC;
while (new_alloc < chunk->map_used + 2)
new_alloc *= 2;
return new_alloc;
}
// chuck: &pcpu_slot[11]: dchunk: 4K만큼 할당 받은 주소
static int pcpu_need_to_extend(struct pcpu_chunk *chunk)
{
int new_alloc;
// chunk->map_alloc: dchunk->map_alloc: 128,
// chunk->map_used: dchunk->map_used: 2
if (chunk->map_alloc >= chunk->map_used + 2)
return 0;
// return 0 수행
new_alloc = PCPU_DFL_MAP_ALLOC;
while (new_alloc < chunk->map_used + 2)
new_alloc *= 2;
return new_alloc;
}
percpu.c::*pcpu_alloc()
for (slot = pcpu_size_to_slot(size); slot < pcpu_nr_slots; slot++) {
// slot: 1~10
// list_for_each_entry 의 &chunk->list != (&pcpu_slot[slot]) 조건에 의해
// 수행 되지 않음
list_for_each_entry(chunk, &pcpu_slot[slot], list) {
// for (chunk = list_first_entry(&pcpu_slot[slot], typeof(*chunk), list);
// &chunk->list != (&pcpu_slot[slot]); chunk = list_next_entry(chunk, list))
// chuck: &pcpu_slot[11]
// size: 16, chunk->contig_hint: (&pcpu_slot[11])->contig_hint: 0x3000
if (size > chunk->contig_hint)
continue;
// chuck: &pcpu_slot[11]: dchunk: 4K만큼 할당 받은 주소
new_alloc = pcpu_need_to_extend(chunk);
// new_alloc: 0
if (new_alloc) {
spin_unlock_irqrestore(&pcpu_lock, flags);
if (pcpu_extend_area_map(chunk,
new_alloc) < 0) {
err = "failed to extend area map";
goto fail_unlock_mutex;
}
spin_lock_irqsave(&pcpu_lock, flags);
/*
* pcpu_lock has been dropped, need to
* restart cpu_slot list walking.
*/
goto restart;
}
// chunk: &
off = pcpu_alloc_area(chunk, size, align);
if (off >= 0)
goto area_found;
}
}
for (slot = pcpu_size_to_slot(size); slot < pcpu_nr_slots; slot++) {
// slot: 1~10
// list_for_each_entry 의 &chunk->list != (&pcpu_slot[slot]) 조건에 의해
// 수행 되지 않음
list_for_each_entry(chunk, &pcpu_slot[slot], list) {
// for (chunk = list_first_entry(&pcpu_slot[slot], typeof(*chunk), list);
// &chunk->list != (&pcpu_slot[slot]); chunk = list_next_entry(chunk, list))
// chuck: &pcpu_slot[11]
// size: 16, chunk->contig_hint: (&pcpu_slot[11])->contig_hint: 0x3000
if (size > chunk->contig_hint)
continue;
// chuck: &pcpu_slot[11]: dchunk: 4K만큼 할당 받은 주소
new_alloc = pcpu_need_to_extend(chunk);
// new_alloc: 0
if (new_alloc) {
spin_unlock_irqrestore(&pcpu_lock, flags);
if (pcpu_extend_area_map(chunk,
new_alloc) < 0) {
err = "failed to extend area map";
goto fail_unlock_mutex;
}
spin_lock_irqsave(&pcpu_lock, flags);
/*
* pcpu_lock has been dropped, need to
* restart cpu_slot list walking.
*/
goto restart;
}
// chunk: &
off = pcpu_alloc_area(chunk, size, align);
if (off >= 0)
goto area_found;
}
}
percpu.c::pcpu_alloc_area()
// ARM10C 20140531
// chuck: &pcpu_slot[11]: dchunk: 4K만큼 할당 받은 주소, size: 16, align: 8
static int pcpu_alloc_area(struct pcpu_chunk *chunk, int size, int align)
{
// chuck: &pcpu_slot[11]: dchunk: 4K만큼 할당 받은 주소
// pcpu_chunk_slot(&pcpu_slot[11]): 11
int oslot = pcpu_chunk_slot(chunk);
// oslot: 11
int max_contig = 0;
// max_contig: 0
int i, off;
// chunk->map_used: dchunk->map_used: 2,
// chunk->map[0]: dchunk->map[0]: -(__per_cpu 실제 할당한 size + 0x2000)
for (i = 0, off = 0; i < chunk->map_used; off += abs(chunk->map[i++])) {
// [loop 1] i: 0, chunk->map_used: dchunk->map_used: 2,
// [loop 2] i: 1, chunk->map_used: dchunk->map_used: 2,
bool is_last = i + 1 == chunk->map_used;
// [loop 1] is_last: 0
// [loop 2] is_last: 1
int head, tail;
/* extra for alignment requirement */
// [loop 1] off: 0, align: 8
// [loop 2] off: __per_cpu 실제 할당한 size + 0x2000, align: 8
head = ALIGN(off, align) - off;
// [loop 1] head: 0
// [loop 2] head: 0
// [loop 1] i: 0, head: 0
// [loop 2] i: 0, head: 0
BUG_ON(i == 0 && head != 0);
// [loop 1] i: 0, chunk->map[0]: -(__per_cpu 실제 할당한 size + 0x2000)
// [loop 2] i: 1, chunk->map[1]: 0x3000
if (chunk->map[i] < 0)
continue;
// [loop 2] i: 1, chunk->map[1]: 0x3000, head: 0, size: 16
if (chunk->map[i] < head + size) {
max_contig = max(chunk->map[i], max_contig);
continue;
}
/*
* If head is small or the previous block is free,
* merge'em. Note that 'small' is defined as smaller
* than sizeof(int), which is very small but isn't too
* uncommon for percpu allocations.
*/
// [loop 2] i: 1, chunk->map[0]: -(__per_cpu 실제 할당한 size + 0x2000),
// [loop 2] head: 0, size: 16
if (head && (head < sizeof(int) || chunk->map[i - 1] > 0)) {
if (chunk->map[i - 1] > 0)
chunk->map[i - 1] += head;
else {
chunk->map[i - 1] -= head;
chunk->free_size -= head;
}
chunk->map[i] -= head;
off += head;
head = 0;
}
/* if tail is small, just keep it around */
// [loop 2] i: 1, chunk->map[1]: 0x3000, head: 0, size: 16
tail = chunk->map[i] - head - size;
// [loop 2] tail: 0x2ff0
// [loop 2] tail: 0x2ff0, sizeof(int): 4
if (tail < sizeof(int))
tail = 0;
// 2014/05/31 종료
// chuck: &pcpu_slot[11]: dchunk: 4K만큼 할당 받은 주소, size: 16, align: 8
static int pcpu_alloc_area(struct pcpu_chunk *chunk, int size, int align)
{
// chuck: &pcpu_slot[11]: dchunk: 4K만큼 할당 받은 주소
// pcpu_chunk_slot(&pcpu_slot[11]): 11
int oslot = pcpu_chunk_slot(chunk);
// oslot: 11
int max_contig = 0;
// max_contig: 0
int i, off;
// chunk->map_used: dchunk->map_used: 2,
// chunk->map[0]: dchunk->map[0]: -(__per_cpu 실제 할당한 size + 0x2000)
for (i = 0, off = 0; i < chunk->map_used; off += abs(chunk->map[i++])) {
// [loop 1] i: 0, chunk->map_used: dchunk->map_used: 2,
// [loop 2] i: 1, chunk->map_used: dchunk->map_used: 2,
bool is_last = i + 1 == chunk->map_used;
// [loop 1] is_last: 0
// [loop 2] is_last: 1
int head, tail;
/* extra for alignment requirement */
// [loop 1] off: 0, align: 8
// [loop 2] off: __per_cpu 실제 할당한 size + 0x2000, align: 8
head = ALIGN(off, align) - off;
// [loop 1] head: 0
// [loop 2] head: 0
// [loop 1] i: 0, head: 0
// [loop 2] i: 0, head: 0
BUG_ON(i == 0 && head != 0);
// [loop 1] i: 0, chunk->map[0]: -(__per_cpu 실제 할당한 size + 0x2000)
// [loop 2] i: 1, chunk->map[1]: 0x3000
if (chunk->map[i] < 0)
continue;
// [loop 2] i: 1, chunk->map[1]: 0x3000, head: 0, size: 16
if (chunk->map[i] < head + size) {
max_contig = max(chunk->map[i], max_contig);
continue;
}
/*
* If head is small or the previous block is free,
* merge'em. Note that 'small' is defined as smaller
* than sizeof(int), which is very small but isn't too
* uncommon for percpu allocations.
*/
// [loop 2] i: 1, chunk->map[0]: -(__per_cpu 실제 할당한 size + 0x2000),
// [loop 2] head: 0, size: 16
if (head && (head < sizeof(int) || chunk->map[i - 1] > 0)) {
if (chunk->map[i - 1] > 0)
chunk->map[i - 1] += head;
else {
chunk->map[i - 1] -= head;
chunk->free_size -= head;
}
chunk->map[i] -= head;
off += head;
head = 0;
}
/* if tail is small, just keep it around */
// [loop 2] i: 1, chunk->map[1]: 0x3000, head: 0, size: 16
tail = chunk->map[i] - head - size;
// [loop 2] tail: 0x2ff0
// [loop 2] tail: 0x2ff0, sizeof(int): 4
if (tail < sizeof(int))
tail = 0;
// 2014/05/31 종료
git log
Updating c43e50c..ce36365
Fast-forward
include/asm-generic/atomic-long.h | 1 +
include/linux/compiler.h | 1 +
include/linux/kernel.h | 1 +
include/linux/list.h | 10
include/linux/mm.h | 1 +
include/linux/page-flags.h | 10
include/linux/percpu.h | 2 +
include/linux/poison.h | 1 +
include/linux/slab.h | 10 +-
include/linux/slub_def.h | 7 +-
mm/highmem.c | 2 +
mm/percpu.c | 83 ++++-
mm/slab.h | 4 +-
mm/slub.c | 255 +-
14 files changed, 378 insertions(+), 10 deletions(-)
Fast-forward
include/asm-generic/atomic-long.h | 1 +
include/linux/compiler.h | 1 +
include/linux/kernel.h | 1 +
include/linux/list.h | 10
include/linux/mm.h | 1 +
include/linux/page-flags.h | 10
include/linux/percpu.h | 2 +
include/linux/poison.h | 1 +
include/linux/slab.h | 10 +-
include/linux/slub_def.h | 7 +-
mm/highmem.c | 2 +
mm/percpu.c | 83 ++++-
mm/slab.h | 4 +-
mm/slub.c | 255 +-
14 files changed, 378 insertions(+), 10 deletions(-)
댓글 없음:
댓글 쓰기