[커널 17차] 107 ~ 111주차

2022.10.23 16:08

ㅇㅇㅇ 조회 수:71

2022/09/24 : 107주차
2022/10/01 : 108주차 (휴식)
2022/10/08 : 109주차
2022/10/15 : 110주차
2022/10/22 : 111주차

 

문C블로그 swap
- http://jake.dothome.co.kr/swap-1/

 

Xarray
- https://www.kernel.bz/boardPost/118679/19
- https://velog.io/@mythos/Linux-Tutorial-21-XArray
- https://lwn.net/Articles/745073/

 

shrink_page_list()
- L1534 : demote 관련으로 pass <— 여기부터 시작
- L1546 : page가 anon이고 swapbacked 이면 if 문 진입. lazyfree면 진입하지 않는다
- L1547 : page가 SwapCache가 아니면 if 문 진입
- L1548 : IO를 사용하지 못하면 keep locked로 이동
- L1550 : page가 DMA 용으로 pinned 되어 있으면 keep locked로 이동
- L1552 : THP인 경우 if 문 진입
- L1554 : page를 split하는게 불가능하면 activate locked로 이동
- L1561 : page split을 수행하고 실패하면 activate locked로 이동
- L1566 : add_to_swap() 수행 <— 진행 중

 

add_to_swap()
- page를 위한 swap 공간을 할당하고, page를 SwapCache에 추가한다
- L189 : PageLocked가 아니면 버그
- L190 : PageUptodate가 아니면 버그. 이는 page fault 이후 처음으로 read할 때 setting된다
- L92 : get_swap_page() 수행 <— 진행 중

 

get_swap_page()
- L305 : local 변수 swap entry를 선언
- L310 : page가 THP이고 CONFIG_THP_SWAP = y이면 get_swap_pages()로 entry에 2MB 1개 swap entry를 받아온다
- L325 : 현재 cpu의 pcpu 변수 swap slot cache swp_slots을 local 변수 cache로 가져온다
- L327 : slot cache가 active이고 cache->slots이 존재하면 if 문 진입. slot cache의 active 여부는 함수 check_cache_active()로 판정한다
- L328 : cache->alloc_lock mutex를 잡는다
- L329 : cache->slots가 있으면 if 문 진입
- L330 : repeat
- L331 : cache->nr 즉 cache에 swap entry가 남아 있으면 해당 swap entry 주소를 entry로 넘기고, cache->nr을 1 차감, cache->slots 주소를 1 증가시켜 다음 entry를 가리키게 한다
- L335 : cache에 entry가 더 이상 남아있지 않으면 함수 refill_swap_slots_cache()로 cache에 entry를 보충하고, 값이 채워졌으면 repeat으로 이동한다
- L339 : cache->alloc_lock mutex를 푼다
- L340 : entry에 value가 있으면 out으로 이동
- L344 : 함수 get_swap_pages()로 직접 entry 값을 가져온다. (size 1 짜리 entry 1개)
- L345 : out
- L346 : swap과 관련된 memcg charge 처리를 수행
- L350 : entry를 리턴

 

check_cache_active()
- L94 : 전역 변수 swap_slot_cache_enabled == false이면 false 리턴
- L97 : swap으로 사용 가능한 page 수 nr_swap_pages를 get_nr_swap_pages()로 가져온다
- L98 : swap_slot_cache_active  == false, 즉 현재 swap slot cache가 inactive이고 동시에 swap 사용 가능 페이지 수가 online cpu 수 x 5 x 64보다 크면 함수 reactivate_swap_slots_cache()로 다시 swap slot cache를 활성화 한다
- L102 : 작으면 out으로 이동
- L106 : swap 사용 가능 페이지 수가 online cpu 수 x 2 x 64보다 작으면 deactivate_swap_slots_cache() 함수로 swap slot cache를 비활성화한다
- L108 : out
- L109 : 전역 변수 swap_slot_cache_active 값을 리턴한다

 

reactivate_swap_slots_cache()
- L61 : mutex lock
- L62 : swap_slot_cache_active = true
- L63 : mutex unlock

 

deactivate_swap_slots_cache()
- L53 : mutex lock
- L54 : swap_slot_cache_active = false
- L55 : 함수 __drain_swap_slots_cache()를 SLOTS_CACHE|SLOTS_CACHE_RET 로 호출하여 swap slot cache 내용을 main pool (swap_map[] 등)으로 flush한다
- L56 : mutex unlock

 

__drain_swap_slots_cache()
- L225 : 모든 online cpu에 대해 drain_slots_cache_cpu() 함수로 swap slot cache를 drain한다

 

drain_slots_cache_cpu()
- 인자로 cpu, type, bool free slot을 받는다
- L173 : pcp 변수 swp_slots을 로컬변수 cache로 가져온다
- L174 : type == SLOT_CACHE이고 cache->slots이 존재하면 if 문을 수행한다
- L175 : cache->alloc_lock (mutex)를 잡는다
- L176 : swapcache_free_entries()로 swap cache entry들을 cache->slots + cache->cur부터 cache->nr 개수만큼 free
- L177 : cache->cur, cache->nr 초기화
- L179 : free_slots == true이면 cache->slots을 kvfree()하고 NULL로 만든다
- L183 : cache->alloc_lock (mutex)를 푼다
- L185 : type == SLOT_CACHE_RET이고 cache->slots이 존재하면 if 문을 수행한다
- L186 : cache->free_lock (spinlock)를 잡는다
- L187 : swapcache_free_entries()로 swap cache entry들을 cache->slots_ret부터 cache->n_ret 개수만큼 free
- L188 : cache->n_ret 초기화
- L189 : free_slots == true이면 cache->slots_ret을 local 변수 slots로 이동시키고 NULL로 만든다
- L193 : cache->free_lock (spinlock)를 푼다
- L194 : kvfree()로 slots을 free

 

