内存管理-5-vm_area_struct->vm_flags
一、vma->flags 简介
vma->vm_flags 标志,控制的是一个 VMA 在内核里的行为属性。里面的每个标志都是位掩码。可以把它理解成:同样都是一段虚拟地址区间,不同 flag 决定了这段区间能不能扩展、是否参与 core dump、是否是 I/O 映射、fork 时怎么继承、缺页时怎么处理。
1. 当前权限位: READ/WRITE/EXEC/SHARED
(1) VM_NONE
全0,就是没有任何标志,表示"空的 vm_flags"。无任何权限。
实际意义:不可读、不可写、不可执行、不共享。在现实中单独存在很少见,通常只在初始化或作为判断边界值时出现。一个真实的 VMA 几乎不会只有 VM_NONE,因为没有权限就没实际用途。
(2) VM_READ
这段 VMA 当前允许读访问。当前可读。
对应 mmap(PROT_READ) 或 mprotect(PROT_READ)。处理缺页时,如果访问类型是"读",内核会检查 VM_READ。页表项会按此标志配置是否有读权限(视架构而定).
(3) VM_WRITE
这段 VMA 当前允许写访问。当前可写。
对应 PROT_WRITE。内核在 page fault 处理时,写 fault 会检查此位,如果置位但没有写权限页表项(典型 COW 场景),会触发 COW, 如果不置位但写入,触发 SIGSEGV。
(4) VM_EXEC
这段 VMA 当前允许执行。当前可执行。
对应 PROT_EXEC。代码段、动态库代码映射通常有此标志,支持 NX(No-Execute)的架构会据此设置页表项的执行保护位,没有此 flag 的区域在 NX 架构上执行会 SIGSEGV。
(5) VM_SHARED
这段 VMA 是共享映射。共享映射(写入对外可见)。
对应 mmap(MAP_SHARED),写入会直接反映到底层文件(文件映射)或被多个进程看到(匿名共享)。没有此 flag 的就是私有映射(MAP_PRIVATE),写时会触发 COW,不影响原文件或其他进程。
以文件映射为例:
MAP_SHARED: 写入 VMA --> 直接修改 page cache --> 可 writeback 到磁盘 --> 其他 mmap 此文件的进程可见。
MAP_PRIVATE: 写入 VMA --> 触发 COW --> 只改进程自己的私有副本 --> 其他进程不可见,文件不变。
2. 允许上限位(MAY位): MAYREAD/MAYWRITE/MAYEXEC/MAYSHARE
MAY 位存在的原因: mprotect() 可以动态修改 VM_READ/WRITE/EXEC,但不能无限制修改。MAY 位就是这段 VMA 权限的上限或合法范围,约束 mprotect 能把权限改到哪里。举例:
/* * 最初以 PROT_READ|PROT_WRITE 建立。 * 内核会设置:VM_READ | VM_WRITE 和 VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC (一般私有映射都允许 EXEC 上限) */ mmap(..., PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0) /* 之后可以: */ mprotect(..., PROT_NONE) //变为 VM_NONE,但MAY位还在(VM_被清0,但是VM_MAY还在) mprotect(..., PROT_READ) //再改回 VM_READ,合法,因为 VM_MAYREAD 存在 /* 如果 VM_MAYEXEC 不在,则以下操作会被拒绝: */ mprotect(..., PROT_EXEC) // 返回 EACCES
两层关系对比总结:
--------------------------------------------------------------------- 当前权限 (现在能不能做) 上限权限 (以后允不允许改) --------------------------------------------------------------------- VM_READ (当前可读) ←→ VM_MAYREAD (允许 mprotect 改为可读) VM_WRITE (当前可写) ←→ VM_MAYWRITE (允许 mprotect 改为可写) VM_EXEC (当前可执行) ←→ VM_MAYEXEC (允许 mprotect 改为可执行) VM_SHARED (当前是共享) ←→ VM_MAYSHARE (允许保持共享语义) ---------------------------------------------------------------------
对应关系是:VM_READ 被清掉,只要 VM_MAYREAD 在,随时可以 mprotect 恢复。但是 VM_MAYREAD 被清掉,则无论如何都不能再加回 VM_READ(内核会拒绝 mprotect).
(1) VM_MAYREAD
允许这段 VMA 在将来被设置为可读(VM_READ)。允许 mprotect 赋予可读。
mprotect(PROT_READ) 的合法性依赖此位,如果当前是 PROT_NONE 但 VM_MAYREAD 还在,说明可以恢复读权限。
(2) VM_MAYWRITE
允许这段 VMA 在将来被设置为可写(VM_WRITE)。允许 mprotect 赋予可写。
mprotect(PROT_WRITE) 的合法性依赖此位。对于某些特殊映射,内核故意不设置 VM_MAYWRITE,从而永久禁止被改为可写。例:/proc/self/exe 对应的文本段映射,永久只读,VM_MAYWRITE 不会被置。
(3) VM_MAYEXEC
允许这段 VMA 在将来被设置为可执行(VM_EXEC)。允许 mprotect 赋予可执行。
mprotect(PROT_EXEC) 的合法性依赖此位。PaX/W^X 类安全加固可能主动取消 VM_MAYEXEC,防止动态生成可执行代码。普通私有匿名映射默认有 VM_MAYEXEC,所以 JIT 可以 mmap + mprotect(EXEC)
(4) VM_MAYSHARE
允许这段 VMA 具备共享属性。允许保持共享语义。
比 VM_MAYREAD/WRITE/EXEC 稍微特殊,主要用于 MAP_SHARED 映射上,表示可以保持共享语义。也用于某些内核诊断和 /proc/PID/maps 的属性展示。具体限制路径不像前三个那么直接,更多是内核内部一致性检查。
3. 地址空间形态类:VM_GROWSDOWN、VM_DONTEXPAND
(1) VM_GROWSDOWN
含义:这是一段“向低地址方向增长”的 VMA。允许 VMA 向低地址扩栈。
典型场景:用户栈,尤其是主线程栈; 某些架构或线程库创建的栈区.
行为特征:当访问落在当前 vm_start 下方、但仍在允许的栈扩展范围内时,内核会尝试把这段 VMA 向下扩展,而不是直接判为非法访问。所以这类 VMA 的下边界不是绝对固定的
存在意义:栈天然是向下生长的,函数调用、局部变量压栈都会让 SP 向低地址移动。如果没有这个标志,每次栈向下越过当前边界都要重新建 VMA,不现实。
补充:它不是“无限扩展”,还受 RLIMIT_STACK、相邻 VMA 冲突、guard page 等约束。内核里常见配套逻辑是 expand_stack() 或相关扩展路径。
(2) VM_DONTEXPAND
含义:这段 VMA 不能被 mremap() 等机制扩展。不能扩展。
为什么需要:某些 VMA 的边界、页属性、底层映射关系很特殊, 扩展可能破坏其语义或安全性.
典型场景:特殊驱动映射; hugetlb 映射; 一些架构/设备专用 VMA.
直观理解:普通匿名映射可能可以放大。带这个 flag 的映射大小更“刚性”。
常见来源:内核在建立某些特殊映射时主动打上。
4. userfaultfd相关:VM_UFFD_MISSING、VM_UFFD_WP
(1) VM_UFFD_MISSING
含义:这段 VMA 开启了 userfaultfd 的“missing page fault tracking”。缺页交给 userfaultfd。
背景:userfaultfd 允许用户态程序接管某些页错误处理; “missing” 指的是页面根本不存在,访问时产生缺页异常
行为:当这段 VMA 上发生“缺失页” fault 时,内核不立即按普通匿名页/文件页逻辑补页; 而是把 fault 事件投递给注册了 userfaultfd 的用户态处理程序; 用户态可以决定是拷贝内容、zeropage 填充、延迟恢复,还是做 live migration 等高级操作
典型用途:虚拟机内存按需填充; 用户态分页; live migration; checkpoint/restore.
一句话:VM_UFFD_MISSING 表示“这段内存缺页时,交给 userfaultfd 用户态去处理”。
(2) VM_UFFD_WP
含义:这段 VMA 开启了 userfaultfd 的 write-protect 跟踪。写保护 fault 交给 userfaultfd。
与 VM_UFFD_MISSING 区别:VM_UFFD_MISSING 管“页不存在”; VM_UFFD_WP 管“页存在,但写访问被拦截”。
行为:页面可以已经在内存里,但当用户写这个页面时,触发 userfaultfd write-protect fault。用户态处理程序收到事件后决定如何解保护、同步、复制等。
典型用途:增量快照; dirty tracking; live migration 中的脏页追踪; 用户态实现类似软 dirty 的高级控制。
一句话:VM_UFFD_WP 表示“写这段内存时,不直接写,先通知 userfaultfd”。
5. 物理映射/设备映射类:VM_PFNMAP、VM_IO
VM_PFNMAP 强调按 PFN 建映射,没有标准 struct page 语义,VM_IO 强调这是 I/O/设备类映射,实际上二者经常一起出现,但不是完全同义。
(1) VM_PFNMAP
含义:这段 VMA 映射的是纯 PFN 范围,而不是普通由 struct page 管理的页。映射特殊 PFN,不是普通 page。
关键点:普通内存页通常能通过 PFN 找到对应 struct page; 但设备 BAR、某些保留内存、特殊物理区域,可能只有物理页号 PFN,没有标准 page 元数据语义。
典型场景:驱动通过 remap_pfn_range() 把设备内存映射到用户态; 显存、MMIO aperture、framebuffer 等映射。
影响:这类 VMA 通常不能参与普通页缓存、LRU、反向映射、匿名页回收等常规内存管理机制。get_user_pages()、migration、KSM、COW 等很多普通页逻辑会受限制或完全不适用。
直观理解:普通 VMA 映射的是“内核内存管理系统认识的页”,VM_PFNMAP 映射的是“只知道物理页号的特殊页范围”。
(2) VM_IO
含义:这段 VMA 是 I/O 内存映射,或具备类似 I/O 映射的特殊属性。设备/I/O 映射。
典型场景:mmap() 驱动设备; MMIO 寄存器空间; framebuffer; PCI BAR 映射.
影响:不适合普通匿名页/文件页管理; 常与 VM_PFNMAP、特殊 pgprot 一起出现; core dump、mlock、NUMA balancing、KSM、THP 等特性通常会规避这类映射.
一句话:VM_IO 强调“这是设备/特殊 I/O 映射,不是普通 RAM 语义”。
6. 文件写保护/执行文件语义:VM_DENYWRITE
(1) VM_DENYWRITE
含义:对这个映射对应的文件施加“拒绝写入”的语义。底层文件写入受限,防止执行中文件被改。
经典背景:可执行文件正在被执行或映射执行时,内核通常不允许别人去改写这个文件内容。否则会出现“正在执行的文本段被覆盖”的问题。
历史语义:和老 Unix 的 ETXTBSY 概念有关,即“text file busy”。试图写一个当前被执行映射占用的文件,可能得到 ETXTBSY
常见场景:可执行文件、解释器、动态装载相关映射。
注意:这是比较老且偏内部的语义标志,现代内核里它更多是与 deny_write_access() 一类机制配合。它不是“VMA 不可写”的意思,跟 VM_WRITE 不是一回事。
一句话:VM_DENYWRITE 主要是保护“底层文件不要在关键执行/映射期间被写坏”。
7. 访问模式提示类:VM_SEQ_READ、VM_RAND_READ
这两个都只是访问模式 hint,不是硬约束,主要影响预读策略。
(1) VM_SEQ_READ
含义:这段 VMA 的访问模式预计是顺序读。提示顺序访问。
本质:给内核的 readahead/预读/页缓存策略一个提示。
典型来源:madvise(..., MADV_SEQUENTIAL)
效果:内核更倾向进行顺序预读; 更积极地把后续页面读入; 已访问完的页也可能更积极回收,因为未来重复访问概率低.
适用:顺序扫描大文件; 流式处理.
注意:这只是“hint”,不是强制保证
(2) VM_RAND_READ
含义:这段 VMA 的访问模式预计是随机读,不适合聚簇预读。提示随机访问。
典型来源:madvise(..., MADV_RANDOM)
效果:内核减少或关闭 readahead, 避免因为误判顺序访问而读入大量无用页.
适用:索引查找; B-tree/数据库随机访问; 大文件跳跃读取.
与 VM_SEQ_READ 对应:一个鼓励预读, 一个抑制预读.
8. fork/mremap/dump/清零行为:VM_DONTCOPY、VM_WIPEONFORK、VM_DONTDUMP
VM_DONTCOPY 是 fork 不继承,VM_WIPEONFORK 是继承地址范围但不继承内容。
(1) VM_DONTCOPY
含义:fork 时不要把这个 VMA 复制到子进程。fork 不继承。
正常 fork 行为:大多数 VMA 会复制 VMA 元数据到子进程。页面则按 COW 共享或按各自语义处理。
这个标志的行为:子进程直接看不到这段 VMA,相当于这段地址空间不继承。
典型场景:某些驱动/设备映射; 特殊 runtime 区域; 不希望子进程继承的用户态管理区。
常见来源:MADV_DONTFORK
和 VM_WIPEONFORK 的区别:VM_DONTCOPY 是子进程里根本没有这段 VMA,VM_WIPEONFORK 是子进程里有这段 VMA,但内容被清零。
(2) VM_WIPEONFORK
含义:fork 后,子进程保留这段 VMA,但其内容被清零。fork 后子进程内容清零。
典型来源:MADV_WIPEONFORK
行为:父进程原 VMA 不变, 子进程会得到同样地址范围的一段 VMA, 但页面内容不继承父进程数据,而是相当于 fresh zeroed memory。
适用:存储敏感信息,但又想保留地址布局。避免 secret 在 fork 后泄漏给子进程。
和 VM_DONTCOPY 区别再强调一次:VM_DONTCOPY 是子进程没有这段映射,VM_WIPEONFORK 是子进程有映射,但内容被抹掉。
(3) VM_DONTDUMP
含义:这段 VMA 不要写入 core dump。不进 core dump。
背景:进程崩溃时,core dump 会把地址空间某些内容写到转储文件, 但有些区域没必要或不应该被转储。
典型场景:大块无意义缓存; 设备映射; 敏感数据; 用户显式声明不想 dump 的区域.
常见来源:MADV_DONTDUMP
好处:减小 core 文件体积; 提高转储速度; 避免泄漏秘密数据。
9. 锁页/内存承诺/资源统计:VM_LOCKED、VM_LOCKONFAULT、VM_ACCOUNT、VM_NORESERVE
VM_LOCKED 是驻留锁定语义已经生效,VM_LOCKONFAULT 是等页 fault 进来再锁,偏延迟生效。VM_ACCOUNT 和 VM_NORESERVE
都与内存承诺/overcommit 有关,前者偏“记账”,后者偏“少预留、少保守”。
(1) VM_LOCKED
含义:这段 VMA 被锁定在内存中,页面不应该被换出。页常驻内存,不换出。
来源:mlock()、mlockall() 等系统调用。
行为:VMA 中已在内存中的页应尽量保持驻留。后续 fault 进来的页也会保持锁定语义。不进入正常 swap 回收路径。
目的:降低实时延迟,防止敏感数据被换出到磁盘,保证关键工作集常驻内存。
注意:锁的是“驻留性”,不是“页表项不变”。仍可能发生缺页,只是进来后要常驻。会受 RLIMIT_MEMLOCK 等限制。
(2) VM_LOCKONFAULT
含义:这段 VMA 不是立刻把所有页锁住,而是在页面 fault 进来时再锁定。fault 进来时再锁页。
背景:普通 VM_LOCKED 可能意味着立即把大量页驻留,代价较高。lock on fault 是一种延迟锁定策略。
典型来源:mlock2(..., MLOCK_ONFAULT)
行为:VMA 具有“将来 fault 到内存的页都锁住”的属性,但还没访问到的页不必现在就拉进来。
优点:避免一次性 fault-in 大量页;兼顾低延迟和较低初始开销。
一句话:VM_LOCKED 更像“现在就锁住”,VM_LOCKONFAULT 更像“以后谁 fault 进来就锁谁”。
(3) VM_ACCOUNT
含义:这段 VMA 需要参与内存 overcommit/accounting 统计。参与内存承诺统计。
背景:Linux 有 overcommit 策略,决定虚拟内存申请时要不要“记账”。某些映射在创建时就要计入 commit charge,表示系统承诺将来有资源满足它。
典型会被 account 的对象:某些私有可写匿名映射; 可能导致实际内存承诺增长的区域.
作用:帮助内核在分配阶段就评估“承诺内存”是否超限; 防止所有进程都过度申请,最终在运行时灾难性 OOM.
一句话:VM_ACCOUNT 表示“这段映射应算入系统内存承诺账本”。
(4) VM_NORESERVE
含义:这段映射不需要预留 swap / commit reserve,抑制常规记账或保留行为。不提前做保守预留。
典型来源:MAP_NORESERVE
行为:创建映射时不为未来可能写入的匿名页提前做严格资源预留,相当于告诉内核:“先别为我保守兜底,后面真用到再说”。
优点:降低创建大映射时的 commit 压力,允许更激进的 overcommit。
风险:运行时真正写入大量页面时,可能更晚才暴露资源不足,某些情况下更容易在后期触发 OOM。
和 VM_ACCOUNT 的关系:两者都和内存承诺有关,一个偏“要计账”,一个偏“别提前保守预留”。
10. 特殊页类型或故障语义:VM_HUGETLB、VM_SYNC
(1) VM_HUGETLB
含义:这段 VMA 使用 hugetlb 页,也就是预留型的大页机制。显式 huge page VMA。
不要和 THP 混淆:VM_HUGETLB 是显式 hugetlbfs / MAP_HUGETLB, THP 是透明大页,机制不同。
特点:页大小是固定 huge page,比如 2MB、1GB。来自 hugetlb pool。管理、fault、回收、页表层级都和普通页不同。
适用:数据库、HPC、需要稳定大页、不希望 THP 抖动的场景。
影响:不走普通匿名页的一些路径;扩展、拆分、swap、migration 等行为与普通页显著不同。
一句话:VM_HUGETLB 表示“这段 VMA 是显式 huge TLB page 映射”。
(2) VM_SYNC
含义:这段 VMA 需要同步语义的 page fault / 持久化故障处理。fault/持久化语义要求同步。
常见背景:DAX 持久内存映射; 对 fault 完成时数据一致性、落久化语义有更严格要求的场景。它不是“所有访问都同步 I/O”的简单意思,而是:page fault 处理不能过于异步/宽松, 需要满足特定同步和持久性要求.
典型关联:MAP_SYNC; 持久内存文件系统; DAX 直接映射.
一句话:VM_SYNC 更多是“这段映射的 fault 和数据可见性要满足同步一致性要求”。
11. 架构私有:VM_ARCH_1
(1) VM_ARCH_1
含义:架构私有标志位之一,语义由具体 CPU 架构定义。架构私有位。
这类标志的特点:在 x86、arm64、powerpc 等架构上用途可能不同; 主线 MM 公共代码通常只保留这个槽位,不赋予统一语义; 真正解释要看对应架构代码。所以它没有一个跨架构统一答案。你只能说:这是给架构专用扩展留的 vm_flags 位。如果你在某个特定内核版本、特定架构上看源码,要结合该架构的 arch/*/include/asm/... 和 fault/mmap 代码一起看。
二、标志位设置接口
1. mmap() 设置的 flag
这些 flag 在 VMA 创建时由 mmap() 的参数直接决定,写入 vm_flags 后一般长期持有。
---------------------------------------------------------------------- flag 触发的mmap参数 说明 ---------------------------------------------------------------------- VM_READ PROT_READ 可读 VM_WRITE PROT_WRITE 可写 VM_EXEC PROT_EXEC 可执行 VM_SHARED MAP_SHARED 共享映射 VM_MAYREAD PROT_READ (任何可读映射) 允许恢复可读 VM_MAYWRITE PROT_WRITE 允许恢复可写 VM_MAYEXEC 一般私有匿名映射默认有 允许恢复可执行 VM_MAYSHARE MAP_SHARED 允许保持共享语义 VM_GROWSDOWN MAP_GROWSDOWN 显式申请向下扩展的栈VMA VM_NORESERVE MAP_NORESERVE 不预留 swap 资源 VM_HUGETLB MAP_HUGETLB 显式 huge page 映射 VM_SYNC MAP_SYNC 同步语义(DAX 场景) VM_DENYWRITE MAP_DENYWRITE(已废弃,现由内核exec路径设置) 见下文 ----------------------------------------------------------------------
特别说明:
VM_MAYREAD/MAYWRITE/MAYEXEC 不是用户显式传的,而是内核在 do_mmap() 内部根据 PROT_* 和映射类型推导出来的。规则大致是:PROT_READ 同时设置 VM_MAYREAD; PROT_WRITE + MAP_PRIVATE 同时设置 VM_MAYWRITE、VM_MAYEXEC; MAP_SHARED 且底层文件只读时, 不会设置 VM_MAYWRITE.
2. mprotect() 修改的 flag
mprotect() 负责动态修改当前权限位,但受 MAY 位约束。
----------------------------------------------------------------------------------------------- 被修改的 flag 条件 ----------------------------------------------------------------------------------------------- VM_READ 需要 VM_MAYREAD 存在 VM_WRITE 需要 VM_MAYWRITE 存在 VM_EXEC 需要 VM_MAYEXEC 存在 mprotect() 不能修改 MAY 位本身,也不能修改 VM_SHARED、VM_HUGETLB 等描述映射类型的 flag。 -----------------------------------------------------------------------------------------------
3. madvise() 设置的 flag
madvise() 是用户给内核传"访问模式提示"或"行为控制"的接口,它设置的 flag 大多影响内核策略,但不影响权限检查。
----------------------------------------------------------------------------------------- flag madvise 参数 含义 ----------------------------------------------------------------------------------------- VM_SEQ_READ MADV_SEQUENTIAL 顺序访问,激进预读 VM_RAND_READ MADV_RANDOM 随机访问,抑制预读 VM_DONTCOPY MADV_DONTFORK fork 不继承此 VMA VM_WIPEONFORK MADV_WIPEONFORK fork 后子进程内容清零 VM_DONTDUMP MADV_DONTDUMP 不写入 core dump VM_LOCKONFAULT MADV_FREE 相关,或 mlock2(MLOCK_ONFAULT) fault 进来时再锁页 -----------------------------------------------------------------------------------------
清除方向也对称:
---------------------------------------------- 清除操作 madvise 参数 ---------------------------------------------- 清除 VM_DONTCOPY MADV_DOFORK 清除 VM_WIPEONFORK MADV_KEEPONFORK 清除 VM_DONTDUMP MADV_DODUMP 清除 VM_SEQ_READ MADV_NORMAL 清除 VM_RAND_READ MADV_NORMAL ----------------------------------------------
4. mlock()/mlock2() 设置的 flag
-------------------------------------------------------- flag 来源 -------------------------------------------------------- VM_LOCKED mlock() 或 mlockall() VM_LOCKONFAULT mlock2(addr, len, MLOCK_ONFAULT) --------------------------------------------------------
解锁时由 munlock() / munlockall() 清除。
5、内核 exec 路径(execve)设置的 flag
装载可执行文件时,内核的 load_elf_binary() 等函数会主动设置某些 flag。
---------------------------------------------------------------------------- flag 谁设置 原因 ---------------------------------------------------------------------------- VM_DENYWRITE exec 路径,文本段映射时设置 防止正在执行的文件被写 VM_EXEC exec 路径,代码段 代码段可执行 VM_GROWSDOWN exec 路径,主线程栈 栈需要向下扩展 VM_READ + VM_EXEC exec 路径,代码段 代码段可读可执行 VM_READ + VM_WRITE exec 路径,数据段/BSS 数据段可读写 ----------------------------------------------------------------------------
6、驱动内部/remap_pfn_range()等内核路径设置的 flag
这类 flag 完全由内核或驱动代码在创建特殊映射时主动写入,用户无法直接触发。
-------------------------------------------------------------------------------------------------------- flag 设置路径 原因 -------------------------------------------------------------------------------------------------------- VM_IO 驱动调用 remap_pfn_range() 或 io_remap_pfn_range() 标识为设备/I/O 映射 VM_PFNMAP 同上,remap_pfn_range() 内部自动设置 纯 PFN 映射,无 struct page 语义 VM_DONTEXPAND 驱动或内核建立特殊 VMA 时主动置位 禁止 mremap 扩展 VM_ACCOUNT 内存统计路径(do_mmap 中按 overcommit 策略决定) 计入内存承诺账本 VM_ARCH_1 架构特定代码(arm/x86/mips 等各自实现) 架构私有语义 --------------------------------------------------------------------------------------------------------
7. userfaultfd 注册路径设置的 flag
-------------------------------------------------------------------------------------------------------- flag 设置路径 -------------------------------------------------------------------------------------------------------- VM_UFFD_MISSING ioctl(uffd, UFFDIO_REGISTER, ...) 时,注册模式包含 UFFDIO_REGISTER_MODE_MISSING VM_UFFD_WP 同上,注册模式包含 UFFDIO_REGISTER_MODE_WP --------------------------------------------------------------------------------------------------------
8. 规律总结
mmap: 负责建立 VMA 的基本形态(权限、共享/私有、大页、不预留等)。
mprotect: 只改当前权限位,不能突破 MAY 位上限。
madvise: 专门管"内核行为策略"(预读、fork 继承、dump 行为)。
mlock/mlock2: 专门管"驻留性"。
exec 路径: 自动按 ELF 段类型设置对应权限和特殊标志。
驱动/内核内部: 设置设备映射、统计、扩展控制类特殊标志。
userfaultfd: 是独立的注册接口,通过 ioctl 打标志。
posted on 2026-04-22 16:01 Hello-World3 阅读(4) 评论(0) 收藏 举报
浙公网安备 33010602011771号