[커널 17차] 91주차

2022.05.28 23:31

ㅇㅇㅇ 조회 수:64

Top Byte Ignored
- ARMv8 aarch64에 모두 구현됨
- TCR_EL1.TBI / TCR_EL1.TBID 비트에서 설정함
- TBI : https://developer.arm.com/documentation/ddi0595/2021-06/AArch64-Registers/TCR-EL1--Translation-Control-Register--EL1-?lang=en#fieldset_0-38_38
- TBID : https://developer.arm.com/documentation/ddi0595/2021-06/AArch64-Registers/TCR-EL1--Translation-Control-Register--EL1-?lang=en#fieldset_0-52_52-1
- TBI = 0이면 top byte ignored 안씀
- TBI = 1이면 top byte ignored 씀
- TBID는 PAC가 구현되어 있으면 존재함 —> PAC 없으면 그냥 RES0
- TBID = 0이면 instruction/data 모두에 TBI 설정 적용됨
- TBID = 1이면 data에만 TBI 설정 적용됨

 

PAC 동작은 TBI 설정과 별개
- https://events.static.linuxfound.org/sites/events/files/slides/slides_23.pdf

 

QARMA
- https://eprint.iacr.org/2016/444.pdf
- https://www.nuee.nagoya-u.ac.jp/labs/tiwata/fse2017/slides/05-02.pdf
- https://developer.arm.com/documentation/ddi0596/2021-12/Shared-Pseudocode/AArch64-Functions?lang=en#impl-aarch64.ComputePAC.4 에서 ComputePAC()
- ComputePAC()은 QARMA 예시임
- modifier는 context 정보로 tweak에 해당됨

 

GFP_ZEROTAGS
- 유저 쪽에서 할당받으면 사용됨
- alloc_zeroed_user_highpage_movable() 함수에서 세팅
- anonymous page fault handling에서 사용

 

MTE 설명 LWN
- https://lwn.net/Articles/834289/
- 유저 애플리케이션은 mmap()을 PROT_MTE 플래그로 호출하여 사용가능
- 이미 매핑된 메모리는 mprotect() 함수로 MTE enable 가능
- Anonymous memory만 PROT_MTE 세팅 가능 (File-backed memory는 사용 불가)
- 처음 할당받으면 TAG는 0으로 세팅되어 있음
- IRG 명령어로 랜덤 태그 만들어서 STG로 세팅 가능
- 태그 관련 명령어들은 EL0에서 사용 가능함 (커널 개입 필요 X)
- prctl() system call로 PR_SET_TAGGED_ADDR_CTRL 명령으로 tag 불일치시 행동 설정 가능
- PR_MTE_TCF_NONE : 디폴트로 아무것도 안함
- PR_MTE_TCF_SYNC : 바로 task kill (SIGSEGV)
- PR_MTE_TCF_ASYNC : queue에 넣고 나중에 kill
- PAC와 같이 쓰면 bit 나누어 써야 하지만 같이 작동 가능함
- MTE는 stack overrun 등을 방지 / PAC는 stack pointer corruption 방지 가능
- GCC/LLVM에서 앱 변경 없이 알아서 해줌 (?)
- 패치 : https://github.com/torvalds/linux/commit/9f3419315f3cdc41a7318e4d50ba18a592b30c8c

 

get_page_from_freelist()
- L4114 : CONFIG_DEFERRED_STRUCT_PAGE_INIT = n이므로 빈 코드
- L4125 : ALLOC_NO_WATERMARKS < NR_WMARK 이면 빌드 에러
- L4126 : 요청된 alloc flags가 ALLOC_NO_WATERMARKS이면 try_this_zone으로 가서 rmqueue()로 워터마크 무관하게 메모리 할당을 받는다
- L4129 : node_reclaim_enabled()이 false이거나 preferred zone의 입장에서 현재 할당 받으려는 zone 사이의 노드 거리가 node_reclaim_distance = RECLAIM_DISTANCE 보다 크면 reclaim을 하지 않고 continue해서 다음 zone으로 넘어간다
- L4133 : 함수 node_reclaim()으로 reclaim 수행하고 ret에 결과 저장
- L4135 : reclaim 결과 NODE_RECLAIM_NOSCAN 또는 NODE_RECLAIM_FULL이면 다음 zone으로 continue
- L4141 : reclaim 결과 NODE_RECLAIM_SOME 또는 NODE_RECLAIM_SUCCESS이면 zone_watermark_ok()로 다시 워터마크 체크하고 성공하면 try_this_zone으로 이동하여 메모리 할당을 수행한다. 아니면 continue로 다음 zone으로 이동한다

 

node_reclaim_enabled()
- 전역 변수 node_reclaim_mode에 RECLAIM_ZONE|RECLAIM_WRITE|RECLAIM_UNMAP 비트가 set 되어 있으면 true 리턴
- node_reclaim_mode는 sysctl로 shell에서 설정 가능함 (이름 : “zone_reclaim_mode”)