swapcache_free_entries()
- 인자로 swap entry entries와 n을 받아 free한다
- L1424 : n <= 0 이면 리턴
- L1435 : nr_swapfiles > 1 인 경우 즉 swap 영역이 2개 이상인 경우엔 swap 영역을 기준으로 swap entry들을 sorting한다
- L1437 : 각 swap entry에 대해 swap_info_get_cont() 함수로 swap info lock을 잡는다
- L1440 : lock을 잡은 swap entry에 대해 swap_entry_free()를 수행한다
- L1443 : swap info lock을 푼다

 

swap_info_get_cont()
- L1185 : entry에 해당하는 swap info struct를 구한다. 이는 전역 변수 배열 swap_info[type]으로 구할 수 있다
- L1187 : 이전 entry와 swap info가 다르면 이전 swap info lock을 풀고 이번 swap info lock을 건다
- L1193 : 현 entry에 해당하는 swap info를 리턴한다

 

swap_entry_free()
- 인자로 swap info struct p, swap entry entry를 받는다
- L1318 : entry로부터 swap offset을 구한다
- L1321 : p, offset으로부터 함수 lock_cluster()로 swap cluster info ci를 lock을 잡고 구한다
- L1322 : swap entry에 해당하는 count값을 p->swap_map[offset]으로부터 구한다
- L1323 : count != SWAP_HAS_CACHE이면 버그. 즉 count는 0이고 cache 사용 플래그는 있어야 함
- L1324 : p->swap_map[offset] = 0으로 초기화
- L1325 : 함수 dec_cluster_info_page() 수행
- L1326 : ci cluster info lock을 푼다
- L1328 : mem_cgroup_uncharge_swap()로 해당 entry에 대해 memcg uncharge 수행
- L1329 : swap_range_free()

 

lock_cluster()
- 인자로 swap info struct si, offset을 받는다
- L354 : si->cluster_info를 ci로 가져온다
- L355 : offset에 맞는 ci를 선택하고 ci->lock을 건다
- L359 : ci를 리턴

 

unlock_cluster()
- ci->lock을 푼다

 

dec_cluster_info_page()
- 인자로 swap info struct p, swap cluster info cluster_info, page_nr을 받는다
- L577 : page_nr을 SWAPFILE_CLUSTER = 256으로 나누어 cluster info index idx를 구한다
- L579 : cluster_info == NULL이면 리턴
- L582 : cluster_info[idx]의 count가 0이면 버그. count는 cluster_count() 함수로 구한다
- L583 : cluster_set_count()으로 cluster_info[idx]의 count를 1 감소시킨다
- L586 : cluster_info[idx]의 count가 0이 되면 함수 free_cluster() 수행

 

cluster_count()
- swap_cluster_info info->data를 리턴

 

cluster_set_count()
- 인자로 c를 받아 info->data = c를 수행

 

free_cluster()
- 인자로 swap_info_struct si, idx를 받는다
- L533 : ci = si->cluster_info + idx를 가져온다
- L535 : ci의 cluster count == 0이 아니면 버그
- L541 : si->flags에 SWP_WRITEOK와 SWP_PAGE_DISCARD가 포함되어 있으면 함수 swap_cluster_schedule_discard()를 수행하고 리턴
- L547 : __free_cluster() 수행

 

swap_cluster_schedule_discard()
- 인자로 swap info struct si, idx를 받는다
- L460 : memset으로 si->swap_map[idx * 256] 부터 256개 entry = byte를 SWAP_MAP_BAD로 초기화한다
- L463 : cluster_list_add_tail()로 si->cluster_info[idx]를 tail에 추가한다
- L465 : schedule_work()로 si->discard_work 함수를 스케줄링한다

 

__free_cluster()
- 인자로 swap_info_struct si, idx를 받는다
- L472 : cluster_set_flag()로 ci + idx의 flags를 CLUSTER_FLAG_FREE로 만든다
- L473 : cluster_list_add_tail()로 ci + idx를 si->free_cluster의 tail에 달아준다

 

cluster_set_flag()
- cluster info와 flag를 받아서 info->flags에 flag를 달아준다

 

cluster_list_add_tail()
- 인자로 swap_cluster_list list, swap_cluster_info ci, idx를 받는다
- L415 : cluster_list_empty()로 list가 비어있는지 확인하고 비어 있으면 cluster_set_next_flag() 함수로 list->head, list->tail을 모두 초기화한다 (flags = 0, data = idx로 초기화)
- L419 : list가 비어있지 않으면 cluster_next()로 list->tail에 연결되어 있는 즉 마지막 cluster info idx를 tail로 가져온다
- L426 : ci + tail로 마지막 cluster info ci_tail을 가져온다
- L427 : ci_tail->lock을 SINGLE_DEPTH_NESTING 모드로 잡는다
- L428 : cluster_set_next()로 ci_tail의 다음 cluster info index를 idx로 한다
- L429 : ci_tail->lock을 푼다
- L430 : cluster_set_next_flag()로 list->tail의 다음 cluster info index를 idx로 잡는다

 

cluster_list_empty()
- 인자로 swap_cluster_list list를 받는다
- 함수 cluster_is_null()로 list->head에 다음 노드가 연결되어 있는지 리턴

 

cluster_is_null()
- 인자로 swap_cluster_info info를 받는다
- info->flags에 CLUSTER_FLAG_NEXT_NULL 플래그가 있는지 리턴

 

cluster_set_next_flag()
- 인자로 swap_cluster_info info, n, f를 받는다
- info->flags = f, info->data = n으로 채워준다

 

cluster_next()
- 인자로 swap_cluster_info info를 받는다
- info->data 리턴

 

