Files
DongHyeonkaandClaude Opus 5 2109f726fe feat(pipeline): keycloak-session-store 25편·virtualization 59편을 S3→S5→S6 으로 돌린다
기록 84편을 계약 에이전트로 다시 썼다. 기존 71편(kss 25 · virt 46)과, 계약에만
있고 안 쓰여 있던 새 글감 13편이다. 원장 84개를 열어 단계마다 스킬 영수증과 관문
종료 코드를 적었고 verify-pipeline-run.py 가 error 0 으로 닫는다.

SSOT 결함 둘을 고쳤다.

- kss 의 `약 58일` 이 반입 중 `약 59일` 로 바뀌어 있었다. 원 증거 파일이
  「남은 일수: 88일 … 실제 갱신까지 약 58일」로 산수를 직접 적는다. D-4a 쪽
  `약 59일` 은 강제 갱신 뒤(`VALID: 89 days`)라 맞는 값이라 그대로 뒀다.
- virt §198 의 `11.6GB` 는 §178 의 원 측정 `Mem: 11648`(MiB)과 어긋나는데
  원 가이드의 표기 그대로라 고치지 않고 쓰이는 자리에 대조를 적었다.

기록의 수치 오류 셋을 고쳤다 — CASE 요약의 「게스트 셋에 8240MB」(5120+3120 은
둘이다), k3s 편이 같은 것을 여섯·일곱·여덟로 세던 것, no-docker 편의 「셋을 더
든다」(§281 의 표는 네 행이고 디스크 행이 빠져 있었다).

계약을 셋 고쳤다.

