티스토리 뷰

4-114

create_kmalloc_caches

kmalloc 캐시를 CACHE_BYTES 부터 배수로 미리 생성

3 부터 2의 배수로 사용하고 0,1 은 96, 192 사이즈

KMALLOC_MIN_SIZE : 캐시 라인 크기

4-115

create_kmalloc_cache

kmem_cache_zalloc: zalloc 은 0으로 모두 set 한다는 의미 -> 452 페이지에서 다시 나옴

kmem_cache 구조체를 할당하기 위한 kmem_cache 객체를 사용. 이것 또한 keme_cache 를 받는 slab 에서 받아오는 것

4.7.4 kmem 캐시 생성 (p426)

4-116

kmem_cache_create

kmem 캐시를 생성

4-117

_kmem_cache_alias

이전에 만들어둔 kmem 캐시와 병합이 가능하다면 해당 kmem 캐시의 object size, inuse(워드 단위 정렬)  를 갱신하고 리턴한다.

#define for_each_memcg_cache(iter, root) \
    list_for_each_entry(iter, &(root)->memcg_params.list, \
                memcg_params.list)

-> memcg_cache 가 정확히 뭔지는 모르겠으나, kmem_cache 에 memcg_params 가 있음. 이것도 kmem_cache 이고 똑같이 정렬4-114
-> kmem_cache 는 글로벌 캐시이고, memcg_params 는 메모리 그룹별 캐시인건가?

4-118

find_mergeable

kmem cache 의 병합 조건

  • slub_nomerge, SLAB_NEVER_MERGE 를 사용중이면 안됨
  • 객체에 생성자를 붙여서 사용중이면 안됨
  • 루트 캐시가 아니어야 함
  • align size 가 동일해야함 등등
struct kmem_cache {
  size: object_size 에 metadata 와 함께 align 맞춘 값 calculate_sizes 에서 지정됨
}

4-119

sysfs_slab_alias

같은 slab cache 를 사용할 수 있다면 링크로 연결, 아직 부팅 프로세스 중이라면 지연처리

struct kobject {
    struct kernfs_node    *sd; /* sysfs directory entry */
}

이후에 at dt 등 심볼릭 링크의 이름은 slub.c 의 create_unique_id 에서 정해지는 듯 하다

ls /sys/kernel/slab/ -l | grep 4096
lrwxrwxrwx 1 root root 0 11월  9 17:18 names_cache -> :t-0004096
lrwxrwxrwx 1 root root 0 11월  9 17:18 sgpool-128 -> :t-0004096

4-120

create_cache

다른 kmem_cache 를 사용할 수 없을때 생성

s = kmem_cache_zalloc(kmem_cache, GFP_KERNEL); // kmem_cache 를 생성
err = __kmem_cache_create(s, flags);

4-121

__kmem_cache_create

생성된 cache 를 초기화 하고, kmem 캐시 디렉토리에 추가한다.

memcg_propagate_slab_attrs -> root kmem_cache 의 attribute 를 복사

static struct attribute *slab_attrs[] = {
    &slab_size_attr.attr,
    &object_size_attr.attr,

각 항목은 매크로로 정의되어 있음. 결국 slab_attribute 라는 구조체가 나옴

SLAB_ATTR_RO(object_size);
#define SLAB_ATTR_RO(_name) \
    static struct slab_attribute _name##_attr = \
    __ATTR(_name, 0400, _name##_show, NULL)

struct slab_attribute {
    struct attribute attr;
    ssize_t (*show)(struct kmem_cache *s, char *buf);                           // kmem_cache -> buf
    ssize_t (*store)(struct kmem_cache *s, const char *x, size_t count); // x-> s
};

sysfs_slab_add: filesystem 에 slab cache 를 추가

kset -> filesystem 에서 사용하는 타입같은걸로 보임

static struct kset ext4_kset = {
    .kobj   = {.ktype = &ext4_ktype},
};

kobject_init_and_add - initialize a kobject structure and add it to the kobject hierarchy
커널 객체를 그룹화 하기 위한게 kset 이고 kobject 에 kset 을 설정 할 수 있음

__kmem_cache_release : cpu 와 node 의 캐시를 클리어해줌

4-122

kmem_cache_open

생성된 kmem cache 를 초기화

슬랩 페이지의 해제를 RCU 방식을 사용하는 경우, 해제가 더 빠르지만 구현이 복잡하다. RCU 를 사용하는 경우 reserve 에 rcu head 크기를 설정한다.
    if (need_reserve_slab_rcu && (s->flags & SLAB_DESTROY_BY_RCU))
        s->reserved = sizeof(struct rcu_head);

kmem_cache->min_partial 은 뭘까? 객체의 size 를 표현하는데 필요한 비트수의 절반을 저장함
 - min_partial: 미리 생성해둘 객체수 정도 인 것 같다.  (페이지 수인지 객체수인지는 좀더 봐야겠지만 일단은 객체수로)
kmem_cache->cpu_partial 은 뭘까? 이것도 size 에 따라 결정됨
 - 각 CPU는 자신만의 cpu_partial 리스트를 유지하여, 다른 CPU들과의 경쟁을 최소화하고 메모리 할당을 최적화

calculate_sizes

kmem_cache 의 size 를 계산한다.

SLAB_RED_ZONE: object 뒤에 무조건 padding 비슷한 redzone 을 둠. 따라서 size = object_size 라면 word 하나만큼 추가
그 외에도 옵션에 따라 size 에 metadata 를 추가


static inline struct kmem_cache_order_objects oo_make(int order, unsigned long size, int reserved)
oo = order_objects

calculat_order(int size, int reserved)

calculate_sizes 에서 order 를 계산중
object 를 최소 몇개정도 넣을 수 있는 페이지 order 를 구한다

몇개나 object 가 들어갈 수 있는지 표현하는 것 같다.
static inline int order_objects(int order, unsigned long size, int reserved)
{
    return ((PAGE_SIZE << order) - reserved) / size;
}

max_objects = order_objects(slub_max_order, size, reserved); // 들어갈 수 있는 최대
min_objects = min(min_objects, max_objects); // 최소 개수 정해두기

slab_order(size, min_objects, slub_max_order, fraction, reserved)
fraction: 허용할 수 있는 "낭비"의 비율

4-123

init_kmem_cache_nodes

노드를 돌면서 kmem cache 를 설정한다. 아직 부팅중이라면 버디를 사용, 그렇지 않다면 슬랩을 사용한다.

4-124

slub.c early_kmem_cache_node_alloc

slab 할당자가 활성화 되기 전, 캐시 노드를 초기화 하기 위해 버디 시스템을 사용한다.

page = new_slab(kmem_cache_node, GFP_NOWAIT, node); // 버디에서 슬랩용 페이지를 가져온다.

이때 page 의 설정을 바꿔줌

page->freelist = fixup_red_left(s, start);
page->inuse = page->objects;
page->frozen = 1; // freelist 를 직접 관리하겠다는 의미

static inline void *get_freepointer(struct kmem_cache *s, void *object)
{
    return *(void **)(object + s->offset);
} // -> 448페이지의 그림 참고. offset 을 더하면 FP(Free Pointer)

n = page->freelist; 이 freelist 는 이미 버디용이 아니라 slap 용임.
BUG_ON(!n);
page->freelist = get_freepointer(kmem_cache_node, n); 처음 비어있는 객체의 주소를 설정
page->inuse = 1; 
page->frozen = 0; // 다시 unfrozen 하는 이유?
kmem_cache_node->node[node] = n;
댓글