[커널 17차] 99주차

2022.07.31 19:10

ㅇㅇㅇ 조회 수:35

lru_add_drain_cpu() 계속
- L596 : 함수 __pagevec_lru_add()로 lru_add pagevec에 있는 page들을 lruvec으로 flush한다
- L599 : pagevec lru_rotate를 받는다
- L601 : lru_rotate pagevee count가 0보다 크면 if 문에 진입한다. data_race()는 kcsan (kernel concurrency sanitizer)를 잠시 끄고 괄호 안의 expression을 수행한 뒤 다시 켜는 구문이다
- L606 : 함수 pagevec_lru_move_fn()와 pagevec_move_tail_fn()으로 lru_rotate pagevec에 있던 page들을 inactive lruvec의 tail로 flush한다. 이렇게 tail로 보내는 것을 rotation이라고 부르고 있다.
- L610 : pagevec lru_deactivate_file에 대해서 동일하게 flush를 수행한다. 함수 lru_deactivate_file_fn()를 사용한다
- L614 : pagevec lru_deactivate에 대해서 flush 수행. 함수 lru_deactivate_fn() 사용
- L618 : pagevec lru_lazyfree에 대해 flush 수행. 함수 lru_lazyfree_fn() 사용
- L622 : 함수 activate_page_drain()로 pagevec activate_page에 대해서 flush를 수행한다. 함수 __activate_page()이 사용된다.

 

pagevec_lru_move_fn()
- L189 : pagevec에 있는 page들에 대해서 루프를 돈다
- L193 : TestClearPageLRU() 함수로 page의 PageLRU가 clear되어 있었으면 continue로 다음 page로 넘어간다. Set되어 있으면 clear하고 아래로 내려간다
- L196 : page에 해당하는 lruvec lock을 잡는다
- L197 : 함수 포인터 인자로 들어온 move_fn()을 수행한다
- L199 : PageLRU를 set해준다
- L201 : lruvec lock을 해제한다
- L203 : 함수 release_pages()로 pagevec의 page들의 refcount를 1 감소시키고 0이 된 page들은 free시킨다
- L204 : pagevec->nr을 0으로 초기화한다

 

pagevec_move_tail_fn()
- L209 : page가 evictable일 때만 코드 수행
- L210 : page를 lruvec에서 제거
- L211 : ClearPageActive()
- L212 : page를 lruvec tail에 추가

 

lru_deactivate_file_fn()
- 인자로 page와 lruvec을 받는다
- L510 : page의 PageActive() bit을 가져온다
- L511 : page의 page 수를 가져온다. Compound이면 THP로 가정하여 512, 아니면 1개 페이지이다. pagevec에서는 compound page = THP로 가정하는 것으로 보인다
- L517 : page가 mapping되어 있는 경우 그냥 나간다. 함수 page_mapped() 매핑 여부를 판단한다
- L520 : lruvec에서 page를 제거한다
- L521 : ClearPageActive / ClearPageReferenced 수행
- L524 : PageWriteback 또는 PageDirty가 set되어 있으면 lurvec head로 page 추가하고 SetPageReclaim() 수행
- L532 : 아니면 lruvec tail에 page 추가한다

 

lru_deactivate_fn()
- L550 : page가 active이고 evictable이면 if 문 수행. 아니면 그냥 리턴
- L551 : page 수를 받아온다
- L553 : lurvec에서 page 제거
- L554 : ClearPageActive(), ClearPageReferenced()
- L556 : lurvec head에 page 추가

 

lru_lazyfree_fn()
- L566 : page가 anon이고 PageSwapBacked()이고 swap cache가 아니면서 evictable이면 코드 수행. 아니면 그냥 리턴
- L568 : page 수 받아온다
- L570 : lruvec에서 page 제거
- L571 : ClearPageActive(), ClearPageReferenced()
- L578 : ClearPageSwapBacked()
- L579 : lruvec head에 page 추가

 

activate_page_drain()
- L317 : pagevec activate_page를 받아온다
- L319 : 함수 __activate_page()로 flush를 수행한다

 