zone_reclaim_mode 관련 문서
- Documentation/admin-guide/sysctl/vm.rst
- 실제로는 node_reclaim_enabled 변수인데 sysctl을 통해 zone_reclaim_mode로 접근 가능함
- Fastpath (get_page_from_freelist())에서 zone iteration에서 watermark 체크에 실패하면 zone_reclaim_mode 설정에 따라 node reclaim을 수행한다
- 디폴트는 off이므로 reclaim을 수행하지 않는데 sysctl로 on시키면 좀 더 aggressive하게 reclaim을 수행하게 할 수 있다


node_reclaim()
- CONFIG_NUMA = n이면 NODE_RECLAIM_NOSCAN을 리턴한다
- CONFIG_NUMA = y이면 아래 함수를 수행
- L4617 : unmapped file backed pages가 min_unmapped_pages 보다 작고 동시에 reclaimable slab page가 min_slab_pages 보다 작으면 reclaim 하지 않고 NODE_RECLAIM_FULL를 리턴한다
- L4625 : 현재 요청이 blocking되면 안되거나 (__GFP_DIRECT_RECLAIM이 아니거나) current->flags가 PF_MEMALLOC이 아니면 NODE_RECLAIM_NOSCAN을 리턴한다
- L4634 : 현재 reclaim 대상 노드에 CPU가 존재하고 대상 노드가 지금 코드를 수행하고 있는 CPU가 아니면, 대상 노드 reclaim은 해당 노드 CPU가 수행하도록 놔두고 NODE_RECLAIM_NOSCAN을 리턴
- L4637 : pgdat->flags의 PGDAT_RECLAIM_LOCKED이 1이면 NODE_RECLAIM_NOSCAN을 리턴하고 나가고, 0이면 atomic test & set으로 1로 만들고 다음으로 진행한다
- L4640 : __node_reclaim()으로 reclaim 수행
- L4641 : pgdat->flags의 PGDAT_RECLAIM_LOCKED bit를 0으로 clear
- L4643 : __node_reclaim()이 실패한 경우 event stat PGSCAN_ZONE_RECLAIM_FAILED을 1 증가시키고 리턴한다


Unmapped file backed pages
- disk IO를 수행할 때 데이터를 요청한 것보다 큰 단위로 읽어와서 DRAM에 캐싱하게 되는데, 이것이 file cache이고, 특히 요청되지 않았으나 곧 사용될 것으로 예측하여 읽어온 file cache가 unmapped file backed page이다. 이러한 page들은 reclaim의 주요 대상이 되는데 그렇다고 너무 자주 reclaim하면 캐싱의 의미가 없어져서 IO 체감 성능이 떨어진다. 이를 방지하기 위해 변수 pgdat->min_unmapped_pages에 최소한의 page수를 정하여 이보다 unmapped page수가 적어지면 reclaim을 하지 않는다.
- pgdat->min_unmapped_pages는 함수 init_per_zone_wmark_min()에서 setup_min_unmapped_ratio() 함수를 통해 설정된다

 

setup_min_unmapped_ratio()
- 전역 변수 sysctl_min_unmapped_ratio에 따라 전체 zone의 managed page 대비 몇 %를 min_unmapped_pages로 설정할 것인지를 sysctl로 설정할 수 있다. (디폴트 1%)
- 설정된 sysctl_min_unmapped_ratio에 따라 일정 비율의 zone managed page를 min_unmapped_pages로 설정한다


min_slab_pages
- Slab에서 메모리가 없으면 buddy에게 new_slab() 함수로 메모리를 요청하게 된다. 이 때 slab cache의 설정에 따라 reclaimable 또는 unreclaimable로 요청이 된다. 이 때 각각 NR_SLAB_RECLAIMABLE_B 및 NR_SLAB_UNRECLAIMABLE_B stat을 업데이트하게 되고 다시 slab에서 buddy로 메모리를 반환할 때 역시 같은 stat 수치를 업데이트하게 된다. 이 수치가 min_slab_pages보다 작으면 reclaimable slab cache가 쓰고 있는 메모리가 너무 작다는 의미이기 때문에 reclaim 대상이 되지 않는다. 그러나 그보다 크면 reclaim의 대상이 될 수 있다
 - pgdat->min_slab_pages는 함수 init_per_zone_wmark_min()에서 setup_min_slab_ratio()를 통해 설정된다

 

setup_min_slab_ratio()
- 전역 변수 sysctl_min_slab_ratio에 따라 전체 zone의 managed page 대비 몇 %를 min_slab_pages으로 설정할 것인지 sysctl로 정할 수 있다. (디폴트 : 5%)
- 설정된 sysctl_min_slab_ratio에 따라 일정 비율의 zone managed page를 min_slab_pages로 설정한다

원래 zone based reclaim을 node based reclaim으로 바꾼 패치
- https://github.com/torvalds/linux/commit/a5f5f91da6ad647fb0cc7fce0e17343c0d1c5a9a

XE Login