目录
- mm/vmalloc:利用物理连续内存加速 ioremap / vmalloc / vmap
- mm/thp:让 mTHP 在不支持 PMD 级大页的架构上也能用
- block:为块设备启用 RWF_DONTCACHE
- iomap & xfs:缓冲 write-through 支持
- ACPI RAS2 特性表与内存 Scrub 支持
- process_vm_readv/writev 的 pidfd 与 NOWAIT 支持
- userfaultfd:允许注册 mmap_min_addr 以下的范围
1. mm/vmalloc:利用物理连续内存加速 ioremap / vmalloc / vmap
系列:[RFC PATCH 0/8] mm/vmalloc: Speed up ioremap, vmalloc and vmap with contiguous memory作者: Barry Song (Xiaomi)版本: RFC(8 个 patch)
背景
vmalloc / vmap / ioremap 在内核中被大量用于建立虚拟连续但物理不一定连续的映射。当底层物理页其实是连续的(例如 __GFP_COMP 分配的高阶 compound page、systemheap 按 order 8/4/0 降序拆解返回的内存,或 ioremap 大段设备内存),理论上可以用 PMD 或 ARM64 的 CONT-PTE 批量建映射,既减少页表 walk 成本,又降低 TLB 压力。但现状是:__vmap_pages_range_noflush() 对每个 page 单独调 vmap_range_noflush(),而 ARM64 arch_vmap_pte_range_map_size() 只支持一次性处理单个 CONT-PTE 区域;对于 VM_ALLOW_HUGE_VMAP,内核是按 PMD 逐个页表项铺设的,形成"锯齿形(zigzag)"映射:反复在不同层级的页表之间切换,既慢又吃不到大页带来的 TLB 红利。
解决的问题
- ioremap 大段物理连续内存时无法一次性用 PMD/CONT-PTE 映射
VM_ALLOW_HUGE_VMAP 路径下页表铺设锯齿化,反复 walk 上层页表vmap() 输入 pages 数组里包含高阶 compound 页时仍按 4K 粒度逐页建映射vm_area 起始地址未按 PMD/CONT-PTE 对齐,导致即使物理连续也凑不出一次批量映射
如何做
系列分三段递进。第 1–2 patch 扩展 ARM64 侧:arm64/hugetlbpage.c 的 set_ptes() 批量路径支持同时安装多个 CONT-PTE 段,arch_vmap_pte_range_map_size() 也允许一次返回"多段 CONT-PTE 合并"的 size。第 3–4 patch 重构公共层:vmap_small_pages_range_noflush() 增加 page_shift 参数以支持非 PAGE_SHIFT 的批量粒度;随后 __vmap_pages_range_noflush() 被极大简化,直接复用同一入口而不再按页 for 循环铺设,从根本消除 huge vmalloc 的页表 zigzag:
if (!IS_ENABLED(CONFIG_HAVE_ARCH_HUGE_VMALLOC))
page_shift = PAGE_SHIFT;
return vmap_small_pages_range_noflush(addr, end, prot, pages,
min(page_shift, PMD_SHIFT));
第 5–8 patch 为 vmap() 添加 contiguous 探测。新引入 get_vmap_batch_order() 用 compound_nr() / compound_order() 识别 compound 页,用 num_pages_contiguous() 校验物理连续,再由新的 vmap_contig_pages_range() 按真实 shift 调用 vmap_range_noflush() 批量建映射;vm_area 起始地址按可能的最大 shift 对齐,并在 vmap 主循环中合并相同 page_shift 的区段避免 pgtable 来回跳;一旦扫描到 4K 小页就停止后续 compound 扫描以节省开销。
收益
作者在 RK3588 8 核 ARM64 SoC 上(任务绑定 CPU2、performance cpufreq 策略)给出如下实测数据:
VM_ALLOW_HUGE_VMAP 下 vmalloc 1 MB 的建立映射耗时(剔除分配):提速 1.5×vmap() 输入含 order-8 页:提速 5.6×
减少的页表 walk 次数同时意味着更低的 TLB miss 与更少的 flush_cache_vmap() 成本,对 DMA buffer、systemheap、驱动 ioremap 大区域等场景直接受益。
2. mm/thp:让 mTHP 在不支持 PMD 级大页的架构上也能用
系列:[PATCH v3 00/10] mm: thp: always enable mTHP support作者: Luiz Capitulino版本: v3(10 个 patch)
背景
Linux 的多尺寸透明大页(mTHP,multi-size THP)允许匿名页和 shmem 使用 2/4/8 … 等小于 PMD 的任意 2 的幂 order,能在 ARM64 contpte、较小 SoC 等场景下显著提升性能。但 THP 层长期有一个隐含假设:只有当架构声明 has_transparent_hugepage()(意味着 CPU 支持 PMD-sized leaf 映射,如 x86 PSE)时整个 THP 框架才启用。后果是:只要 CPU 不支持 PMD 大页(例如部分 32 位 x86、某些嵌入式平台),所有 order 的 mTHP 也一起被禁,连 64K/16K 这类完全可以通过普通 PTE 表达的中等 order 也享受不到。另外 has_transparent_hugepage() 与 thp_disabled_by_hw() 语义含糊且与 THP 开关耦合,长期被当作"CPU 是否支持 PMD leaf"的隐式探测,是社区反复指出的技术债。David Hildenbrand 此前建议抽象出一个干净的查询 API,本系列即实现该方案。
解决的问题
- mTHP 在不支持 PMD-sized page 的架构/CPU 上被一刀切禁用
- 缺少一个"PMD 层是否可做 leaf"的明确 API,
has_transparent_hugepage() 语义含糊且 treewide 滥用 - shmem、dax、nvdimm、
debug_vm_pgtable 等模块各自用 has_transparent_hugepage() 当作 PMD leaf 探测
如何做
patch 2 在 include/linux/pgtable.h 引入新接口 pgtable_has_pmd_leaves() 及其弱符号 arch_has_pmd_leaves(),并由 init/main.c 在 start_kernel() 中调用 init_arch_has_pmd_leaves()(v3 特意挪到 early_param 之后以避免 CPU feature flag 被清掉)。patch 3–5 把 dax、nvdimm、debug_vm_pgtable 迁移到新 API;patch 6 让 shmem 不再依赖 has_transparent_hugepage();patch 7 treewide 把 has_transparent_hugepage() 改名为 arch_has_pmd_leaves(),语义从"支持 THP"变为"pgtable 可以做 PMD leaf"。patch 8 用新接口替换 thp_disabled_by_hw()。核心 patch 9 修改 __thp_vma_allowable_orders():原本在不支持 PMD leaf 时直接 return 0,现在改为只从 supported_orders 里剥掉 PMD_ORDER | PUD_ORDER,其余 mTHP order 继续走;hugepage_init() 不再因 !pgtable_has_pmd_leaves() 早退,hugepage_init_sysfs() 仅在支持 PMD 时才把 huge_anon_orders_inherit 默认置为 BIT(PMD_ORDER),并在创建 thpsize sysfs 目录时跳过 PMD/PUD 两档;shmem 的 shmem_allowable_huge_orders() / shmem_alloc_and_add_folio() 同步采用相同过滤逻辑。patch 10 清理 x86:64 位默认总是开 PSE,直接假定 arch_has_pmd_leaves()=true,只在 32 位下保留 X86_FEATURE_PSE 运行时检测。
收益
作者未提供 benchmark 数据,收益是功能性与可维护性:不支持 PMD leaf 的架构(部分 32 位 x86、老 MIPS、某些 PowerPC 配置等)此后可以享受 contpte 之类的中等 order mTHP 带来的 TLB 收益与缺页次数下降,而不必为了 PMD 硬件特性把整条 mTHP 路径关闭;同时 treewide 新增的 pgtable_has_pmd_leaves() / arch_has_pmd_leaves() 提供了清晰契约,消除了 has_transparent_hugepage() 长期以来"既表示 THP 可用又表示硬件支持 PMD leaf"的语义混乱,使后续 mTHP/shmem/dax 代码逻辑更易推理。
3. mm/mglru:改造回收循环并修复脏页处理
系列:[PATCH v4 00/14] mm/mglru: improve reclaim loop and dirty folio handling作者: Kairui Song版本: v4(14 个 patch)
背景
MGLRU(Multi-Gen LRU)自进入主线以来承担了越来越多的生产回收压力,但它的回收主循环 try_to_shrink_lruvec() → get_nr_to_scan() → should_run_aging() → evict_folios() 与 aging / rotation / 扫描配额计算耦合得非常紧:每轮迭代都重算扫描数,priority 只在特定分支下才移位,aging 是否触发要间接从 nr_to_scan 的值反推;此外 MGLRU 的脏页回写路径与传统 shrink_folio_list 所用的 sc->file_taken / sc->unqueued_dirty 反馈完全脱节,导致 dirty flush 在 MGLRU 下几乎启动不了。这在腾讯生产环境以及 LSF/MM/BPF topic 的 MGLRU 压测中暴露出两个显著问题:一是高写入 workload 上 MongoDB/YCSB 会产生大量 file refault,吞吐明显低于预期;二是在"14G 匿名 + 8G 文件 vs 16G memcg limit"这类 mix workload 下会莫名 OOM,虽然还有大量 evictable file folio 也杀不掉;同样 dd + cgroup limit 容易触发 throttling OOM。
解决的问题
- MGLRU 回收循环把 aging、scan 数计算和 rotation 揉在一起,不易跟踪,priority 仅在部分分支下生效
DEF_PRIORITY 下即使无法回收也不 aging,浪费一整轮 priority 升级,破坏多 cgroup reclaim 平衡- 脏页回写反馈在 MGLRU 下失效,高写 workload 出现大量 file refault
- aging + throttling 联合触发 OOM:file-anon mix 压力下仍有可回收 file folio 却 OOM;dd + cgroup limit 触发 dirty throttling OOM
sc->file_taken / sc->unqueued_dirty 在 MGLRU 路径下冗余且语义不一致
如何做
14 个 patch 分三组。清理组(patch 1–3、11–14)统一 evictable size 查询、重命名 aging/rotation 变量、把 MAX_LRU_BATCH 从内部挪给 caller,并在传统 vmscan 侧删除 sc->file_taken / sc->unqueued_dirty,统一 writeback 统计与 throttling。核心改造组(patch 4–7)重写 try_to_shrink_lruvec():在循环开头用 get_nr_to_scan() 一次性算出本轮 scan 预算(按 sc->priority 右移,offline memcg 不 shift 以便快速收割),循环里每次取 min(nr_to_scan, MAX_LRU_BATCH) 作为 batch,从 evict_folios() 返回的 delta 中扣减,nr_to_scan <= 0 即退出,aging 与 rotation 通过独立的 need_rotate 标志显式表达;should_run_aging() 也被简化为只决定"是否现在必须 aging",DEF_PRIORITY 时允许推迟,而非默认路径总是尊重 priority。patch 7 额外保证"刚 aging 完就立刻 abort 扫描"不再发生,避免只长 max_seq 不干活。脏页处理组(patch 9–10)把脏/回写 reactivation 改为调用公共例程,并把 dirty flush 判定搬进 MGLRU 回收 loop 内部,让反馈能真正影响本轮是否触发 writeback;patch 8 顺手删掉 isolate 路径上多余的 swap 约束检查。patch 14 收尾,把 writeback 相关统计和 throttling 在 MGLRU 与传统 vmscan 之间统一。整套改动净删代码——mm/vmscan.c 从 327 行变化中净减 51 行(+138 / -189)。
收益
Cover letter 在 48c/96t NUMA、128G、NVMe 机器上给出了详尽数据。
MongoDB YCSB workloadb(10G memcg、WiredTiger 4.5G cache、95% read + 5% update):
- 吞吐:62485 ops/s → 79760 ops/s(+27.6%)
- 平均延迟:500.97 µs → 391.25 µs(**−21.9%**)
pgpgin:159M → 111M(**−30.3%**)workingset_refault_file:34.5M → 19.6M(**−43.3%**)
作者原文:"The test is done on NVME and the performance gap would be even larger for slow devices, such as HDD or network storage. We observed over 100% gain for some workloads with slow IO."
其他负载验证:
- Yu Zhao Chrome/Node.js 压测(256G ZRAM、32 memcg × 64 worker):总请求数 79915 → 81382,Jain 公平度保持 0.99+,多 cgroup 平衡无退化
- MySQL sysbench oltp_read_only、FIO ext4 ramdisk mmap randread、kernel build(
make -j96):均在噪声级或略优,无回归
功能性修复:
- file-anon-mix 复现器(14G anon + 8G file vs 16G memcg limit):原开 MGLRU 会在 10–20 轮后 OOM,打上本系列后能稳定跑完 128 轮
- dd + cgroup limit 触发的 dirty throttling OOM:一并修掉
总的来看,这是一次"代码变少、语义更清、性能更好、修掉 OOM"的难得四赢重构。
4. mm/damon:支持冻结 kdamond
系列:[PATCH] mm/damon: support freeze kdamond作者: Lin Ruifeng版本: 单 patch
背景
DAMON(Data Access MONitor)是 Linux 内核中用于在线监控进程/内核地址空间访问频率的框架,其核心工作线程 kdamond 周期性地对目标区域进行采样、聚合与 scheme 执行。系统进入 suspend-to-RAM/disk 流程时,内核会冻结用户态任务以及标记为 freezable 的内核线程,以保证挂起/恢复过程中各子系统处于可预期的静止状态。然而目前 kdamond_fn() 并未接入冻结器(freezer)框架,线程在 suspend/resume 路径中不会被挂起。
解决的问题
- suspend/resume 过程中
kdamond 仍在后台运行,但此时目标进程被冻结,采样得到的访问频率信息不再反映真实工作负载,数据语义失真 - 某些 DAMOS action(如
PAGEOUT、MIGRATE_{HOT,COLD})会触发 I/O 或页迁移操作,在系统挂起窗口内继续发起 I/O 可能与存储子系统的挂起流程发生竞争 - 作者原文:"During suspend and resume, the data monitored by kdamond is no longer meaningful. Meanwhile, since kdamond may involve I/O operations, it is necessary to freeze it."
如何做
改动非常小,集中在 mm/damon/core.c 的 kdamond_fn():
- 引入
<linux/freezer.h> 头文件; - 线程启动、完成
kdamond_init_ctx(ctx) 之后调用 set_freezable(),向冻结器声明本内核线程愿意被冻结; - 在 kdamond 主循环顶部(
kdamond_wait_activation() 之前)插入 try_to_freeze(),使线程在 suspend 流程触发冻结时在此处安全阻塞,直到 resume 后再继续。
该位置选择在一次完整 sampling 迭代的边界处,保证冻结发生时 DAMON 上下文处于一致状态,不会打断某一次 region 遍历或 scheme 应用中途。
收益
作者未提供量化性能数据。从代码逻辑推断的预期收益:(1) 避免挂起窗口内产生无效访问频率样本,消除 resume 后 region hotness 评分被噪声污染的问题;(2) 阻止 DAMOS 在挂起期间继续发起 pageout/migrate 等 I/O,降低与存储/块层冻结流程发生竞态的风险;(3) 使 kdamond 与其他 freezable kthread 行为一致,便于系统级电源管理调试。
5. block:为块设备启用 RWF_DONTCACHE
系列:[PATCH RFC v5 0/3] block: enable RWF_DONTCACHE for block devices作者: Tal Zussman版本: RFC v5(3 个 patch)
背景
RWF_DONTCACHE 是近期引入的 per-I/O 语义,允许用户以 buffered I/O 的接口发起请求,但在 I/O 完成后立即丢弃(dropbehind)相应的 page cache 页,避免一次性大流量读写污染整个 page cache。目前该标志已在常规文件系统(如 XFS via iomap)上可用,但对直接操作裸块设备(/dev/nvmeXnY 等)的 open()+read/write 路径尚未支持。这对以裸盘为后端的数据库、对象存储等用户态应用是一个明显缺口。难点在于 dropbehind 语义需要在 I/O 完成时将对应 folio 从 page cache 踢出(folio_end_dropbehind),而该操作会反过来获取地址空间锁、触发可能睡眠的操作,必须运行在任务上下文。块设备 writeback bio 通常在 NVMe 完成中断的 IRQ 上下文中走 bio_endio(),无法就地完成 dropbehind 清理。此前 XFS 通过 IOMAP_IOEND_DONTCACHE 标志配合专门的 workqueue 做延迟处理,但这是 FS 特定 hack。
解决的问题
- 裸块设备路径(
block/fops.c、fs/buffer.c)无法透传 RWF_DONTCACHE 语义,大范围顺序读写会污染 page cache - XFS 需要为 dropbehind 完成维护专门 workqueue 与 IOMAP 标志,是 FS 专有而非通用基础设施
如何做
系列 3 个 patch,核心是在块层引入通用的"任务上下文完成"机制:
- **Patch 1 –
block: add BIO_COMPLETE_IN_TASK**:在 include/linux/blk_types.h 新增 BIO_COMPLETE_IN_TASK 标志;block/bio.c 的 bio_endio() 检测该标志且当前处于非任务上下文时,把 bio 挂入 per-CPU 的 struct llist(lockless list),并通过专用 workqueue + delayed_work(延迟 1 jiffie)调度 worker 在任务上下文执行 bi_end_io。worker 采用 do/while 循环批量处理,并在 need_resched() 时主动让出避免霸占 CPU;仅当队列此前为空时才触发新的 schedule_delayed_work,降低 enqueue 开销(v5 根据 Dave/Jens/Christoph 反馈调整)。使用专用 workqueue 是为避免与全局 workqueue 死锁(Christoph 建议)。 - Patch 2 –
iomap: use BIO_COMPLETE_IN_TASK for dropbehind writeback:将 iomap writeback 中 dropbehind folio 的 bio 打上 BIO_COMPLETE_IN_TASK,删除 IOMAP_IOEND_DONTCACHE 及 NOMERGE 条目,并去掉 XFS (fs/xfs/xfs_aops.c) 专为 DONTCACHE 设置的 workqueue 逻辑——dropbehind 延迟统一下沉到块层。 - **Patch 3 –
block: enable RWF_DONTCACHE for block devices**:在 CONFIG_BUFFER_HEAD=y 路径下 submit_bh_wbc() 为 dropbehind 写回 bio 设置 BIO_COMPLETE_IN_TASK;同时在 block/fops.c 启用 DONTCACHE 标志的传递,允许用户通过 preadv2/pwritev2(RWF_DONTCACHE) 在 /dev/* 上生效。
总改动约 +117/-18 行。
收益
作者在单盘 VM(/dev/nvme0n1)上给出了 fio 数据:
- 读
/dev/nvme0n1p2,45 GB 范围(约 2×RAM),14 秒平均:normal = 1173.7 MB/s → dontcache = 1828.8 MB/s,提升 +56% - 写
/dev/nvme0n1p3(~1 GB),在 244 MB memcg 中触发回收压力,10 秒平均:normal = 3762.5 MB/s → dontcache = 7699.1 MB/s,提升 +105% - normal 写路径抖动极大(27.9 ~ 7249.2 MB/s),而 dontcache 稳定保持 8000+ MB/s,显示 memcg 直回收被显著缓解
作者原文:"This support is useful for databases that operate on raw block devices, among other userspace applications." 对以裸盘为后端的数据库、对象存储(需要避免日志/批量扫描污染 page cache)尤其有价值;Patch 2 顺带清理了 XFS 的 dropbehind workqueue hack。
6. iomap & xfs:缓冲 write-through 支持
系列:[RFC PATCH v2 0/5] Add buffered write-through support to iomap & xfs作者: Ojaswin Mujoo版本: RFC v2(5 个 patch)
背景
Linux 的写路径目前主要分两类:(a) 常规 buffered write,数据先进 page cache,随后由 writeback 线程异步刷盘,O_DSYNC 情况下同步走一遍 writeback + FUA/flush;(b) Direct I/O(DIO),绕过 page cache 直接到磁盘。DIO 天然是 "write-through" 的,但其要求对齐、无缓存共享等约束限制了适用场景。社区讨论 RWF_ATOMIC buffered I/O 时,Dave Chinner 与 Jan Kara 提议引入一条新路径:buffered write-through——数据既进入 page cache(对读友好、允许未对齐),同时像 DIO 那样在 syscall 返回前把数据落盘。这条路径可同时服务三类需求:(1) buffered RWF_ATOMIC;(2) 真正异步的 O_DSYNC AIO;(3) 更可扩展的同步 buffered I/O。
解决的问题
- 现有
O_DSYNC buffered 路径本质是"先脏后刷",AIO 语义下无法真正异步(必须在完成前经历 writeback),影响数据库类负载的并发度 RWF_ATOMIC 期望的"要么全写进磁盘要么不写"语义在普通 buffered 写下无法表达,因为脏页生命周期与 syscall 解耦- iomap 缺少统一的 write-through 出口,XFS 等 FS 难以在不重复造轮子的前提下支持上述语义
folio_clear_dirty_for_io() 总调用 folio_mkclean() 并清 dirty 位,write-through 需要的是"mkclean 但仅在整页全干净时才清 dirty"
如何做
5 个 patch,共 +540/-9 行,主要触及 fs/iomap/buffered-io.c、fs/xfs/xfs_file.c、mm/page-writeback.c:
- **Patch 1 –
mm: Refactor folio_clear_dirty_for_io()**:拆分 mkclean 与 dirty bit 清除语义,暴露可被 write-through 复用的原语。 - Patch 2 –
iomap: Add initial support for buffered RWF_WRITETHROUGH:在 iomap 中新增 write-through 主体,复制数据到 page cache 同时下发 bio;从"每 folio 一个 bio"改为"每个 iomap 一个 bio",仅当整个 iomap 的 IO 完成后才回调 FS ->end_io()。非 AIO 的 write-through 语义与 DIO 对齐:syscall 要等 IO 完成后返回并上报错误(v2 关键修正)。 - **Patch 3 –
xfs: Add RWF_WRITETHROUGH support to xfs**:引入新的 ->writethrough_submit() 操作,使 FS 可在 bio 提交前完成前置工作,例如把 COW 映射转为 written。 - Patch 4 –
iomap: Add aio support to RWF_WRITETHROUGH:AIO 变体遵循 DIO 行为,提交后立即返回,完成时通过回调报告结果,提供真正异步的 write-through。 - **Patch 5 –
iomap: Add DSYNC support to writethrough**:O_DSYNC 与 RWF_WRITETHROUGH 叠加时使用 FUA 优化(若设备支持),省掉额外的 cache flush。
用户空间接口:include/uapi/linux/fs.h 新增 RWF_WRITETHROUGH 标志。
收益
作者未提供 benchmark,但给出了 xfstests 稳定性验证:"these patches survive fsx with integrity verification as well as fsstress parallel stressing",-g quick(blocksize == pagesize 及 blocksize < pagesize 两种配置)"shows no new regressions"。设计上可预期的收益:(1) 为 RWF_ATOMIC buffered I/O 铺路,使数据库类应用可以在不放弃 page cache 优势的前提下获得原子写语义;(2) O_DSYNC AIO 首次获得真正异步的可扩展实现;(3) ->writethrough_submit() 抽象出 FS 钩子,为 ext4 等后续接入留出干净接口;(4) Patch 1 的 folio_clear_dirty_for_io() 拆分是通用 MM 改进。
7. ACPI RAS2 特性表与内存 Scrub 支持
系列:[PATCH v19 0/2] ACPI: Add support for ACPI RAS2 feature table作者: Shiju Jose版本: v19(2 个 patch,经历 19 轮迭代)
背景
ACPI 6.5 规范 5.2.21 节定义了 RAS2(RAS Feature Table 2)表,用于向操作系统暴露平台级 RAS 能力,其中最重要的能力之一是基于硬件的内存 patrol scrub(巡检式清理)和 demand scrub(按需清理)。Patrol scrub 通过后台周期性读取 DRAM 单元并借助 ECC 纠正软错误,能有效减缓错误累积为不可纠正错误(UE)的风险;demand scrub 允许软件针对指定地址范围强制发起一次 scrub。RAS2 通过 PCC(Platform Communication Channel)共享内存邮箱与固件通信,按 NUMA Proximity Domain 提供独立的 scrub 实例,但 Linux 此前缺乏对应驱动。
解决的问题
- Linux 无法解析 ACPI RAS2 表,更无法驱动硬件 patrol / demand scrub 引擎
- 缺乏统一的用户态接口来查询与配置 per-NUMA 节点的 scrub 速率、地址范围和使能状态
- 需要兼容两种部署形态:每个 NUMA 域独立 PCC 通道,以及(如 Ampere 平台)所有 proximity domain 共享单一 PCC 通道
- 与固件交互存在并发、超时、字节序和错误恢复等健壮性问题
如何做
系列分两个 patch:
drivers/acpi/ras2.c(441 行)+ include/acpi/ras2.h:由 acpi_init() 调用 acpi_ras2_init() 入口。parse_ras2_table() 解析 RAS2 表并校验 num_pcc_descs;register_pcc_channel() 为每个 PCC subspace 建立通道(处理 pcc_chan->latency==0 与 poll timeout 边界)。ras2_send_pcc_cmd() 封装 PCC doorbell 交互,加入 lockdep_assert_held()、MPAR(Maximum Periodic Access Rate)节流保护以及 s64 time_delta;所有共享内存字段访问改为 ioreadX()/iowriteX() 以兼容大端架构。每个 proximity domain 通过 auxiliary_device_add() 创建辅助设备,失败路径调 auxiliary_device_uninit() 避免双重释放。数据结构拆分为 struct ras2_mem_ctx_hdr 与 struct ras2_pxm_domain,从而支持单 PCC 通道跨所有 NUMA 域的共享场景。drivers/ras/acpi_ras2.c(540 行):作为 auxiliary 驱动注册到 EDAC scrub 框架。scrub 实例 sysfs 目录命名为 acpi_ras_mem_idX;新增 enable_demand 属性用于启动/停止 demand scrub;set_scrub_cycle 标志避免 cache 覆盖用户设置值;ras2_hw_scrub_set_enabled_od() 避免 monitor 线程过早重启后台 scrub 的竞态;kthread_stop() 在 remove 路径显式停止监控线程;ras2_hw_scrub_read_addr/size() 等路径补齐 pcc_lock 获取。sysfs ABI 文档(Documentation/ABI/testing/sysfs-edac-scrub)及 Documentation/edac/scrub.rst 一并更新。
收益
作者未提供性能 benchmark 数据。从代码逻辑推断的收益:(1) 首次使 Linux 能够按 ACPI 6.5 标准驱动服务器硬件的 patrol scrub 引擎,显著降低 DRAM 软错误演化为 UE 的概率;(2) 通过统一的 EDAC scrub sysfs 接口,运维可按 NUMA 节点调整 scrub 周期、地址范围与使能状态;(3) 兼容 Ampere 等共享单 PCC 通道的平台;(4) 历经 19 轮迭代的健壮性修复(大端 IO、PCC 锁、MPAR 节流、probe 失败清理、monitor 线程停止)使该驱动可用于生产级 RAS 场景。
8. process_vm_readv/writev 的 pidfd 与 NOWAIT 支持
系列:[PATCH v2 0/2] mm/process_vm_access: pidfd and nowait support for process_vm_readv/writev作者: Alban Crequy版本: v2(2 个 patch)
背景
process_vm_readv(2) / process_vm_writev(2) 允许一个进程直接跨地址空间读写另一进程的内存,是调试器、崩溃转储采集器、容器监控以及 eBPF 用户态数据抓取等工具的基础原语。然而其原型采用 pid_t 标识目标进程,存在经典的 PID 复用(TOCTOU)竞态:一旦目标进程退出而 PID 被复用,调用者可能错误地访问或覆写毫不相关的新进程内存。现代 Linux 的 pidfd 机制已经为 kill、waitid、setns 等接口解决了同类问题,但 process_vm_* 始终未对齐。此外,该接口在触发缺页时会阻塞在 IO 上,这对低延迟采样、追踪场景不可接受。
解决的问题
process_vm_readv/writev 存在 PID 复用 TOCTOU 风险,无法与 pidfd 生态协同- 远程内存访问触发 page fault 时无条件阻塞,不适合低延迟/原子上下文的采样
- 原接口没有 flags 参数语义扩展位,需要在保持 ABI 兼容的前提下新增标志
如何做
Patch 1 在 mm/process_vm_access.c 扩展内核实现,并新增 UAPI 头 include/uapi/linux/process_vm.h 定义两个标志:
PROCESS_VM_PIDFD (1UL << 0):表示 pid 参数语义改为 pidfd 文件描述符,内核通过 pidfd_get_task() 安全解析目标任务,消除 PID 复用竞态;PROCESS_VM_NOWAIT (1UL << 1):传递到底层 get_user_pages_remote() 路径(FOLL_NOWAIT 语义),遇到需要 IO 的缺页直接返回而非阻塞。
为避免未来 flags 扩展遗漏校验,内核侧引入 PROCESS_VM_SUPPORTED_FLAGS 掩码集中定义支持的位,不认识的位一律返回 -EINVAL。pvm_flags 参数统一使用 unsigned long(David Hildenbrand 建议)。UAPI 头使用 (1UL << N) 而非 BIT(),因为后者定义在 vdso/bits.h 不对用户态导出。Patch 2 新增 selftest tools/testing/selftests/mm/process_vm_readv.c(368 行),覆盖 pidfd 正常路径、pidfd 指向已退出进程、NOWAIT 遇到被换出页、未知 flag 被拒绝等场景,并更新 MAINTAINERS。
收益
作者未提供性能数据。从语义上评估:(1) pidfd 路径彻底消除跨进程内存读写中的 PID 复用漏洞,使 process_vm_* 可安全用于长时间运行的调试器、监控代理和容器管理面;(2) NOWAIT 让低延迟采样工具在远程内存已被换出时能立刻失败并选择重试或跳过,对 tracing / profiling 工作负载尤其关键;(3) 集中式 PROCESS_VM_SUPPORTED_FLAGS 校验为后续扩展该接口铺平道路;(4) 随补丁提供的 selftest 保证上述语义在回归测试中持续被覆盖。
9. userfaultfd:允许注册 mmap_min_addr 以下的范围
系列:[RFC PATCH] userfaultfd: allow registration of ranges below mmap_min_addr作者: Denis M. Karpov版本: RFC(1 个 patch,fs/userfaultfd.c +1/-3)
背景
mmap_min_addr 是用于缓解 NULL 指针解引用漏洞利用的安全策略,禁止普通进程把内存映射到低地址。但这并非绝对禁令:mmap(2) 走 LSM/capability 路径 security_mmap_addr()(默认实现 cap_mmap_addr() 检查 CAP_SYS_RAWIO 并比较 dac_mmap_min_addr,后者还可通过 /proc/sys/vm/mmap_min_addr 运行时调节)。因此具有 CAP_SYS_RAWIO 的特权进程可以合法 mmap 到 mmap_min_addr 以下。然而 fs/userfaultfd.c:validate_unaligned_range() 却对 start < mmap_min_addr 做了无条件硬拒绝,这与 mmap 允许的行为不一致,造成一个不合理的能力差:进程有权映射低地址,却无权对自己合法映射出的区域调用 UFFDIO_REGISTER。
解决的问题
- userfaultfd 与 mmap 安全策略不一致:一个按
mmap_min_addr 硬比较,另一个走 security_mmap_addr() 并尊重 capability 与 LSM - 特权应用(典型:二进制翻译器/JIT、动态编译器、模拟器)即使已成功
mmap() 了低地址,也无法对其 UFFDIO_REGISTER
如何做
改动极小——在 validate_unaligned_range() 中删除直接的 if (start < mmap_min_addr) return -EINVAL;,改为在函数末尾 return security_mmap_addr(start);:
- if (start < mmap_min_addr)
- return -EINVAL;
...
- return0;
+ return security_mmap_addr(start);
这样 userfaultfd 的低地址策略改为复用与 mmap(2) 完全一致的内核安全钩子,尊重 CAP_SYS_RAWIO 特权、运行时可调的 dac_mmap_min_addr 和任何注册到 security_mmap_addr 的 LSM hook。普通无特权进程依旧被 cap_mmap_addr() 拒绝(返回 -EACCES),安全语义没有放松。
收益
作者未提供性能数据;此为语义一致性改动。预期收益:(1) 消除 userfaultfd 与 mmap 之间长期存在的策略不一致;(2) 解锁二进制翻译器、模拟器、JIT 编译器等需要把访客地址空间放在低地址的工具使用 userfaultfd 做按需分页、COW、写保护追踪;(3) 管理员通过 sysctl 调低 mmap_min_addr 时 userfaultfd 会自动跟进;(4) 返回码从一刀切的 -EINVAL 变为更准确的 -EACCES,有利于用户态诊断。改动净 -2 行。
总结
新机制 / 新接口
| | |
|---|
| always enable mTHP support | 新增 pgtable_has_pmd_leaves() / arch_has_pmd_leaves() API,让不支持 PMD leaf 的架构也能享受 mTHP 中等 order |
| iomap buffered write-through | 新 UAPI RWF_WRITETHROUGH + ->writethrough_submit() FS 钩子,为 RWF_ATOMIC/异步 DSYNC 铺路 |
| ACPI RAS2 feature table | 首次支持 ACPI 6.5 RAS2,暴露 per-NUMA patrol/demand scrub 至 EDAC sysfs |
| process_vm_access pidfd/NOWAIT | 新增 PROCESS_VM_PIDFD / PROCESS_VM_NOWAIT UAPI 标志,消除 TOCTOU 并支持非阻塞读取 |
| userfaultfd 低地址注册 | 将 mmap_min_addr 硬比较换成 security_mmap_addr(),与 mmap 策略对齐 |
| damon freeze kdamond | kdamond 接入 freezer 框架,支持 suspend/resume |
性能优化
| | |
|---|
| vmalloc 连续内存加速 | RK3588 ARM64:ioremap 1M +1.2×,huge vmalloc 1M +1.5×,vmap order-8 +5.6× |
| MGLRU reclaim 重构 + dirty | MongoDB YCSB:吞吐 **+27.6%**,延迟 **−21.9%**,file refault **−43.3%**;修复 file-anon-mix OOM |
| RWF_DONTCACHE for block | fio NVMe:读 **+56%**,memcg 写 **+105%**;新增 BIO_COMPLETE_IN_TASK 通用机制并清理 XFS workqueue hack |
Bug Fix
本期入选 feature 中无独立 bug fix 系列;Feature 3 (MGLRU) 顺带修复了 file-anon mix 场景下 memcg OOM 与 dd + dirty throttling OOM。
内部优化 / 清理
| | |
|---|
| has_transparent_hugepage → arch_has_pmd_leaves | treewide 重命名,消除 "THP 可用" 与 "硬件支持 PMD leaf" 语义混淆 |
| MGLRU 代码瘦身 | mm/vmscan.c 净减 51 行(+138/-189),删 sc->file_taken、sc->unqueued_dirty |
| XFS dropbehind workqueue 下沉块层 | 删除 IOMAP_IOEND_DONTCACHE 与 XFS 专属 workqueue,基础设施通用化 |