cluster_set_next()
- 인자로 swap_cluster_info info, n을 받는다
- info->data = n 처리

 

swap_range_free()
- 인자로 swap_info_struct si, offset, nr_entries를 받는다
- L719 : begin, end를 offset부터 nr_entries 개수 만큼으로 설정
- L721 : 함수 포인터 swap_slot_free_notify 선언
- L723 : offset이 si->lowest_bit보다 작으면 si->lowest_bit를 offset으로 설정
- L725 : end > si->highest_bit이면 si->highest_bit를 end로 설정. 또한 원래 si->highest_bit = 0 즉 full이었으면, si->flags에 SWP_WRITEOK가 있는 경우 함수 add_to_avail_list()로 si를 swap 가용한 list에 추가함
- L732 : 전역 변수 nr_swap_pages를 nr_entries 만큼 증가시킴
- L733 : si->inuse_pages를 nr_entries 만큼 감소
- L734 : si->flags에 SWP_BLKDEV가 있으면 swap_slot_free_notify에 callback 함수 si->bdev->bd_disk->fops->swap_slot_free_notify를 달아준다
- L737 : 아니면 swap_slot_free_notify = NULL
- L739 : while 문 루프 offset <= end 인 경우 아래 반복 수행
- L740 : arch_swap_invalidate_page()로 si->type, offset에 대해 MTE tag를 invalidate한다
- L741 : frontswap_invalidate_page()는 빈 함수 (CONFIG_FRONTSWAP)
- L742 : swap_slot_free_notify callback있으면 수행한다
- L744 : offset 1 증가
- L745 : while 문 종료
- L746 : clear_shadow_from_swap_cache() 함수로 xarray에 존재하는 swap page cache를 삭제한다

 

add_to_avail_list()
- 인자로 swap_info_struct p를 받는다
- L708 : swap_avail_lock (spinlock)을 잡는다
- L709 : 각 노드에 대해 루프를 돌면서
- L710 : p->avail_lists[nid]가 빈 nodelist를 가지고 있으면 경고 출력
- L711 : plist_add()로 swap_avail_heads[nid] plist에 p를 추가한다 (p->avail_lists[nid]에 연결)
- L713 : swap_avail_lock을 푼다

 

plist_add()
- 인자로 plist_node node, plist_head head를 받는다
- L78 : plist head 체크
- L79 : plist_node_empty() 함수로 node가 빈 plist_node 인지 체크하고 경고
- L80 : node->prio_list가 빈 list이면 경고
- L82 : head가 빈 plist_head 이면 ins_node로 이동
- L85 : head의 첫 번째 plist node를 first, iter로 가져온다
- L87 : iter가 다시 first로 한 바퀴 돌아올 때까지 루프를 돌면서 insert하는 node의 priority가 iter 노드의 priority보다 낮아질 때까지 iter->prio_list를 search한다. 찾으면 node_next에 iter 노드의 위치를 기록하고 break
- L98 : node의 priority가 기존 모든 노드들의 priority 보다 작거나 크면 node를 적절한 priority list 위치에 추가한다 (맨 앞 또는 맨 뒤)
- L100 : ins_node
- L101 : node를 node_next 다음에 insert한다
- L103 : plist head sanity 체크

 

plist_node_empty()
- node->node_list가 empty인지 체크

 

clear_shadow_from_swap_cache()
- 인자로 type, begin, end를 받는다. type은 swap 영역을 의미
- L256 : curr를 begin으로 세팅
- L259 : curr > end가 될 때까지 루프
- L260 : type, curr(offset)을 가지고 swap entry를 entry로 가져온다
- L261 : entry를 가지고 address space를 가져온다. 함수 swap_address_space() 이용
- L262 : address_space->i_pages의 xarray에서 curr에 해당하는 offset을 search할 준비를 한다
- L264 : xa lock
- L265 : xarray의 entry를 end 범위까지 search해서 iteration한다. 찾은 노드는 old에 기록된다
- L266 : old가 value가 아니면 continue
- L268 : old가 value이면 NULL을 기록하여 노드를 삭제한다
- L270 : address_space->i_pages의 xarray의 begin ~ end까지 모든 노드를 삭제 후 xa unlock
- L273 : curr를 64MB (address space, 즉 xarray 1개 단위 크기) 만큼 증가시킨다
- L276 : curr가 end보다 커지면 break

 

swap_address_space()
- &swapper_spaces[swp_type(entry)][swp_offset(entry) >> SWAP_ADDRESS_SPACE_SHIFT] 리턴

 

refill_swap_slots_cache()
- 인자로 swap_slots_cache cache를 받는다
- L260 : 전역변수 use_swap_slot_cache == false 이거나 cache->nr > 0, 즉 cache에 entry가 이미 있으면 0 리턴
- L263 : cache->cur = 0으로 캐시 위치 초기화
- L264 : swap_slot_cache_active == true이면 함수 get_swap_pages()로 크기 1 짜리 entry 64개를 cache->slots에 가져온다
- L268 : cache->nr을 리턴

 

