目录
- fadvise 避免因映射 folio 失败而触发远程 LRU drain
- HugeTLB 分配路径泛化:解除对 VMA 的依赖
- vmscan: 重设计 lru_shrink 与 write_folio tracepoint
- khugepaged: mm_slot_alloc() 失败时清除 MMF_VM_HUGEPAGE
- swap: 添加 cond_resched() 防止 swap_reclaim_full_clusters softlockup
1. 匿名大页(large folio)批量 unmap 优化
系列:[PATCH v3 0/9] Optimize anonymous large folio unmapping作者: Dev Jain版本: v3(9个patch)
背景
内核在 6.12 合并窗口期间引入了文件映射大页(file-backed large folio)的批量 unmap 支持(commit a67fe41e214f),将同一 folio 的多个 PTE 一次性清除,减少了逐页处理的开销。然而,匿名大页(anonymous large folio,即 swapbacked anon folio)的 unmap 路径仍然采用逐页处理方式。每次 unmap 一个 PTE 都需要:调用 page_vma_mapped_walk() 遍历页表、执行 ptep_get() 读取 PTE、单独进行 swap entry 分配/引用计数操作、单独清除 PTE、单独进行 rmap 统计。对于 arm64 的 contpte 映射,逐页处理还需反复拆解和重建连续 PTE 映射(contpte-unfolding),带来冗余的 TLB 刷洗。文件大页的批量支持已经证明了批量处理的收益,但匿名大页路径由于其涉及的 swap entry 管理、PageAnonExclusive 处理、uffd-wp 标记等复杂性,一直未被批量化。
解决的问题
- 匿名大页 swapout 延迟过高:256 MiB 的 64K 大页 swapout 在 arm64 上需约 37.4 ms(Vanilla),每次 unmap 都需要逐页进行 swap 条目分配、PTE 清除和 TLB 维护。
- arm64 contpte 冗余开销:在 arm64 contpte 系统上,逐页 unmap 会反复触发 contpte 映射的拆解/重建,导致大量不必要的
ptep_get() 调用和 TLB 刷洗。 - 匿名大页 unmap 无法利用批量原子操作:
add_mm_counter、rmap 统计(folio_remove_rmap_ptes)等操作均可批量完成,但逐页路径只能逐个原子操作。 - uffd-wp VMA 上的文件大页 unmap 被强制逐页处理:当前代码在检测到 VMA 有
userfaultfd_wp 标记时直接回退到 nr_pages=1,即使 PTE 批量在 uffd-wp 语义下也是安全的。
如何做
本系列共 9 个 patch,核心思路是将 try_to_unmap_one() 中匿名 swapbacked folio 的 unmap 逻辑重构为批量处理模式,与已有的文件/懒释放大页批量路径统一。
Patch 1-3 为前置重构:Patch 1 修复了 nr_pages 在循环开始时未初始化的潜在问题。Patch 2 将 try_to_unmap_one() 中长达 55 行的 hugetlb PTE 清除内联代码抽取为独立函数 unmap_hugetlb_folio()。Patch 3 将 MADV_FREE(lazyfree)folio 的 unmap 后检查逻辑抽取为 can_unmap_lazyfree_folio_range(),并将成功路径的跳转标签重命名为更语义化的 finish_unmap。
Patch 4-5 建立 uffd-wp 批量支持:Patch 4 将 pte_install_uffd_wp_if_needed() 重构为批量版本 install_uffd_wp_ptes_if_needed(),接受 nr_ptes 参数。Patch 5 移除了 folio_unmap_pte_batch() 中对 userfaultfd_wp(vma) 的提前返回检查,使 uffd-wp VMA 上的大页 unmap 也能批量进行。关键安全保证:folio_unmap_pte_batch() 已确保批量内所有 PTE 的 uffd-wp 状态一致。
Patch 6-8 建立 swap/rmap 批量基础:Patch 6 引入 folio_dup_swap_pages(folio, page, nr_pages),将 swap count 增加操作泛化为任意连续页面范围。Patch 7 对称地引入 folio_put_swap_pages() 和 folio_put_swap()。Patch 8 引入 folio_try_share_anon_rmap_ptes() 和辅助函数 folio_clear_pages_anon_exclusive(),批量清除多个子页的 PageAnonExclusive 标志。
Patch 9 是核心实现,引入以下关键函数:
set_swp_ptes(mm, address, ptep, entry, pteval, anon_exclusive, nr_pages):批量设置 swap PTE,使用 pte_next_swp_offset() 自动推进 swap 偏移。finish_folio_unmap(vma, folio, subpage, nr_pages):统一 unmap 成功后的收尾工作——批量移除 rmap、处理 mlock drain、批量释放引用计数。__unmap_anon_folio_range():对一个子批次执行实际 unmap:folio_dup_swap_pages() → folio_try_share_anon_rmap_ptes() → add_mm_counter 批量统计 → set_swp_ptes() 批量写入 → finish_folio_unmap()。unmap_anon_folio_range():对批量 PTE 按 PageAnonExclusive 状态拆分为子批次,调用 page_anon_exclusive_sub_batch() 确定子批次长度,然后逐子批次调用 __unmap_anon_folio_range()。
folio_unmap_pte_batch() 中移除了 folio_test_anon(folio) && folio_test_swapbacked(folio) 的提前返回,使匿名 swapbacked 大页也能利用现有的 PTE 批量探测逻辑。
收益
| | | | |
|---|
| 256 MiB 64K 大页 MADV_PAGEOUT | 37,401,913 ns (std dev 12%) | 17,420,282 ns (std dev 11%) | ~53.4% |
| 256 MiB 64K 大页 MADV_PAGEOUT | 54,986,286 ns (std dev 1.5%) | 51,930,795 ns (std dev 3%) | |
| | | | |
arm64 上显著收益来源:(1) 批量处理减少了 ptep_get() 调用——逐页路径每页都需读取 PTE,批量路径只读一次然后通过 pte_advance_pfn()/pte_next_swp_offset() 推导后续 PTE;(2) 避免了 contpte 拆解/重建过程中的冗余 TLB 刷洗。x86 改善不明显因不使用 contpte,ptep_get() 开销低且无 contpte TLB 刷洗开销。
2. mm/fadvise: 避免因映射 folio 失败而触发远程 LRU drain
系列:[PATCH] mm/fadvise: avoid remote LRU drain for mapped folio failures作者: fujunjie版本: v1(1个patch)
背景
POSIX_FADV_DONTNEED 语义是通知内核指定范围的文件页不再需要,可以回收。generic_fadvise() 的实现流程是:先排空本地 CPU 的 LRU 批次缓存(lru_add_drain()),然后调用 mapping_try_invalidate() 尝试逐出页面。如果在此过程中有任何 folio 逐出失败,现有代码保守地认为失败原因可能是 folio 被远程 CPU 的 per-CPU LRU 批次缓存持有引用,于是无条件调用 lru_add_drain_all()——一个需要向所有 CPU 发送 IPI、等待所有 CPU 排空其本地 LRU 缓存的全局同步操作——然后重试。
然而,mapping_evict_folio() 的 refcount 检查失败原因远不止远程 LRU 批次引用一种:dirty/writeback folio、被用户空间映射的 folio、有文件系统私有状态的 folio 都会因为额外的引用计数导致逐出失败。对于这些原因,全局 LRU 排空根本无济于事——排空 LRU 缓存无法清除脏标志、无法解除用户映射、也无法释放文件系统的私有资源——但当前代码仍然无条件触发昂贵的跨 CPU 同步操作。在常见的流式 I/O 场景中,应用 mmap 一个文件后调用 fadvise,文件页因被映射而始终有额外引用,每次 fadvise 调用都会触发不必要的全局 LRU 排空。
解决的问题
- 映射 folio 导致虚假的全局 LRU 排空:应用使用
mmap 映射文件后调用 fadvise,所有 folio 因被映射而 refcount 超标,无法逐出,但每次都会触发一次无意义的 lru_add_drain_all()(跨所有 CPU 的 IPI)。 - dirty/writeback 和文件系统私有状态的 folio 同样被错误纳入远程 LRU 怀疑范围,造成不必要的全局同步开销。
如何做
这是一个单 patch 的精确修复,修改涉及 3 个文件。核心变化是将 mapping_evict_folio() 改造为能区分"可通过远程 LRU 排空修复的失败"和"无法通过远程 LRU 排空修复的失败"。
- 将
mapping_evict_folio() 重构为 __mapping_evict_folio():新增一个 bool *lru_refs 输出参数。在 refcount 检查失败时,额外检查 folio 是否被映射:只有 !folio_mapped(folio)(即未被映射的干净 folio)才将 *lru_refs 设为 true,表示此失败可能通过远程 LRU 排空解决。映射的 folio 不会标记为 lru_refs,因为排空 LRU 缓存无法解除页表映射。
if (folio_ref_count(folio) >
folio_nr_pages(folio) + folio_has_private(folio) + 1) {
if (lru_refs && !folio_mapped(folio))
*lru_refs = true;
return0;
}
**mapping_try_invalidate() 改为使用 __mapping_evict_folio()**:仅当 lru_refs == true 时才递增 *nr_lru_refs 计数器。其他原因的失败不再计入。
generic_fadvise() 使用语义重命名后的计数器:变量从 nr_failed 重命名为 nr_lru_refs,只有 nr_lru_refs > 0 时才触发 lru_add_drain_all() 并重试。映射 folio 导致的失败不再触发全局排空。
收益
| | | | |
|---|
| 128 MiB MAP_SHARED 文件流式读取,2 MiB chunk,每 chunk 后 fadvise | 112,116 ns/call,256 lru_add_drain_all()/轮 | 79,012 ns/call,0 lru_add_drain_all()/轮 | ~29.5% 延迟降低 |
同时作者验证了跨 CPU 场景(CPU 0 写入文件,CPU 1 调用 fsync+fadvise)在 patched 内核中仍然正确触发全局排空:10/10 轮测试中均调用了 lru_add_drain_all() 一次,且后续 mincore() 检查确认 0 驻留页。修复精确地消除了误报,同时保留了跨 CPU 场景的正确性。
3. HugeTLB 分配路径泛化:解除对 VMA 的依赖
系列:[PATCH v2 0/6] Open HugeTLB allocation routine for more generic use作者: Ackerley Tng版本: v2(6个patch)
背景
HugeTLB 子系统的核心分配函数 alloc_hugetlb_folio() 历来强依赖于 struct vm_area_struct (VMA)。这种耦合体现在两个层面:(1) 通过 vma->vm_policy 获取 NUMA 内存策略(mpol),(2) 通过 VMA 关联的 resv_map 查询和消耗预留(reservation)。这种设计导致即便是 HugeTLBfs 自身也不得不构造 "pseudo-VMA" 来调用分配函数,而新兴的 guest_memfd 场景则从根本上不拥有 VMA(guest 内存可能永远不会被映射),无法使用既有的 HugeTLB 分配路径。此外,alloc_hugetlb_folio() 内部混杂了预约管理、cgroup 计费、memcg 计费和实际页面分配等多种职责,整体逻辑难以理解和复用。
解决的问题
- HugeTLB 分配必须提供 VMA:
alloc_hugetlb_folio() 的两个核心子函数均通过 huge_node(vma, ...) 从 VMA 中解析 mpol 和 NUMA 节点,无法被无 VMA 的调用者(如 guest_memfd)使用。 - 子池(subpool)信息与 fs 挂载点耦合:
alloc_hugetlb_folio() 直接从 VMA 文件对应的 superblock 获取 subpool,这意味着 guest_memfd(计划每个 fd 一个 subpool,存储在 inode 上)无法复用现有的页面分配逻辑。 - 分配/预留/计费职责混杂:
gbl_chg 的判断逻辑分散在多处,cgroup 计费、memcg 计费与 subpool 操作交错在一起,错误处理路径混乱。
如何做
整个系列采用渐进式重构策略——将与 VMA 相关的决策(mpol 解析、reservation 查找、subpool 操作)上提到 alloc_hugetlb_folio(),同时将纯粹的页面分配逻辑下沉到新的 hugetlb_alloc_folio() 中。
Patch 1-3 逐层剥离 mpol 解析与 gbl_chg 解读:将它们从 dequeue_hugetlb_folio_vma() 和 alloc_buddy_hugetlb_folio_with_mpol() 移出,两个子函数改为直接接收 mpol、nid、nodemask 参数。mpol 解析仅执行一次,被两个路径共享。
Patch 4-5 统一错误码传递,提前 memcg 计费以修复 subpool 泄漏 bug。
Patch 6 是核心重构,提取 hugetlb_alloc_folio():
struct folio *hugetlb_alloc_folio(struct hstate *h, struct hugepage_subpool *spool,
struct mempolicy *mpol, int nid, nodemask_t *nodemask,
bool charge_hugetlb_cgroup_rsvd, bool use_global_reservation);
新函数接受显式参数替代 VMA 的隐性信息(mpol、spool、cgroup rsvd 标记、全局预留标记),内部完成 hugetlb cgroup 计费、freelist 出队/buddy 分配、全局预留递减、memcg charge。alloc_hugetlb_folio() 变为薄封装层。
收益
作者未提供性能数据。从代码逻辑推断的预期收益:(1) hugetlb_alloc_folio() 可被 guest_memfd 直接调用,无需 VMA;(2) HugeTLBfs 可在未来去掉 pseudo-VMA;(3) mpol 解析从两次减少为一次;(4) 修复了 memcg 计费失败时的 subpool 泄漏;
4. cgroup/dmem: 引入峰值监控文件
系列:[PATCH 0/2] cgroup/dmem: introduce a peak file作者: Thadeu Lima de Souza Cascardo版本: v1(2个patch)
背景
cgroup v2 的 memory.peak 文件允许用户空间查询一个 memory cgroup 自创建或上次重置以来的最大内存使用量。dmeme cgroup 控制器(device memory cgroup)用于管理设备内存(如 GPU 显存等)的分配和隔离,已有 dmem.current、dmem.min、dmem.max 等文件,但缺少类似 memory.peak 的峰值监控能力。此外,memory.peak 接受任意写入即重置全局峰值,但 dmeme 有多个独立的区域(region,如 vram、stolen),需要能定向重置特定区域的峰值。
解决的问题
- dmeme cgroup 无法追踪区域内历史峰值使用量:无法回答"该 cgroup 的 GPU 显存历史上最高用到了多少"这类基本运维问题。
- memory.peak 的全局重置不适用于 dmeme 的多区域模型:需要按 region 名称定向重置特定区域的峰值。
如何做
Patch 1 将 mm/memcontrol.c 中 peak_write() 的核心逻辑提取为通用函数 of_peak_reset(),放置于 kernel/cgroup/cgroup.c,使 future cgroup 控制器可复用。OFP_PEAK_UNSET 宏移至 include/linux/cgroup-defs.h 成为 cgroup 通用定义。
Patch 2 在 dmeme cgroup 中引入 dmem.peak 文件。关键数据结构:
- 在
struct dmem_cgroup_pool_state 中添加 struct list_head peaks 链表 - 在通用
struct cgroup_of_peak 中添加 struct dmem_cgroup_pool_state *pool 指针
dmem.peak 作为 "nested-keyed" 文件实现:写操作接受 region 名称,通过 RCU 查找对应 region 并定向重置其峰值;读操作处理跨区域切换、未初始化 watcher 的 fallback 到全局 watermark;文件关闭时清理 watcher 链表注册。
收益
作者未提供性能数据。从代码逻辑推断的预期收益:(1) 运维人员可观察设备内存的历史峰值使用量,支持容量规划和异常检测;(2) 写入 region 名称可定向重置特定区域峰值,比 memory.peak 更精细;(3) of_peak_reset() 的通用化使未来 cgroup 控制器可复用 peak 机制。
5. kmemleak: 冗余泄露报告的去重
系列:[PATCH v3 0/2] mm/kmemleak: dedupe verbose scan output作者: Breno Leitao版本: v3(2个patch)
背景
kmemleak 的 verbose 扫描模式会在每次扫描中向 dmesg 打印每个未引用对象的完整信息(对象头、hex dump、16 帧调用栈回溯)。当工作负载从同一个分配点泄露大量对象时,dmesg 会被逐字节相同的回溯信息淹没,使得管理员难以识别不同来源的泄露,也会冲刷掉其他内核消息。而 /sys/kernel/debug/kmemleak 文件始终保留每个对象的完整列表,不受此影响。
解决的问题
- Verbose 模式下的重复回溯信息风暴:100 个相同分配点泄露的对象会产生 100 份完全相同的 16 帧回溯和 hex dump。
- 重复输出占用 dmesg 环形缓冲区空间:可能导致更早的有价值日志被挤出。
如何做
方案利用 stackdepot 的 trace_handle 作为去重键,在一次扫描范围内合并具有相同回溯的泄露对象。
在 struct kmemleak_object 中添加 unsigned int dup_count 字段。在 kmemleak_scan() 中创建 per-scan 的 struct xarray dedup。
扫描阶段调用 dedup_record():在 xarray 中查找 trace_handle——如果已存在,递增 dup_count;不存在则 xa_store() 存入。trace_handle == 0 时直接内联打印。xa_store() 失败时回退到内联打印。
扫描完成后调用 dedup_flush():dup_count > 1 时跳过 hex dump 并追加汇总行 "... and N more object(s) with the same backtrace";dup_count == 1 时正常完整打印。
安全性保证:(1) dedup_record() 在 object->lock 之外执行,避免 lockdep 冲突;(2) 打印前重新检查 OBJECT_ALLOCATED 标志防止 use-after-free;(3) get_object() 失败安全跳过。
附带 selftest (ksft_kmemleak_dedup.sh):加载 kmemleak-test 模块,启用 verbose,执行扫描后检查 dmesg 中无同一扫描内重复回溯。策略为宽松检测、严格防退化。
收益
作者未提供具体数字的性能数据。从代码逻辑推断的预期收益:对于有 N 个对象共享 M 种唯一回溯的场景(N >> M),dmesg 输出量从 O(N) 降至 O(M),在大规模泄露场景下日志量可减少数十倍甚至上百倍。/sys/kernel/debug/kmemleak 输出完全不受影响。
6. mm: vmscan: 重设计 lru_shrink 与 write_folio tracepoint
系列:[PATCH v2] mm: vmscan: rework lru_shrink and write_folio tracepoints作者: qiwu.chen版本: v2(1个patch)
背景
vmscan 子系统的 tracepoint 提供了内存回收过程的可观测性。历史上,lru_shrink 系列 tracepoint 通过 reclaim_flags 字段输出 RECLAIM_WB_ANON、RECLAIM_WB_FILE、RECLAIM_WB_SYNC、RECLAIM_WB_ASYNC 等标志位。然而,自 commit 41ac1999c3e35 后,所有内存回收路径的 writeback 均采用异步模式,RECLAIM_WB_SYNC 不再被任何代码路径使用。trace_reclaim_flags() 宏使得 reclaim_flags 始终输出固定值,区分度极低。此外,mm_vmscan_write_folio tracepoint 中打印的 PFN 信息在 folio 体系下已冗余,而 lru_shrink tracepoint 缺乏对回收触发原因(kswapd / direct reclaim / khugepaged / proactive reclaim)的区分能力。
解决的问题
reclaim_flags 信息无效:RECLAIM_WB_SYNC 从未被设置,RECLAIM_WB_ASYNC 始终被设置,flags 字段丧失诊断意义。- 缺少回收原因(reason)和精确的 LRU 类型信息:原有 tracepoint 只能区分匿名页/文件页回收,无法知道回收触发者是 kswapd、direct reclaim、khugepaged 还是 proactive reclaim,也无法区分 active/inactive LRU。
如何做
从根本上重新设计 lru_shrink 和 write_folio 两个 tracepoint 的输出字段。
删除已失效的 RECLAIM_WB_* 标志位体系:移除 6 个宏及配套打印函数和辅助宏。
引入 trace_reclaim_reason_ops 符号表:将 PGSTEAL_KSWAPD、PGSTEAL_DIRECT、PGSTEAL_KHUGEPAGED、PGSTEAL_PROACTIVE 映射为可读字符串,与 enum node_stat_item 保持一致。
mm_vmscan_write_folio 重设计:删除 pfn 和 reclaim_flags,新增 folio 指针和 lru(精确表示 5 种 LRU 链表之一)。
mm_vmscan_lru_shrink_inactive/active 重设计:删除 file 布尔值和 reclaim_flags,新增 lru(精确 LRU 类型)和 reason(回收触发者)。输出格式从 flags=%s 变为 lru=%s reason=%s,使用 __print_symbolic() 转换。
收益
作者未提供性能数据。从代码逻辑推断的预期收益:(1) 调试效率显著提升——可直接从 tracepoint 看到每条回收操作的触发者(kswapd/direct/khugepaged/proactive)和精确 LRU 位置;(2) tracepoint 输出更精简,移除了无效 noise,perf/bpftrace 脚本更易编写;(3) reason 枚举直接复用 PGSTEAL_* 统计项,与 /proc/vmstat 保持一致。
7. mm/khugepaged: 清除 mm_slot_alloc() 失败时的 MMF_VM_HUGEPAGE
系列:[PATCH v2] mm/khugepaged: clear MMF_VM_HUGEPAGE on mm_slot_alloc() failure作者: Ye Liu版本: v2(1个patch)
背景
khugepaged 的注册流程分两步:(1) 设置 MMF_VM_HUGEPAGE 标志位表示已注册;(2) 分配 mm_slot 结构体并插入哈希表。commit 16618670276a 优化了流程,使用原子操作 mm_flags_test_and_set() 避免重复分配。但引入一个缺陷:MMF_VM_HUGEPAGE 在 mm_slot_alloc() 之前就已设置,如果后续 mm_slot_alloc() 分配失败(如系统内存紧张时 kmem_cache_alloc 返回 NULL),函数直接返回,但标志位已被设置且永远不会被清除。
解决的问题
- mm 永久处于不一致状态:
MMF_VM_HUGEPAGE 被设置但 mm 不在 khugepaged 的任何跟踪数据结构中,永远不会被扫描。 - 后续注册尝试被阻塞:
khugepaged_enter_vma() 检查 !mm_flags_test(MMF_VM_HUGEPAGE, ...),因标志位仍被设置,即使之前注册失败,后续 VMA 也不会再尝试注册。
如何做
在 __khugepaged_enter() 中 mm_slot_alloc() 失败时,调用 mm_flags_clear(MMF_VM_HUGEPAGE, mm) 清除标志位:
slot = mm_slot_alloc(mm_slot_cache);
if (!slot) {
mm_flags_clear(MMF_VM_HUGEPAGE, mm);
return;
}
Fixes: 16618670276a ("mm: khugepaged: avoid pointless allocation for struct mm_slot")
收益
作者未提供性能数据。从代码逻辑推断的预期收益:修复内存紧张时 mm_slot_alloc() 失败导致进程永久丧失 THP 合并能力的 bug。内存压力缓解后进程可自动恢复注册。
8. mm/swap: 添加 cond_resched() 防止 swap_reclaim_full_clusters softlockup
系列:[PATCH v2] mm/swap: Add cond_resched() in swap_reclaim_full_clusters to prevent softlockup作者: Zijiang Huang版本: v2(1个patch)
背景
swap 子系统的 swap_reclaim_full_clusters() 函数在 workqueue 上下文中扫描 full cluster,尝试回收无引用的 swap entry 以释放 cluster。当 swap 设备存在大量 full cluster 时,外层 while 循环遍历 si->full_clusters 链表,内层循环遍历单个 cluster 内的每个 swap entry,可能在多个 cluster 的遍历中长时间不主动让出 CPU。
解决的问题
- softlockup 风险:在 320 CPUs、约 1TB 内存、8.6GB swap 的 arm64 系统上运行 LTP memory/swap 压力测试约 3 天后,
kworker/48:7 在 swap_reclaim_full_clusters() 中被 watchdog 检测到 softlockup。调用栈:swap_cache_del_folio -> __try_to_reclaim_swap -> swap_reclaim_full_clusters
-> swap_reclaim_work -> process_one_work -> worker_thread -> kthread
如何做
在 swap_reclaim_full_clusters() 每处理完一个 cluster(swap_cluster_unlock(ci) 之后、to_scan <= 0 检查之前),添加 cond_resched():
swap_cluster_unlock(ci);
if (to_scan <= 0)
break;
cond_resched();
cond_resched() 位于 cluster 锁外,避免持锁调度。对于 force=false 的路径(to_scan=1),cond_resched() 几乎无额外开销。
Fixes: 5168a68eb78f ("mm, swap: avoid over reclaim of full clusters")
收益
| | | |
|---|
| 320 CPUs, ~1TB RAM, 8.6GB swap, arm64 | | |
总结
性能优化
| | |
|---|
| 匿名大页批量 unmap 优化 | arm64 MADV_PAGEOUT 延迟 53.4%↓(37.4→17.4ms), x86 5.5%↓, 4K folio 无退化 |
| fadvise 避免远程 LRU drain | mmap+fadvise 延迟 29.5%↓(112→79 μs/call), lru_add_drain_all() 256→0 次 |
新机制 / 新接口
| | |
|---|
| HugeTLB 分配路径泛化 | 提取 hugetlb_alloc_folio() 解除对 VMA 的依赖,为 guest_memfd 铺路 |
| cgroup/dmem peak | 引入 dmem.peak 文件,支持按 region 名称定向重置设备内存峰值 |
| kmemleak 去重 | 以 trace_handle 为键合并 verbose 输出,大幅减少重复回溯日志 |
Bug Fix
| | |
|---|
| khugepaged 清除 MMF_VM_HUGEPAGE | 修复 mm_slot_alloc() 失败时标志位泄漏导致进程永久丧失 THP 能力;Fixes: 16618670276a |
| swap cond_resched() 防 softlockup | 修复 320 CPU / 1TB RAM 大机器上 swap 压力测试 3 天后触发的 softlockup;Fixes: 5168a68eb78f |
内部优化 / 清理
| | |
|---|
| vmscan tracepoint 重设计 | 删除失效的 RECLAIM_WB_* flag,新增 lru 精确类型和 reason 触发者字段 |