[커널 17차] 88주차

2022.05.08 01:07

ㅇㅇㅇ 조회 수:101

Zoned Allocator PCP 내용
- http://jake.dothome.co.kr/per-cpu-page-frame-cache/

 

totalreserve_pages
- usermode에서 메모리 할당 요청할 때 남은 메모리양을 추정하기 위한 용도로 사용된다
- 그래서 lowmem_reserve[] 중 가장 높은 zone 기준으로 totalreserve_pages 값을 업데이트한다

 

memmap_init_zone_range() 함수에서 초기에 함수 memmap_init_range()로 메모리를 migrate_movable로 세팅함
또한 CMA는 별도의 함수로 세팅함
—> 나머지 migrate type은 메모리 할당시 movable에서 steal해서 사용한다. 이 때 page_alloc 단계에서 flag 변경할 것으로 예상된다
—> sparse mem의 ms->usage->pageblock_flags에 해당 page의 migrate type이 쓰여있다


get_page_from_freelist()
- L4109부터 계속

- L4109 : zone_watermark_fast()에서 메모리양을 체크한 뒤 충분하지 않으면 if문으로 진입
- L4152 : 아니면 try_this_zone으로 진입한다
- L4152 : 함수 rmqueue()로 page를 할당받는다
- L4154 : <— 진행할 차례

 

rmqueue()
- 인자로 preferred zone, zone, order, gfp flags, alloc flags, migrate type을 받는다
- 주어진 zone으로 부터 페이지를 할당받아 리턴한다

- L3683 : 함수 pcp_allowed_order()로 요청된 order가 pcp에서 허용되는지 판단한다
- L3688 : CONFIG_CMA = y이고 CMA 할당이 허용된 것이 아니면서 migrate type이 MOVABLE이면 할당을 skip한다. 아니면 함수 rmqueue_pcplist()로 페이지를 요청하고 out으로 이동한다
- L3700 : gfp flags가 __GFP_NOFAIL이면서 order > 1이면 경고한다
- L3701 : zone->lock spinlock을 잡고 irq disable()
- L3711 : order > 0이고 alloc_flags가 ALLOC_HARDER이면 함수__rmqueue_smallest()로 migrate type = MIGRATE_HIATOMIC으로 page를 할당받는다
- L3716 : page == NULL이면 함수 __rmqueue()로 page를 할당받는다
- L3718 : 할당 받은 page를 함수 check_new_pages()로 체크한다. 이상이 있는 경우 다시 L3711로 이동하여 할당을 수행한다
- L3719 : page == NULL이면 failed로 이동한다
- L3722 : zone의 NR_FREE_PAGES를 1 << order 만큼 감소시킨다
- L3724 : zone->lock spinlock을 풀고 irq_enable()
- L3726 : page에 해당하는 zone의 PGALLOC 값을 1 << order 만큼 증가시킨다
- L3727 : 함수 zone_statistics()로 preferred zone과 현재 zone이 같은 노드인지 보고 NUMA_HIT / NUMA_MISS 통계를 1 증가시킨다
- L3729 : out
- L3730 : zone->flags에 ZONE_BOOSTED_WATERMARK가 set되어 있으면 clear하고, 함수 wakeup_kswapd()으로 kswapd() task를 깨운다
- L3737 : 할당된 page를 리턴한다
- L3739 : failed
- L3740 :  zone->lock spinlock을 풀고 irq_enable()한 뒤, NULL을 리턴한다

 

pcp_allowed_order()
- 인자로 order를 받아 해당 order가 pcp에서 허용되는지 리턴한다
- order <= PAGE_ALLOC_COSTLY_ORDER 이거나 order == pageblock_order인 경우 (CONFIG_TRANSPARENT_HUGEPAGE == y) 만 true이다
- 현재는 CONFIG_TRANSPARENT_HUGEPAGE = y이다

 

rmqueue_pcplist()
- 인자로 preferred zone, zone, order, gfp flags, migrate type, alloc_flags를 받는다
- percpu list로부터 페이지를 할당받아 리턴한다