get_swap_pages()
- 인자로 n_goal, swp_entries[], entry_size를 받는다
- L1041 : swap_entry_size() 매크로로 entry_size로부터 size를 가져온다. CONFIG_THP_SWAP = y이면 entry_size 그대로 이고 아니면 1이다. 현재 세팅은 1
- L1048 : n_goal > 1, size == SWAPFILE_CLUSTER로 요청하면 경고. single cluster request만 지원한다고 함
- L1050 : swap_avail_lock spinlock을 건다
- L1052 : 전역 변수 nr_swap_pages를 size를 나눈 값을 avail_pgs에 기록
- L1053 : avail_pgs <= 0 이면 swap_avail_lock  spinlock을 풀고 noswap으로 이동한다
- L1058 : n_goal을 n_goal, SWAP_BATCH = 64, avail_pgs 중 가장 작은 것으로 한다. 현재 세팅에서는 1 또는 64이다
- L1060 : nr_swap_pages에서 n_goal * size 만큼 차감한다
- L1062 : start_over
- L1063 : 현재 node id를 node로 가져온다
- L1064 : 매크로 plist_for_each_entry_safe()로 전역 변수 swap_avail_heads[node]에 달려 있는 swap_info_struct si 들에 대해서 iteration을 수행한다. si는 si->avail_lists[node]로 swap_avail_heads[node]에 달려있다
- L1066 : 함수 plist_requeue()로 현재 si를 동일한 priority 가지는 si의 마지막으로 이동시킨다
- L1067 : swap_avail_lock spinlock을 푼다
- L1068 : si->lock을 잡는다
- L1069 : si->highest_bit == 0 이거나 si->flags에 SWP_WRITEOK가 아니면 if 문 진입
- L1070 : swap_avail_lock spinlock을 건다
- L1071 : si->avail_lists[node]가 empty이면 si->lock을 풀고 nextsi로 이동한다
- L1075 : si->highest_bit 및 si->flags에 대한 경고를 출력한다
- L1081 : __del_from_avail_list() 함수로 si를 swap_avail_heads[node]에서 삭제한다
- L1082 : si->lock을 푼다
- L1083 : nextsi로 이동
- L1084 : if 문 종료
- L1085 : size == SWAPFILE_CLUSTER = 256이고 si->flags가 SWP_BLKDEV이면 swap_alloc_cluster() 함수로 swp_entires[]에 swap entry 할당을 받고 그 수를 n_ret에 저장한다
- L1089 : 그 외의 경우에는 함수 scan_swap_map_slots()으로 si로부터 n_goal 개를 목표로 swap_entries에 swap entry 할당을 받고 그 수를 n_ret에 저장한다
- L1091 : si->lock을 푼다
- L1092 : n_ret이 있거나 size == SWAPFILE_CLUSTER = 256이면 checkout으로 이동한다
- L1094 : 버그 프린트를 출력
- L1097 : swap_avail_lock spinlock을 잡는다
- L1098 : nextsi
- L1110 : next->avail_list[node]가 연결이 끊겨있으면 L1064 루프에서 무한루프를 돌게 되므로, start_over로 이동하여 처음부터 루프를 재시작한다
- L1114 : swap_avail_lock spinlock을 푼다
- L1116 : check_out
- L1117 : n_ret < n_goal이면 미리 차감한 nr_swap_pages를 실제 할당한 swap page 수를 고려하여 조정한다
- L1120 : no_swap
- L1121 : n_ret을 리턴한다

 

plist_for_each_entry_safe() 매크로
- plist_head->node_list에 대해 루프를 돈다

 

plist_requeue()
- 인자로 plist_node node와 plist_head head를 받는다
- L148 : node_next를 head->node_list로 초기화한다
- L150 : head sanity check
- L151 : head와 node가 empty인지 체크한다. 둘다 node_list가 빈 list인지 체크
- L154 : node가 이미 마지막 node이면 그냥 리턴
- L157 : node의 다음 node_list를 iter로 가져온다
- L159 : node->prio와 iter->prio가 다르면 이미 node가 동일 priority의 마지막 노드이므로 그냥 리턴
- L162 : plist_del() 함수로 node를 list에서 삭제한다
- L164 : plist_for_each_continue() 매크로로 iter로 list의 node_list를 하나씩 가져온다
- L165 : node->prio가 iter->prio와 달라지면 iter->prio가 이제 더 크므로 node_next를 iter->node_list로 만들고 break
- L170 : node를 node_next 직전에 삽입한다
- L172 : head sanity check

 

plist_del()
- 인자로 plist_node node, plist_head head를 받는다
- L114 : head sanity check
- L116 : node->prio_list가 비어있지 않으면, node가 동 priority를 가진 노드 중 가장 앞에 있는 노드라는 의미이다. 이 떄 동 priority를 가진 다른 노드가 없으면 그냥 list_del_init()으로 node를 prio_list에서 삭제한다
- L117 : node->prio_list가 비어 있지 않고, 동 priority를 가진 다른 노드가 있으면 그 노드를 node->prio_list 다음에 추가하고, 원래 node는 prio_list에서 제거한다
- L130 : node->prio_list가 비어있거나, 아닌 경우 위에서 prio_list 처리를 모두 했으므로 node_list에서 node를 삭제한다
- L132 : head sanity check

 

__del_from_avail_list()
- 인자로 swap info struct p를 받는다
- L676 : 모든 노드에 대해 루프를 돌면서 swap_avail_heads[nid]에 달려있는 p를 제거한다

 