__activate_page()
- L300 : page가 non active이고 evictable인 경우에만 코드 수행
- L301 : page 수 받아옴
- L303 : lruvec에서 page 제거
- L304 : SetPageActive()
- L305 : lruvec head에 page 추가

 

page_mapped()
- L682 : page가 compound가 아닌 경우 page->_map_count가 0보다 같거나 크면 true 아니면 false 리턴
- L684 : compound head page를 가져옴
- L685 : page의 compound mapcount를 가져와서 0보다 같거나 크면 true를 리턴한다
- L687 : page가 hugetlbfs page인 경우는 false 리턴
- L689 : 아니면 page 중에서 하나라도 _map_count가 0 이상이면 true를 리턴한다
- L693 : 모든 page가 -1이면 false 리턴
- 참고로 page의 map count는 시작이 -1이고 mapping이 하나씩 늘 때마다 1 증가한다
- 주석에 따르면 이는 atomic_inc_and_test 및 atomic_add_negative를 이용해서 mapping tracking을 하기 위해서이다

PageSwapBacked()
- page가 swapbacked이 아니면 file page 취급한다


lru_cache_add()
- lruvec에 처음으로 page 추가될 때 부르는 함수로, 일단 pagevec lru_add에 추가한다
- L449 : get_page()로 page->_refcount를 1 증가
- L451 : pagevec lru_add를 가져온다
- L452 : 함수 pagevec_add_and_need_flush()를 이용, lru_add pagevec에 page를 추가한다
- L453 : 만약 pagevec에서 lruvec으로 flush할 필요가 있으면 함수 __pagevec_lru_add()로 flush 수행

 

pagevec_add_and_need_flush()
- pagevec pvec에 page를 추가하고, flush가 필요한지를 리턴한다
- L222 : 함수 pagevec_add()로 page를 pvec에 추가하고, pvec이 다 찼거나, page가 compound이거나 (이건 아마 THP여서 page 수가 512나 되기 때문으로 보임), pagevec 자체를 안쓰는 상황이면 true를 리턴한다. 아니면 false 리턴

 

pagevec_add()
- L74 : page를 pagevec pvec에 추가하고 pvec->nr를 1 증가
- L75 : PAGEVEC_SIZE (= 15) - pvec->nr 을 리턴한다

 

mark_page_accessed()
- 인자 page가 access된 경우 사용되는 함수
- L404 : page의 compound head를 가져온다
- L406 : referenced가 아닌 경우 SetPageReferenced() 수행
- L408 : referenced이고 unevictable이면 아무것도 안함
- L414 : referenced + inactive이면 아래에서 처리
- L421 : PageLRU set이면 activate_page()로 pagevec activage_page에 추가
- L424 : PageLRU clear이면 이미 pagevec에 추가되었다고 보고 __lru_cache_activate_page() 함수로 해당 page를 찾아 SetPageActive() 수행. 만약 다른 CPU의 pagevec에 속한 page였을 경우엔 아무것도 수행되지 않는다
- L425 : referenced clear
- L426 : workingset_activation() 함수로 현 lruvec의 nonresident age를 page의 thp_nr_pages() 만큼 더해준다. 이는 memcg를 타고 올라가 모든 parent memcg lruvec에도 적용한다
- L428 : 원래 page가 idle이었으면 idle PG를 clear한다


- 결론적으로 아래와 같이 처리된다
- inactive,unreferenced    ->  inactive,referenced
- inactive,referenced      ->  active,unreferenced
- active,unreferenced      ->  active,referenced

 

activate_page()
- 인자로 page를 받아 pagevec activate_page에 추가하고 필요시 lruvec으로 flush한다
- L330 : page의 compound head를 가져온다
- L331 : PageLRU가 참이고, nonactive이면서 evictable인 경우에만 동작하고 아니면 그냥 리턴
- L335 : pagevec activate_page를 가져온다
- L336 : page의 refcount 1 증가
- L337 : pagevec_add_and_need_flush()로 page를 pagevec activate_page에 추가한다
- L338 : 필요시 pagevec_lru_move_fn(), __activate_page()로 lruvec에 flush 수행

 

