[커널 17차] 82주차
2022.03.27 00:17
리눅스 커널 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 개수를 리턴한다
댓글 0
번호 | 제목 | 글쓴이 | 날짜 | 조회 수 |
---|---|---|---|---|
공지 | [공지] 스터디 정리 노트 공간입니다. | 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 |
.