当前位置:首页>Linux>Linux MM 2026-04-23~26 最新 Feature 分析报告

Linux MM 2026-04-23~26 最新 Feature 分析报告

  • 2026-06-22 03:58:44
Linux MM 2026-04-23~26 最新 Feature 分析报告

目录

  1. 使用 VMA 锁优化 /proc/pid/{smaps, numa_maps} 读取
  2. 实现新的通用页表遍历 API (pt_range_walk)
  3. 修复 hugetlb __mmap_region 错误路径中 resv_map 内存泄漏
  4. DAMON 新增节点 eligible 内存比例目标指标
  5. DAMON 热分数计算优化与 DAMOS_COLLAPSE 操作
  6. DAMON 引入数据属性监控
  7. 优化 RWF_DONTCACHE 写入性能
  8. virtio 跳过主机已清零页面的冗余清零
  9. LRU 批量添加时预释放已死亡 folio
  10. 修复 vmemmap 优化的计数与初始化
  11. 双位图伙伴分配器一致性检查器
  12. 跳过 TLB flush 已发 IPI 后的冗余同步 IPI
  13. 动态内核栈
  14. 修复设备迁移中 PMD 自旋锁泄漏
  15. 修复设备迁移中页表泄漏
  16. KASAN HW-tags 禁用栈与页表的标签
  17. userfaultfd 检测 copy 重试后 VMA 类型变更
  18. MGLRU 改进回收循环与脏页处理
  19. 内存故障不可恢复时添加 panic 选项
  20. NOMMU 下正确处理 FOLL_PIN 引用计数
  21. KHO 支持延迟 struct page 初始化
  22. 修复 DAMON sysfs 路径 use-after-free
  23. 避免内存碎片化下回收-驱逐循环
  24. 内存 cgroup 限制支持内存层级感知

1. 使用 VMA 锁优化 /proc/pid/{smaps, numa_maps} 读取

系列[PATCH v2 0/3] use vma locks for proc/pid/{smaps|numa_maps} reads作者: Suren Baghdasaryan版本: v2(3 个 patch)

背景

/proc/pid/maps 已先行支持 per-VMA lock + RCU 遍历来避免持有 mmap_lock,但 /proc/pid/smaps 和 /proc/pid/numa_maps 却无法简单套用相同方案,原因是这两个接口需要做 page table walk,而 page table walk 可能睡眠(例如 shmem_swap_usage() 会访问 swap cache)。在 RCU read lock 下睡眠是不允许的,因此这两者长期以来必须全程持有 mmap_lock,导致与并发地址空间修改(mmap/munmap/mprotect)产生严重锁竞争。

解决的问题

  • smaps/numa_maps 读取期间全程持有 mmap_lock,阻塞并发 VMA 操作
  • page table walk 可睡眠与 RCU 不可睡眠之间的矛盾:既需要 RCU 保护 VMA tree 遍历,又需要在 walk 期间释放 RCU
  • 缺乏 smaps 并发撕裂测试(已有 maps 测试,但 smaps 未被覆盖)

如何做

核心思路是在 page table walk 前 drop RCU(但保持 VMA 被 per-VMA lock 锁定),walk 完成后重新 acquire RCU 并重置 VMA iterator

引入关键辅助函数:lock_ctx_mm() / unlock_ctx_mm() 封装 mmap_lock 操作并追踪 mmap_locked 状态;drop_rcu(priv) 在 per-VMA lock 模式下释放 rcu_read_lock()(VMA 本身已被 vma_start_read() 锁定保持稳定);reacquire_rcu(priv) 重新 rcu_read_lock() 并调用 vma_iter_set() 重置 VMA iterator 确保从锁定 VMA 结束后继续安全遍历。

为 page table walk 引入新的 mm_walk_ops 变体,使用 PGWALK_VMA_RDLOCK_VERIFY 标记表示 walk 是在 per-VMA lock 下进行的。具体流程:smap_gather_stats() 先检查 gate VMA(跳过),然后 drop_rcu(),执行 walk_page_vma(),最后 reacquire_rcu()get_smaps_walk_ops() 和 get_show_numa_ops() 根据 mmap_locked 状态动态选择 walk ops。

测试方面引入 FIXTURE_VARIANT 机制让已有 maps 测试同时运行 smaps 变体,实现 parse_vma_line() 确保 sscanf() 输入 NUL-terminated,以及对 smaps 差异化输出格式的适配。

收益

作者未提供性能数据,[从代码逻辑推断:对于大地址空间(数百个 VMA),smaps 读取涉及完整 page table walk 并可能触发 I/O,在此期间 mmap_lock 被持续持有。改为 per-VMA lock 后,mmap_lock 的持有时间变为零(仅 RCU + per-VMA lock),并发 mmap/munmap 操作可以在遍历间隙正常进行,大幅降低锁竞争]。


2. 实现新的通用页表遍历 API (pt_range_walk)

系列[RFC PATCH v2 0/7] Implement a new generic pagewalk API作者: Oscar Salvador版本: RFC v2(7 个 patch)

背景

LSFMM/BPF 2025 达成共识:需要一个通用 pagewalk API 替代当前基于 mm_walk_ops 回调的旧接口。痛点包括:/proc/pid/smapsnuma_mapspagemap 各自维护几乎相同的页表遍历逻辑,HugeTLB 总是被当作 PTE 处理(需要特殊 .hugetlb_entry 回调),大量代码在锁管理、contiguous 条目批处理等方面存在重复。

解决的问题

  • 多个 /proc 接口中 page table walk 代码高度重复(smaps: ~200 行,numa_maps: ~120 行,pagemap: ~450 行专用遍历代码)
  • HugeTLB 在旧 API 中被视为 PTE 级别,无法以真实粒度(PMD/PUD)处理
  • 缺少 PUD 级别 HugeTLB(1GB 大页)的遍历和 softleaf 提取基础设施
  • contiguous 条目批处理(PTE batch、HugeTLB contiguous PMD batch)在各子系统中重复实现
  • 锁管理(page table lock、VMA lock、i_mmap lock)由每个 caller 自行处理,容易出错

如何做

基础设施(Patch 1-3):softleaf_from_pud() 从 PUD 中提取 softleaf entry,需为 arm64/x86/powerpc/s390/loongarch 添加 __pud_to_swp_entry/__swp_entry_to_pud 宏。pmd_huge_lock() / pud_huge_lock() 统一的 huge page 锁获取函数,THP 和 HugeTLB 共用。folio_pmd_batch() 模拟 folio_pte_batch() 的 PMD 批处理,支持 arm64 CONT_PMDS。

核心 API(Patch 4):pt_range_walk_start() / pt_range_walk_next() / pt_range_walk_done() 三类函数。输出 struct pt_range_walk 包含 foliopagenr_entriessizewritable/young/dirty/presentlevel(PUD/PMD/PTE)等。内部统一处理 pgd→p4d→pud→pmd→pte 层次遍历、自动批处理 contiguous PTEs/PMDs、自动锁管理、HugeTLB PMD shared 检测。

消费者转换(Patch 5-7):smap_gather_stats() 从回调模式转为 pt_range_walk 循环(精简 307 行);show_numa_map() 精简 159 行;pagemap 最复杂的转换(1826 行重构),pagemap_read_walk_range() 替代旧的 pagemap_pmd_range()+pagemap_hugetlb_range()

收益

测试项
结果
tools/mm/page-types.c
 新旧 API 输出
几乎一致(仅 referenced 位有个别差异)
pagemap_ioctl
 selftest
117 个测试中 113 个通过
/proc/pid/numa_maps
 输出验证
与旧 API 对比通过
/proc/pid/smaps
 输出验证
与旧 API 对比通过
架构测试
x86_64 和 arm64 通过

作者标注待完成工作:i_mmap lock 集成(HugeTLB WP vs pmd-sharing)、make_uffd_wp_huge_pte 统一化、更多 pagewalk 消费者有待转换。


3. 修复 hugetlb __mmap_region 错误路径中 resv_map 内存泄漏

系列[RFC PATCH] mm/hugetlb: fix resv_map memory leak in __mmap_region error path作者: Mingyu Wang版本: RFC v1(1 个 patch)