- L3652 : 현재 LOCK_DEP 및 CONFIG_DEBUG_LOCK_ALLOC이 설정 안되어 있으므로 pageset local lock은 없다. 따라서 함수 local_lock_irqsave()로 IRQ disable만 수행한다
- L3659 : zone->per_cpu_pageset을 pcp로 가져온다
- L3660 : pcp->free_factor를 절반으로 감소시킨다
- L3661 : 함수 order_to_pindex()를 이용하여 order와 migrate type에 맞는 pcplist를 가져온다
- L3662 : 함수 __rmqueue_pcplist()로 페이지를 요청, 할당받아 가져온다
- L3663 : irq enable()
- L3664 : page 할당이 성공하면 함수 __count_zid_vm_events()로 pcp event counter로 페이지 할당 성공을 카운팅한다. 또한 함수 zone_statistics()으로 NUMA hit/miss 통계도 업데이트한다
- L3668 : 할당 받은 page를 리턴한다

 

order_to_pindex()
- pcplist 순서는 다음과 같다

order 0 : unmovable / movable / reclaimable (0 ~ 2)
order 1 : unmovable / movable / reclaimable (3 ~ 5)
order 2 : unmovable / movable / reclaimable (6 ~ 8)
order 3 : unmovable / movable / reclaimable (9 ~ 11)
order pageblock : unmovable / movable / reclaimable (12 ~ 14)

- 위 순서대로 pcplist index를 계산해서 리턴한다

 

__rmqueue_pcplist()
- 인자로 zone, order, migrate type, alloc_flags, per_cpu_pages pcp, pcplist list를 받는다

- L3611 : pcplist가 empty이면 if문 진입, buddy에서 페이지를 받아서 list에 채우게 된다
- L3612 : pcp->batch에서 한 번에 받아올 페이지 수를 batch로 가져온다
- L3622 : batch > 1이면 batch를 order에 해당하는 page 수로 나눈 값과 2 중에서 더 큰 값으로 조정한다
- L3624 : 함수 rmqueue_bulk()로 buddy에서 요청된 batch만큼 pcplist로 페이지를 받아오고, 그 수를 alloced에 저장한다
- L3628 : pcplist에 받아온 page 수만큼 pcp->count를 증가시킨다
- L3629 : pcplist가 여전히 비어 있으면 할당 실패로, NULL을 리턴한다

- L3633 : pcplist의 첫 번째 page를 가져온다
- L3634 : pcplist에서 첫 번째 page 삭제
- L3635 : pcp->count에서 받아간 page 수 만큼 감소시킴
- L3636 : 함수 check_new_pcp()는 디버그 용도이며, CONFIG_DEBUG_VM = n, CONFIG_DEBUG_PAGEALLOC = n 이므로 false이다
- L3638 : 할당받은 페이지를 리턴한다

 

rmqueue_bulk()
- 인자로 zone, order, count, pcplist list, migrate type, alloc_flags를 받는다
- 버디에서 count만큼 page를 할당받아 pcplist에 넣어준다. 그리고 할당 받은 compound 페이지 수를 리턴한다

- L3019 : 지역 변수 allocated를 0으로 초기화
- L3025 : zone->lock spinlock을 잡는다
- L3026 : count 만큼 루프를 돌면서 아래를 수행한다
- L3027 : 함수 __rmqueue()로 페이지를 버디에서 page를 할당받는다
- L3029 : page == NULL이면 루프 break
- L3032 : 함수 check_pcp_refill()로 page를 체크, 실패하면 루프 break
- L3045 : page를 pcplist의 tail에 추가한다
- L3046 : allocated를 1 증가시킨다
- L3047 : page->index를 체크하여 MIGRATE_CMA인 경우 함수 __mod_zone_page_state()로 해당 zone의 NR_FREE_CMA_PAGES 수를 1 << order 만큼 감소시킨다
- L3050 : 루프 종료
- L3058 : 함수 __mod_zone_page_state()로 해당 zone의 NR_FREE_PAGES 수를 buddy로부터 할당한 수 만큼 감소 시킨다
- L3059 : zone->lock spinlock을 해제한다
- L3060 : 할당된 compound page 수 allocated를 리턴한다

 

check_pcp_refill()
- 함수 check_new_page()로 page를 체크한다
- check_new_page()의 결과를 리턴

 

check_new_page()
- 함수 page_expected_state()로 page를 체크한다. 이때 플래그는 PAGE_FLAGS_CHECK_AT_PREP|__PG_HWPOISON로 체크한다
- 함수 page_expected_state() 체크가 성공하면 0 리턴, 실패하면 1 리턴

 

page_expected_state()
- 인자로 받은 page에 대해 체크를 수행한다
- 다음의 경우 체크 실패로 false 리턴
1) page->_mapcount != -1
2) page->mapping, page->_refcount, page->memcg_data가 0, NULL이 아닌 경우
3) page->flags가 요청된 flag와 겹치는 것이 있을 경우
- 나머지는 true 리턴

 