scan_swap_map_slots()
- 인자로 swap_info_struct si, usage, nr, swap_entry_t slots[]를 받는다
- usage == SWAP_HAS_CACHE로 설정되어 호출되었다
- L800 : si->flags에 SWP_SCANNING을 추가한다
- L806 : si->flags에 SWP_SOLIDSTATE가 있으면 scan_base에 si->cluster_next_cpu pcpu 변수값을 읽어온다
- L809 : SSD가 아니면 scan_base에 si->cluster_next 값을 읽어온다
- L810 : offset을 scan_base로 설정한다
- L813 : si->cluster_info가 있으면, 즉 SSD의 경우이면 함수 scan_swap_map_try_ssd_cluster()를 실행하여 offset과 scan_base를 업데이트한다. 실패하면 scan으로 이동한다
- L816 : SSD가 아닌 경우는 생략
- L855 : checks
- L856 : si->cluster_info가 있는 SSD의 경우 if 문 진입
- L857 : 함수 scan_swap_map_ssd_cluster_conflict()로 conflict 체크 후 있으면 n_ret, 즉 할당 받은 swap entry가 있으면 done으로 이동하고, 없으면 다시 함수 scan_swap_map_try_ssd_cluster()로 swap entry 할당 시도한다. 안되면 scan으로 이동한다. conflict 없는 offset을 받을 때까지 while 문으로 반복한다
- L865 : if 문 종료
- L866 : si->flags에 SWP_WRITEOK가 없으면 no_page 이동
- L868 : si->highest_bit == 0, 즉 full 이면 no_page 이동
- L870 : offset > si->highest_bit 이면 scan_base = offset = si->lowest_bit으로 조정
- L873 : si, offset에 해당하는 ci를 lock 잡고 가져온다
- L875 : vm_swap_full()로 swap 가용 페이지의 절반 이상이 사용 중인지 확인하고, 절반 이상 사용 중이면서 si->swap_map[offset] == SWAP_HAS_CACHE, 즉 offset이 swap page cache는 존재하지만 count = 0이라 사용 중이 아닌 경우에 swap 영역의 reclaim을 시도하기 위해 if 문 진입한다
- L877 : ci lock을 푼다
- L878 : si->lock을 푼다
- L879 : 함수 __try_to_reclaim_swap()으로 si, offset 영역의 swap 영역을 reclaim하여 free 시도하고, free된 swap entry 수를 swap_was_freed에 기록한다
- L880 : si->lock을 건다
- L882 : swap_was_freed > 0 이면 free 되었으므로 checks로 다시 이동한다 (실제로는 아직 slots_ret에만 있고 swap_map[]은 여전히 SWAP_HAS_CACHE 일 수 있음)
- L884 : free 실패한 경우 scan으로 이동
- L885 : if 문 종료
- L887 : si->swap_map[offset] == 0이 아니면, ci->lock을 풀고 n_ret이 있으면 done, 없으면 scan으로 이동한다
- L894 : 이제 si->swap_map[offset] == 0이므로 usage를 기록한다
- L895 : 함수 inc_cluster_info_page()로 si->cluster_info의 offset에 해당하는 ci의 counter를 increment한다. 만약 ci가 여전히 free cluster list에 속해 있으면 free list에서 제외한다
- L896 : ci lock을 푼다
- L898 : swap_range_alloc() 함수로 si->lowest_bit, highest_bit, inuse_pages를 조정한다
- L899 : slots[n_ret++]에 si->type, offset에 해당하는 swap entry를 적어준다
- L902 : 요청한 만큼 swap entry를 확보했거나, offset이 highest_bit를 넘어가면 done으로 이동한다
- L908 : latency_ration < 0이 되면 n_ret > 0 인 경우 done으로 이동하고, 아니면 si->lock unlock 후 cond_reshed()로 sleep()한다. 이후 wake하면 si->lock 다시 lock하고 latency_ration = LATENCY_LIMIT = 256으로 다시 세팅한다
- L918 : si->cluster_info가 있으면 즉 SSD이면 함수 scan_swap_map_try_ssd_cluster()로 새 offset, scan_base를 받아오고 성공시 checks로 이동한다
- L921 : HDD의 경우 생략
- L932 : scanned_many == false인 경우 (초기값 false), latency_ration이 남아있는 한에서 scan_limit 범위 안에서 swap_map[offset] == 0이 되는 offset을 찾고, 성공하면 checks로 이동한다
- L946 : done
- L947 : set_cluster_next()로 si->cluster_next_cpu pcpu 변수를 offset + 1로 업데이트한다
- L948 : si->flags에서 SWP_SCANNING을 제거한다
- L949 : n_ret을 리턴한다
- L951 : scan
- L952 : si->lock을 푼다
- L953 : offset이 highests_bit에 도달할 때까지 offset 증가시키며 while 문 수행
- L954 : si->swap_map[offset] == 0이면 si->lock을 잡고 checks로 이동
- L958 : vm_swap_full()이고 si->swap_map[offset] == SWAP_HAS_CACHE 이면 si->lock을 잡고 checks로 이동
- L963 : latency_ration을 1 감소시키고 while 문을 반복하되 0보다 작아지면 cond_reshed() 수행 후 다시 latency_ration = LATENCY_LIMIT = 256으로 다시 세팅하고 scanned_many = true로 설정한다
- L968 : while 문 종료
- L969 : offset = si->lowest_bit로 설정
- L970 : offset < scan_base 이면 while 문 수행
- L971 :  si->swap_map[offset] == 0이면 si->lock을 잡고 checks로 이동
- L975 : vm_swap_full()이고 si->swap_map[offset] == SWAP_HAS_CACHE 이면 si->lock을 잡고 checks로 이동
- L980 : atency_ration을 1 감소시키고 while 문을 반복하되 0보다 작아지면 cond_reshed() 수행 후 다시 latency_ration = LATENCY_LIMIT = 256으로 다시 세팅하고 scanned_many = true로 설정한다
- L985 : offset++
- L986 : while 문 종료
- L987 : si->lock lock
- L989 : no_page
- L990 : si->flags에서 SWP_SCANNING을 제거한다
- L991 : n_ret을 리턴

 