背景

通过 Syzkaller + failslab fault injection 进行模糊测试时,发现 hugetlb mmap 错误路径中存在 persistent resv_map 内存泄漏。这是近期 VMA iterator 和 mmap region 重构引入的回归,该重构将 mmap 准备阶段与 VMA 完成阶段解耦。

解决的问题

  • __mmap_region() 中 call_mmap_prepare() 触发 hugetlbfs_file_mmap_prepare(),成功分配 resv_map(通过 resv_map_alloc() 和 hugetlb_reserve_pages()
  • 如果后续 __mmap_new_vma() 失败(如 vma_iter_prealloc() 因 failslab 返回 -ENOMEM),代码跳转到 abort_munmapdesc 结构被直接丢弃无任何清理
  • 新分配的 VMA 被释放但因为从未到达 set_vma_user_defined_fields()vm_area_free() 不会调用 hugetlb_vm_close() 正常释放路径
  • KASAN 报告 BUG: memory leak -- unreferenced object 0xffff888110b92400, size 512

如何做

在 struct mmap_action 中新增 abort_hook 回调,与已有的 success_hook 形成对称。hugetlbfs_file_mmap_prepare() 设置 abort_hook 为 hugetlb_file_mmap_prepare_abort__mmap_region() 错误路径在 vms_abort_munmap_vmas() 之前调用 desc.action.abort_hook(&desc)。当前 hugetlb_file_mmap_prepare_abort() 为桩函数,标注 TODO:需要实现 hugetlb_reserve_pages() 的正确回滚逻辑并释放 resv_map 引用。

收益

作者未提供性能数据,[这是一个正确性修复:在内存压力下每次失败的 hugetlb mmap 调用将永久泄漏 resv_map(512 字节),持续累积可能 OOM。abort_hook 架构提供通用机制,任何 mmap_prepare 回调都可利用它清理资源]。


4. DAMON 新增节点 eligible 内存比例目标指标

系列[PATCH v9] mm/damon: add node_eligible_mem_bp goal metric作者: Ravi Jonnalagadda版本: v9(1 个 patch)

背景

在异构内存系统(如 DRAM + CXL)中,跨 NUMA 节点的内存分布控制对性能优化至关重要。DAMON 的 quota goal 框架已提供 node_mem_free_bp 等指标,允许用户设置"保持 NUMA 节点 0 可用内存不低于某阈值"的目标。但这些指标都是绝对值导向——跟踪某节点上的绝对资源量,而非跨节点的相对分布比例。用户无法表达"60% 热内存在 DRAM 上,40% 在 CXL 上"这样的分布目标。

解决的问题

  • 缺乏一种 quota goal metric 衡量 scheme 匹配的 eligible memory 在各 NUMA 节点间的分布比例
  • 异构内存 tiering 场景中无法让 DAMON 自动将热/冷内存按目标比例分布在不同 tier 上
  • 现有 PUSH+PULL 双 scheme 架构(migrate_hot/migrate_cold)缺乏基于当前分布状态的自动调节能力

如何做

新增 metric 类型 DAMOS_QUOTA_NODE_ELIGIBLE_MEM_BP(单位:basis points,0-10000)。核心计算函数 damos_get_node_eligible_mem_bp() 完成三级计算:遍历所有 target region,通过 __damos_valid_target() 过滤匹配该 scheme 访问模式的 region;对每个 eligible region 逐 folio 遍历物理地址范围,使用 folio_nid() 判定 NUMA 节点归属;大 folio 精确处理 region 边界与 folio 的部分重叠。每处理完一个 region 调用 cond_resched()

重构 quota auto-tuning 内部接口:damos_set_quota_goal_current_value() 等函数签名从接受 struct damos_quota * 改为 struct damon_ctx *, struct damos *,因为新 metric 需要访问 DAMON context 获取 addr_unit 和 scheme 的 access pattern filters。

安全机制:damon_commit_ctx() 中非 DAMON_OPS_PADDR 返回 -EINVAL;三重防御(非 PADDR 返回 0、无效 nid 返回 0、total_eligible==0 返回 0);#ifdef CONFIG_DAMON_PADDR 编译守卫。sysfs 新增 "node_eligible_mem_bp" 名称映射。

收益

作者在两节点 DRAM+CXL 异构内存系统上进行了功能验证。使用 TEMPORAL tuner 时系统快速收敛到目标分布——tuner 在未达标时驱动 esz 到最大值,达标后立即置零。CONSIST tuner 也能收敛但速度较慢。作者未提供量化收敛时间或吞吐量数据,[从代码逻辑推断,主要开销在 damos_calc_eligible_bytes() 中逐 folio 遍历,对于大内存系统可产生可观 CPU 开销,但 cond_resched() 缓解了调度延迟]。


5. DAMON 热分数计算优化与 DAMOS_COLLAPSE 操作

系列[PATCH v2 0/4] mm/damon: repost non-hotfix reviewed patches in damon/next tree作者: SeongJae Park版本: v2

5a. mm/damon/ops-common: optimize damon_hot_score() using ilog2()

背景damon_hot_score() 中 age_in_log 的计算原使用手动 for 循环逐次右移,效率低下。

解决的问题:手动 for 循环实现 log2 计算在 10,000,000 次迭代的模拟内核模块测试中平均延迟为 12ns。

如何做:用 ilog2(age_in_sec) + 1 替换整个 for 循环,min_t() 限制上限。ilog2() 在多数架构映射为 fls() 或硬件指令(如 x86 的 bsr),O(1) 复杂度。

收益

指标
for-loop
ilog2
平均延迟
12 ns
1 ns
P95 延迟
51 ns
41 ns
P99 延迟
60 ns
41 ns

5b. mm/damon: support MADV_COLLAPSE via DAMOS_COLLAPSE scheme action

背景DAMOS_HUGEPAGE 在 THP=never 时完全失效(khugepaged 不运行);khugepaged collapse 整个 VMA 而非仅 hot region;无法实现基于 DAMON 访问模式的确定性 THP collapse。

如何做:新增 DAMOS_COLLAPSE action,在 damon_va_apply_scheme() 中映射为 MADV_COLLAPSE,调用 madvise_collapse() 同步对指定地址范围执行 collapse,不依赖 khugepaged。

收益(MariaDB + sysbench,ARM 物理服务器,read only + gaussian row hitting):

配置
总内存
Huge Pages
TPS
DTLB miss%
ITLB miss%
THP=never, DAMOS_HUGEPAGE
2.13 GB
0
18225
0.059%
0.089%
THP=madvise, DAMOS_HUGEPAGE
2.20 GB
1.30 GB
18252
0.042%
0.090%
THP=never, DAMOS_COLLAPSE
2.20 GB
1.27 GB
18270
0.045%
0.085%

关键发现:DAMOS_COLLAPSE 在 THP=never 下仍能产生大量 huge page(1.27 GB),collapse 速度更快(5 秒 vs 45 秒分配 190 huge pages),且因只 collapse hot region 而内存消耗略低于 khugepaged 方案。


6. DAMON 引入数据属性监控

系列[RFC PATCH 00/19] mm/damon: introduce data attributes monitoring作者: SeongJae Park版本: RFC v1(19 个 patch)

背景

DAMON 自诞生以来始终只监控数据访问这一种属性。6.14 内核合入了基于 DAMOS filter 的 page-level properties monitoring,该功能允许对每个 DAMON region 的所有 folio 逐一应用 filter 判定页面属性(如 cgroup 归属),但开销与内存大小成正比,只能用于测试/调试。用户需要始终在线(always-on)、开销可控的多维度数据属性监控能力。

解决的问题

  • 基于 DAMOS filter 的 page-level monitoring 开销过高(O(内存大小)),无法生产环境始终启用
  • DAMON 的采样机制天然提供有界低开销,但过去仅用于 access check,未复用于其他数据属性
  • 缺乏统一框架扩展 DAMON 监控除访问之外的数据属性

如何做

引入"data attributes monitoring"概念,核心思想是复用 DAMON 现有采样机制和 region 结构,在每次 access check 采样时同时应用用户注册的 data probe

数据结构:struct damon_probe 代表数据属性探测器,链接到 damon_ctx->probes,包含一组 struct damon_filterstruct damon_region 中新增 unsigned char probe_hits[DAMON_MAX_PROBES] 数组(每个 region 仅 4 字节)。struct damon_operations 新增 .apply_probes() 回调。

执行流程:check_accesses() 后调用 ops->apply_probes();每次 aggregation 重置 probe_hits;用户通过 sysfs(probes/ 目录树)配置和读取。983 行新增代码实现完整 sysfs 分层目录结构。

收益

作者未提供性能数据(RFC 阶段),[从代码逻辑推断:复用 access check 采样时机,无额外地址空间遍历;probe_hits 使用 unsigned char 数组每 region 增加 4 字节;采样粒度与 access check 一致,额外开销与 sampling interval 成反比,最大程度上保持了 DAMON 的有界低开销承诺]。


7. 优化 RWF_DONTCACHE 写入性能

系列[PATCH v3 0/4] mm: improve write performance with RWF_DONTCACHE作者: Jeff Layton版本: v3(4 个 patch)

背景

RWF_DONTCACHE 标志允许应用告诉内核"这份数据不需要缓存"。当前主线实现中,generic_write_sync() 检测到 IOCB_DONTCACHE 时调用 filemap_flush_range() 在写入者上下文中内联提交 writeback。这导致 p99.9 延迟从 buffered 的 23ms 膨胀到 93ms。此外内联 writeback 不区分 dontcache 脏页和普通 buffered 脏页,可能刷出大量不相关的缓冲数据。

解决的问题

  • 当前 filemap_flush_range() 在写入者热路径中内联执行,阻塞写入者并推高尾延迟
  • 内联 writeback 不区分 dontcache 脏页和普通脏页,损害 buffered I/O 性能
  • 缺乏针对 dontcache 脏页的精确跟踪手段

如何做

采用 Jan Kara 和 Christoph Hellwig 建议的方案:不再内联执行 writeback,而是 kick flusher 线程执行与写入量成比例的回写。

第一层:添加 NR_DONTCACHE_DIRTY 节点页面计数器,在 folio_account_dirtied() 中与 NR_FILE_DIRTY 同时递增(folio 设置了 dropbehind 标志时),通过 /proc/vmstat 暴露为 nr_dontcache_dirty

第二层:新增 WB_start_dontcache 标志位和 wb_check_start_dontcache() 处理函数,替换 filemap_flush_range() 调用。新函数 filemap_dontcache_kick_writeback() 定位正确的 cgroup writeback 域,设置标志并唤醒 flusher。Flusher 读取 NR_DONTCACHE_DIRTY 计数确定回写页数,使用 wb_split_bdi_pages() 按比例分配。新增 WB_REASON_DONTCACHE

收益

测试环境:双路 Xeon Gold 6138(80 CPU、256 GB RAM、Samsung NVMe、本地 XFS)。

场景
指标
baseline
patched
变化
本地单客户端顺序写
dontcache 吞吐
1347.9 MB/s
1461.5 MB/s
+8.4%
本地单客户端顺序写
dontcache p99.9
85459 us
23199 us
-72.9%
本地多写者聚合
dontcache 吞吐
1281.1 MB/s
1629.4 MB/s
+27.2%
NFS 单客户端顺序写
dontcache 吞吐
3028.3 MB/s
3723.1 MB/s
+22.9%
NFS 单客户端顺序写
dontcache p99.9
759169 us
175112 us
-76.9%
NFS 多写者聚合
dontcache 吞吐
1894.9 MB/s
9442.6 MB/s
+398.3%

NFS 多写者 dontcache 吞吐提升近 5 倍,几乎追平 buffered I/O。脏页足迹在顺序负载下下降 85-95%。


8. virtio 跳过主机已清零页面的冗余清零

系列[PATCH RFC v4 00/22] mm/virtio: skip redundant zeroing of host-zeroed reported pages作者: Michael S. Tsirkin版本: RFC v4(22 个 patch)

背景

当虚拟机通过 virtio-balloon 的 free page reporting 向 hypervisor 报告空闲页面时,host 通常将其清零(如通过 MADV_DONTNEED)。Guest 重新分配时内核再次清零造成冗余。更严重的是,在具有别名缓存(aliasing caches)的架构上启用 init_on_alloc 时存在双重清零:post_alloc_hook 中 kernel_init_pages() 清零一次 + clear_user_highpage() 再次清零。

解决的问题

  • Virtio-balloon 报告并回收的页面在 host 侧被清零后,guest 重新分配时内核再次清零
  • 别名缓存架构上 init_on_alloc 启用时存在双重清零(kernel_init_pages() + clear_user_highpage()
  • 清零操作消耗 CPU 时间、污染缓存,在高频分配场景下成为显著开销

如何做

横跨 mm 核心、page reporting 和 virtio 子系统的大型系列(22 patch)。

Cache-friendly zeroing 基础设施(Patch 1-6):将 vma_alloc_folio() 移到 page_alloc.c,新增 vma_alloc_folio_user_addr() 传递精确 fault 地址。post_alloc_hook() 中使用 folio_zero_user() 替代 kernel_init_pages(),按从远到近(相对 fault 地址)的顺序清零。

消除双重清零(Patch 7-12):使用 __GFP_ZERO 统一清零,移除 clear_user_highpage() 第二次清零以及 x86/s390/m68k/alpha 上的 arch vma_alloc_zeroed_movable_folio 覆盖。

PG_zeroed 标志位跟踪(Patch 13-17):PG_zeroed(别名到 PG_private,仅在空闲列表页面有效)标记已知为零的 buddy 页面。设置路径:page_reporting_drain + buddy 合并传播到合并后页面 + expand 传播到子页面。清除路径:buddy 合并前清除 + post_alloc_hook 消耗后清除 + __isolate_free_page() 清除。

收益

测试环境:2GB VM,1 vCPU,分配 256MB 匿名页面。

场景
指标
baseline
optimized
改善
THP 启用(256MB 匿名页)
task-clock
175 +/- 10 ms
40 +/- 9 ms
-77%
THP 启用(256MB 匿名页)
cache-misses
924K +/- 323K
287K +/- 93K
-69%
Hugetlb surplus pages
task-clock
169 +/- 9 ms
49 +/- 19 ms
-71%
Hugetlb surplus pages
cache-misses
1.24M +/- 222K
316K +/- 114K
-75%

优化在 THP 启用时效果最佳(整个 2MB 页面直接从报告的 order-9+ buddy 页面分配)。不使用 THP 时仅约 21% 的 order-0 分配来自报告页面。


9. LRU 批量添加时预释放已死亡 folio

系列[PATCH v2] mm/lruvec: preemptively free dead folios during lru_add drain作者: JP Kobryn版本: v2(1 个 patch)

背景

Meta 在生产环境(Instagram 工作负载)中观测到 lruvec 锁竞争中约 24% 发生在 lru_add batch drain 时存在已死亡(dead)folio。Dead folio 是指引用计数仅剩下 batch 持有的那一份引用(refcount == 1),即将被释放的 folio。这些 folio 被加入 LRU 后立即被 folios_put_refs() 移除,导致两次不必要的锁获取。

解决的问题

  • Lruvec 锁竞争中 ~24% 源于 dead folio 的 LRU 加入-立即移除操作
  • 每个 dead folio 经历两次不必要的 LRU 锁获取
  • 间接导致 direct reclaim scanning、allocation stalls、compaction stalls 等系统级指标恶化

如何做

仅在 mm/swap.c 的 folio_batch_move_lru() 中修改约 40 行。当 move_fn == lru_add 时,使用 folio_ref_freeze(folio, 1) 检测 refcount 是否恰好为 1。对检测到的 dead folio:清除 PG_active 和 PG_unevictable 标志(可能由 migration 路径设置),folio_unqueue_deferred_split() 从 deferred split 列表移除,将 folio 加入临时 free_fbatch。遍历结束后 mem_cgroup_uncharge_folios() + free_unref_folios() 批量释放。

v2 改进:增加了 PG_active 和 PG_unevictable 标志的清除,处理通过 migration 路径加入 LRU 的 folio。

收益

Meta 生产环境 Instagram 工作负载 A/B 测试(每侧 60 台主机,3 次 60 秒采样,95% CPU 负载):

指标
未打补丁
打补丁后
变化
dead folios/分钟
1,297,785
14
-99.999%
dead folio 占比
6.7097%
0.0001%
-
节省的锁获取/分钟/主机
-
~2.6M
-
direct reclaim scanning
-
-
-7%
allocation stalls
-
-
-5.2%
compaction stalls
-
-
-12.3%
page frees
-
-
-4.9%

无性能退化,requests per second 和 p99 尾延迟均未观测到退化。


10. 修复 vmemmap 优化的计数与初始化

系列[PATCH v7 0/6] mm: Fix vmemmap optimization accounting and initialization作者: Muchun Song版本: v7(6 个 patch)

背景

vmemmap 优化(HugeTLB 和 DAX 的 compound page 复用 tail struct page 以减少元数据开销)自 v5.14 引入后持续演进。该优化在 DAX 内存热插拔(memory hotplug)和 ZONE_DEVICE 页面初始化路径中存在多个边界条件 bug,包括页面计数错误、altmap 传递错误、migratetype 未初始化以及 tail struct pages 未初始化,特定配置下可能导致内存损坏(machine check)或系统崩溃。

解决的问题

  • vmemmap 计数下溢(patch 1):section 激活失败回滚路径中 vmemmap 页面 count 多减
  • altmap 错误传递导致内存损坏(patch 2):create_memory_block_devices() 失败后的错误路径向 arch_remove_memory() 传入 NULL altmap,导致 vmemmap 页面被错误释放到 buddy allocator,后续分配使用触发 machine check
  • DAX 热插拔路径缺乏 vmemmap 优化信息传递(patch 3-4):memory deactivation 路径未传递 @pgmap 参数导致计数错误
  • ZONE_DEVICE compound page 的 pageblock migratetype 未完全初始化(patch 5):compound page 大小超过 pageblock_nr_pages 时后续 pageblock 的 migratetype 未初始化
  • ZONE_DEVICE tail struct pages 未初始化(patch 6):DAX 内存热插拔到早期 section 时 boot memmap 被视为优化过但实际未优化

如何做

采用"先建立正确信息传递,后基于信息做正确决策"的分层修复策略。

计数和 altmap 修复:patch 1 修复下溢;patch 2 将错误路径的 NULL 改为 params.altmap 确保正确归还。

pgmap 信息传递链:patch 3 将 @pgmap 参数沿 memory deactivation 路径传递(涉及 x86、arm64、loongarch、powerpc、riscv、s390 六个架构);patch 4 利用 pgmap 通过 vmemmap_can_optimize() 正确计算 DAX vmemmap 页面数量。

DIVICE 初始化修复(patch 5 最关键):从 __init_zone_device_page() 中分离 migratetype 初始化,新增 pageblock_migratetype_init_range() 函数,以 pageblock 粒度遍历整个 PFN 范围初始化 migratetype 为 MIGRATE_MOVABLE,在 section 边界插入 cond_resched()

patch 6 修改 compound_nr_pages() 签名新增 pfn 参数,通过 early_section() 检查判断是否复用早期 section,若是则回退到完整的 struct page 数量。

收益

作者未提供性能数据,[修复避免:内存损坏/machine check(patch 2)、buddy allocator 污染导致的不可预知分配行为、ZONE_DEVICE tail struct pages 未初始化导致的崩溃、pageblock migratetype 未初始化导致的内存迁移异常。所有修复带 Fixes: 和 Cc: stable 标签,表明是生产环境中可触发的真实 bug]。


11. 双位图伙伴分配器一致性检查器

系列[RFC 0/7] mm: dual-bitmap page allocator consistency checker作者: Sasha Levin版本: RFC v1(7 个 patch)

背景

现有内核内存调试工具(KASAN、KFENCE、page_poisoning)均检测非法内存访问或内容损坏,但无人检测 page allocator 自身元数据的静默损坏(silent corruption)。当硬件 bit flip 破坏了 buddy allocator 的分配位图时,可能分配已被占用的页面或无法分配空闲页面,而内核对此毫无察觉。面向 ISO 26262(汽车功能安全)等场景,需要可审计、可认证的内存分配完整性检测机制。

解决的问题

  • page allocator 元数据静默损坏检测:硬件 bit flip 破坏 buddy allocator 位图后系统无法感知
  • 现有调试工具(KASAN/KFENCE/page_poisoning)覆盖盲区:不检查 allocator 内部元数据完整性
  • page_ext 方案的局限性:元数据存储在被同一硬件故障影响的内存中,违反独立性原则
  • 功能安全认证需求:汽车、工业、航空、医疗领域需要可审计的内存分配完整性机制

如何做

核心数据结构:struct dual_bitmap 维护两个独立 memblock 分配的位图,主位图(PRIMARY)0=空闲/1=已分配,辅位图(SECONDARY)取反,不变量 primary == ~secondary

原子操作原语(include/linux/dual_bitmap.h,header-only):dual_bitmap_set() 两端 atomic test_and_set/clear 并返回旧值检测 double-alloc;dual_bitmap_clear() 检测 double-free;dual_bitmap_validate() 冷路径诊断函数带重试逻辑和 smp_rmb() 屏障应对并发更新。

初始化由 page_consistency_init()mm/mm_init.c 中调用)通过 memblock_alloc() 分配两个独立位图。通过 static key(page_consistency_enabled)控制,未启用时编译为近乎零开销的预测不跳转分支。热路径集成在 post_alloc_hook() 和 free_pages_prepare() 中。CONFIG_DEBUG_PAGE_CONSISTENCY_PANIC 控制检测到违规时 panic 还是 WARN。debugfs 接口提供统计和手动全量扫描。

收益

作者未提供性能数据,[内存开销:每物理页帧 2 bits,64 GB 系统约需 4 MB;性能开销:每次 alloc/free 增加两次原子 bitop,对安全关键部署可接受;正确性保证:任何单 bit 损坏被立即检测,设计简单到可审计和认证]。static key 控制使未启用时零开销。


12. 跳过 TLB flush 已发 IPI 后的冗余同步 IPI

系列[PATCH 7.2 v10 0/2] skip redundant sync IPIs when TLB flush sent them作者: Lance Yang版本: v10(2 个 patch)

背景

当页表操作需要与软件/无锁页表遍历器(如 GUP-fast)同步时,TLB flush 之后须调用 tlb_remove_table_sync_one() 或 tlb_remove_table_sync_rcu() 广播 IPI 或等待 RCU。然而在 x86 上,TLB flush 已通过 on_each_cpu_mask() 向所有目标 CPU 发送了 IPI,随后的 sync IPI 广播完全冗余。这在大型系统上尤为昂贵,64 核 x86 服务器折叠 20 GiB 内存时 CAL 中断从 646,316 降至 785(-99.88%)。

解决的问题

  • 冗余 IPI 广播:x86 native TLB flush 已发送 IPI,sync 路径再广播第二次
  • 实时工作负载受损:不必要的大范围 IPI 中断实时任务
  • 可扩展性:大型系统上冗余 sync IPI 开销随 CPU 数量线性增长

如何做

采用两阶段方案。Step 1(本系列)在 100% 确定 TLB flush 已发送 IPI 时跳过冗余 sync。

Patch 1(通用框架):引入 tlb_table_flush_implies_ipi_broadcast()(默认 false),在 tlb_remove_table_sync_one() 和 tlb_remove_table_sync_rcu() 开头插入早期返回检查。

Patch 2(x86 启用):native_pv_tlb_init() 启动时一次性决策,通过 DEFINE_STATIC_KEY_FALSE(tlb_ipi_broadcast_key) 实现零开销热路径。三个条件:使用 native TLB flush(非 PV backend)、不支持 INVLPGB 指令、通过 static key 固定决策。flush_tlb_info.freed_tables 重命名为 wake_lazy_cpus 更准确描述语义。

收益

指标
优化前
优化后
改善
CAL 中断(64 核 x86,折叠 20 GiB)
646,316
785
-99.88%

每次 tlb_remove_table_sync_one() 节省一次 smp_call_function() 对所有 CPU 的 IPI 广播;每次 tlb_remove_table_sync_rcu() 节省一次 synchronize_rcu() 宽限期等待。这在 hugetlb PMD unshare 和 khugepaged collapse 场景中频繁触发。


13. 动态内核栈

系列[PATCH v2 00/13] Dynamic Kernel Stacks作者: David Stevens, Pasha Tatashin版本: v2(13 个 patch)

背景

Linux 为每个线程静态分配固定大小内核栈(x86_64 上通常 16 KiB = 4 个页面)。在 Android 等拥有大量线程的系统上,常规设备系统进程通常有 2000-3000 个线程,4 GB 设备可能将 1-2% 总内存用于内核线程栈。动态内核栈按需增长,仅在栈深度不足时才分配新页面。

解决的问题

  • 内核栈内存浪费:静态 16 KiB 栈大量未用但已全部分配,数千线程浪费可达数十 MB
  • 栈溢出防御与内存开销的平衡:增大默认栈大小进一步加剧内存浪费
  • vmap 栈的栈深度不能自适应变化
  • 动态栈与现有机制(STACK_END_MAGIC、栈缓存、memcg 统计)的兼容性

如何做

栈初始仅分配 THREAD_PREALLOC_PAGES(默认 1 页 = 4 KiB),剩余 THREAD_DYNAMIC_PAGES(默认 3 页)初始未映射形成"栈洞"。当栈使用超出已映射区域时触发 page fault,处理函数从 per-CPU 页面池分配新页建立映射。

关键数据结构:task_struct.stack 替换为 packed_stack,指针低位编码已记账页面数;per-CPU 页面池 dynamic_stack_pages[DYNSTK_PAGE_POOL_NR]

Page fault 处理:检查 fault 地址落在内核栈区域后,从 hole_end 向下逐页分配映射,设置 PF_DYNAMIC_STACK 标记。调度路径集成:dynamic_stack() 在 __schedule() 前补充 per-CPU 池(GFP_ATOMIC)并完成 memcg 记账。

x86 FRED 支持:FRED 可用时内核页错误在栈级别 1 处理;FRED 不可用时使用专用 IST 栈(新增 PF/PF2/UDI 三个 IST 栈)处理页错误,非动态栈故障弹回常规栈。外部中断无条件弹回原始栈避免中断丢失。

收益

平台
CPU
线程数
静态栈 (KiB)
动态栈 (KiB)
节省
AMD Genoa
384
5,786
92,576
23,388
~75%
Intel Skylake
112
3,182
50,912
12,860
~75%
AMD Rome
128
3,401
54,416
14,784
~73%
AMD Rome
256
4,908
78,528
20,876
~73%
Intel Haswell
72
2,644
42,304
10,624
~75%

所有测试机器仅消耗原始栈内存约 25%,节省 65-70%。仅约 5% 活动任务在其生命周期中触发栈页错误。


14. 修复设备迁移中 PMD 自旋锁泄漏

系列[PATCH] mm/migrate_device: fix spinlock leak in migrate_vma_insert_huge_pmd_page作者: Sunny Patel版本: v1(1 个 patch)

背景

migrate_vma_insert_huge_pmd_page() 在设备迁移过程中插入 huge PMD 页面映射,需持有 PMD spinlock(通过 pmd_lock() 获取)确保 PMD 修改的原子性。

解决的问题

  • pmd_lock() 获取 PMD spinlock 后 check_stable_address_space() 可能返回非零(地址空间不稳定),代码跳转到 abort 标签而非 unlock_abort,直接跳过 spin_unlock(ptl) 调用
  • PMD spinlock 被永久持有,后续尝试获取同一 spinlock 的操作死锁,导致进程 hang 直至 NMI watchdog 触发

如何做

将 check_stable_address_space() 失败后的跳转目标从 abort 改为 unlock_abort(先释放 spinlock 再进入 abort 清理)。修复恢复正确的 lock/unlock 配对,确保任何错误路径 spinlock 都能释放。

收益

作者未提供性能数据,[消除确定死锁场景——并发内存热插拔或 memory failure 与 device migration 同时发生时,修复后系统优雅 abort 迁移操作而非死锁]。


15. 修复设备迁移中页表泄漏

系列[PATCH] mm/migrate_device: fix pgtable leak in migrate_vma_insert_huge_pmd_page作者: Sunny Patel版本: v1(1 个 patch)

背景

与 Feature 14 同一函数。migrate_vma_insert_huge_pmd_page() 通过 pte_alloc_one() 分配 pgtable 页用于 deposit 到 PMD 级别页表。在多个异常路径上 pgtable 未得到释放。

解决的问题

  • unlock_abort 标签可从多条路径到达:check_stable_address_space() 失败后、userfaultfd_missing() 返回 true、PMD 检查失败
  • 在这些路径上,pte_alloc_one() 分配的 pgtable 直接泄漏(通常 4KB,64KB 页架构为 64KB)
  • GPU 计算等重度 device migration 场景下泄漏累积消耗系统内存

如何做

在 unlock_abort 标签处(spin_unlock(ptl) 之后)增加 pte_free(vma->vm_mm, pgtable) 调用。正常成功路径中 pgtable 或被 pte_free() 释放(flush 路径)或被 pgtable_trans_huge_deposit() 存入 PMD,unlock_abort 作为统一异常出口补充释放逻辑。

收益

作者未提供性能数据,[消除确定内存泄漏——每次触发 unlock_abort 路径泄漏一个页帧,GPU 计算等重度场景累积影响显著]。


16. KASAN HW-tags 禁用栈与页表的标签

系列[PATCH v3 0/3] kasan: hw_tags: Disable tagging for stack and page-tables作者: Dev Jain版本: v3(3 个 patch)

背景

Hardware Tag-Based KASAN 利用硬件内存标签机制(如 ARM MTE)检测越界访问和 use-after-free。内核栈和页表始终通过 match-all tag(0xFFKASAN_TAG_KERNEL)的指针访问,给这些内存打随机标签完全是无效开销。

解决的问题

  • 内核栈的无效标签开销:每个线程创建/销毁时对 16KB 栈中每个 16 字节颗粒设置/清除标签
  • vmap 栈缓存的无效 poison 开销:fork() 复用缓存栈时 kasan_unpoison_range() 在 HW-tags 模式下无意义
  • 页表的无效标签开销:每个 PTE/PMD/PUD/PGD 页面设置随机标签,频繁分配/释放场景下累积开销可观

如何做

Patch 1(vmalloc 层):在 __vmalloc_node_range_noprof() 中如果 __GFP_SKIP_KASAN 置位且 prot 为 PAGE_KERNEL,跳过标签启用和 kasan_unpoison_vmalloc()

Patch 2(内核线程栈):THREADINFO_GFP 和 GFP_VMAP_STACK 添加 __GFP_SKIP_KASAN;复用缓存 vmap 栈时 kasan_hw_tags_enabled() 守卫跳过 kasan_unpoison_range()

Patch 3(页表页):GFP_PGTABLE_KERNEL 添加 __GFP_SKIP_KASANGFP_PGTABLE_USER 自动继承。__GFP_SKIP_KASAN 在非 HW-tags 模式下为 0,软件 KASAN 不受影响。

收益

场景
优化前
优化后
提升
2000 iterations, 2000 threads
2.575 s
2.229 s
~13.4%
2048 MB pgtable, 2000 iterations
19.08 s
17.62 s
~7.6%

每次 4KB 页面分配和释放原本需执行约 256 条标签设置指令,移除后直接减少指令数和 cache miss。


17. userfaultfd 检测 copy 重试后 VMA 类型变更

系列[PATCH v7] mm/userfaultfd: detect VMA type change after copy retry in mfill_copy_folio_retry()作者: David Carlier版本: v7(1 个 patch)

背景

mfill_copy_folio_retry() 由 __mfill_atomic_pte() 调用:当在 mmap_lock 下执行 copy_from_user() 失败时需要 drop lock、不持锁重试、再重新获取 VMA 引用。然而在此期间 VMA 可能被其他进程/线程替换为完全不同类型(如被 hugetlb VMA 替换),而调用者仍持有旧的 ops 指针。

解决的问题

  • Drop mmap_lock 后 VMA 可能被并发替换为不同类型
  • 调用者 __mfill_atomic_pte() 仍持有 stale ops 指针(如 anon_uffd_ops
  • 在错误类型 VMA 上调用错误 ops 函数指针导致 kernel crash 或数据损坏
  • mfill_atomic_pte_copy() 对 MAP_PRIVATE 文件映射 VMA 将 ops 覆盖为 anon_uffd_ops,使得简单 ops 比较不足以检测变化

如何做

在 drop lock 前捕获 vma_uffd_ops(state->vma) 为 orig_ops,重新获取 VMA 后比较 vma_uffd_ops(state->vma) != orig_ops。若 VMA 类型确实变化则返回 -EAGAIN让上层重试。使用 vma_uffd_ops() 而非 caller's ops 进行比较,对于 MAP_PRIVATE 文件映射 VMA 被替换为 anonymous VMA 时不触发虚假 -EAGAIN。

收益

作者未提供性能数据,[消除 TOCTOU 竞态条件:修复后检测到 VMA 类型变化返回 -EAGAIN 重试,避免 stale ops 导致的 crash。-EAGAIN 额外开销仅在 VMA 被并发替换的极端情况下发生]。测试覆盖:uffd-unit-tests 67 项全部通过,uffd-stress anon/shmem/shmem-private 各 4 次 bounce 均通过。


18. MGLRU 改进回收循环与脏页处理

系列[PATCH v6 00/14] mm/mglru: improve reclaim loop and dirty folio handling作者: Kairui Song版本: v6(14 个 patch)

背景

MGLRU(Multi-Gen LRU)回收循环中 aging、扫描数量计算和回收循环三者紧密耦合,dirty folio 处理逻辑与常规路径差异较大,代码难以理解和维护。生产环境中观察到 MongoDB 等混合读写负载下性能不佳,文件 refault 率偏高,特定压力场景下出现意外 OOM kill。

解决的问题

  • 回收循环中 get_nr_to_scan() 每次迭代重新计算扫描数量,逻辑不清
  • dirty/writeback folio 冲刷逻辑在回收循环之外,无法及时触发,导致大量文件页 refault
  • 特定条件下 aging 被跳过导致 OOM(即使存在可回收文件页)
  • dirty throttle 相关计数器与 aging 未正确联动
  • 代码冗余,evictable_size 在两处重复实现

如何做

从整体上重构 MGLRU 回收循环。核心思路:引入 scan budget 机制——循环开始时一次性计算需扫描的 folio 数量(nr_to_scan = lruvec_evictable_size() >> sc->priority),后续每次迭代从中扣除直至预算耗尽或无法继续回收。

具体变更:提取 lruvec_evictable_size() 统一计算可回收 folio 总量;重构 get_nr_to_scan() 与 aging 解耦;should_run_aging() 纯粹判断是否需要 aging,在 DEF_PRIORITY 温和回收中尽量避免 aging 但当只有 3 代 folio 时主动触发;batch 分割提升到调用者层面;scan_folios 返回精确扫描数量,try_to_inc_min_seq 改为 void;dirty/writeback folio 的重新激活逻辑使用公共函数 folio_check_dirty_writeback() 统一处理,writeback 冲刷移入回收循环内部。

收益

负载
指标
改进前
改进后
变化
MongoDB YCSB (no swap)
吞吐量 (ops/sec)
62,485
79,761
+27.6%
MongoDB YCSB (no swap)
平均延迟 (us)
501.0
391.3
-21.9%
MongoDB YCSB (no swap)
pgpgin
159M
111M
-30.3%
MongoDB YCSB (no swap)
file refault
34.5M
19.6M
-43.3%
Chrome & Node.js
总请求数
79,915
81,382
+1.8%
Build kernel (ZRAM swap)
系统时间 (s)
2,589.6
2,543.6
-1.8%
Android 冷启动
P95 延迟 (ms)
1,399
1,228
-12.2%

两个 OOM 问题被修复。


19. 内存故障不可恢复时添加 panic 选项

系列[PATCH v5 0/4] mm/memory-failure: add panic option for unrecoverable pages作者: Breno Leitao版本: v5(4 个 patch)

背景

在大规模服务器集群中,multi-bit ECC 错误命中内核 slab 页是常见问题。memory_failure() 遇到无法恢复的内核页时当前仅记录"Ignored"并继续运行,意味着已损坏数据仍可被内核访问,导致静默数据损坏或在无关代码路径上延迟崩溃。生产实例:arm64 服务器上 multi-bit ECC 命中 dentry cache slab 页 67 秒后 d_lookup() 访问已中毒缓存行触发 synchronous external abort。

解决的问题

  • 不可恢复的内核内存故障(reserved pages、高阶内核分配尾页、未知状态页)被静默忽略
  • 缺少让管理员选择在故障发生当下获取干净 crash dump 的机制
  • reserved pages 被错误分类为 MF_MSG_GET_HWPOISON 而非 MF_MSG_KERNEL

如何做

Patch 1:修复 PageReserved(p) 分类为 MF_MSG_KERNEL 替代 MF_MSG_GET_HWPOISON

Patch 2:核心 patch。新增 sysctl vm.panic_on_unrecoverable_memory_failure(默认 0),对三类 result == MF_IGNORED 情况触发 panic。MF_MSG_KERNEL_HIGH_ORDER 处理 TOCTOU 竞态:先 cpu_relax() 再重新检查 page_count/mapping/LRU/free buddy,真正确认是内核尾页。

Patch 3:sysctl 文档。Patch 4:selftest 验证用户空间页 SIGBUS 恢复路径不受影响。

收益

作者未提供性能数据,[启用后不可恢复故障第一时间触发 panic,生成包含完整调用栈和硬件错误信息的 crash dump,根因分析从"在无关代码路径崩溃"变为"在故障发生点崩溃",大幅缩短故障定位时间]。


20. NOMMU 下正确处理 FOLL_PIN 引用计数

系列[PATCH v2] mm/gup: honour FOLL_PIN in NOMMU __get_user_pages_locked()作者: Greg Kroah-Hartman版本: v2(1 个 patch)

背景

!CONFIG_MMU 配置下,__get_user_pages_locked() 对每个获取的 page 调用 get_page()(refcount +1),无视 FOLL_PIN。但 pin_user_pages*() 设置 FOLL_PIN,对应的 unpin_user_page() 无条件调用 gup_put_folio(..., FOLL_PIN)——该函数减去 GUP_PIN_COUNTING_BIAS(1024)而非 1。导致 pin +1 、unpin -1024 的严重非对称。

解决的问题

  • NOMMU 系统 pin_user_pages*() / unpin_user_page() 的 refcount 不对称导致 use-after-free
  • 具体场景:映射页 refcount=1 → io_uring 固定缓冲区注册 1023 次 → refcount=1024 → 第一次 unpin subtract 1024 → refcount=0 → 页面被释放 → 剩余 1022 次 unpin 写入已释放内存 → 陈旧映射仍可访问已释放页面

如何做

用 try_grab_folio(page_folio(pages[i]), 1, foll_flags) 替代裸 get_page(pages[i])try_grab_folio() 在 FOLL_PIN 时添加 GUP_PIN_COUNTING_BIAS(1024),FOLL_GET 时添加 1,与 MMU 路径完全对称。v2 改进错误处理:保存 try_grab_folio() 返回值作为错误码传播给调用者。

收益

作者未提供性能数据,[消除 NOMMU 系统严重安全漏洞(use-after-free leading to memory corruption),使 pin_user_pages*/unpin_user_page 在 NOMMU 与 MMU 路径行为一致。由 Anthropic 报告]。


21. KHO 支持延迟 struct page 初始化

系列[PATCH v9 0/3] kho: add support for deferred struct page init作者: Michal Clapinski, Evangelos Petrongonas版本: v9(3 个 patch)

背景

CONFIG_DEFERRED_STRUCT_PAGE_INIT 在内核启动时将 struct page 元数据初始化推迟到后期由并行 kthread 完成以加速早期启动。KHO (Kexec HandOver) 的 Kconfig 声明 depends on !DEFERRED_STRUCT_PAGE_INIT,两者互斥,大内存服务器无法同时享受两者的好处。

解决的问题

  • preserved 区域 struct page 未初始化导致 page fault:KHO 反序列化时目标 struct page 尚未初始化
  • scratch 区域 migratetype 被延迟初始化覆盖:KHO scratch 需设为 MIGRATE_CMA 但被 deferred_init_pages() 用 MIGRATE_MOVABLE 覆盖
  • Kconfig 限制:!DEFERRED_STRUCT_PAGE_INIT 阻止大内存系统同时使用 KHO 和延迟初始化

如何做

Patch 1:新增 kho_get_preserved_page() 函数——遍历 preserved 区域所有页框,对每个调用 init_deferred_page()(已初始化时 no-op)。移除 Kconfig 互斥限制。

Patch 2:将 KHO scratch migratetype 设置集成到现有 page init 路径。新增 memblock_is_kho_scratch_memory()(二分查找 memblock.memory)和 inline 辅助函数 kho_scratch_migratetype(pfn, mt)(属于 scratch 区域返回 MIGRATE_CMA)。在 __init_page_from_nid()memmap_init()deferred_free_pages() 和 deferred_init_memmap_chunk() 中使用该函数。删除独立的 kho_release_scratch() 和 memmap_init_kho_scratch_pages()

Patch 3:CI 配置启用相关 config。

收益

作者未提供性能数据,[消除 KHO 与 DEFERRED_STRUCT_PAGE_INIT 互斥限制,大内存服务器可获得快速启动和在线更新双重能力;kho_scratch_migratetype() 在 !CONFIG_MEMBLOCK_KHO_SCRATCH 时编译为空操作零开销;从根本上防止覆盖问题]。


22. 修复 DAMON sysfs 路径 use-after-free

系列[PATCH 0/2] mm/damon/sysfs-schemes: fix use-after-free for [memcg_]path作者: SeongJae Park版本: v1(2 个 patch)

背景

mm/damon/sysfs-schemes.c 中 damon_sysfs_scheme_filter->memcg_path 和 damos_sysfs_quota_goal->path 是两个动态分配的字符串缓冲区,通过 sysfs 属性文件读写。_store() 回调 kfree 旧缓冲区后赋新值,_show() 读取指针输出字符串。DAMON 内部使用全局 damon_sysfs_lock 保护 sysfs 目录项并发访问,但用户态直接通过 read()/write() 访问这两个属性文件时未持有该锁。

解决的问题

  • memcg_path 的 use-after-free:并发 write(kfree 旧值 + 赋新值)与 read(访问已释放内存)之间的竞态
  • path (quota goal) 的 use-after-free:完全相同的竞态条件
  • 同一 FD 的并发读写有 kernfs 内部锁保护,但不同 FD(多次 open)之间的并发是常见场景

如何做

使用 mutex_trylock(&damon_sysfs_lock) 而非 mutex_lock():避免在 damon_sysfs_lock 已被持有的上下文中被 sysfs 读/写路径调用时导致死锁。_store() 先分配拷贝新字符串(锁外操作),再尝试获取锁——失败返回 -EBUSY 保持旧值不变;成功则 kfree 旧值赋新值。_show() 同理。

收益

作者未提供性能数据,[非竞争场景 mutex_trylock() 几乎总是立即成功仅一次原子操作;竞争场景竞争方收到 -EBUSY 而非 page fault,正确性得到保证。两个 patch 带有 Fixes: 标签和 Cc: stable]。


23. 避免内存碎片化下回收-驱逐循环

系列[PATCH v2 0/5] mm, drm/ttm, drm/xe: Avoid reclaim/eviction loops under fragmentation作者: Matthew Brost版本: v2(5 个 patch)

背景

当系统内存碎片化严重时 Intel Xe GPU 驱动的 TTM 内存管理器陷入病态回收循环:kswapd → shrinker → eviction → rebind(exec ioctl)→ 重复。空闲内存充裕(~2.8GB)但因没有 order-9 连续块,kswapd 持续运行、CPU 占用高、GPU 前向推进严重受损。复现:iGPU + mem=8G + 10 个 Chrome 标签 WebGL aquarium demo,每标签帧率降至 ~2 FPS。

解决的问题

  • 内存碎片下回收-驱逐循环:高 order 分配失败 → kswapd 回收 → 驱逐活跃 BO → rebind 触发新分配 → 再次失败
  • kswapd 无意义回收:空闲内存充裕但碎片化时回收无法产生高 order 连续页
  • GPU 性能严重退化:每个标签从正常帧率降至 ~2 FPS

如何做

核心 MM 层:zone_appears_fragmented() 轻量级内联启发式——当 zone 空闲页面数超过 high watermark 两倍时判定为碎片化。

TTM 层:对超过 bo->beneficial_order 的分配使用 __GFP_NORETRY 快速返回避免深度回收。新增 ttm_bo_shrink_kswap_fragmented() 辅助函数供驱动 shrinker 调用。

Xe 驱动层:beneficial_order = 9xe_shrinker_scan() 中 kswapd 上下文 + 碎片化判定成立时尽早返回 SHRINK_STOP

收益

指标
修复前
修复后
每标签帧率 (Ubuntu 24.04)
~2 FPS
~10 FPS
每标签帧率 (Ubuntu 24.10)
~2 FPS
~15 FPS
kswapd 活动
持续高频
恢复正常
Normal zone order-9 块数
0
13

该系列体现跨子系统协作模式:核心 MM 提供轻量探测接口,TTM 提供分配策略抽象层,驱动层实现最终决策逻辑。


24. 内存 cgroup 限制支持内存层级感知

系列[RFC PATCH 0/9 v2] mm/memcontrol: Make memory cgroup limits tier-aware作者: Joshua Hahn版本: RFC v2(9 个 patch)

背景

在 tiered memory 系统(DRAM + CXL)中,不同类型内存效用不均质。当前 memcg 的 memory.{min, low, high, max} 限制只看内存占用量不区分 tier。占用 10G DRAM 的 cgroup 和占用 10G CXL 的 cgroup 在 memcg 看来"消耗相同",但实际上前者抢占的稀缺资源远多于后者。在多租户场景下先启动的 workload 可独占 DRAM,违反内存隔离初衷。

解决的问题

  • tiered memory 系统上 memcg 无法公平分配 toptier(DRAM)这一稀缺资源
  • 现有隔离机制仅基于内存占用总量,无法反映不同 tier 内存的真实消耗差异
  • 缺乏系统级公平性机制保证 cgroup 按 toptier:total 容量比例获取 toptier 内存

如何做

五层架构:

第一层:cgroup2 mount option memory_tiered_limitsCGRP_ROOT_MEMORY_TIERED_LIMITS)。

第二层:mm/memory-tiers.c 中 toptier_capacity 变量在 establish_demotion_targets() 重建降级目标时更新。提供 mt_scale_by_toptier(val) 缩放函数(mult_frac(val, toptier_capacity, totalram_pages()))。

第三层:struct mem_cgroup 新增独立 struct page_counter toptier,启用 per-CPU stock。try_charge_memcg() 中 folio 节点 node_is_toptier() 时同时向 toptier 记账;uncharge 和 migrate 路径相应处理。

第四层:设置 memcg 限制时,当 mem_cgroup_tiered_limits() 返回 true,将用户 limit 值经 mt_scale_by_toptier() 缩放后写入 toptier page_counter。

第五层:toptier 节点定向回收——当 toptier 用量超限时在 toptier 节点上发起回收将冷内存降级到 lowtier。导出 4 个只读 sysfs 文件 memory.toptier_{min, low, high, max}

收益

测试环境:1TB 主机(750G DRAM + 250G CXL),4 个 220G workload(3 个 hog + 1 个 victim)。

模式
指标
baseline
tier-aware
变化
随机访问 (NUMAB=2)
Victim 吞吐
12.315 Mops/s
16.950 Mops/s
+37.6%
随机访问 (NUMAB=2)
Hog 吞吐
21-23 Mops/s
16-18 Mops/s
均衡化
随机访问 (NUMAB=2)
Victim DRAM
69.3G
181-187G
均分
Hot/cold (90/10)
Victim 吞吐
11.624 Mops/s
15.998 Mops/s
+37.6%

DRAM 分布从"hog 独占全部 220G"变为"所有 cgroup 均分 181-187G DRAM",CXL 使用也相应均衡。


总结

新机制 / 新接口

#
系列
要点
2
Generic Pagewalk API
 [RFC v2, 7p]
全新 pt_range_walk API 替代旧 mm_walk_ops,统一 HugeTLB/THP 处理,已转换 smaps/numa_maps/pagemap
4
DAMON node_eligible_mem_bp
 [v9, 1p]
新 quota goal metric 支持按 NUMA 节点分布比例目标自动调节异构内存 tiering
5b
DAMOS_COLLAPSE action
 [v2]
新 DAMOS action 支持同步 MADV_COLLAPSE,不依赖 khugepaged,THP=never 下也可工作
6
DAMON data attributes monitoring
 [RFC, 19p]
复用采样机制实现始终在线、开销可控的多维度数据属性监控框架
11
Dual-bitmap allocator checker
 [RFC, 7p]
维护 primary==~secondary 不变量检测 buddy allocator 元数据静默损坏,面向 ISO 26262
13
Dynamic Kernel Stacks
 [v2, 13p]
按需动态增长内核栈,初始仅 4KB,节省 65-70% 栈内存
19
panic_on_unrecoverable_memory_failure
 [v5, 4p]
新 sysctl 允许不可恢复内存故障立即 panic 获取完整 crash dump
24
Tier-aware memcg limits
 [RFC v2, 9p]
cgroup2 tier-aware 内存限制,toptier:total 比例缩放,DRAM 公平分配

性能优化

#
系列
量化数据
1
VMA locks for smaps/numa_maps
 [v2, 3p]
免除 mmap_lock 持有,预期大幅降低大地址空间下的锁竞争
5a
DAMON ilog2 optimization
 [v2]
damon_hot_score()
 平均延迟 12ns→1ns,P99 60ns→41ns
7
RWF_DONTCACHE writeback
 [v3, 4p]
NFS 多写者 +398%,p99.9 -76.9%;本地单客户端 p99.9 -72.9%
8
Virtio skip redundant zeroing
 [RFC v4, 22p]
THP 分配 task-clock -77%,cache-misses -69%
9
Free dead folios in lru_add drain
 [v2, 1p]
Dead folios -99.999%,节省 ~2.6M 锁获取/分钟/主机,compaction stalls -12.3%
12
Skip redundant sync IPIs
 [v10, 2p]
CAL 中断 646,316→785(-99.88%)
16
KASAN skip stack/pgtable tagging
 [v3, 3p]
线程创建 +13.4%,页表操作 +7.6%
18
MGLRU reclaim loop optimization
 [v6, 14p]
MongoDB YCSB +27.6%,file refault -43.3%,Android P95 -12.2%
21
KHO deferred page init
 [v9, 3p]
消除 KHO 与 DEFERRED_STRUCT_PAGE_INIT 互斥限制
23
Avoid TTM reclaim/eviction loops
 [v2, 5p]
GPU 帧率 ~2→10-15 FPS,Normal zone order-9 块 0→13

Bug Fix

#
系列
影响
3
Hugetlb resv_map leak
 [RFC, 1p]
Syzkaller 发现,__mmap_region 错误路径 resv_map 泄漏(512B),引入 abort_hook 框架
10
Vmemmap optimization fixes
 [v7, 6p]
修复 altmap 错误传递→machine check、migratetype/struct page 未初始化、count 下溢等 5 个 bug,Fixes: + Cc: stable
14
migrate_device spinlock leak
 [v1, 1p]
check_stable_address_space 失败后 PMD spinlock 未释放→死锁
15
migrate_device pgtable leak
 [v1, 1p]
异常路径 pgtable 未 pte_free→内存泄漏
17
Userfaultfd VMA type change
 [v7, 1p]
Drop mmap_lock 后 VMA 类型变更导致 stale ops→crash,Fixes: 6ab703034f14
20
NOMMU FOLL_PIN refcount skew
 [v2, 1p]
Pin +1 vs unpin -1024 非对称→UAF,Anthropic 报告
22
DAMON sysfs use-after-free
 [v1, 2p]
memcg_path/path 读写竞态→UAF,Fixes: + Cc: stable

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-07-03 15:21:06 HTTP/2.0 GET : https://f.mffb.com.cn/a/489588.html
  2. 运行时间 : 0.108244s [ 吞吐率:9.24req/s ] 内存消耗:4,879.95kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=a6f94e8021479bd838ebe23f5bbd6ec6
  1. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/composer/autoload_static.php ( 4.90 KB )
  7. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  10. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  11. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  12. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  13. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  14. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  15. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  16. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  17. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  18. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  19. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  21. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  22. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/provider.php ( 0.19 KB )
  23. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  24. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  25. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  26. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/common.php ( 0.03 KB )
  27. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  28. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  29. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/app.php ( 0.95 KB )
  30. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cache.php ( 0.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/console.php ( 0.23 KB )
  32. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/cookie.php ( 0.56 KB )
  33. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/database.php ( 2.48 KB )
  34. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  35. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/filesystem.php ( 0.61 KB )
  36. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/lang.php ( 0.91 KB )
  37. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/log.php ( 1.35 KB )
  38. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/middleware.php ( 0.19 KB )
  39. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/route.php ( 1.89 KB )
  40. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/session.php ( 0.57 KB )
  41. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/trace.php ( 0.34 KB )
  42. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/config/view.php ( 0.82 KB )
  43. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/event.php ( 0.25 KB )
  44. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  45. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/service.php ( 0.13 KB )
  46. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/AppService.php ( 0.26 KB )
  47. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  48. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  49. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  50. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  51. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  52. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/services.php ( 0.14 KB )
  53. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  54. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  55. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  56. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  57. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  58. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  59. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  60. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  61. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  62. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  63. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  64. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  65. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  66. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  67. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  68. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  69. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  70. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  71. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  72. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  73. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  74. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  75. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  76. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  77. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  78. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  79. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  80. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  81. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  82. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  83. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/Request.php ( 0.09 KB )
  84. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  85. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/middleware.php ( 0.25 KB )
  86. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  87. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  88. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  89. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  90. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  91. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  92. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  93. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  94. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  95. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  96. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  97. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  98. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  99. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/route/app.php ( 1.72 KB )
  100. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  101. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  102. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  103. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/controller/Index.php ( 4.81 KB )
  104. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/app/BaseController.php ( 2.05 KB )
  105. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  106. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  108. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  109. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  110. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  111. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  112. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  113. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  114. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  115. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  116. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  117. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  118. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  119. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  120. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  121. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  122. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  123. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  124. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  125. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  126. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  127. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  128. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  129. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  130. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  131. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  132. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  133. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  134. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  135. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  136. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  137. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  138. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  139. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/runtime/temp/067d451b9a0c665040f3f1bdd3293d68.php ( 11.98 KB )
  140. /yingpanguazai/ssd/ssd1/www/f.mffb.com.cn/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000630s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000809s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000309s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000304s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000490s ]
  6. SELECT * FROM `set` [ RunTime:0.000192s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000531s ]
  8. SELECT * FROM `article` WHERE `id` = 489588 LIMIT 1 [ RunTime:0.004393s ]
  9. UPDATE `article` SET `lasttime` = 1783063266 WHERE `id` = 489588 [ RunTime:0.012066s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 67 LIMIT 1 [ RunTime:0.000297s ]
  11. SELECT * FROM `article` WHERE `id` < 489588 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.000725s ]
  12. SELECT * FROM `article` WHERE `id` > 489588 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.000430s ]
  13. SELECT * FROM `article` WHERE `id` < 489588 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.001947s ]
  14. SELECT * FROM `article` WHERE `id` < 489588 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.003936s ]
  15. SELECT * FROM `article` WHERE `id` < 489588 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.001081s ]
0.109853s