Files
document-haness/docs/virtualization/final/.techviz/guest-block-io-to-virtqueue/spec.json
T

339 lines
10 KiB
JSON

{
"version": "1.1",
"id": "guest-block-io-to-virtqueue",
"title": "게스트의 write() 가 virtqueue 에 실리기까지",
"question": "게스트 애플리케이션의 write() 는 virtqueue 에 실리기 전에 게스트의 어느 계층을 어떤 순서로 지나는가",
"type": "flow",
"direction": "TB",
"audience": [
"게스트에서 본 저장소 지연을 계층별로 가르려는 사람",
"virtio-blk 경로를 처음 읽는 사람"
],
"summary": "게스트 애플리케이션의 write() 는 VFS 와 ext4/XFS, Guest Page Cache, Guest Block Layer, /dev/vda, virtio-blk Frontend 를 차례로 지나 virtqueue 에 실린다.",
"alt": "게스트 사용자 공간의 PostgreSQL/Keycloak 에서 시작한 write() 가 게스트 커널의 VFS, ext4/XFS, Guest Page Cache, Guest Block Layer, /dev/vda, virtio-blk Frontend 를 거쳐 virtqueue 에 도달하는 위에서 아래로 읽는 흐름도.",
"long_description": "위에서 아래로 읽는다. 맨 위 Guest Userspace 구역에 PostgreSQL / Keycloak 이 있고 write() 가 게스트 커널로 내려간다. Guest Kernel 구역 안에서 VFS 가 먼저 받고, ext4 / XFS 가 파일을 block 공간에 배치하고, Guest Page Cache 가 그 내용을 dirty page 로 받아 두었다가 writeback 으로 Guest Block Layer 에 내려보낸다. Guest Block Layer 는 그것을 WRITE 나 FLUSH 요청으로 바꿔 /dev/vda 에 걸고, virtio-blk Frontend 가 그 요청을 virtqueue 에 게시한다. virtqueue 아래의 VM Boundary 부터는 QEMU 와 호스트 계층이라 이 그림에서 잘랐다. 완료가 같은 virtqueue 로 되돌아오는 역방향은 SSOT 의 다른 절이 대는 사실이라 이 그림에 넣지 않았고 본문 문단이 맡는다.",
"source_context": {
"document": "docs/virtualization/final/document.md",
"document_sha256": "181e2b3cc8a45bae81e7e8193d026937c4d586ae4495d3b2c323eb7e6abcfadd",
"anchor": {
"kind": "heading",
"value": "128. 전체 구조",
"line": 5804
}
},
"composition": {
"profile": "component-flow",
"diagram_only": true,
"reference_ids": [
"payment-event-flow"
],
"rationale": "이 절이 주장하는 것은 요청 하나가 한 방향으로 지나가는 계층의 순서다. sequence 는 참여자마다 생명선을 세우고 메시지를 주고받는 그림인데 이 구간에는 되돌아오는 메시지가 없어 생명선이 전부 빈 세로줄이 된다. two-zone-pipeline 은 구역 안쪽 엣지 라벨을 캔버스 위쪽에 고정해 writeback 과 WRITE / FLUSH 가 제자리를 잃는다. 구역은 groups 로 두고 흐름은 component-flow 로 세운다.",
"focus_node": "virtqueue"
},
"groups": [
{
"id": "guest-userspace",
"label": "Guest Userspace",
"kind": "boundary",
"description": "게스트 사용자 공간. 저장장치를 직접 다루지 않는다.",
"evidence": [
{
"start_line": 5807,
"end_line": 5809
}
],
"assumption": false
},
{
"id": "guest-kernel",
"label": "Guest Kernel",
"kind": "boundary",
"description": "게스트 커널 공간. VM Boundary 위쪽 계층이 전부 여기 있다.",
"evidence": [
{
"start_line": 5815,
"end_line": 5833
}
],
"assumption": false
}
],
"nodes": [
{
"id": "app",
"label": "PostgreSQL / Keycloak",
"kind": "service",
"role": "source",
"shape": "box",
"group": "guest-userspace",
"description": "파일 연산을 요청하는 게스트 프로세스.",
"evidence": [
{
"start_line": 5807,
"end_line": 5809
},
{
"start_line": 5885,
"end_line": 5885
},
{
"start_line": 5811,
"end_line": 5813
}
],
"assumption": false,
"details": [
"read / write",
"fsync / sync"
]
},
{
"id": "vfs",
"label": "VFS",
"kind": "service",
"role": "service",
"shape": "box",
"group": "guest-kernel",
"description": "열린 파일이 어느 filesystem 구현에 속하는지 보고 연산을 넘기는 공통 계층.",
"evidence": [
{
"start_line": 5815,
"end_line": 5817
},
{
"start_line": 5905,
"end_line": 5905
}
],
"assumption": false
},
{
"id": "fs",
"label": "ext4 / XFS",
"kind": "service",
"role": "service",
"shape": "box",
"group": "guest-kernel",
"description": "파일과 디렉터리를 block 공간에 배치하는 게스트 filesystem.",
"evidence": [
{
"start_line": 5819,
"end_line": 5819
}
],
"assumption": false
},
{
"id": "page-cache",
"label": "Guest Page Cache",
"kind": "store",
"role": "store",
"shape": "box",
"group": "guest-kernel",
"description": "게스트 RAM 에 있는 cache. write() 가 성공해도 데이터는 아직 여기까지만 확정된다.",
"evidence": [
{
"start_line": 5821,
"end_line": 5821
}
],
"assumption": false
},
{
"id": "block-layer",
"label": "Guest Block Layer",
"kind": "service",
"role": "service",
"shape": "box",
"group": "guest-kernel",
"description": "파일 세계의 요청을 block device 세계의 요청으로 바꾸는 계층.",
"evidence": [
{
"start_line": 5825,
"end_line": 5825
}
],
"assumption": false
},
{
"id": "vda",
"label": "/dev/vda",
"kind": "device",
"role": "service",
"shape": "box",
"group": "guest-kernel",
"description": "게스트 Linux 가 하나의 block device 로 인식하는 이름.",
"evidence": [
{
"start_line": 5829,
"end_line": 5829
},
{
"start_line": 5879,
"end_line": 5879
}
],
"assumption": false
},
{
"id": "virtio-blk",
"label": "virtio-blk Frontend",
"kind": "service",
"role": "service",
"shape": "box",
"group": "guest-kernel",
"description": "그 가상 block device 를 제어하는 게스트 커널 driver.",
"evidence": [
{
"start_line": 5831,
"end_line": 5831
},
{
"start_line": 5789,
"end_line": 5789
}
],
"assumption": false
},
{
"id": "virtqueue",
"label": "virtqueue",
"kind": "queue",
"role": "queue",
"shape": "box",
"emphasis": "primary",
"group": "guest-kernel",
"description": "요청이 실리는 자리. 바로 아래가 VM Boundary 다.",
"evidence": [
{
"start_line": 5833,
"end_line": 5835
}
],
"assumption": false
}
],
"edges": [
{
"id": "app-to-vfs",
"from": "app",
"to": "vfs",
"label": "",
"kind": "data",
"style": "solid",
"order": 1,
"evidence": [
{
"start_line": 5811,
"end_line": 5813
},
{
"start_line": 5890,
"end_line": 5890
}
],
"assumption": false
},
{
"id": "vfs-to-fs",
"from": "vfs",
"to": "fs",
"label": "",
"kind": "data",
"style": "solid",
"order": 2,
"evidence": [
{
"start_line": 5817,
"end_line": 5819
}
],
"assumption": false
},
{
"id": "fs-to-page-cache",
"from": "fs",
"to": "page-cache",
"label": "",
"kind": "data",
"style": "solid",
"order": 3,
"evidence": [
{
"start_line": 5819,
"end_line": 5821
}
],
"assumption": false
},
{
"id": "page-cache-to-block-layer",
"from": "page-cache",
"to": "block-layer",
"label": "writeback",
"kind": "data",
"style": "solid",
"order": 4,
"evidence": [
{
"start_line": 5823,
"end_line": 5825
}
],
"assumption": false
},
{
"id": "block-layer-to-vda",
"from": "block-layer",
"to": "vda",
"label": "WRITE / FLUSH",
"kind": "data",
"style": "solid",
"order": 5,
"evidence": [
{
"start_line": 5827,
"end_line": 5829
}
],
"assumption": false
},
{
"id": "vda-to-virtio-blk",
"from": "vda",
"to": "virtio-blk",
"label": "",
"kind": "data",
"style": "solid",
"order": 6,
"evidence": [
{
"start_line": 5829,
"end_line": 5831
}
],
"assumption": false
},
{
"id": "virtio-blk-to-virtqueue",
"from": "virtio-blk",
"to": "virtqueue",
"label": "Virtio block request",
"kind": "data",
"style": "solid",
"order": 7,
"evidence": [
{
"start_line": 5831,
"end_line": 5833
}
],
"assumption": false
}
],
"legend": [],
"metadata": {
"rationale": "component-flow 를 고른 이유는 이 절이 답하는 물음이 「write() 가 virtqueue 에 닿기까지 무엇을 어떤 순서로 지나는가」이기 때문이다. Guest Userspace 와 Guest Kernel 은 §128 이 대괄호로 직접 그어 둔 구역이라 groups 로 두었다. 완료가 같은 virtqueue 로 되돌아오는 역방향은 §166 과 §172 가 대는 사실인데 두 절 모두 이 앵커의 준비된 문맥(§127~§129) 밖이라 넣지 않았다 — 그 문맥 안에서 인용할 줄이 없다. VM Boundary 아래의 QEMU·호스트 계층은 같은 §128 안에 있지만 이 기록이 virtqueue 까지만 따라간다고 밝혀 두었고, 그 아래는 다른 기록의 그림이 맡는다. 첫 엣지에 write() 라벨을 달았더니 라벨 상자가 Guest Kernel 구역 이름을 덮어(PNG 로 확인) 라벨을 지우고 그 두 줄을 출발 노드의 details 로 내렸다. virtio-blk Frontend → virtqueue 엣지의 라벨 「Virtio block request」는 이 앵커의 문맥이 화살표만 그려 두어 이름 자체는 §138 이 대는 것이고, 기록 본문도 같은 이름을 쓴다."
}
}