__rmqueue()
- 인자로 zone, order, migrate type, alloc_flags를 받는다
- 요청된 조건의 페이지를 버디에서 할당받아 리턴한다

- L2980 : CONFIG_CMA = y이고 alloc_flags에 ALLOC_CMA가 설정되어 있으며 현재 zone에 NR_FREE_CMA_PAGES 가 NR_FREE_PAGES의 절반보다 더 많은 경우 함수 __rmqueue_cma_fallback()으로 cma area로부터 페이지를 할당받아 리턴한다
- L2995 : 함수 __rmqueue_smallest()로 page를 할당받는다
- L2997 : __rmqueue_smallest()가 할당 실패한 경우 alloc_flags에 ALLOC_CMA가 설정되어 있으면 __rmqueue_cma_fallback()으로 다시 할당 시도
- L3000 : 여전히 page == NULL이면 __rmqueue_fallback()으로 fallback 및 steal이 가능하면 L2995로 다시 이동하여 재시도한다
- L3007 : 할당받은 page를 리턴한다

 

__rmqueue_cma_fallback()
- 인자로 zone, order를 받는다
- 함수 __rmqueue_smallest()에서 migrate type을 MIGRATE_CMA로 고정해서 호출한다

 

__rmqueue_smallest()
- 인자로 zone, order, migrate type을 받는다

- L2456 : 요청받은 order에서 시작하여 MAX_ORDER - 1까지 current_order에 대해서 루프를 돌면서 아래를 수행한다
- L2457 : zone->free_area[current_order]를 area로 가져온다
- L2458 : area->free_list[migrate_type]의 첫 번째 page를 가져온다
- L2459 : page가 NULL이면 order를 증가시켜 continue
- L2461 : 함수 del_page_from_free_list()로 area->free_list[migrate_type]의 첫 page를 free_list에서 제거한다
- L2462 : expand() 함수로 할당 받은 메모리 중 반납할 수 있는 부분은 반납한다 (필요한 order보다 더 큰 order로 할당 받은 경우 나머지 절반은 반납 가능하며 이것을 할 수 있을 때까지 계속 반복한다)
- L2463 : page->index를 migratetype으로 업데이트한다
- L2464 : 할당 받은 page를 리턴한다
- L2467 : 할당 받지 못하고 루프를 모두 돌게 되는 경우에는 NULL을 리턴한다

 

del_page_from_free_list()
- L999 : CONFIG_PAGE_REPORTING = y이고 static key page_reporting_enabled = true이면서 현재 page가 reported로  pageflag가 설정되어 있으면 해당 page의 reported pageflag를 clear한다. 현재 설정은 CONFIG_PAGE_REPORTING = y이다
- L1002 : 현재 page를 list에서 제거한다
- L1003 : 현재 page를 버디에서 제거 (__ClearPageBuddy)
- L1004 : page->private = 0으로 설정한다 (page order 설정)
- L1005 : zone->free_area[order].nr_free를 1 감소시킨다

 

expand()
- 인자로 zone, page, low, high, migratetype을 받는다
- L2292 : size = 1 << high 설정
- L2294 : high > low 이면 while 루프를 수행한다
- L2295 : high를 1 감소시키고 size >>= 1 수행
- L2297 : CONFIG_DEBUG_VM = n이므로 그냥 넘어간다
- L2305 : CONFIG_DEBUG_PAGEALLOC = n이므로 빈 함수이고 false를 리턴한다
- L2308 : 함수 add_to_free_list()로 page[size]를 zone->free_area[high]->free_list[migratetype]에 추가한다
- L2309 : 함수 set_buddy_order()로 page의 order를 high로 설정하고, page를 버디에 추가한다 (__SetPageBuddy)
- 기본적으로 low == high이면 아무것도 하지 않고 나가게 된다

 

add_to_free_list()
- 인자로 page, zone, order, migratetype을 받는다
- page를 zone->free_area[order]->free_list[migratetype]에 추가하고 area->nr_free를 1 증가시킨다

 