scan_swap_map_try_ssd_cluster()
- 인자로 si, offset, scan_base를 받는다
- L625 : new_cluster
- L626 : cluster에 si->percpu_cluster pcpu 값을 받아온다
- L627 : cluster->index가 null이면 if 문 진입
- L628 : si->free_clusters가 비어 있지 않으면 cluster->index를 free_clusters.head로, cluster->next를 cluster->index에 256을 곱해서 offset으로 변환하여 저장
- L632 : free_clusters가 비어있는 경우 si->discard_clusters가 비어 있지 않으면 함수 swap_do_scheduled_discard() 수행하여 새 free cluster를 만들고 offset, scan_base를 si->cluster_next_cpu로 업데이트하고 new_cluster로 이동한다
- L642 : discard_cluster도 비어 있으면 false 리턴
- L650 : tmp에 cluster->next, 즉 offset을 가져온다
- L651 : tmp에서 256 큰 수 또는 si->max를 max로 설정
- L653 : tmp < max이면 si, tmp에 해당하는 ci lock을 건뒤 tmp < max이면서 si->swap_map[tmp] == 0인 tmp를 찾는다. 찾거나 tmp == max가 되면 ci lock을 푼다
- L662 : tmp >= max가 되면 cluster->index를 null로 만들고 new_cluster로 이동한다
- L666 : cluster->next = tmp + 1로 설정
- L667 : offset, scan_base를 tmp로 설정
- L669 : true를 리턴

 

swap_do_scheduled_discard()
- 인자로 swap info struct si를 받는다
- L485 : info에 si->cluster_info를 받는다
- L487 : si->discard_clusters가 empty가 아니면 while 문 반복수행
- L488 : 함수 cluster_list_del_first()로 si->discard_clusters의 첫 ci를 제거하고 그 idx를 가져온다
- L489 : si->lock을 푼다
- L491 : 함수 discard_swap_cluster()
- L494 : si->lock을 건다
- L495 : si, idx에 해당하는 ci를 lock을 걸고 가져온다
- L496 : si, idx에 해당하는 ci를 free 시킨다
- L497 : si->swap_map[idx*256] 부터 256개 영역을 0으로 memset한다
- L499 : ci lock을 푼다

 

cluster_list_del_first()
- 인자로 swap_cluster_list list, swap_cluster_info ci를 받는다
- L439 : list의 첫 cluster idx를 가져온다
- L440 : 첫 idx가 tail과 같으면 list의 head/tail을 모두 0으로 만든다
- L444 : 아니면 ci[idx]의 다음 ci의 idx를 head에 쓴다
- L447 : idx를 리턴한다

 

discard_swap_cluster()
- 인자로 swap info struct si, start page, nr pages를 받는다
- L242 : offset_to_swap_extent() 함수로 si, start_page로부터 swap extent se를 받아온다
- L244 : nr pages가 0이 될때까지 while 문 수행
- L245 : offset = start_page - se->start_page
- L246 : se->start_block에 offset을 더해서 start_page에 해당하는 block을 start_block에 저장
- L247 : se->nr_pages에서 offset을 빼서 se에 해당되는 block 수를 nr_blocks에 저장
- L249 : nr_blocks > nr_pages이면 nr_blocks = nr_pages로 조정
- L251 : start_page를 nr_blocks 만큼 증가
- L252 : nr_pages를 nr_blocks 만큼 감소
- L254 : start_block, nr_blocks를 64배로 조정
- L256 : blkdev_issue_discard() 함수로 si->bdev 장치에 start_block부터 nr_blocks 개수 만큼을 discard 요청한다
- L260 : 다음 se를 가져온다

 

offset_to_swap_extent()
- L208 : sis->swap_extent_root.rb_node에서 rb를 받는다
- L209 : rb가 유효하면 while 문 수행
- L210 : rb에서 se entry를 받아온다
- L211 : offset이 se 범위보다 아래쪽이면 rb = rb->left
- L213 : 오른쪽이면 rb = rb->right
- L215 : 범위 내면 se 리턴

 

scan_swap_map_ssd_cluster_conflict()
- 인자로 si, offset을 받는다
- L601 : offset을 256으로 나누어 idx로 변환
- L602 : si->free_clusters가 비어있지 않고, idx가 si->free_clusters의 첫 ci index가 아니고, ci[idx]가 free이면 conflict
- L606 : conflict가 아니면 false 리턴
- L609 : conflict이면 si->percpu_cluster를 가져와서 index를 null로 만들고 true 리턴

 

__try_to_reclaim_swap()
- 인자로 swap info struct si, offset, flags를 받는다
- L128 : si->type, offset으로부터 swap entry를 구한다
- L132 : find_get_page() 함수로 swap entry에 해당하는 page를 구한다.
- L133 : page == NULL이면 0 리턴
- L142 : page를 구했으면 trylock을 시도
- L143 : locking에 성공하면 flags에 따라 TTRS_ANYWAY이거나, TTRS_UNMAPPED이면서 page가 unmap이거나, TTRS_FULL이면서 memcg swap full이면 try_to_free_swap() 함수로 page에 대해 free를 시도하고 결과를 ret에 저장한다
- L147 : page를 unlock
- L149 : page를 put <— L132에서 find_get_page() 함수 내에서의 ref 증가에 대칭
- L150 : free 결과 ret을 리턴한다

 

find_get_page()
- 인자로 address space mapping, offset을 받는다
- 함수 pagecache_get_page()를 호출

 

pagecache_get_page()
- 인자로 address space mapping, index, fgp_flags, gfp_mask를 받는다
- 현재 mask는 모두 0으로 들어옴
- L1894 : 함수 mapping_get_entry()로 mapping, index에 대한 page를 구한다
- L1895 : page가 xarray value 아니고 pointer이므로 패스
- L1900 : page == NULL이면 no_page로 이동
- L1903 : 플래그 0이므로 패스
- L1922 : 플래그 0이므로 패스
- L1929 : THP이면 index에 따라 tail page를 구한다
- L1932 : no_page
- L1933 : 플래그 0이므로 패스
- L1967 : page를 리턴한다

 

