Files
document-haness/docs/virtualization/final/.techviz/qcow2-mapping-clusters/spec.json
T

218 lines
6.1 KiB
JSON

{
"version": "1.1",
"id": "qcow2-mapping-clusters",
"title": "qcow2 L1·L2 매핑과 backing fallback",
"question": "게스트 오프셋은 qcow2 파일의 데이터 클러스터로 어떻게 매핑되고, L2 항목이 0일 때 왜 backing file이나 zero-fill로 갈리는가",
"type": "data-flow",
"direction": "LR",
"audience": [
"qcow2 overlay 내부를 이해하려는 개발자",
"virtual size와 실제 disk size 차이를 이해하려는 운영자"
],
"summary": "게스트 오프셋의 상위 비트가 L1, 중간 비트가 L2, 하위 비트가 클러스터 내부 위치를 고른다. L2 항목에 값이 있으면 현재 qcow2의 데이터 클러스터를 읽고, 0이면 backing file 유무에 따라 같은 위치를 읽거나 0으로 채운 클러스터를 돌려준다.",
"alt": "게스트 오프셋이 L1과 L2 표를 지나 현재 qcow2 데이터 클러스터로 가거나, L2 항목이 0일 때 backing file 또는 zero-fill로 갈라지는 qcow2 매핑도.",
"long_description": "게스트가 읽으려는 위치는 L1 표와 L2 표를 통해 파일 안 데이터 클러스터 오프셋으로 변환된다. 매핑된 값이 있으면 현재 qcow2의 데이터 클러스터를 읽는다. 값이 0이고 backing file이 있으면 base.qcow2의 같은 가상 위치를 읽고, backing file이 없으면 0으로 채운 64KB를 반환한다. backing file 경로는 qcow2 헤더의 문자열이므로 오버레이만 옮기면 부팅할 수 없다는 제한도 그림 끝에 반영한다.",
"source_context": {
"document": "docs/virtualization/final/document.md",
"document_sha256": "8c4ecc64c8cea9a4450ed7131fdd9cb2048dc092b66cd969f6346ed77887c210",
"anchor": {
"kind": "heading",
"value": "231. qcow2 파일 내부는 어떻게 생겼나 — 매핑표가 전부다",
"line": 14221
}
},
"composition": {
"profile": "component-flow",
"diagram_only": true,
"reference_ids": [
"payment-event-flow"
],
"rationale": "매핑의 핵심은 한 위치가 L1/L2를 지나 세 결과 중 하나로 흐르는 관계다.",
"focus_node": "l2"
},
"groups": [],
"nodes": [
{
"id": "guest-offset",
"label": "Guest offset",
"kind": "data",
"role": "source",
"details": [
"virtual disk position"
],
"description": "게스트가 읽으려는 가상 디스크 위치.",
"evidence": [
{
"start_line": 14317,
"end_line": 14325
}
],
"assumption": false
},
{
"id": "l1",
"label": "L1 table",
"kind": "component",
"role": "service",
"details": [
"상위 비트"
],
"description": "필요한 L2 표가 있는 클러스터 위치를 찾는다.",
"evidence": [
{
"start_line": 14312,
"end_line": 14337
}
],
"assumption": false
},
{
"id": "l2",
"label": "L2 entry",
"kind": "component",
"role": "service",
"emphasis": "primary",
"details": [
"중간 13비트"
],
"description": "현재 qcow2 데이터 클러스터 오프셋을 가지거나 0일 수 있다.",
"evidence": [
{
"start_line": 14320,
"end_line": 14347
}
],
"assumption": false
},
{
"id": "local-cluster",
"label": "현재 qcow2 data cluster",
"kind": "store",
"role": "store",
"shape": "database",
"description": "L2 값이 있을 때 같은 qcow2 파일 안에서 읽는 데이터 클러스터.",
"evidence": [
{
"start_line": 14267,
"end_line": 14272
},
{
"start_line": 14343,
"end_line": 14345
}
],
"assumption": false
},
{
"id": "backing",
"label": "base.qcow2",
"kind": "store",
"role": "store",
"shape": "database",
"details": [
"backing file"
],
"description": "L2 항목이 0이고 backing file이 있을 때 같은 가상 위치를 읽는 바닥 파일.",
"evidence": [
{
"start_line": 14343,
"end_line": 14354
}
],
"assumption": false
},
{
"id": "zero-fill",
"label": "zero-filled 64KB",
"kind": "result",
"role": "sink",
"description": "L2 항목이 0이고 backing file도 없을 때 만들어 반환하는 0 데이터.",
"evidence": [
{
"start_line": 14343,
"end_line": 14347
}
],
"assumption": false
}
],
"edges": [
{
"id": "offset-l1",
"from": "guest-offset",
"to": "l1",
"label": "상위 비트",
"kind": "data",
"evidence": [
{
"start_line": 14317,
"end_line": 14324
}
],
"assumption": false
},
{
"id": "l1-l2",
"from": "l1",
"to": "l2",
"label": "L2 cluster",
"kind": "data",
"evidence": [
{
"start_line": 14320,
"end_line": 14337
}
],
"assumption": false
},
{
"id": "l2-local",
"from": "l2",
"to": "local-cluster",
"label": "mapped",
"kind": "data",
"evidence": [
{
"start_line": 14343,
"end_line": 14345
}
],
"assumption": false
},
{
"id": "l2-backing",
"from": "l2",
"to": "backing",
"label": "0 + backing",
"kind": "data",
"style": "dashed",
"evidence": [
{
"start_line": 14343,
"end_line": 14350
}
],
"assumption": false
},
{
"id": "l2-zero",
"from": "l2",
"to": "zero-fill",
"label": "0 + no backing",
"kind": "result",
"style": "dashed",
"evidence": [
{
"start_line": 14343,
"end_line": 14347
}
],
"assumption": false
}
],
"legend": [],
"metadata": {
"rationale": "refcount·압축·스냅샷은 같은 파일 형식의 다른 질문이라 제외하고, 읽기 매핑과 backing fallback에만 집중했다."
}
}