[커널 17차] 82주차

2022.03.27 00:17

ㅇㅇㅇ 조회 수:65

리눅스 커널 lock 종류
- https://blog.daum.net/tlos6733/162

 

kmalloc() <—> kfree() vs. kmem_cache_alloc() <—> kmem_cache_free()
- 둘 다 slab에서 메모리를 할당받고 해제하는 역할을 한다
- 차이점은 kmalloc은 사이즈에 기반에서 일반적인 메모리를 할당/해제하지만
- kmem_cache_alloc은 커널에서 자주 사용되는 특수 자료구조에 대한 메모리를 할당/해제한다
- 또한 kmalloc/kfree는 큰 사이즈에 대해서 buddy로 직접 연결해주는 path가 존재한다

 

slab_free()
- 함수 slab_free_freelist_hook()로 head와 tail로 연결된 freelist 순서를 뒤집는다
- KASAN이 켜져 있는 경우엔 해제하면 안되는 object는 freelist에서 배제하고 넘겨준다
- 이후 함수 do_slab_free()에서 head ~ tail에 해당하는 object를 해제해준다

 

slab_free_freelist_hook()
- head ~ tail에 해당하는 object를 받아서 list 순서를 반대로 설정하고 리턴한다
- 함수 slab_free_hook()는 KASAN이 설정되어 있는 경우 KASAN 체크가 실패한 object는 리스트에서 제외하고 제외된 object 수만큼 count를 줄여주는 역할을 한다

 

do_slab_free()
- head ~ tail 까지의 object를 받아서 할당 해제한다 (#object = cnt)
- 우선 fastpath로 c->freelist에 head ~ tail을 반환시도한다
- 즉 원래 c->page->freelist -> obj1 -> obj2 -> obj3 -> NULL 이면 해제 이후에는 c->freelist -> head -> … -> tail -> obj1 -> obj2 -> obj3 -> NULL이 된다
- 만약 page와 c->page가 다르면 slowpath를 타게 되며 함수 __slab_free()를 호출한다

- L3433 : pcpu slab cache인 s->cpu_slab을 가져온다
- L3437 : barrier() 호출
- L3439 : page == c->page인 경우 fastpath를 수행한다
- L3441 : c->freelist를 가져온다
- L3443 : tail object 뒤에 c->freelist를 달아준다
- L3445 : cmpxchg_double()을 이용해서 c->freelist와 c->tid를 각각 head와 next tid로 업데이트한다
- L3451 : 실패하면 재시도한다

- L3453 : RT이므로 생략. 기본적으로 동작은 동일하며 다만 cmpxchg 대신 cpu_slab->lock을 사용한다
- L3480 : page != c->page인 경우 함수 __slab_free()를 사용해서 slowpath로 이동한다

 

__slab_free()
- L3297 : kfence check 수행
- L3300 : 디버그 체크 수행. 디버그 설정하지 않는 경우에는 패스
- L3304 : 메인 코드 수행

 

1) 타 cpu의 page->freelist로 반환하는 경우
- 이 경우는 현재 cpu의 c->page가 아닌 다른 cpu의 page로 반환하는 경우이다
- L3309 : page->freelist를 가져온다
- L3310 : page->counters를 가져온다
- L3311 : tail 다음에 page->freelist를 붙인다
- L3312 : new page의 counters를 page->counters로 가져온 뒤 inuse를 cnt 만큼 줄여준다. 또한 page->frozen을 was_frozen으로 가져온다
- L3315 : 타 cpu의 page이므로 was_frozen = 1이다. 따라서 if 문 스킵
- L3343 : page->freelist를 head로, page->inuse로 cmpxchg로 업데이트한다
- L3348 : n == NULL이므로 진입
- L3350 : was_frozen == 1이므로 아무것도 하지 않고 리턴한다

 