- kss 의 sourceRepository 리비전이 cdac9b8 이었는데 그 커밋에는 docs/guides/**
  28개가 아예 없다. 9465582b 로 바꾸고, 반입한 바이트가 어느 커밋과도 같지 않다는
  것을 측정값과 함께 적었다 — 반입은 커밋이 아니라 그 시점의 작업 트리에서 떠 온
  것이다(kss 297/306 · virt 12/14 가 작업 트리와 같고, 200 커밋을 거슬러 전수
  대조했을 때 가장 가까운 커밋도 28개가 어긋났다).
- virt 계약이 「2026-09-11 재배분」이라고 적는데 SSOT 는 재배분 날짜를 적지 않고
  재배분 뒤 값은 이미 2026-09-10 측정에 찍혀 있다.
- kss 후보 대장이 지나친 절 아홉에 처분을 적었다(warn 9 → 0). 새 글감은 0건이고
  넷은 앵커가 h3 슬러그의 접두가 아니라 중간 토막이라 검사기가 못 본 것이었다.

style_profile.mjs 의 결함 둘을 고쳤다 — frontmatter 가 문장으로 세어져
(실측 398자짜리 「문장」 하나) 평균 길이를 기준 안으로 밀어 올리고 있었고,
engPerSent 의 분자는 목록을 포함한 글에서, 분모는 목록을 걷어낸 글에서 세고
있었다(Question 기록에서 11.94 → 3.86).

verify-pipeline.py 전 항목 PASS · error 0 · unittest 334건 OK.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 11:01:55 +09:00

13 KiB

id, kind, slug, title, topic, topicName, project, status, basisVersion, studio, assets, sourceRevision, source
id kind slug title topic topicName project status basisVersion studio assets sourceRevision source
e80853fa-98b8-4cc3-a2df-427c7147794b CONCEPT page-fault-layers-in-a-vm VM 에서 page fault 는 세 계층에서 따로 일어난다 memory-virtualization 메모리 가상화 virtualization 초안 x86-64 Intel EPT 기준의 second-stage translation · Linux Guest/Host kernel 의 page fault 처리 · AMD 는 NPT 계열로 대응 https://hyeonworks.com/studio/documents/e80853fa-98b8-4cc3-a2df-427c7147794b/edit
key file
page-fault-layers-in-a-vm ../../../final/assets/diagrams/page-fault-layers-in-a-vm/page-fault-layers-in-a-vm.svg
no-commit · 밖에서 반입한 문서 한 편. 고정할 저장소 리비전이 없다
final/document.md#35-tlb-주소-변환-결과의-cpu-cache
final/document.md#45-guest-page-fault
final/document.md#46-page-fault의-대표적인-원인
final/document.md#47-ept-violation
final/document.md#48-guest-page-fault와-ept-violation-비교
final/document.md#49-host-page-fault도-별도로-존재한다
final/document.md#82-핵심-claim-registry
final/document.md#86-문제를-진단할-때의-분류

VM 에서 page fault 는 세 계층에서 따로 일어난다

가상 머신 안에서 메모리 접근이 완료되지 못하면 그 사건을 받는 곳이 셋이다. GVA(Guest Virtual Address)를 GPA(Guest Physical Address)로 바꾸는 첫 단계에서 막히면 Guest Page Fault 가 나서 게스트 커널이 처리한다. 그 GPA 를 HPA(Host Physical Address)로 바꾸는 두 번째 단계에서 막히면 EPT Violation 이 나고, VM Exit 뒤 KVM 이 받는다. QEMU 도 호스트의 일반 프로세스여서 자기가 마련한 메모리에 대해 Host Page Fault 를 따로 겪는다. 이름이 모두 fault 라 한 덩어리로 읽히지만 일어나는 단계도 처리하는 쪽도 다르고, 셋 중 어느 것이 늘었는지에 따라 볼 지표가 갈린다.

관계

  • Guest 메모리 주소가 물리 RAM 에 닿기까지 — GVA · GPA · HPA 정상일 때 접근이 어떤 경로를 지나는지를 그 글이 세운다. 이 글은 그 경로가 완료되지 않을 때를 맡는다.
  • Host 메모리 압박이 Guest 와 스토리지까지 내려가는 경로 호스트 쪽 fault 가 늘어나는 배경인 reclaim 과 swap 을 그 글이 다룬다.
  • 게스트 page fault 증가는 workload 변화를 따라가는가 게스트 쪽 fault 지표를 이 호스트에서 재는 질문이다. 이 글은 원인 분류까지만 적었다.
  • 호스트 major fault 와 스토리지 지연은 같은 시간축에서 함께 움직이는가 호스트 쪽 major fault 와 스토리지 지연을 같은 시간축에 놓는 질문이다.
  • 메모리 증상 하나로 계층을 단정하지 않는다 이 세 갈래가 그 기준이 요구하는 계층 구분을 만든다.

본문

TLB Miss 와 Page Fault 는 다른 사건이다

주소 변환 결과는 CPU 의 TLB(Translation Lookaside Buffer, 주소 변환 캐시)에 담긴다. 거기에 찾는 변환이 없으면 TLB Miss 가 나지만, 그것으로 접근이 실패하지는 않는다.

TLB에 translation cache가 없음
        ↓
Page Table을 조회
        ↓
정상 mapping 존재
        ↓
계속 실행

Page Fault 는 조건이 다르다. 페이지 테이블 상태로는 지금 접근을 정상으로 끝낼 수 없어서, 커널이 끼어들어 페이지를 마련하거나 매핑을 고쳐야 명령을 다시 시도할 수 있다. TLB Miss 는 테이블을 한 번 더 읽으면 풀리는데, 이쪽은 커널 처리를 부른다.

첫 번째 단계 — Guest Page Fault

이 fault 는 GVA 를 GPA 로 바꾸는 첫 번째 변환 단계에서 일어난다.

GVA
 ↓
Guest Page Table
 ↓
현재 접근을 완료할 수 없음
 ↓
Guest #PF
 ↓
Guest Kernel Page Fault Handler

게스트 프로세스가 아직 물리 페이지가 붙지 않은 가상 메모리 영역에 처음 접근하면 이 사건이 난다. 게스트 안의 Keycloak 을 예로 들면, 새 영역의 첫 접근에서 fault 가 나고 게스트 커널이 페이지를 확보해 매핑을 갱신한 뒤 명령을 다시 시도한다.

Keycloak
 ↓
새 Virtual Memory 영역에 첫 접근
 ↓
Guest Page Table
 ↓
현재 usable physical mapping 없음
 ↓
Page Fault
 ↓
Guest Kernel
 ↓
Page 확보 / mapping 갱신
 ↓
Instruction 재시도

이 사건 자체가 프로그램 오류를 뜻하지는 않는다. 정상적인 메모리 관리에서도 늘 일어난다.

Guest Page Fault 를 부르는 다섯 가지

원문은 대표적인 원인을 다섯으로 나눈다. 앞의 넷은 커널이 처리해 실행이 이어지고, 마지막 하나만 프로세스로 신호가 간다.

원인 게스트 커널이 무엇을 하나
Demand Paging 아직 물리 페이지가 필요하지 않았던 영역에 첫 접근이 오면 페이지를 준비한다
Swap-in 필요한 페이지가 게스트 RAM 에 없으면 게스트 swap 에서 읽어 RAM 을 복원하고 페이지 테이블을 갱신한다
Permission Fault 읽기 전용 페이지에 쓰기가 들어오는 접근을 걸러 낸다
Copy-on-Write 쓰기에서 난 fault 를 의도적으로 이용해 페이지를 복제하고 쓰기 가능한 매핑을 새로 만든다
Invalid Access 정상 매핑으로 해결할 수 없는 접근이면 SIGSEGV 등으로 이어질 수 있다

권한이 fault 를 부르는 까닭은 페이지 테이블 엔트리가 매핑만 담고 있지 않기 때문이다. 같은 엔트리에 읽기·쓰기·실행 권한이 함께 들어 있다.

Physical Frame: 1234
Present:        1
Writable:       0
Executable:     0

이 엔트리로 매핑된 페이지에 쓰기가 들어가면 fault 가 날 수 있고, Copy-on-Write 는 그 성질을 거꾸로 이용해 쓰기가 들어온 순간에만 페이지를 복제한다. 다섯 가운데 Invalid Access 만 결과가 다르다. 게스트 커널이 정상적인 매핑으로 해결할 수 없는 접근이면 SIGSEGV 로 이어질 수 있고, 그래서 Page Fault 와 Segmentation Fault 는 같은 것이 아니다.

두 번째 단계 — EPT Violation

이번에는 게스트 페이지 테이블 변환이 성공해 GPA 까지 얻었다고 하자. 그런데 그 GPA 에 대한 두 번째 단계 접근을 지금 EPT(Extended Page Tables) 조건으로 끝낼 수 없으면 EPT Violation 이 된다.

GVA
 ↓
Guest Page Table
 ↓
GPA              ← Guest translation 성공
 ↓
EPT
 ↓
EPT Violation
 ↓
VM Exit
 ↓
KVM

게스트 안에서는 첫 단계가 정상으로 끝났으므로 게스트 커널의 fault 처리기가 이 사건을 보지 않는다. 제어권이 VM Exit 으로 VMX(Virtual Machine Extensions) Root 쪽으로 넘어가 KVM 이 처리한다.

두 사건이 갈리는 다섯 항목

무엇을 견주나 Guest Page Fault EPT Violation
문제 위치 GVA → GPA GPA → HPA
관련 테이블 게스트 페이지 테이블 EPT
기본 관점 게스트 가상 메모리 가상화 메모리 매핑
주요 처리 계층 게스트 커널 VM Exit 후 KVM 쪽
앱 오류를 뜻하는가 반드시 아님 반드시 아님

Guest Page Fault 는 게스트가 자기 가상 메모리를 처리하는 사건이고, EPT Violation 은 두 번째 단계 가상화 변환에서 하이퍼바이저 처리가 필요한 사건이다. 마지막 줄이 둘 다 「반드시 아님」인 까닭은 앞에서 본 대로다. demand paging 이나 copy-on-write 처럼 정상 동작이 두 계층 모두에서 fault 를 만든다.

세 번째 — Host Page Fault

QEMU 도 호스트의 일반 사용자 공간 프로세스이므로 QEMU 가 마련한 메모리에는 호스트의 가상 메모리 관리가 그대로 적용된다. 게스트 RAM 을 담고 있는 그 영역도 호스트 페이지 테이블을 지나 호스트 물리 주소로 이어지고, 그 경로에서 demand allocation 이나 reclaim, swap 때문에 fault 가 날 수 있다.

QEMU / Guest RAM Backing
        ↓
Host Virtual Memory
        ↓
Host Page Fault
        ↓
Host Kernel
        ↓
필요한 Host page 처리

게스트 안에서는 이 사건이 fault 로 보이지 않는다. 게스트는 자기 메모리 접근이 오래 걸렸다고만 관측하고, 그 지연의 원인은 호스트 쪽 지표에 남는다. 그래서 가상 머신 메모리를 분석할 때는 Guest Page Fault 와 Host Page Fault, 그리고 EPT 관련 가상화 사건을 적어도 셋으로 갈라 놓는다.

Guest Page Table 에서 갈래가 둘로 나뉘어 하나는 Guest Page Fault 로 Guest Kernel 에 가고 다른 하나는 GPA 를 들고 EPT 로 내려가며, EPT 에서는 EPT Violation 이 VM Exit 을 거쳐 KVM 으로 가고, 따로 놓인 QEMU 의 Guest RAM Backing 에서는 Host Page Fault 가 Host Kernel 로 가는 갈래도. 받는 곳의 이름이 그대로 처리 계층의 이름이다.

그림에서 QEMU 쪽 갈래는 위의 두 갈래와 선으로 이어져 있지 않다. 근거 문서가 EPT 로 얻은 HPA 와 QEMU 가 마련한 메모리의 호스트 물리 주소를 같은 것이라고 적지 않아서 그 선을 긋지 않았다.

메모리 지연이나 OOM(Out Of Memory) 이 보일 때 셋을 어디에 놓나

증상 하나로 "메모리 부족"을 결론내리지 않고 어느 계층의 사건인지부터 가른다. 세 사건은 이 분류에서 서로 다른 가지에 들어간다.

문제
 │
 ├─ Guest Virtual Memory?
 │    ├─ Page Fault
 │    ├─ Guest reclaim
 │    ├─ Guest swap
 │    └─ Guest OOM
 │
 ├─ Virtualization Translation?
 │    ├─ EPT-related event
 │    ├─ TLB pressure
 │    └─ Huge-page/mapping 특성
 │
 └─ Host Memory?
      ├─ Host reclaim
      ├─ Host swap
      ├─ Host major fault
      └─ Host OOM

원문의 분류에는 Dynamic Memory 와 NUMA(Non-Uniform Memory Access) 가지가 더 있고, 위에 옮긴 셋이 fault 가 걸리는 가지다. 게스트 쪽 fault 가 늘었으면 게스트의 reclaim 과 swap 을 같이 보고, 호스트 쪽 major fault 가 늘었으면 호스트의 reclaim 과 swap 을 같이 본다. 어느 쪽 지표를 먼저 여느냐가 이 구분에서 정해진다. 다만 이 호스트에서는 게스트 쪽 fault 지표도 호스트 쪽 major fault 도 아직 열지 않았다. 그래서 이 분류는 지금 어느 지표부터 열지 정하는 데만 쓰인다.

이 글이 확정하지 않는 것

이 호스트에서 fault 를 잰 값은 하나도 없다. 게스트 쪽 fault 지표도 호스트 쪽 major fault 도 읽지 않았고, 앞의 다섯 원인 가운데 무엇이 이 환경에서 실제로 일어나는지도 세지 않았다. 원문 제2부는 개념 서술이고 실제 서버에 딸린 값은 OQ(Open Question) 번호가 붙은 확인 목록 열넷으로 미뤄져 있다.

게스트 쪽은 OQ-13 이 받는다. page-fault 관련 지표를 관측한 뒤 그 증가가 무엇에서 왔는지를 네 갈래로 갈라 보는 확인이고, 증가 자체를 오류로 읽지 않는 것이 조건이다.

정상 demand paging?
COW?
Guest swap-in?
application working-set 증가?

호스트 쪽은 OQ-14 가 받는다. 호스트 메모리 압박 실험을 하면서 아래 넷을 같은 시간축에 놓고 견준다.

Host Fault
   +
Swap activity
   +
Storage latency
   +
Guest application latency

가운데 계층은 그 목록이 받지 않는다. 위 분류에는 EPT 관련 사건과 TLB 압박이 한 가지로 들어 있는데, 그것을 이 호스트에서 재라고 적은 항목은 열넷 가운데 없다. 이 글이 갈라 놓은 세 계층에서 확인 계획이 붙은 것은 게스트 쪽과 호스트 쪽 둘이다.

원문 제2부가 fault 처리를 서술하면서 커널 버전을 적지 않아 이 글도 특정 버전에 고정하지 않았다. 이 실험대의 커널은 §197 이 7.2.2-arch1-1 로 적었다. 그 위에서 fault 지표를 읽은 기록은 없다. 여기 적은 것은 그 문서가 서술한 처리 구조이고, 이 서버에서 어떤 값이 나오는지는 위 두 확인을 돌려야 안다.