{ "version": "1.1", "id": "vm-exit-handling-cycle", "title": "VM Exit 은 KVM 에서 끝나기도 하고 QEMU userspace 까지 가기도 한다", "question": "VM Exit 이 난 뒤 제어권은 어디까지 올라갔다가 어떻게 Guest 로 돌아오는가", "type": "flow", "direction": "LR", "audience": [ "VM 안의 지연을 계층별로 가르려는 사람", "KVM 실행 경로를 처음 읽는 사람" ], "summary": "VM Exit 은 KVM 에서 Exit Reason 을 보고 두 갈래로 나뉘며, 커널 안에서 끝난 갈래와 QEMU userspace 를 거친 갈래가 어느 쪽이든 VM Entry 를 지나 Guest 실행으로 돌아온다.", "alt": "Guest 에서 VM Exit 으로 KVM 에 닿은 뒤 커널 처리와 QEMU 처리 두 갈래로 갈라졌다가 VM Entry 로 다시 Guest 실행 재개에 모이는 흐름도.", "long_description": "왼쪽에서 오른쪽으로 읽는다. 왼쪽 끝에 Guest 가 있고 VM Exit 이 KVM 으로 제어권을 넘긴다. KVM 은 Exit Reason 을 확인해 두 갈래 중 하나를 고른다. 커널 안에서 처리할 수 있는 Exit 은 Kernel 쪽 KVM 커널 처리로 가고, userspace 처리가 필요한 Exit 만 KVM_RUN 이 반환되면서 Userspace 쪽 QEMU 로 간다. QEMU 는 필요한 장치 동작을 처리한 뒤 KVM_RUN 을 다시 호출한다. 두 갈래는 오른쪽 끝에서 다시 만나며 어느 쪽이든 VM Entry 를 지나 Guest 실행 재개로 돌아온다. 무엇이 Exit 을 부르는지와 Exit 이 잦을 때 무엇을 함께 보는지는 본문의 표와 문단이 맡는다.", "source_context": { "document": "docs/virtualization/final/document.md", "document_sha256": "181e2b3cc8a45bae81e7e8193d026937c4d586ae4495d3b2c323eb7e6abcfadd", "anchor": { "kind": "heading", "value": "9. VM Exit 이후 처리", "line": 493 } }, "composition": { "profile": "component-flow", "diagram_only": true, "reference_ids": [ "payment-event-flow" ], "rationale": "이 절이 주장하는 것은 제어권이 한 방향으로 지나가는 경로와 그 경로가 Exit Reason 에서 갈렸다가 다시 만난다는 것이다. sequence 는 참여자마다 생명선을 세우고 메시지를 시각 순서로 세우는데 이 절에는 갈래가 있어 한 줄로 세울 수 없고, orchestrator-workers 는 KVM 아래에 교체 가능한 워커들을 두는 그림이라 커널 갈래와 userspace 갈래가 서로 다른 경계에 있다는 사실이 지워진다.", "focus_node": "kvm" }, "groups": [], "nodes": [ { "id": "guest", "label": "Guest", "kind": "service", "role": "source", "shape": "box", "description": "VM Exit 이 나기 직전까지 실행 중이던 Guest.", "evidence": [ { "start_line": 498, "end_line": 501 } ], "assumption": false }, { "id": "kvm", "label": "KVM", "kind": "service", "role": "service", "shape": "box", "emphasis": "primary", "details": [ "Exit Reason" ], "description": "VM Exit 을 받아 Exit Reason 을 확인하고 갈래를 고르는 자리.", "evidence": [ { "start_line": 495, "end_line": 495 }, { "start_line": 502, "end_line": 504 } ], "assumption": false }, { "id": "kvm-kernel-handling", "label": "KVM 커널 처리", "kind": "service", "role": "service", "shape": "box", "description": "커널 안에서 끝낼 수 있는 Exit 을 처리하는 갈래. QEMU 까지 올라가지 않는다.", "evidence": [ { "start_line": 508, "end_line": 510 }, { "start_line": 531, "end_line": 531 } ], "assumption": false, "details": [ "Kernel" ] }, { "id": "qemu", "label": "QEMU", "kind": "service", "role": "service", "shape": "box", "details": [ "Userspace", "device emulation", "KVM_RUN 재호출" ], "description": "userspace 처리가 필요한 Exit 에서만 개입하는 갈래.", "evidence": [ { "start_line": 510, "end_line": 516 }, { "start_line": 533, "end_line": 533 } ], "assumption": false }, { "id": "guest-resume", "label": "Guest 실행 재개", "kind": "service", "role": "sink", "shape": "box", "description": "두 갈래가 다시 만나는 자리. VM Exit 은 VM 종료가 아니라 여기로 돌아온다.", "evidence": [ { "start_line": 521, "end_line": 524 }, { "start_line": 529, "end_line": 529 } ], "assumption": false } ], "edges": [ { "id": "exit-to-kvm", "from": "guest", "to": "kvm", "label": "VM Exit", "kind": "control", "style": "solid", "evidence": [ { "start_line": 495, "end_line": 495 }, { "start_line": 498, "end_line": 502 } ], "assumption": false }, { "id": "kernel-branch", "from": "kvm", "to": "kvm-kernel-handling", "label": "커널 처리 가능", "kind": "control", "style": "solid", "evidence": [ { "start_line": 504, "end_line": 510 }, { "start_line": 531, "end_line": 531 } ], "assumption": false }, { "id": "userspace-branch", "from": "kvm", "to": "qemu", "label": "KVM_RUN return", "kind": "control", "style": "solid", "evidence": [ { "start_line": 508, "end_line": 512 }, { "start_line": 533, "end_line": 533 } ], "assumption": false }, { "id": "kernel-reentry", "from": "kvm-kernel-handling", "to": "guest-resume", "label": "VM Entry", "kind": "control", "style": "solid", "evidence": [ { "start_line": 518, "end_line": 524 }, { "start_line": 531, "end_line": 531 } ], "assumption": false }, { "id": "userspace-reentry", "from": "qemu", "to": "guest-resume", "label": "VM Entry", "kind": "control", "style": "solid", "evidence": [ { "start_line": 514, "end_line": 524 }, { "start_line": 533, "end_line": 533 } ], "assumption": false } ], "legend": [], "metadata": { "rationale": "flow 로 고른 이유는 이 절이 답하는 물음이 「제어권이 어디까지 갔다가 어떻게 돌아오는가」이기 때문이다. Kernel·Userspace 를 경계 상자로 그리면 두 상자가 같은 열에서 겹쳐(check-figure-overlap 15750px²) 어느 노드가 어느 경계인지 오히려 흐려져 노드의 details 로 내렸다. 무엇이 Exit 을 부르는지(§8)와 Exit 이 잦을 때 무엇을 함께 보는지는 본문 표가 이미 맡고 있어 그림에 넣지 않았다." } }