__lru_cache_activate_page()
- 인자로 받은 page를 pagevec lru_add에서 찾아서 active로 변경한다
- 찾는 순서는 pagevec index의 반대 순서
- 못 찾으면 아무것도 하지 않고 종료

 

workingset_activation()
- 인자로 page를 받는다
- L403 : rcu read lock을 잡는다
- L411 : page에 해당하는 memcg를 찾는다
- L412 : memcg가 없거나 mem cgroup이 disable이면 rcu read lock 풀고 그냥 리턴
- L414 : page에 해당하는 lruvec을 구한다
- L415 : 함수 workingset_age_nonresident()로 lruvec의 nonresident age를 page의 thp_nr_pages() 수만큼 증가시킨다
- L417 : rcu read lock 풀고 리턴

 

workingset_age_nonresident()
- L243 : 인자로 lruvec과 nr_pages를 받아서 lruvec->nonresident_age에 nr_pages를 더한다
- L244 : 이를 lruvec의 모든 부모 lruvec에 대해 반복한다

 

lru_cache_add_inactive_or_unevictable()
- 인자로 page와 vm_area_struct vma를 받아서 page를 적절한 pagevec에 추가한다
- L473 : vm flags를 보고 page가 unevictable인지 판정한다
- L481 : unevictable이면 관련 accounting 처리를 수행한다
- L484 : 함수 lru_cache_add()로 pagevec에 page를 추가한다

 

deactivate_file_page()
- 파일 페이지를 강제로 deactivate 한다
- L639 : page가 evictable이면 그냥 리턴
- L642 : 함수 get_page_unless_zero()로 page refcount가 0이 아니면 1 증가시키고 0이면 그냥 나간다
- L646 : pagevec lru_deactivate_file을 잡는다
- L648 : 함수 pagevec_add_and_need_flush()로 pagevec lru_deactivate_file에 page를 추가한다
- L649 : flush 필요하면 함수 lru_deactivate_file_fn()로 flush

 

deactivate_page()
- 페이지를 deactivate 한다
- L664 : PageLRU 이고 active 이면서 evictable일 때만 함수 수행하고 아니면 리턴
- L668 : pagevec lru_deactivate을 잡는다
- L669 : get_page()로 refcount 1 증가
- L670 : 함수 pagevec_add_and_need_flush()로 pagevec lru_deactivate에 page를 추가한다
- L671 : flush 필요하면 함수 lru_deactivate_fn()로 flush

 

mark_page_lazyfree()
- 인자로 넘어온 anon page를 lazy free로 만든다
- L685 : page가 LRU, anon, swapbacked이고 swapcache가 아니고 evictable이면 함수 수행. 아니면 그냥 리턴
- L690 : pagevec lru_lazyfree를 가져온다
- L691 : get_page()로 refcount 1 증가
- L692 : 함수 pagevec_add_and_need_flush()로 pagevec lru_lazyfree에 page를 추가한다
- L693 : flush 필요하면 함수 lru_lazyfree_fn()로 flush

 

rotate_reclaimable_page()
- L238 : page가 locked, dirty가 아니고 evictable 및 LRU 일 때 함수 수행. 아니면 그냥 리턴
- L243 : get_page()로 refcount 1 증가
- L245 : pagevec lru_rotate를 가져온다
- L246 : 함수 pagevec_add_and_need_flush()로 pagevec lru_rotate에 page를 추가한다
- L247 : flush 필요하면 함수 pagevec_move_tail_fn()로 flush

 

각 pagevec flush 함수 부르는 경로

1. lru_cache_add() —> __pagevec_lru_add()

 

2. bdev_write_page() —> end_page_writeback() —> rotate_reclaimable_page() —> pagevec_lru_move_fn () —> pagevec_move_tail_fn()
- Reclaim 요청된 page가 write back 수행 중이었으면 기다렸다가 끝난 이후 reclaim clear하고 rotate_reclaimable_page()로 inactive list tail로 보내서 reclaim 유도한다

 