__rmqueue_fallback()
- 인자로 zone, order, start_migratetype, alloc_flags를 받는다
- L2908 : alloc_flags에 ALLOC_NOFRAGMENT가 있으면 min_order를 pageblock_order로 고정하여 서로 다른 migrate type page가 pageblock 내에 섞이지 않도록 한다
- L2916 : fallback인 경우이므로 fragmenration이 최대한 덜 발생하도록 MAX_ORDER에서부터 할당을 시도한다. 따라서 current_order 루프는 MAX_ORDER - 1 에서 1 씩 감소시켜 min_order까지 수행한다
- L2918 : zone->free_area[current_order]를 area로 가져온다
- L2919 : 함수 find_suitable_fallback()으로 fallback migrate type을 구한다. 이 때 only_stealable == false이다
- L2921 : fallback이 되는 경우가 아니면 다음 order로 continue
- L2932 : fallback이 되는데 start migrate type == MOVABLE 이고 can_steal == false이면 order < pageblock_order/2이므로 작은 order를 할당하는 경우이다. 이 때는 그냥 작은 order부터 할당 시도하는 것이 낫다고 판단하여 find_smallest로 이동한다
- L2939 : MAX_ORDER - 1에서 min_order까지 모두 fallback이 안되면 false를 리턴한다
- L2941 : find_smallest
- L2942 : current_order를 order에서 MAX_ORDER - 1까지 1 증가시키면서 루프를 수행
- L2944 : 마찬가지로 zone->free_area[current_order]에 대해서 함수 find_suitable_fallback()으로 fallback migrate type을 구한다. 이 때 only_stealable == false이다.
- L2947 : fallback이 안되면 다음 order를 시도하고 아니면 break
- L2955 : 첫 루프에서 fallback 가능한 order가 최소 1개는 있었으므로 current_order == MAX_ORDER는 불가능하다
- L2957 : do_steal
- L2958 : area->free_list[fallback_mt]의 첫 page를 가져온다
- L2960 : 함수 steal_suitable_fallback()로 page를 start migrate type으로 훔쳐온다. 이 때 whole block은 can steal로 설정된다
- L2966 : true 리턴

 

find_suitable_fallback()
- 인자로 free_area area, order, migratetype, bool only_stealable, bool can_steal을 받는다
- only_stealable이 true이면 can_steal == true 결과가 나와야 migrate type을 리턴하고 아니면 -1을 리턴한다
- can_steal은 리턴값이다

- L2739 : area->nr_free == 0이면 -1을 리턴한다
- L2742 : can_steal = false로 초기화
- L2743 : i = 0에서 시작하여 1씩 증가시키며 루프
- L2744 : 전역 변수 배열 fallbacks[][]는 각 migrate type이 다른 migrate type으로 fallback 되는 순서를 리스트로 만든 것으로, fallbacks[migrate type][i]를 fallback_mt로 받아온다
- L2745 : fallback_mt == MIGRATE_TYPE이면 루프를 모두 돌았는데 적절한 migrate type을 못 찾은 것이므로 break
- L2748 : area->free_list[fallback_mt]가 비었으면 다음 fallback migrate type으로 continue
- L2751 : 함수 can_steal_fallback()으로 steal 가능한 경우인지 확인하고 가능하면 can_steal을 true로 한다
- L2754 : only_stealable == false이면 fallback_mt를 리턴한다
- L2757 : can_steal == true이면 fallback_mt를 리턴한다
- L2761 : 그 외에는 -1을 리턴한다 (fallback 안됨)

 

can_steal_fallback()
- 인자로 order와 start_mt를 받는다
- pageblock의 migrate type pollution을 최대한 방지하기 위해 최대한 많은 page를 steal하기를 원함
- reclaimable/unmovable allocation의 경우, movable pageblock을 오염시키면 안 좋기 때문에 이 경우에는 steal을 항상 허용함
- 반대로 movable allocation이 reclaimable/unmovable pageblock을 오염시키는 경우는 딱히 개입하지 않는다
- L2594 : order >= pageblock_order 이면 항상 steal 허용
- L2597 : order >= pageblock_order / 2 인 경우이거나 start_mt == MIGRATE_RECLAIMABLE 또는 MIGRATE_UNMOVABLE 인 경우는 항상 허용한다. 또한 전역 변수 page_group_by_mobility_disabled == true인 경우도 항상 steal을 허용하는데 이 경우는 시스템의 물리 메모리 자체가 매우 부족한 경우이다
- L2603 : 그 외의 경우에는 불허한다

 

