[커널 17차] 46주차
2021.07.18 00:13
free_area_init() 계속
- find_zone_movable_pfns_for_nodes() 부터 시작
- 각 zone 별로 이름, start pfn과 end pfn을 출력한다
- 각 node 별로 노드 id와 movable 영역 시작 pfn을 출력한다
- 각 노드의 memblock별로 노드 id, 시작 pfn, 종료 pfn을 출력하고 각 memblock의 시작 pfn부터 마지막 pfn까지 영역에 대해 subsection_map_init()을 수행하여 subsection bitmask를 set한다
- mminit_verify_pageflags_layout()을 수행하여 page 구조체의 pageflags의 layout을 커널 로그로 출력한다
- setup_nr_node_ids()를 수행하여 nr_node_ids 전역변수를 possible node의 최대 index + 1로 설정한다
- init_unavailable_mem()를 수행 --> 여기까지 진행
find_zone_movable_pfns_for_nodes()
- 각 노드 별로 movable 영역이 시작되는 pfn을 계산한다
- restart: 부분부터 진행
- required_kernelcore (kernelcore 영역으로 할당, 즉 non-movable로 설정해야 하는 pfn 수)를 usable_nodes로 나누어서 각 노드별로 할당 받아야 하는 kernel pfn 수를 계산한다 (kernelcore_node 값)
- 물리 메모리가 존재하는 노드 별로 loop를 돌면서 다음을 수행한다
1) kernelcore_remaining에 현재 노드에 할당해야 하는 커널 페이지를 입력
2) 현재 노드의 각 memblock 별로 루프를 돌면서 아래를 수행한다
-- zone_movable_pfn[nid] 이하의 page들은 이미 커널에 할당된 것이므로 패스한다
-- usable_startpfn보다 낮은 pfn들은 무조건 커널에 할당하고 그 사이즈만큼 kernelcore_remaining 및 required_kernelcore에서 차감한다
-- 해당 memblock의 end_pfn이 usable_startpfn보다 낮거나 같으면 memblock이 통째로 커널에 할당되었으므로 zone_movable_pfn[nid]를 현재 memblock의 end_pfn로 업데이트하고 다음 memblock으로 넘어간다
-- 아니면 usable_startpfn부터 시작해서 memblock에 남은 메모리 영역을 남은 커널 할당량만큼 커널에 할당해야 한다
-- 또는 usable_startpfn이 memblock의 start_pfn보다 낮으면 무조건 커널에 할당해야 하는 페이지는 없으므로 할당된 커널 사이즈만큼을 현재 memblock에서 할당하면 된다
-- 남은 memblock 영역이 남은 커널 할당량보다 크면 남은 커널 할당량을 이번 memblock에 모두 할당하고 zone_movable_pfn[nid]를 usable_startpfn/start_pfn부터 해당 사이즈만큼 올려서 업데이트한다
-- 남은 memblock 영역이 남은 커널 할당량보다 작으면 남은 memblock 영역을 모두 커널에 할당하고 그 사이즈만큼 usable_startpfn/start_pfn부터 올려서 zone_movable_pfn[nid]를 업데이트한다
-- 커널에 할당된 만큼 required_kernelcore/kernelcore_remaining을 차감한다
-- 남은 커널 할당량이 0이면 memblock 루프를 break한다
3) 노드 별 할당해야 하는 커널 사이즈를 남은 커널 할당량을 이용해서 재계산한다
- usable_nodes를 1 감소시킨다
- usable_nodes가 0보다 크고 required_kernelcore > usable_nodes이면 restart로 다시 점프해서 남은 커널 할당량은 재분배한다
- 여기서 남은 커널 할당량 페이지 수가 남은 노드 수보다 같거나 작으면 남은 커널 할당량을 굳이 할당하지 않고 무시하고 넘어간다
- out2 : 각 노드에 대해 zone_movable_pfn[nid]를 1024로 roundup 수행한다
- out : node_states[N_MEMORY]를 saved_node_state로 복원한다
subsection_map_init()
- 시작 pfn과 페이지 수를 인수로 받아서 subsection bitmap을 업데이트하는 함수
- 시작 pfn과 페이지수를 인수로 받아서 시작 section 및 끝 section 번호를 구한다
- page 수가 0이면 그냥 리턴
- 시작 section 번호부터 마지막 section 번호까지 루프를 돌면서 아래를 수행한다
1) 시작 pfn과 남은 페이지 수(nr_pages)를 이용해서 현재 section에서 처리해야 할 page 수를 계산한다 (pfns)
2) 현재 section에 해당하는 mem_section 2nd level 구조체를 가져온다 (ms)
3) 함수 subsection_mask_set()로 ms->usage->subsection_map을 시작 pfn부터 page 개수 만큼의 subsection에 대해서 1로 setting한다. 즉 mem_section 자료 구조에 어떤 subsection이 존재하는지 계산해서 bitmap에 반영한다.
4) section number, 페이지 수, section에 할당된 subsection의 시작과 마지막 index를 출력한다
5) 처리한 페이지 수 만큼 시작 pfn과 처리해야 할 페이지 수 (nr_pages)를 업데이트한다
subsection_mask_set()
- 인수 pfn부터 nr_pages 만큼의 페이지를 subsection index로 변환해서 인수 map의 bitmap에 반영한다
- subsection index는 subsection 당 page 512개가 포함되고, section 당 subsection이 512개가 포함되는 단위이다
- 따라서 pfn의 하위 9bit를 없애고 하위 18bit 보다 상위의 bit를 제거해서 그 사이의 9bit를 구해서 이를 index로 계산한다
- 이렇게 계산한 index를 mem_section_usage의 subsection_map(512bit)의 bitmap에 대응시킨다
mminit_verify_pageflags_layout()
- config 설정에 따라 struct page의 flags의 각 bit의 layout이 달라진다
- 본 함수는 현재 설정에서 page flags의 layout을 커널 로그로 출력한다
- 출력을 위해 매크로 mminit_dprintk()를 사용하여 "mminit::" 및 prefix를 앞에 출력하고 그 뒤에 로그를 출력한다
init_unavailable_mem()
- 각 memblock.memory에 대해서 루프를 돌면서 memblock.memory에 포함되지 않는 영역에 대해 init_unavailable_range() 함수를 수행하여 초기화하고 초기화된 페이지의 총 수를 계산한다
- 이후 마지막 memblock.memory 다음부터 마지막 pfn(section 단위로 align up)까지 영역을 init_unavailable_range() 함수로 다시 초기화하고 초기화된 페이지를 더한다
- 초기화된 페이지 총 수를 로그에 출력한다
init_unavailable_range()
- 현재 설정으로 pageblock_nr_pages = 1024임
- 시작 pfn부터 end pfn까지 루프를 돌면서 아래를 수행한다
1) 현재 pfn을 pageblock 단위로 align한 pfn이 valid하지 않으면 pfn을 pageblock_nr_pages(1024) 만큼 더하고 continue
- pfn valid check를 pageblock(1024개 page) 단위로 하는 것으로 보임
2) 현재 pfn을 pageblock 단위로 align한 pfn이 valid하면 현재 page에 대해서 __init_single_page()로 초기화하고 __SetPageReserved()로 reserve 처리한다. 또한 본 함수에서 초기화한 page 수를 카운트한다
- 루프가 끝나면 초기화한 page 수를 리턴한다
- 현재로써는 memblock.memory에 포함되지 않는 pfn을 넘겨주었는데, valid_pfn()은 memblock.memory에 포함되어야 valid하므로 대부분의 경우 그냥 skip하는 코드가 된다
- 다만 pageblock 단위로 align down한 다음 pfn_valid() 체크를 하기 때문에 memblock 마지막에 pageblock align이 맞지 않는 pfn들의 경우에는 일부 초기화가 된다 (한 pageblock 이하 만큼만)
- 그러나 이것이 의도된 동작인지는 의문이다
- memblock 앞의 pageblock 만큼은 초기화가 안되는데 뒤의 pageblock 만큼은 초기화를 하고 있다
pfn_valid()
- 인수 pfn이 valid한지 판정
- pfn의 section number가 NR_MEM_SECTIONS (1 << 18)보다 크면 invalid
- pfn의 section이 valid하지 않으면 invalid (valid_section() 함수 사용)
- memblock_is_map_memory() 함수로 pfn에 해당하는 물리 주소가 memblock.memory에 존재하는지, 또한 nomap인지 체크해서 memblock.memory에 존재하지 않거나 nomap이면 invalid이고 아니면 valid로 리턴한다
valid_section()
- 인수 mem_section의 section_mem_map flag가 SECTION_HAS_MEM_MAP이 0이면 invalid로 리턴
memblock_is_map_memory()
- 인수 addr에 해당하는 memblock.memory가 없으면 0 리턴
- 있어도 해당 memblock이 nomap이면 0 리턴
- 아니면 1 리턴
관련 패치
- https://www.mail-archive.com/linux-kernel@vger.kernel.org/msg1550457.html
- https://github.com/torvalds/linux/commit/e8c24773d6b2cd9bc8b36bd6e60beff599be14be
- https://lore.kernel.org/lkml/20171201095048.GA3084@dhcp-128-65.nay.redhat.com/#t
- https://github.com/torvalds/linux/commit/720e14ebec642bc56c44e5e60a2d595900e5bbf0
- https://github.com/torvalds/linux/commit/e822969cab48b
- https://github.com/torvalds/linux/commit/a4a3ede2132ae0863e2d43e06f9b5697c51a7a3b
5.14-rc1에서의 모습
- https://elixir.bootlin.com/linux/v5.14-rc1/source/mm/page_alloc.c
댓글 0
번호 | 제목 | 글쓴이 | 날짜 | 조회 수 |
---|---|---|---|---|
공지 | [공지] 스터디 정리 노트 공간입니다. | woos | 2016.05.14 | 623 |
86 | [커널 17차] 53주차 | ㅇㅇㅇ | 2021.09.11 | 28 |
85 | [커널 17차] 52주차 | JSYoo5B | 2021.09.04 | 55 |
84 | [커널 17차] 51주차 | ㅇㅇㅇ | 2021.08.21 | 210 |
83 | [커널 17차] 50주차 | ㅇㅇㅇ | 2021.08.15 | 173 |
82 | [커널 17차] 49주차 | ㅇㅇㅇ | 2021.08.07 | 216 |
81 | [커널 17차] 48주차 | ㅇㅇㅇ | 2021.08.01 | 168 |
80 | [커널 18차] 9주차 | Runixs | 2021.07.29 | 258 |
79 | [커널 17차] 47주차 | ㅇㅇㅇ | 2021.07.24 | 83 |
78 | [커널 18차] 8주차 | Runixs | 2021.07.22 | 168 |
» | [커널 17차] 46주차 | ㅇㅇㅇ | 2021.07.18 | 60 |
76 | [커널 18차] 7주차 | Runixs | 2021.07.12 | 129 |
75 | [커널 17차] 45주차 | ㅇㅇㅇ | 2021.07.10 | 127 |
74 | [커널 17차] 44주차 | ㅇㅇㅇ | 2021.07.04 | 76 |
73 | [커널 18차] 6주차 | V4bel | 2021.07.03 | 75 |
72 | [커널 17차] 43주차 | ㅇㅇㅇ | 2021.06.27 | 139 |
71 | [커널 18차] 5주차 | V4bel | 2021.06.26 | 102 |
70 | [커널 17차] 42주차 | ㅇㅇㅇ | 2021.06.20 | 297 |
69 | [커널 18차] 4주차 | V4bel | 2021.06.19 | 92 |
68 | [커널 17차] 41주차 | ㅇㅇㅇ | 2021.06.13 | 36535 |
67 | [커널 18차] 3주차 | V4bel | 2021.06.12 | 103 |
.