3. invalidate_mapping_pages() —> __invalidate_mapping_pages() —> deactivate_file_page() —> pagevec_lru_move_fn () —> lru_deactivate_file_fn()

 

4. madvise_cold_or_pageout_pte_range() —> deactivate_page() —> pagevec_lru_move_fn() —> lru_deactivate_fn()
- madvise를 통해 cold 인지 pageout인지 hint를 주면, cold인 경우에는 deactivate_page()를 주어서 page를 deactivate 하고, pageout인 경우엔 reclaim_pages()를 수행한다

 

5. madvise_free_pte_range() 또는 madvise_free_huge_pmd() —> mark_page_lazyfree() —> pagevec_lru_move_fn() —> lru_lazyfree_fn()
- madvise를 통해 free가 들어오면 pte AF / Dirty (SW/HW 모두) 인 경우 1) af clear, 2) dirty clear, 3) read only set 수행하고 mark_page_lazyfree()로 reclaim 유도
- madvise로 free hint 줘서 mark_page_lazyfree() 수행되고 inactive list에 들어간다음에 다시 write 하면?
- 이 경우엔 reclaim 시 try_to_unmap_one()에서 dirty가 아닌 경우에만 discard (reclaim) 하고 아니면 다시 swapbacked으로 만들어서 다시 page table로 remap하게 된다 (L1572)
- shrink_inactive_list() —> shrink_page_list() —> try_to_unmap() —> try_to_unmap_one()


MADV_FREE
- https://manpages.ubuntu.com/manpages/bionic/man2/madvise.2.html

 

activate_page_drain() 함수 batch 처리
- https://github.com/torvalds/linux/commit/744ed1442757767ffede5008bb13e0805085902e
- https://github.com/torvalds/linux/commit/7a608572a282a74978e10fd6cd63090aebe29f5c
- https://github.com/torvalds/linux/commit/eb709b0d062efd653a61183af8e27b2711c3cf5c#

 

DBM 기능
- https://developer.arm.com/documentation/102376/0100/Access-Flag
- https://developer.arm.com/documentation/ddi0595/2020-12/AArch64-Registers/TCR-EL1--Translation-Control-Register--EL1-?lang=en#fieldset_0-39_39-1

 

PTE 포맷
- https://developer.arm.com/documentation/102376/0100/Describing-memory-in-AArch64

번호 제목 글쓴이 날짜 조회 수
공지 [공지] 스터디 정리 노트 공간입니다. woos 2016.05.14 626
148 [커널 17차] 103주차 ㅇㅇㅇ 2022.08.28 35
147 [커널 18차] 66주차 kkr 2022.08.27 76
146 [커널 17차] 101~102주차 ㅇㅇㅇ 2022.08.21 47
145 [커널 18차] 65주차 kkr 2022.08.20 28
144 [커널 18차] 64주차 kkr 2022.08.13 75
143 [커널 17차] 100주차 [1] ㅇㅇㅇ 2022.08.06 100
142 [커널 18차] 63주차 kkr 2022.08.06 102
» [커널 17차] 99주차 ㅇㅇㅇ 2022.07.31 35
140 [커널 18차] 62주차 kkr 2022.07.30 26
139 [커널 17차] 97~98주차 ㅇㅇㅇ 2022.07.24 52
138 [커널 18차] 61주차 kkr 2022.07.23 113
137 [커널 18차] 60주차 kkr 2022.07.16 129
136 [커널 17차] 95~96주차 ㅇㅇㅇ 2022.07.10 105
135 [커널 18차] 59주차 kkr 2022.07.09 126
134 [커널 19차] 8주차 kanlee 2022.07.02 160
133 [커널 19차] 7주차 kanlee 2022.07.02 95
132 [커널 19차] 6주차 kanlee 2022.07.02 42
131 [커널 19차] 5주차 kanlee 2022.07.02 38
130 [커널 19차] 4주차 kanlee 2022.07.02 106
129 [커널 18차] 57주차 kkr 2022.06.25 129
XE Login