mapping_get_entry()
- 인자로 address space mapping, index를 받는다
- L1820 : mapping->i_pages, index를 가지고 xarray를 세팅
- L1823 : rcu read lock
- L1826 : xarray에서 page를 읽어온다
- L1833 : page != NULL 이고 page는 pointer이므로 패스. 여기서 value는 shadow value를 의미하는 듯?
- L1836 : page_cache_get_speculative() 함수로 page ref가 0이 아닌 경우 1 증가시킨다 (CONFIG_TINY_RCU = n)
- L1849 : rcu read unlock
- L1851 : page 리턴

 

try_to_free_swap()
- 인자로 page를 받는다
- L1718 : page가 locked가 아니면 버그
- L1720 : page가 PageSwapCache이면 0 리턴
- L1722 : page가 PageWriteback이면 0 리턴
- L1724 : page가 swapped이면 0 리턴. 함수 page_swapped()으로 판정
- L1742 : pm_suspended_storage() 함수로 현재 storage가 power suspend 상태이면 reclaim 불가하므로 0 리턴한다
- L1745 : page의 head를 가져온다
- L1746 : delete_from_swap_cache() 함수로 page를 swap cache에서 삭제
- L1747 : SetPageDiry(). 이는 anon의 경우 pte가 dirty이거나 page가 dirty여야 하는데 swap in되어서 다시 anon으로 변경되는 경우 pte가 clean이므로 page를 dirty로 만들어주는 것이다
- 1748 : 1 리턴

 

page_swapped()
- 인자로 page를 받는다
- L1593 : CONFIG_THP_SWAP = n이므로 page_swapcount(page) != 0을 리턴

 

page_swapcount()
- L1460 : page의 private로부터 swap entry를 구한다
- L1461 : entry로부터 swap info struct p를 구한다
- L1462 : p가 존재하면
- L1463 : entry로부터 swap offset을 계산하고
- L1464 : p, offset으로부터 ci를 lock을 잡고 구한다
- L1465 : p->swap_map[offset]에서 SWAP_HAS_CACHE bit만 클리어하여 swap count를 구한다
- L1466 : ci lock을 푼다
- L1468 : swap count를 리턴한다

 

pm_suspended_storage()
- 전역 변수 gfp_allowed_mask에 __GFP_IO | __GFP_FS 가 존재하면 false, 아니면 true 리턴

 

delete_from_swap_cache()
- 인자로 page를 받는다
- L242 : page의 private로부터 swap entry를 구한다
- L243 : entry로부터 swap address space를 계산한다
- L245 : address_space->i_pages의 xarray lock을 잡는다
- L246 : 함수 __delete_from_swap_cache()로 xarray page cache에 page를 지우고 NULL shadow를 기록한다
- L247 : address_space->i_pages의 xarray lock을 푼다
- L249 : put_swap_page() 함수로
- L250 : page의 refcount를 감소시킨다

 

__delete_from_swap_cache()
- 인자로 page, swp_entry_t entry, shadow를 받는다
- L155 : entry로부터 swap address_space를 구한다
- L156 : page의 tail page 수를 nr에 기록
- L157 : entry로부터 swap offset을 계산한다
- L158 : address_space->i_pages xarray의 offset을 setting한다
- L160 : PageLocked가 아니면 버그
- L161 : PageSwapCache가 아니면 버그
- L162 : PageWriteback이 아니면 버그
- L164 : tail page 수에 따라 루프 수행
- L165 : offset에 해당하는 page cache 노드에 shadow를 기록
- L167 : page의 private에 0 기록 (entry 삭제)
- L168 : 다음 xarray page cache 노드로 이동
- L170 : ClearPageSwapCache()
- L171 : address_space->nrpages에서 nr 만큼 감소
- L172 : pgdat의 NR_FILE_PAGES를 nr 차감
- L173 : page의 LRUVEC stat 중 NR_SWAPCACHE nr 차감
- L174 : swap_cache_info.del_total 값을 nr 증가

 

put_swap_page()
- 인자로 page와 swap entry를 받는다
- L1350 : entry로부터 swap offset 계산
- L1351 : offset으로부터 idx 계산
- L1357 : 현재 설정으로는 size = 1
- L1359 : entry로부터 swap info struct si를 구함
- L1363 : si, offset으로부터 ci를 lock 잡고 구함
- L1364 : size = 1 이므로 패스
- L1383 : size 만큼 루프 수행
- L1384 : 함수 __swap_entry_free_locked()로 count 값을 반환받고 swap_map[offset]에 SWAP_HAS_CACHE을 기록함
- L1385 : count = 0이므로 ci lock unlock
- L1386 : free_swap_slot()으로 entry를 slots_ret pcpu에 반환
- L1387 : 모든 entry가 free되면 리턴

 

__swap_entry_free_locked()
- 인자로 swap info struct p, offset, usage를 받는다
- L1203 : count에 p->swap_map[offset]을 가져온다
- L1205 : has_cache에 count의 SWAP_HAS_CACHE 플래그 비트를 가져온다
- L1206 : count에서 SWAP_HAS_CACHE 플래그 비트를 지운다
- L1208 : usage == SWAP_HAS_CACHE 이므로 has_cache = 0으로 설정
- L1227 : usage = count | has_cache
- L1228 : 현재는 count = 0이므로 p->swap_map[offset] = SWAP_HAS_CACHE 로 설정
- L1233 : usage를 리턴 (현재는 0)

 