2) page가 어느 cpu에도 속하지 않는 경우(not frozen)이고, 동시에 page->freelist가 비어 있었을 경우
- L3309 : page->freelist를 가져온다
- L3310 : page->counters를 가져온다
- L3311 : tail 다음에 page->freelist를 붙인다
- L3312 : new page의 counters를 page->counters로 가져온 뒤 inuse를 cnt 만큼 줄여준다. 또한 page->frozen을 was_frozen으로 가져온다
- L3315 : was_frozen == 0이다. 여기서 page->freelist가 비어있었으므로 if 문을 탄다
- L3317 : page->freelist가 비어있었으므로 if 문을 탄다
- L3325 : new.frozen = 1로 세팅하여 cpu partial list로 보낼 준비를 한다
- L3343 : page->freelist를 head로, page->inuse로 cmpxchg로 업데이트한다
- L3348 : n == NULL이므로 if 문 진입
- L3356 : was_frozen == 0 이고 new.frozen == 1이므로 else if 문 진입
- L3361 : 함수 put_cpu_partial()로 page를 cpu partial list에 추가하고 리턴한다

 

3) page가 어느 cpu에도 속하지 않는 경우(not frozen)이고, 동시에 page->freelist가 비어 있지 않았고, page에 모든 object가 반환되어 inuse == 0이 되는 경우
- L3309 : page->freelist를 가져온다
- L3310 : page->counters를 가져온다
- L3311 : tail 다음에 page->freelist를 붙인다
- L3312 : new page의 counters를 page->counters로 가져온 뒤 inuse를 cnt 만큼 줄여준다. 또한 page->frozen을 was_frozen으로 가져온다
- L3315 : was_frozen == 0이고 new.inuse == 0 이므로 if 문을 탄다
- L3327 : page->freelist가 비어 있지 않았으므로 else 문 이동
- L3329 : page의 노드를 가져온다
- L3338 : 해당 노드의 partial list lock을 잡는다
- L3343 : page->freelist를 head로, page->inuse로 cmpxchg로 업데이트한다
- L3348 : n != NULL 이므로 if 문은 패스
- L3368 : new.inuse == 0이고 동시에 n->nr_partial 보다 s->min_partial이 더 큰 경우 slab_empty로 이동하여 buddy로 반환한다
- L3375 : cpu partial이 존재하므로 패스
- L3380 : 노드 partial list lock을 푼다
- L3381 : 리턴한다
- L3383 : 만약 new.inuse == 0이고 동시에 n->nr_partial 보다 s->min_partial이 더 커서 slab에서 buddy로 해당 page를 반환해야 하는 경우이다
- L3384 : 만약 원래 page->freelist에 object가 있었다면 해당 page는 node partial list에 달려 있었으므로 제거한다.
- L3390 : object가 없었다면 해당 page는 node full list에 달려 있었으므로 제거한다
- L3395 : 노드 partial list lock을 푼다
- L3397 : discard_slab() 함수로 page를 버디로 반환한다

 

discard_slab()
- 함수 dec_slabs_node()로 n->nr_slabs를 1 감소시키고, n->total_objects도 objects 수만큼 감소시킨다
- 함수 free_slab()로 page를 버디로 반환한다

 

free_slab()
- 함수 __free_slab()로 page를 buddy로 반환한다

 

__free_slab()
- L1976 : page의 order와 개수를 계산한다
- L1979 : 디버그 플래그에 consistency check가 켜져 있으면 slab pad를 체크하고 페이지의 각 오브젝트에 대해서 오브젝트 체크를 수행한다
- L1988 : page의 pfmemalloc page flag를 클리어한다
- L1989 : page의 slab page flag를 클리어한다
- L1991 : page->slab_cache = NULL로 지워준다
- L1992 : current->reclaim_state == true이면 current->reclaim_state->reclaimed_slab에 page 수를 더해준다
- L1994 : 함수 unaccount_slab_page()로 cgroup accounting을 수행하고, vmstat을 조정한다
- L1995 : 함수 __free_pages()로 버디로 페이지를 반환한다

 

