feat: 가상화 문서들 추가

This commit is contained in:
DongHyeonka
2026-09-10 08:54:05 +09:00
parent e9f6a93327
commit 43e1aadef0
695 changed files with 153404 additions and 12754 deletions
@@ -0,0 +1,32 @@
# 게스트의 write() 가 virtqueue 에 실리기까지
## Alternative text
게스트 사용자 공간의 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 의 다른 절이 대는 사실이라 이 그림에 넣지 않았고 본문 문단이 맡는다.
## Elements and evidence
- **Boundary: Guest Userspace** (boundary): 게스트 사용자 공간. 저장장치를 직접 다루지 않는다. Evidence: L5807L5809.
- **Boundary: Guest Kernel** (boundary): 게스트 커널 공간. VM Boundary 위쪽 계층이 전부 여기 있다. Evidence: L5815L5833.
- **PostgreSQL / Keycloak** (service): 파일 연산을 요청하는 게스트 프로세스. Evidence: L5807L5809, L5885L5885, L5811L5813.
- **VFS** (service): 열린 파일이 어느 filesystem 구현에 속하는지 보고 연산을 넘기는 공통 계층. Evidence: L5815L5817, L5905L5905.
- **ext4 / XFS** (service): 파일과 디렉터리를 block 공간에 배치하는 게스트 filesystem. Evidence: L5819L5819.
- **Guest Page Cache** (store): 게스트 RAM 에 있는 cache. write() 가 성공해도 데이터는 아직 여기까지만 확정된다. Evidence: L5821L5821.
- **Guest Block Layer** (service): 파일 세계의 요청을 block device 세계의 요청으로 바꾸는 계층. Evidence: L5825L5825.
- **/dev/vda** (device): 게스트 Linux 가 하나의 block device 로 인식하는 이름. Evidence: L5829L5829, L5879L5879.
- **virtio-blk Frontend** (service): 그 가상 block device 를 제어하는 게스트 커널 driver. Evidence: L5831L5831, L5789L5789.
- **virtqueue** (queue): 요청이 실리는 자리. 바로 아래가 VM Boundary 다. Evidence: L5833L5835.
## Relationships
- **PostgreSQL / Keycloak → VFS:** data. Evidence: L5811L5813, L5890L5890.
- **VFS → ext4 / XFS:** data. Evidence: L5817L5819.
- **ext4 / XFS → Guest Page Cache:** data. Evidence: L5819L5821.
- **Guest Page Cache → Guest Block Layer:** writeback. Evidence: L5823L5825.
- **Guest Block Layer → /dev/vda:** WRITE / FLUSH. Evidence: L5827L5829.
- **/dev/vda → virtio-blk Frontend:** data. Evidence: L5829L5831.
- **virtio-blk Frontend → virtqueue:** Virtio block request. Evidence: L5831L5833.
@@ -0,0 +1,38 @@
# 게스트의 write() 가 virtqueue 에 실리기까지
# Question: 게스트 애플리케이션의 write() 는 virtqueue 에 실리기 전에 게스트의 어느 계층을 어떤 순서로 지나는가
direction: down
g0: "Guest Userspace" {
n0: "PostgreSQL / Keycloak" {
shape: rectangle
}
}
g1: "Guest Kernel" {
n1: "VFS" {
shape: rectangle
}
n2: "ext4 / XFS" {
shape: rectangle
}
n3: "Guest Page Cache" {
shape: rectangle
}
n4: "Guest Block Layer" {
shape: rectangle
}
n5: "/dev/vda" {
shape: rectangle
}
n6: "virtio-blk Frontend" {
shape: rectangle
}
n7: "virtqueue" {
shape: queue
}
}
g0.n0 -> g1.n1
g1.n1 -> g1.n2
g1.n2 -> g1.n3
g1.n3 -> g1.n4: "writeback"
g1.n4 -> g1.n5: "WRITE / FLUSH"
g1.n5 -> g1.n6
g1.n6 -> g1.n7: "Virtio block request"
@@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8"?>
<mxfile host="app.diagrams.net" modified="2026-07-23T00:00:00.000Z" agent="techviz-harness" version="24.7.17" type="device">
<diagram id="guest-block-io-to-virtqueue" name="게스트의 write() 가 virtqueue 에 실리기까지">
<mxGraphModel dx="680" dy="1360" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1360" math="0" shadow="0">
<root>
<mxCell id="0"/>
<mxCell id="1" parent="0"/>
<mxCell id="g_guest-userspace" value="Guest Userspace" style="swimlane;html=1;rounded=1;startSize=30;horizontal=1;dashed=1;strokeWidth=1.5;fillColor=#f7f9fb;strokeColor=#66788a;fontStyle=1;fontSize=13;" vertex="1" parent="1">
<mxGeometry x="40.0" y="35.0" width="241.0" height="160.0" as="geometry"/>
</mxCell>
<mxCell id="g_guest-kernel" value="Guest Kernel" style="swimlane;html=1;rounded=1;startSize=30;horizontal=1;dashed=1;strokeWidth=1.5;fillColor=#f7f9fb;strokeColor=#66788a;fontStyle=1;fontSize=13;" vertex="1" parent="1">
<mxGeometry x="47.0" y="219.0" width="227.0" height="1096.0" as="geometry"/>
</mxCell>
<mxCell id="n_app" value="PostgreSQL / Keycloak&lt;br/&gt;read / write&lt;br/&gt;fsync / sync" tooltip="파일 연산을 요청하는 게스트 프로세스. | Evidence: L5807-L5809, L5885-L5885, L5811-L5813" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;" vertex="1" parent="1">
<mxGeometry x="70.0" y="81.0" width="181.0" height="88.0" as="geometry"/>
</mxCell>
<mxCell id="n_vfs" value="VFS" tooltip="열린 파일이 어느 filesystem 구현에 속하는지 보고 연산을 넘기는 공통 계층. | Evidence: L5815-L5817, L5905-L5905" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;" vertex="1" parent="1">
<mxGeometry x="85.5" y="265.0" width="150.0" height="64.0" as="geometry"/>
</mxCell>
<mxCell id="n_fs" value="ext4 / XFS" tooltip="파일과 디렉터리를 block 공간에 배치하는 게스트 filesystem. | Evidence: L5819-L5819" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;" vertex="1" parent="1">
<mxGeometry x="85.5" y="425.0" width="150.0" height="64.0" as="geometry"/>
</mxCell>
<mxCell id="n_page-cache" value="Guest Page Cache" tooltip="게스트 RAM 에 있는 cache. write() 가 성공해도 데이터는 아직 여기까지만 확정된다. | Evidence: L5821-L5821" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;" vertex="1" parent="1">
<mxGeometry x="85.5" y="585.0" width="150.0" height="64.0" as="geometry"/>
</mxCell>
<mxCell id="n_block-layer" value="Guest Block Layer" tooltip="파일 세계의 요청을 block device 세계의 요청으로 바꾸는 계층. | Evidence: L5825-L5825" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;" vertex="1" parent="1">
<mxGeometry x="84.0" y="745.0" width="153.0" height="64.0" as="geometry"/>
</mxCell>
<mxCell id="n_vda" value="/dev/vda" tooltip="게스트 Linux 가 하나의 block device 로 인식하는 이름. | Evidence: L5829-L5829, L5879-L5879" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;" vertex="1" parent="1">
<mxGeometry x="85.5" y="905.0" width="150.0" height="64.0" as="geometry"/>
</mxCell>
<mxCell id="n_virtio-blk" value="virtio-blk Frontend" tooltip="그 가상 block device 를 제어하는 게스트 커널 driver. | Evidence: L5831-L5831, L5789-L5789" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;" vertex="1" parent="1">
<mxGeometry x="77.0" y="1065.0" width="167.0" height="64.0" as="geometry"/>
</mxCell>
<mxCell id="n_virtqueue" value="virtqueue" tooltip="요청이 실리는 자리. 바로 아래가 VM Boundary 다. | Evidence: L5833-L5835" style="whiteSpace=wrap;html=1;rounded=1;strokeWidth=2;fontSize=14;fontStyle=1;fillColor=#ffffff;strokeColor=#2d4357;verticalAlign=middle;strokeColor=#2563eb;strokeWidth=2;" vertex="1" parent="1">
<mxGeometry x="85.5" y="1225.0" width="150.0" height="64.0" as="geometry"/>
</mxCell>
<mxCell id="e_app-to-vfs" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_app" target="n_vfs">
<mxGeometry relative="1" as="geometry">
<mxPoint x="184.5" y="217.0" as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="e_vfs-to-fs" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_vfs" target="n_fs">
<mxGeometry relative="1" as="geometry">
<mxPoint x="184.5" y="377.0" as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="e_fs-to-page-cache" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_fs" target="n_page-cache">
<mxGeometry relative="1" as="geometry">
<mxPoint x="184.5" y="537.0" as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="e_page-cache-to-block-layer" value="writeback" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_page-cache" target="n_block-layer">
<mxGeometry relative="1" as="geometry">
<mxPoint x="184.5" y="697.0" as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="e_block-layer-to-vda" value="WRITE / FLUSH" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_block-layer" target="n_vda">
<mxGeometry relative="1" as="geometry">
<mxPoint x="184.5" y="857.0" as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="e_vda-to-virtio-blk" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_vda" target="n_virtio-blk">
<mxGeometry relative="1" as="geometry">
<mxPoint x="184.5" y="1017.0" as="offset"/>
</mxGeometry>
</mxCell>
<mxCell id="e_virtio-blk-to-virtqueue" value="Virtio block request" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeWidth=2;endArrow=block;endFill=1;" edge="1" parent="1" source="n_virtio-blk" target="n_virtqueue">
<mxGeometry relative="1" as="geometry">
<mxPoint x="184.5" y="1177.0" as="offset"/>
</mxGeometry>
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>
@@ -0,0 +1,31 @@
{
"harness_version": "0.2.0",
"spec_id": "guest-block-io-to-virtqueue",
"spec_version": "1.1",
"spec_sha256": "f41eedadcb8a6841cf981bea9e0a9e50a3df836df3cad528b4245a8d42e83915",
"source_context": {
"document": "docs/virtualization/final/document.md",
"document_sha256": "181e2b3cc8a45bae81e7e8193d026937c4d586ae4495d3b2c323eb7e6abcfadd",
"anchor": {
"kind": "heading",
"value": "128. 전체 구조",
"line": 5804
}
},
"outputs": [
"guest-block-io-to-virtqueue.svg",
"guest-block-io-to-virtqueue.drawio",
"guest-block-io-to-virtqueue.mmd",
"guest-block-io-to-virtqueue.d2",
"guest-block-io-to-virtqueue.excalidraw",
"guest-block-io-to-virtqueue.alt.md"
],
"lint_issue_count": 5,
"assumption_count": 0,
"assumptions_allowed": false,
"composition_profile": "component-flow",
"reference_ids": [
"payment-event-flow"
],
"diagram_only": true
}
@@ -0,0 +1,22 @@
%% 게스트의 write() 가 virtqueue 에 실리기까지
%% question: 게스트 애플리케이션의 write() 는 virtqueue 에 실리기 전에 게스트의 어느 계층을 어떤 순서로 지나는가
flowchart TB
subgraph g_guest_userspace["Guest Userspace"]
n0["PostgreSQL / Keycloak"]
end
subgraph g_guest_kernel["Guest Kernel"]
n1["VFS"]
n2["ext4 / XFS"]
n3["Guest Page Cache"]
n4["Guest Block Layer"]
n5["/dev/vda"]
n6["virtio-blk Frontend"]
n7(["virtqueue"])
end
n0 --> n1
n1 --> n2
n2 --> n3
n3 -->|"writeback"| n4
n4 -->|"WRITE / FLUSH"| n5
n5 --> n6
n6 -->|"Virtio block request"| n7
@@ -0,0 +1,107 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="680" height="1360" viewBox="0 0 680 1360" role="img" aria-labelledby="diagram-title diagram-description">
<title id="diagram-title">게스트의 write() 가 virtqueue 에 실리기까지</title>
<desc id="diagram-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 의 다른 절이 대는 사실이라 이 그림에 넣지 않았고 본문 문단이 맡는다.</desc>
<metadata>{&quot;techviz&quot;:{&quot;spec_version&quot;:&quot;1.1&quot;,&quot;id&quot;:&quot;guest-block-io-to-virtqueue&quot;,&quot;profile&quot;:&quot;component-flow&quot;},&quot;source_context&quot;:{&quot;document&quot;:&quot;docs/virtualization/final/document.md&quot;,&quot;document_sha256&quot;:&quot;181e2b3cc8a45bae81e7e8193d026937c4d586ae4495d3b2c323eb7e6abcfadd&quot;,&quot;anchor&quot;:{&quot;kind&quot;:&quot;heading&quot;,&quot;value&quot;:&quot;128. 전체 구조&quot;,&quot;line&quot;:5804}},&quot;evidence_policy&quot;:&quot;Each factual element cites source lines or is marked assumption.&quot;,&quot;diagram_only&quot;:true}</metadata>
<defs>
<marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
<path d="M 0 0 L 10 5 L 0 10 z" />
</marker>
<style>
:root { color-scheme: light; }
text { font-family: Inter, Pretendard, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; fill: #111827; }
.canvas { fill: #ffffff; }
.group-box { fill: #ffffff; stroke: #9ca3af; stroke-width: 1.4; stroke-dasharray: 7 5; }
.group-label-bg { fill: #ffffff; }
.group-label { font-size: 13px; font-weight: 650; fill: #374151; }
.edge { fill: none; stroke: #374151; stroke-width: 1.8; stroke-linejoin: round; stroke-linecap: round; marker-end: url(#arrow); }
.edge.style-dashed, .edge.semantic-dashed, .edge.assumption { stroke-dasharray: 7 5; }
.edge.style-dotted { stroke-dasharray: 2 5; }
.edge.emphasis-primary { stroke: #2563eb; stroke-width: 2.2; }
.edge.emphasis-muted { stroke: #9ca3af; }
.edge.emphasis-warning, .edge.kind-failure, .edge.kind-error { stroke: #dc2626; stroke-width: 2.2; }
.edge-label-bg { fill: #ffffff; }
.edge-label { font-size: 12px; font-weight: 560; text-anchor: middle; }
.node-shape { fill: #ffffff; stroke: #4b5563; stroke-width: 1.7; }
.node-shape.emphasis-primary { stroke: #2563eb; stroke-width: 2.2; }
.node-shape.emphasis-muted { stroke: #9ca3af; fill: #f9fafb; }
.node-shape.emphasis-warning { stroke: #d97706; stroke-width: 2; fill: #fffdf5; }
.node-shape.kind-database, .node-shape.kind-datastore, .node-shape.kind-storage { fill: #f8fafc; }
.node-shape.kind-queue, .node-shape.kind-event, .node-shape.kind-topic { fill: #fafafa; }
.node-shape.assumption { stroke-dasharray: 4 4; }
.storage-bottom, .controller-divider { fill: none; stroke: #4b5563; stroke-width: 1.4; }
.controller-led { fill: #4b5563; }
.actor-symbol { fill: none; stroke: #4b5563; stroke-width: 1.8; stroke-linecap: round; }
.actor-symbol.emphasis-primary { stroke: #2563eb; stroke-width: 2.2; }
.node-label { font-size: 14px; font-weight: 650; text-anchor: middle; }
.node-role { font-size: 10px; letter-spacing: 0.04em; text-anchor: middle; fill: #6b7280; }
.node-detail-divider { stroke: #d1d5db; stroke-width: 1; }
.node-detail { font-size: 11px; fill: #374151; }
.assumption-badge { font-size: 9px; font-weight: 700; fill: #92400e; }
.failure-mark { stroke: #dc2626; stroke-width: 4; stroke-linecap: round; }
.lifeline { stroke: #9ca3af; stroke-width: 1.2; stroke-dasharray: 5 5; }
.timeline-axis { stroke: #374151; stroke-width: 1.8; marker-end: url(#arrow); }
.timeline-stem { stroke: #6b7280; stroke-width: 1.3; }
.timeline-marker { fill: #ffffff; stroke: #374151; stroke-width: 1.7; }
.timeline-marker.primary { fill: #2563eb; stroke: #2563eb; }
.timeline-marker.warning { fill: #dc2626; stroke: #dc2626; }
.timeline-label { font-size: 13px; font-weight: 650; text-anchor: middle; }
.timeline-detail { font-size: 11px; fill: #4b5563; text-anchor: middle; }
</style>
</defs>
<rect class="canvas" width="680" height="1360" />
<rect class="group-box" x="40.0" y="35.0" width="241.0" height="160.0" rx="8" />
<rect class="group-label-bg" x="54.0" y="25.0" width="127.0" height="22" />
<text class="group-label" x="64.0" y="40.0">Guest Userspace</text>
<rect class="group-box" x="47.0" y="219.0" width="227.0" height="1096.0" rx="8" />
<rect class="group-label-bg" x="61.0" y="209.0" width="106.0" height="22" />
<text class="group-label" x="71.0" y="224.0">Guest Kernel</text>
<polyline class="edge kind-data style-solid emphasis-normal" points="160.5,169.0 160.5,217.0 160.5,217.0 160.5,265.0" data-evidence="5811-5813,5890-5890" />
<polyline class="edge kind-data style-solid emphasis-normal" points="160.5,329.0 160.5,377.0 160.5,377.0 160.5,425.0" data-evidence="5817-5819" />
<polyline class="edge kind-data style-solid emphasis-normal" points="160.5,489.0 160.5,537.0 160.5,537.0 160.5,585.0" data-evidence="5819-5821" />
<polyline class="edge kind-data style-solid emphasis-normal" points="160.5,649.0 160.5,697.0 160.5,697.0 160.5,745.0" data-evidence="5823-5825" />
<rect class="edge-label-bg" x="145.3" y="683.0" width="78.3" height="22" rx="3" />
<text class="edge-label" x="184.5" y="698.0">writeback</text>
<polyline class="edge kind-data style-solid emphasis-normal" points="160.5,809.0 160.5,857.0 160.5,857.0 160.5,905.0" data-evidence="5827-5829" />
<rect class="edge-label-bg" x="131.9" y="843.0" width="105.1" height="22" rx="3" />
<text class="edge-label" x="184.5" y="858.0">WRITE / FLUSH</text>
<polyline class="edge kind-data style-solid emphasis-normal" points="160.5,969.0 160.5,1017.0 160.5,1017.0 160.5,1065.0" data-evidence="5829-5831" />
<polyline class="edge kind-data style-solid emphasis-normal" points="160.5,1129.0 160.5,1177.0 160.5,1177.0 160.5,1225.0" data-evidence="5831-5833" />
<rect class="edge-label-bg" x="108.5" y="1163.0" width="152.0" height="22" rx="3" />
<text class="edge-label" x="184.5" y="1178.0">Virtio block request</text>
<g id="node-app">
<rect class="node-shape kind-service emphasis-normal role-source" data-evidence="5807-5809,5885-5885,5811-5813" x="70.0" y="81.0" width="181.0" height="88.0" rx="7" />
<text class="node-label" x="160.5" y="108.0">PostgreSQL / Keycloak</text>
<line class="node-detail-divider" x1="84.0" y1="129.0" x2="237.0" y2="129.0" />
<text class="node-detail" x="86.0" y="146.0">read / write</text>
<text class="node-detail" x="86.0" y="162.0">fsync / sync</text>
</g>
<g id="node-vfs">
<rect class="node-shape kind-service emphasis-normal role-service" data-evidence="5815-5817,5905-5905" x="85.5" y="265.0" width="150.0" height="64.0" rx="7" />
<text class="node-label" x="160.5" y="295.0">VFS</text>
</g>
<g id="node-fs">
<rect class="node-shape kind-service emphasis-normal role-service" data-evidence="5819-5819" x="85.5" y="425.0" width="150.0" height="64.0" rx="7" />
<text class="node-label" x="160.5" y="455.0">ext4 / XFS</text>
</g>
<g id="node-page-cache">
<rect class="node-shape kind-store emphasis-normal role-store" data-evidence="5821-5821" x="85.5" y="585.0" width="150.0" height="64.0" rx="7" />
<text class="node-label" x="160.5" y="615.0">Guest Page Cache</text>
</g>
<g id="node-block-layer">
<rect class="node-shape kind-service emphasis-normal role-service" data-evidence="5825-5825" x="84.0" y="745.0" width="153.0" height="64.0" rx="7" />
<text class="node-label" x="160.5" y="775.0">Guest Block Layer</text>
</g>
<g id="node-vda">
<rect class="node-shape kind-device emphasis-normal role-service" data-evidence="5829-5829,5879-5879" x="85.5" y="905.0" width="150.0" height="64.0" rx="7" />
<text class="node-label" x="160.5" y="935.0">/dev/vda</text>
</g>
<g id="node-virtio-blk">
<rect class="node-shape kind-service emphasis-normal role-service" data-evidence="5831-5831,5789-5789" x="77.0" y="1065.0" width="167.0" height="64.0" rx="7" />
<text class="node-label" x="160.5" y="1095.0">virtio-blk Frontend</text>
</g>
<g id="node-virtqueue">
<rect class="node-shape kind-queue emphasis-primary role-queue" data-evidence="5833-5835" x="85.5" y="1225.0" width="150.0" height="64.0" rx="7" />
<text class="node-label" x="160.5" y="1255.0">virtqueue</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.9 KiB