free_swap_slot()
- 인자로 swap entry를 받는다
- L275 : swp_slots pcpu 포인터를 cache로 받는다
- L276 : use_swap_slot_cache == true이고 cache->slots_ret이 있으면 if 문 진입
- L277 : cache->free_lock을 건다
- L279 : use_swap_slot_cache == false이거나 cache->slots_ret이 없으면 cache->free_lock 풀고 direct_free로 이동
- L283 : cache->n_ret, 즉 캐시에 쌓인 entry 수가 SWAP_SLOTS_CACHE_SIZE = 64보다 같거나 크면 swapcache_free_entries() 함수로 글로벌 풀에 flush하고 cache->n_ret = 0으로 리셋
- L293 : cache->slots_ret[cache->n_ret++]에 entry를 기록
- L294 : cache->free_lock을 푼다
- L295 : if 문 종료
- L295 : use_swap_slot_cache == false이거나 cache->slots_ret이 없으면 else 진입
- L296 : direct_free
- L297 : swapcache_free_entries() 함수로 직접 global pool에 entry 반환
- L300 : 0 리턴

 

swapcache_free_entries()
- 인자로 swap_entry_t entries, n을 받는다
- L1424 : n <= 0이면 리턴
- L1435 : swap 영역이 여러 개면 (nr_swapfiles > 1), entries[]를 swap 영역 기준으로 sorting한다
- L1437 : n 만큼 for 문 수행
- L1438 : swap_info_get_cont() 함수로 entries[i]에 해당하는 swap info struct p를 lock 잡고 가져온다. 이전과 p가 달라지면 이전 lock은 풀고 새 swap info struct의 lock을 잡는다
- L1440 : p가 있으면 swap_entry_free()로 swap entry free 수행
- L1443 : 마지막 p lock을 푼다

 

inc_cluster_info_page()
- 인자로 swap info struct p, swap_cluster_info cluster_info, page_nr을 받는다
- L557 : page_nr을 SWAPFILE_CLUSTER = 256으로 나누어 idx를 구한다
- L559 : cluster_info == NULL이면 리턴
- L561 : cluster_info[idx]가 free인지 cluster_is_free()로 판정하고 맞으면 alloc_cluster() 함수로 alloc 수행
- L564 : cluster_info[idx]의 count가 SWAPFILE_CLUSTER 이상이면 버그
- L565 : cluster_info[idx]의 count를 1 증가

 

cluster_is_free()
- swap_cluster_info info를 받아 info->data가 CLUSTER_FLAG_FREE 플래그를 가지고 있는지 리턴

 

alloc_cluster()
- 인자로 swap info struct si, idx를 받는다
- L524 : si->cluster_info를 ci로 가져온다
- L526 : si->free_clusters의 처음 cluster_info가 ci + idx가 아니면 버그. 판정에 cluster_list_first() 함수 사용
- L527 : cluster_list_del_first()로 si->free_clusters의 첫 cluster info, 즉 ci + idx를 제거
- L528 : cluster_set_count_flag()로 ci + idx의 data, flags를 0으로 초기화

 

cluster_list_first()
- 인자로 swap_cluster_list list를 받아서 list->head에 쓰인 idx를 리턴

 

cluster_set_count_flag()
- 인자로 swap_cluster_info info, c, f를 받는다
- info->flags = f, info->data = c 수행

 

swap_range_alloc()
- 인자로 swap_info_struct si, offset, nr_entries를 받는다
- L690 : end = offset + nr_entries - 1 마지막 offset 계산
- L692 : offset == si->lowest_bit 이면 si->lowest_bit을 nr_entries 만큼 증가
- L694 : end == si->highest_bit 이면 si->highest_bit를 nr_entries 만큼 감소
- L696 : si->inuse_pages를 nr_entries 만큼 증가
- L697 : si->inuse_pages == si->pages, 즉 full이 되면 si->lowest_bit = si->max, si->highest_bit = 0을 설정하고 함수 del_from_avail_list()로 si를 available list에서 제거한다

 

set_cluster_next()
- 인자로 swap_info_struct si, next를 받는다
- L753 : si->flags & SWP_SOLIDSTATE == 0이면 si->cluster_next = next 수행하고 리턴
- L758 : si->cluster_next_cpu pcpu 를 prev로 읽어온다
- L764 : prev와 next가 64MB 단위가 달라지면 next 값을 pseudorandom하게 설정하고 64MB align을 맞춘 뒤 si->lowest_bit으로 하한을 맞춘다
- L765 : si->cluster_next_cpu 값을 next로 업데이트한다

번호 제목 글쓴이 날짜 조회 수
공지 [공지] 스터디 정리 노트 공간입니다. woos 2016.05.14 623
165 [커널 19차] 27 주차 Min 2022.11.22 82
164 [커널 18차] 78주차 kkr 2022.11.19 186
163 [커널 19차] 25 ~ 26 주차 Min 2022.11.14 71
162 [커널 18차] 76-77주차 kkr 2022.11.12 384
161 [커널 19차] 24주차 Min 2022.10.31 108
160 [커널 17차] 112주차 ㅇㅇㅇ 2022.10.30 81
159 [커널 18차] 75주차 kkr 2022.10.29 40
» [커널 17차] 107 ~ 111주차 ㅇㅇㅇ 2022.10.23 71
157 [커널 19차] 22주차 Min 2022.10.17 76
156 [커널 18차] 73주차 kkr 2022.10.15 44
155 [커널 18차] 72주차 kkr 2022.10.09 182
154 [커널 18차] 71주차 kkr 2022.10.01 74
153 [커널 18차] 70주차 kkr 2022.09.24 76
152 [커널 18차] 69주차 kkr 2022.09.22 57
151 [커널 17차] 105~106주차 ㅇㅇㅇ 2022.09.18 50
150 [커널 17차] 104주차 ㅇㅇㅇ 2022.09.04 87
149 [커널 18차] 67주차 kkr 2022.09.03 138
148 [커널 17차] 103주차 ㅇㅇㅇ 2022.08.28 35
147 [커널 18차] 66주차 kkr 2022.08.27 74
146 [커널 17차] 101~102주차 ㅇㅇㅇ 2022.08.21 45
XE Login