kfree()
- L4544 : 오브젝트가 zero 또는 null pointer인 경우 그냥 리턴
- L4547 : 오브젝트로부터 헤드 페이지를 가져온다
- L4548 : 페이지가 슬랩 페이지가 아니면 함수 free_nonslab_page()로 페이지를 버디에서 해제한다
- L4552 : 슬랩페이지인 경우 함수 slab_free()로 오브젝트를 해제한다

 

free_nonslab_page()
- 함수 mod_lruvec_page_state()로 vmstat을 조정한다
- 함수 __free_pages()로 버디로 페이지를 반환한다

 

kmem_cache_alloc_bulk()
- 요청한 개수의 object를 할당해서 반환한다

- L3647 : 함수 slab_pre_alloc_hook()에서 memcg 및 debug 설정을 수행한다
- L3655 : preempt_disable() 및 cpu slab c를 가져온다
- L3656 : irq disable을 수행한다
- L3658 : 할당 요청된 object 수에 따라 루프를 돌면서 할당 수행
- L3666 : c->freelist에서 object를 가져온다
- L3667 : c->freelist가 NULL인 경우 slowpath로 이동한다
- L3675 : c->tid를 업데이트한다
- L3677 : irq enable() 수행
- L3683 : 함수 ___slab_alloc()로 object를 받아와서 p 배열에 저장
- L3688 : cpu slab c를 다시 가져온다. 이는 함수 ___slab_alloc() 내에서 migration이 가능하기 때문이다.
- L3689 : init on alloc 등을 처리한다
- L3691 : irq disable() 수행
- L3693 : continue로 다음 for loop로 이동
- L3695 : c->freelist에서 첫 object 제거
- L3696 : c->freelist 첫 object를 p 배열에 저장
- L3697 : init on alloc 수행
- L3699 : c->tid를 업데이트한다
- L3700 : irq enable()
- L3701 : preempt enable()
- L3706 : 함수 slab_post_alloc_hook()로 memory init 및 memcg/debug support를 수행한다
- L3709 : 할당 성공한 object 개수를 리턴한다

번호 제목 글쓴이 날짜 조회 수
공지 [공지] 스터디 정리 노트 공간입니다. woos 2016.05.14 627
128 [커널 17차] 94주차 ㅇㅇㅇ 2022.06.19 80
127 [커널 18차] 56주차 kkr 2022.06.18 71
126 [커널 17차] 92~93주차 ㅇㅇㅇ 2022.06.11 93
125 [커널 18차] 54주차 kkr 2022.06.04 82
124 [커널 19차] 3주차 리턴 2022.06.04 217
123 [커널 18차] 53주차 kkr 2022.05.29 93
122 [커널 17차] 91주차 ㅇㅇㅇ 2022.05.28 64
121 [커널 19차] 2주차 리턴 2022.05.28 169
120 [커널 17차] 90주차 ㅇㅇㅇ 2022.05.22 149
119 [커널 18차] 52주차 kkr 2022.05.21 124
118 [커널 19차] 1주차 리턴 2022.05.16 456
117 [커널 17차] 89주차 ㅇㅇㅇ 2022.05.15 65
116 [커널 18차] 51주차 kkr 2022.05.14 159
115 [커널 18차] 50주차 kkr 2022.05.10 207
114 [커널 17차] 88주차 ㅇㅇㅇ 2022.05.08 101
113 [커널 19차] 0주차 - 오리엔테이션 리턴 2022.05.07 600
112 [커널 17차] 86~87주차 ㅇㅇㅇ 2022.04.30 101
111 [커널 17차] 84~85주차 JSYoo5B 2022.04.16 86
110 [커널 17차] 83주차 ㅇㅇㅇ 2022.04.03 92
» [커널 17차] 82주차 ㅇㅇㅇ 2022.03.27 65
XE Login