steal_suitable_fallback()
- 인자로 zone, page, alloc_flags, start type, whole block을 받는다
- L2654 : 함수 buddy_order()로 page->private (= order)를 current_order로 가져온다
- L2658 : 함수 get_pageblock_migratetype()으로 page의 pageblock migrate type을 old block type으로 가져온다
- L2664 : old block type이 high atomic이면 single_page로 이동한다
- L2668 : current_order >= pageblock_order이면 함수 change_pageblock_range()으로 현재 compound page에 속한 pageblock들의 migrate type을 start type으로 변경하고 single_page로 이동한다
- L2678 : 함수 boost_watermark()로 현재 zone의 watermark를 상승시키고 alloc flags에 ALLOC_KSWAPD가 참이면 zone->flags의 ZONE_BOOSTED_WATERMARK를 set 한다
- L2682 : 인자 whole block == false이면 single_page로 이동
- L2685 : 함수 move_freepages_block()로 page들을 steal한다. free_pages에 steal한 page 수를 기록하고, movable_pages에 추가로 이동 가능한 page를 기록한다
- L2692 : start type이 movable인 경우, alike pages에 movable pages를 넣는다
- L2694 : 그 외의 경우 만약 old block type이 movable인 경우 alike_pages에 pageblock에 있는 모든 non-movable page 수를 기록한다. 이는 총 pageblock page 수에 free pages와 movable pages 수를 더한 값이다. 만약 old block type이 movable이 아니면, alike pages = 0으로 한다
- L2710 : free_pages == 0이면 block 단위 steal이 실패한 것으로 single_page로 이동한다
- L2717 : free_pages + alike_pages가 pageblock 전체 page 수의 절반 이상이거나 page_group_by_mobility_disabled == true이면 함수 set_pageblock_migratetype()로 현재 page의 pageblock migrate type을 start type으로 변경한다
- L2721 : 리턴

- L2723 : single_pages
- L2724 : 함수 move_to_free_list()로 page를 start type의 freelist의 tail에 추가하고 리턴한다

 

get_pageblock_migratetype()
- page의 ms->usage->pageblock_flags와 pfn으로부터 page가 속한 pageblock의 migrate type을 리턴한다

 

move_freepages_block()
- 인자로 zone, page, migrate type, num movable을 받는다
- num movable은 리턴값이다

- L2545 : num movable pointer가 NULL이 아니면 값을 0으로 초기화한다
- L2548 : page의 pfn을 계산한다
- L2549 : pfn을 pageblock 단위 align을 맞추어 start pfn을 계산한다
- L2550 : start pfn + pageblock의 page 수 - 1을 더해 end pfn을 계산한다
- L2553 : start pfn이 현재 zone 영역 안에 있지 않으면 start pfn을 page pfn으로 변경한다
- L2555 : end pfn이 현재 zone 영역 안에 있지 않으면 0을 리턴한다
- L2558 : 함수 move_freepages()으로 start pfn부터 end pfn까지의 page들을 migrate type의 free list로 이동시키고, 이동된 page 수를 리턴한다. 또한 num movable로 기할당되어 있으나 추가로 migrate type의 free list로 이동이 가능할 것으로 보이는 page 수도 리턴한다

 

move_freepages()
- 인자로 zone, start pfn, end pfn, migrate type, num movable을 받는다
- start pfn에서 end pfn 까지 page들을 migrate type의 freelist로 이동시키고, 이동된 page 수를 리턴한다
- 또한 buddy에는 속하지 않으나 pageLRU 및 pageMovable에 해당하는 page들은 이동 가능한 것으로 보고 카운팅하여 num movable에 포함시켜 리턴한다

- L2512 : pfn을 start pfn에서 end pfn까지 루프를 돌린다
- L2513 : pfn에 해당하는 page를 가져온다
- L2514 : page가 buddy에 속해있지 않으면, 즉 이미 할당되어 있으면 pageLRU 및 pageMovable에 해당하는 경우 이동 가능한 것으로 보고 num movable에 카운팅한다
- L2528 : page와 zone의 node가 다르면 버그
- L2529 : page의 zone이 인자로 들어온 zone과 다르면 버그
- L2531 : page의 order를 order로 가져온다
- L2532 : 함수 move_to_free_list()로 page를 migrate type의 free list의 tail에 추가한다
- L2533 : 루프 변수 pfn을 증가시킨다
- L2534 : 이동한 page 수를 업데이트한다
- L2537 : 루프가 끝나고 이동된 총 page 수를 리턴한다

 

move_to_free_list()
- 인자로 page, zone, order, migrate type을 받는다
- zone->free_area[order]->free_list[migrate type]의 tail에 page를 추가한다

번호 제목 글쓴이 날짜 조회 수
공지 [공지] 스터디 정리 노트 공간입니다. 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 210
» [커널 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
109 [커널 17차] 82주차 ㅇㅇㅇ 2022.03.27 65
XE Login