Part 2 核心数据结构与内存管理开篇。适用代码:
kernel-open/nvidia-uvm/
1. 本篇要回答的问题
VA block 是 UVM 里迁移和映射的最小操作单位 (Part 0.2 第 3 层)。本篇把它彻底拆开:
- 一个 block 覆盖多大地址?为什么是 2MB?
- "某页驻留在哪、被谁映射、权限如何"这些信息用什么数据结构表达?
- CPU 侧(含 per-NUMA)和 GPU 侧的状态为什么要分开存?
read_duplicated_pages/maybe_mapped_pages这些辅助位图各自的坑在哪?
理解本篇后,Part 3 的迁移流程就只是"读写这些位图 + 建/拆页表"而已。
2. 尺寸常量:为什么是 2MB / 512 页
c
#define UVM_VA_BLOCK_BITS 21 // 2^21 = 2MB
#define UVM_VA_BLOCK_SIZE (1ULL << UVM_VA_BLOCK_BITS) // 2MB
#define PAGES_PER_UVM_VA_BLOCK (UVM_VA_BLOCK_SIZE / PAGE_SIZE) // 4K 页 → 512
| 常量 | 值(4K 页系统) | 含义 |
|---|---|---|
UVM_VA_BLOCK_BITS |
21 | block 跨度的位数 |
UVM_VA_BLOCK_SIZE |
2 MB | 一个 block 最大覆盖的虚拟地址 |
PAGES_PER_UVM_VA_BLOCK |
512 | 一个 block 最多多少页 → 每张位图的位数 |
2MB 的选择不是随意的 :它正好等于 GPU 的一个 2M 大页 PTE 覆盖范围,让 block 能整体用一个 2M PTE 映射(见下文 pte_is_2m),也让 per-block 的位图大小固定为 512 位(一个 uvm_page_mask_t)。
c
typedef struct {
DECLARE_BITMAP(bitmap, PAGES_PER_UVM_VA_BLOCK); // 512 位
} uvm_page_mask_t;
核心心智模型 :block 里几乎所有"哪些页......"的状态,都是一个 512 位的 uvm_page_mask_t,位索引 = block 内页号。
3. uvm_va_block_struct 顶层字段
摘录 uvm_va_block.h 关键字段:
| 字段 | 类型 | 作用 |
|---|---|---|
kref |
nv_kref_t |
引用计数(父 range / VA space + 驱逐路径临时持有),原子 |
lock |
uvm_mutex_t |
保护整个 block 的锁 |
managed_range |
uvm_va_range_managed_t * |
managed block 指向父 range;HMM block 为 NULL |
start / end |
NvU64 |
block 覆盖的 [start, end] 虚拟地址 |
resident |
uvm_processor_mask_t |
哪些处理器有本 block 某些页的一致副本(快查) |
mapped |
uvm_processor_mask_t |
哪些处理器有指向本 block 的有效映射 |
evicted_gpus |
uvm_processor_mask_t |
哪些 GPU 有页被驱逐到 sysmem |
ever_fully_resident |
uvm_processor_mask_t |
曾完整驻留过的处理器(决定 GPU chunk 是否要清零) |
cpu |
内嵌 struct | CPU 侧(含 per-NUMA)状态,见第 4 节 |
gpus[UVM_ID_MAX_GPUS] |
uvm_va_block_gpu_state_t * |
每 GPU 一份状态指针,见第 5 节 |
read_duplicated_pages |
uvm_page_mask_t |
哪些页处于读复制态 |
maybe_mapped_pages |
uvm_page_mask_t |
保守估计"可能被映射"的页 |
discarded_pages |
uvm_page_mask_t |
被丢弃的页(迁移/驱逐时须清除) |
两级索引结构 :处理器级掩码(resident / mapped)用于快速判断"有没有某处理器参与",一旦命中再下钻到该处理器的页级掩码看具体哪些页。
#mermaid-svg-ekGh5GQQ33oULRcz{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ekGh5GQQ33oULRcz .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ekGh5GQQ33oULRcz .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ekGh5GQQ33oULRcz .error-icon{fill:#552222;}#mermaid-svg-ekGh5GQQ33oULRcz .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ekGh5GQQ33oULRcz .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ekGh5GQQ33oULRcz .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ekGh5GQQ33oULRcz .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ekGh5GQQ33oULRcz .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ekGh5GQQ33oULRcz .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ekGh5GQQ33oULRcz .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ekGh5GQQ33oULRcz .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ekGh5GQQ33oULRcz .marker.cross{stroke:#333333;}#mermaid-svg-ekGh5GQQ33oULRcz svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ekGh5GQQ33oULRcz p{margin:0;}#mermaid-svg-ekGh5GQQ33oULRcz .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ekGh5GQQ33oULRcz .cluster-label text{fill:#333;}#mermaid-svg-ekGh5GQQ33oULRcz .cluster-label span{color:#333;}#mermaid-svg-ekGh5GQQ33oULRcz .cluster-label span p{background-color:transparent;}#mermaid-svg-ekGh5GQQ33oULRcz .label text,#mermaid-svg-ekGh5GQQ33oULRcz span{fill:#333;color:#333;}#mermaid-svg-ekGh5GQQ33oULRcz .node rect,#mermaid-svg-ekGh5GQQ33oULRcz .node circle,#mermaid-svg-ekGh5GQQ33oULRcz .node ellipse,#mermaid-svg-ekGh5GQQ33oULRcz .node polygon,#mermaid-svg-ekGh5GQQ33oULRcz .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ekGh5GQQ33oULRcz .rough-node .label text,#mermaid-svg-ekGh5GQQ33oULRcz .node .label text,#mermaid-svg-ekGh5GQQ33oULRcz .image-shape .label,#mermaid-svg-ekGh5GQQ33oULRcz .icon-shape .label{text-anchor:middle;}#mermaid-svg-ekGh5GQQ33oULRcz .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ekGh5GQQ33oULRcz .rough-node .label,#mermaid-svg-ekGh5GQQ33oULRcz .node .label,#mermaid-svg-ekGh5GQQ33oULRcz .image-shape .label,#mermaid-svg-ekGh5GQQ33oULRcz .icon-shape .label{text-align:center;}#mermaid-svg-ekGh5GQQ33oULRcz .node.clickable{cursor:pointer;}#mermaid-svg-ekGh5GQQ33oULRcz .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ekGh5GQQ33oULRcz .arrowheadPath{fill:#333333;}#mermaid-svg-ekGh5GQQ33oULRcz .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ekGh5GQQ33oULRcz .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ekGh5GQQ33oULRcz .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ekGh5GQQ33oULRcz .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ekGh5GQQ33oULRcz .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ekGh5GQQ33oULRcz .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ekGh5GQQ33oULRcz .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ekGh5GQQ33oULRcz .cluster text{fill:#333;}#mermaid-svg-ekGh5GQQ33oULRcz .cluster span{color:#333;}#mermaid-svg-ekGh5GQQ33oULRcz div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ekGh5GQQ33oULRcz .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ekGh5GQQ33oULRcz rect.text{fill:none;stroke-width:0;}#mermaid-svg-ekGh5GQQ33oULRcz .icon-shape,#mermaid-svg-ekGh5GQQ33oULRcz .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ekGh5GQQ33oULRcz .icon-shape p,#mermaid-svg-ekGh5GQQ33oULRcz .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ekGh5GQQ33oULRcz .icon-shape .label rect,#mermaid-svg-ekGh5GQQ33oULRcz .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ekGh5GQQ33oULRcz .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ekGh5GQQ33oULRcz .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ekGh5GQQ33oULRcz :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} CPU 位
GPU 位
uvm_va_block_t
processor_mask: resident / mapped
(哪些处理器参与)
cpu 子结构
per-NUMA 页级掩码
gpusid
uvm_va_block_gpu_state_t
node_statenid
resident / allocated / chunks
resident / evicted / pte_bits\[\]
chunks\[\] / big_ptes
4. CPU 侧状态:per-NUMA 是关键
block->cpu 子结构把 CPU 状态再按 NUMA 节点细分(uvm_va_block.h):
| 字段 | 类型 | 含义 |
|---|---|---|
node_state[] |
uvm_va_block_cpu_node_state_t ** |
每个可能 NUMA 节点一份状态(稠密数组) |
allocated |
uvm_page_mask_t |
至少一个 NUMA 节点分配了 CPU 页的页 |
resident |
uvm_page_mask_t |
各 NUMA resident 的累积 OR,只用于快测"是否驻留在 CPU" |
pte_bits[UVM_PTE_BITS_CPU_MAX] |
uvm_page_mask_t[] |
CPU 映射权限位图,见下 |
ever_mapped : 1 |
位域 | CPU 是否曾映射本 block(ATS 上强制 PDE1 预填充) |
fault_authorized |
struct | 多线程同页缺页竞争的启发式抑制 |
per-NUMA 的 uvm_va_block_cpu_node_state_t:
c
typedef struct {
uvm_page_mask_t resident; // 本 NUMA 节点有一致副本的页
uvm_page_mask_t allocated; // 本 NUMA 节点已分配 CPU chunk 的页
unsigned long chunks; // CPU chunk 存储(opaque,见 uvm_pmm_sysmem)
} uvm_va_block_cpu_node_state_t;
一致性陷阱 :
block->cpu.resident是所有 per-NUMAresident的逻辑 OR,不能直接写 ,否则会和 per-NUMA 掩码不一致。必须用uvm_va_block_cpu_[set|clear]_residency_*()辅助函数维护。这是 NUMA 迁移(uvm-numa-migration)代码里的高频约束。
CPU pte_bits 的语义(两位)
c
UVM_PTE_BITS_CPU_READ, UVM_PTE_BITS_CPU_WRITE
READ清零 → CPU 无有效映射(访问会缺页),且WRITE必然也清零。READ置位 → 至少可读;WRITE再决定只读 / 读写。
managed 与 HMM 语义相反 :managed 下 pte_bits 是 PTE"最大 可能权限"(内核可能在 UVM 不知情时降级,如 MADV_DONTNEED);HMM 下是"最小权限"(Linux 可能把只读升级为读写而不通知 UVM,这也是 HMM 暂不支持读复制的原因)。
5. GPU 侧状态:uvm_va_block_gpu_state_t
每个活跃 GPU 一份(block->gpus[id]),既有页级驻留位图,又有页表状态:
| 字段 | 类型 | 含义 |
|---|---|---|
resident |
uvm_page_mask_t |
本 GPU 显存中有一致副本的页 |
evicted |
uvm_page_mask_t |
已驱逐到 sysmem 的页 |
chunks[] |
uvm_gpu_chunk_t ** |
自然对齐的 GPU 显存块数组(大小不均,见 Part 2.3) |
page_table_range_2m/big/4k |
uvm_page_table_range_t |
三种粒度的页表范围(按需分配) |
pte_is_2m |
bool |
整个 block 是否被一个 2M PTE 覆盖 |
big_ptes |
bitmap | 非 2M 时,哪些大页区间用 big PTE(否则 4k PTE) |
pte_bits[UVM_PTE_BITS_GPU_MAX] |
uvm_page_mask_t[] |
GPU 映射权限(READ/WRITE/ATOMIC) |
egm_pages |
uvm_page_mask_t |
使用 EGM 映射的页 |
GPU 的 pte_bits 有三位:UVM_PTE_BITS_GPU_READ / WRITE / ATOMIC。与 CPU 不同,这些位永远精确------UVM 驱动完全掌控 GPU 页表,内核不会背着它改。
PTE 粒度:2M / big / 4k 的三态
pte_is_2m 与 big_ptes 位图共同描述 block 的 PTE 混合方式(源码里那张 HW/SW 状态表):
#mermaid-svg-5LLPcEqb1avvfY3v{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-5LLPcEqb1avvfY3v .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-5LLPcEqb1avvfY3v .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-5LLPcEqb1avvfY3v .error-icon{fill:#552222;}#mermaid-svg-5LLPcEqb1avvfY3v .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-5LLPcEqb1avvfY3v .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-5LLPcEqb1avvfY3v .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-5LLPcEqb1avvfY3v .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-5LLPcEqb1avvfY3v .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-5LLPcEqb1avvfY3v .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-5LLPcEqb1avvfY3v .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-5LLPcEqb1avvfY3v .marker{fill:#333333;stroke:#333333;}#mermaid-svg-5LLPcEqb1avvfY3v .marker.cross{stroke:#333333;}#mermaid-svg-5LLPcEqb1avvfY3v svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-5LLPcEqb1avvfY3v p{margin:0;}#mermaid-svg-5LLPcEqb1avvfY3v defs #statediagram-barbEnd{fill:#333333;stroke:#333333;}#mermaid-svg-5LLPcEqb1avvfY3v g.stateGroup text{fill:#9370DB;stroke:none;font-size:10px;}#mermaid-svg-5LLPcEqb1avvfY3v g.stateGroup text{fill:#333;stroke:none;font-size:10px;}#mermaid-svg-5LLPcEqb1avvfY3v g.stateGroup .state-title{font-weight:bolder;fill:#131300;}#mermaid-svg-5LLPcEqb1avvfY3v g.stateGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-5LLPcEqb1avvfY3v g.stateGroup line{stroke:#333333;stroke-width:1;}#mermaid-svg-5LLPcEqb1avvfY3v .transition{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-5LLPcEqb1avvfY3v .stateGroup .composit{fill:white;border-bottom:1px;}#mermaid-svg-5LLPcEqb1avvfY3v .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px;}#mermaid-svg-5LLPcEqb1avvfY3v .state-note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-5LLPcEqb1avvfY3v .state-note text{fill:black;stroke:none;font-size:10px;}#mermaid-svg-5LLPcEqb1avvfY3v .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-5LLPcEqb1avvfY3v .edgeLabel .label rect{fill:#ECECFF;opacity:0.5;}#mermaid-svg-5LLPcEqb1avvfY3v .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-5LLPcEqb1avvfY3v .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-5LLPcEqb1avvfY3v .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-5LLPcEqb1avvfY3v .edgeLabel .label text{fill:#333;}#mermaid-svg-5LLPcEqb1avvfY3v .label div .edgeLabel{color:#333;}#mermaid-svg-5LLPcEqb1avvfY3v .stateLabel text{fill:#131300;font-size:10px;font-weight:bold;}#mermaid-svg-5LLPcEqb1avvfY3v .node circle.state-start{fill:#333333;stroke:#333333;}#mermaid-svg-5LLPcEqb1avvfY3v .node .fork-join{fill:#333333;stroke:#333333;}#mermaid-svg-5LLPcEqb1avvfY3v .node circle.state-end{fill:#9370DB;stroke:white;stroke-width:1.5;}#mermaid-svg-5LLPcEqb1avvfY3v .end-state-inner{fill:white;stroke-width:1.5;}#mermaid-svg-5LLPcEqb1avvfY3v .node rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-5LLPcEqb1avvfY3v .node polygon{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-5LLPcEqb1avvfY3v #statediagram-barbEnd{fill:#333333;}#mermaid-svg-5LLPcEqb1avvfY3v .statediagram-cluster rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-5LLPcEqb1avvfY3v .cluster-label,#mermaid-svg-5LLPcEqb1avvfY3v .nodeLabel{color:#131300;}#mermaid-svg-5LLPcEqb1avvfY3v .statediagram-cluster rect.outer{rx:5px;ry:5px;}#mermaid-svg-5LLPcEqb1avvfY3v .statediagram-state .divider{stroke:#9370DB;}#mermaid-svg-5LLPcEqb1avvfY3v .statediagram-state .title-state{rx:5px;ry:5px;}#mermaid-svg-5LLPcEqb1avvfY3v .statediagram-cluster.statediagram-cluster .inner{fill:white;}#mermaid-svg-5LLPcEqb1avvfY3v .statediagram-cluster.statediagram-cluster-alt .inner{fill:#f0f0f0;}#mermaid-svg-5LLPcEqb1avvfY3v .statediagram-cluster .inner{rx:0;ry:0;}#mermaid-svg-5LLPcEqb1avvfY3v .statediagram-state rect.basic{rx:5px;ry:5px;}#mermaid-svg-5LLPcEqb1avvfY3v .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#f0f0f0;}#mermaid-svg-5LLPcEqb1avvfY3v .note-edge{stroke-dasharray:5;}#mermaid-svg-5LLPcEqb1avvfY3v .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-5LLPcEqb1avvfY3v .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-5LLPcEqb1avvfY3v .statediagram-note text{fill:black;}#mermaid-svg-5LLPcEqb1avvfY3v .statediagram-note .nodeLabel{color:black;}#mermaid-svg-5LLPcEqb1avvfY3v .statediagram .edgeLabel{color:red;}#mermaid-svg-5LLPcEqb1avvfY3v #dependencyStart,#mermaid-svg-5LLPcEqb1avvfY3v #dependencyEnd{fill:#333333;stroke:#333333;stroke-width:1;}#mermaid-svg-5LLPcEqb1avvfY3v .statediagramTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-5LLPcEqb1avvfY3v :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 分配 4k 页表
某大页区间升为 big PTE
(big_ptes 置位)
拆分回 4k
整块可用 2M PTE
(pte_is_2m=true)
合并为 2M
需要更细粒度时拆分
Mixed
Big
TwoM
- 2M (
pte_is_2m=true):整个 2MB block 一个 PTE,最省页表、最省 TLB,但要求全块同权限、同驻留。 - big :
big_ptes中置位的大页区间用 big PTE,其余用 4k。 - 4k:最细粒度,权限/驻留可逐页不同。
迁移和权限变更常触发 PTE 的拆分(split)/合并(merge) ,这是 Part 3.1(30-mmu-pagetable)的主题。
6. 辅助位图的坑点
这几个 block 级位图是"性能优化用的近似值",用错方向会出 bug:
| 位图 | 精确性 | 正确用法 |
|---|---|---|
maybe_mapped_pages |
可能假负(unmap 不总是清除) | 只能用于"为 0 就一定没映射"的快路径,反向不成立 |
read_duplicated_pages |
精确 | 判断某页是否读复制态 |
cpu.resident(累积 OR) |
精确但只读 | 快测是否驻留 CPU;改动必须走辅助函数 |
ever_fully_resident |
单调置位 | 决定 GPU chunk 是否需清零 |
maybe_mapped_pages的语义:"0 = 一定没被任何处理器映射;1 = 可能映射"。它在 map 时置位,但 unmap 时为省开销不总是清除 ,所以只能用于像uvm_va_block_migrate_locked这类"没映射就走快路径"的优化,绝不能反过来当"1 就一定映射了"。HMM block 不用这个位图(CPU 可随时映射而不通知驱动)。
7. 边界与坑点小结
- 一切以页索引对齐 :所有
uvm_page_mask_t的位 = block 内页号,跨结构比较前先确认是同一 block、同一索引基准。 - block ≤ 2MB 但常更小 :位图仍按 512 位分配,尾部位无效------用 region /
uvm_va_block_num_cpu_pages界定有效范围。 - CPU resident 别直接写:per-NUMA 与累积掩码的一致性只能靠辅助函数维护。
- managed vs HMM 的 pte_bits 语义相反:一个是最大权限,一个是最小权限,读迁移代码时务必区分。
- 状态有效性靠 tracker:block 的驻留/映射状态只有在 block 的 GPU work tracker 完成后才可信(字段见结构末尾)。
8. 小结与下一篇
- VA block 固定覆盖 ≤2MB / ≤512 页,每页状态用 512 位
uvm_page_mask_t表达。 - 两级索引:processor_mask 快查哪些处理器参与 → 下钻 CPU(per-NUMA)/ GPU 页级掩码。
- GPU 侧还带 PTE 粒度状态(2M/big/4k),迁移伴随 PTE 拆分合并。
- 辅助位图多为近似优化,
maybe_mapped_pages可假负、cpu.resident只读,用错方向即 bug。
下一篇 Part 2.2 21-processor-mask:深入 uvm_processor_id_t / uvm_processor_mask_t 的编码,它是本篇 resident / mapped / accessed_by(Part 1.3)等无数掩码的底层表示。
交叉引用 :block 在四层模型中的位置见 01-four-layer-model;policy 如何驱动这些位图变化见 12-policy-api;GPU chunk / CPU chunk 细节见 Part 2.3/2.4;per-NUMA residency 的迁移应用见 .../uvm-numa-migration/02-kernel-migration-flow。