当前位置:首页>Linux>Linux MM 2026-05-13 最新 Feature 分析报告

Linux MM 2026-05-13 最新 Feature 分析报告

  • 2026-07-02 02:50:05
Linux MM 2026-05-13 最新 Feature 分析报告

目录

  1. HVO 泛化:将 HugeTLB 和 device DAX 的 vmemmap 优化统一为通用框架
  2. KASAN HW_TAGS 微优化:消除 slab/vmalloc 路径中的重复 poison/unpoison 操作
  3. HMM mmap lock-drop 支持:使 HMM 框架兼容 userfaultfd 映射
  4. mm/memory-failure: 为不可恢复页面添加 panic 选项
  5. arm64: 支持 FEAT_D128 128 位页表格式
  6. cgroup/dmem: 引入 dmem.peak 文件

1. HVO 泛化:将 HugeTLB 和 device DAX 的 vmemmap 优化统一为通用框架

系列[PATCH v2 00/69] mm: Generalize HVO for HugeTLB and device DAX作者: Muchun Song版本: v2(47 个 patch)

背景

HVO(Hugepage Vmemmap Optimization)是内核中一项关键的 struct page 内存节省技术。当使用大页(如 HugeTLB 的 1GB 页或 device DAX 的 2MB/1GB 映射)时,每个物理页都需要一个 struct page(通常 64 字节)来管理,但对于大页的大部分 tail page,其中的大量字段从未被使用。HVO 通过复用(remap)一个共享的 vmemmap tail page 来消除这些冗余的 struct page 映射,从而节省大量物理内存。

历史上,HVO 是作为 HugeTLB 子系统的一个专属优化实现的。当 device DAX 需要类似的 vmemmap 优化时,它开发了一套并行但独立的处理路径。作者在封面信中明确指出问题的本质:"The existing code grew around the original HugeTLB-specific HVO path, while device DAX developed similar but separate vmemmap optimization handling. As a result, the current implementation carries duplicated logic, boot-time special cases, and subsystem-specific interfaces around what is fundamentally the same sparse-vmemmap optimization."

这导致了几层问题:首先,HVO 的初始化时机严重受限于启动顺序——原来的 HVO 必须在 zone 信息可用后才能进行,但 bootmem 大页在此之前就已经分配;其次,HugeTLB 和 DAX 各自维护了不同的 tail page 查找、映射和管理逻辑;第三,powerpc 架构有专门的一整套 vmemmap compound page 填充代码,与通用路径完全不同。

解决的问题

  • HugeTLB 与 device DAX 的 vmemmap 优化代码重复:两套独立的 tail page 处理、映射、计数逻辑本质上做相同的事情
  • HVO 初始化时机过早导致的问题:原有的 SPARSEMEM_VMEMMAP_PREINIT 和 pre-HVO 路径在 zone 尚未初始化时就尝试设置优化映射,导致启动 panic(Patch 1 修复的 CONFIG_DEBUG_VM 启动 panic)
  • device DAX 的 struct page 节省未达到最优:DAX 额外预留了一个 tail page 未参与共享,浪费了内存
  • 共享 vmemmap 页面缺乏写保护:多个大页的 vmemmap 可能映射到同一个共享 tail page,但该页面是可写的,存在稳定性风险
  • HVO 启用逻辑分散vmemmap_can_optimize() 分布在 HugeTLB、powerpc、通用代码三处,且语义不一致
  • 启动时跨 zone 的大页导致后续 HVO 失败:bootmem 阶段分配的 gigantic 大页如果跨越多个 zone,在初始化时会被迫降级或丢弃

如何做

该系列是一个大型重构系列,从 69 个初始 patch 对 vmemmap 优化的整个生命周期进行了系统性的重新设计。工作分为以下几个层次:

第一层:基础修复(Patches 1-6)

在重构之前修复了 3 个关键 bug:

  • 修复 CONFIG_DEBUG_VM 下的 HVO 启动 panic:commit 622026e87c40 后 HVO 使用 per-zone 共享 tail page(zone->vmemmap_tails[]),但 bootmem HugeTLB folio 在 gather_bootmem_prealloc() 中准备时,这些共享 tail page 尚未初始化(原在 hugetlb_vmemmap_init() 中初始化)。修复的方式是将共享 tail page 的初始化提前到 gather_bootmem_prealloc() 中,确保在 bootmem hugepage 被访问前可用
  • 修复 __hugetlb_vmemmap_optimize_folios() 中的逻辑错误
  • 修复 powerpc mm 中 compound vmemmap 填充的 addr_pfn 追踪错误

第二层:启动顺序重排(Patches 7-11)

这是使统一框架成为可能的关键基础工作。原有的启动顺序中,sparse_init() 在 zone 初始化之前运行,导致 vmemmap 优化无法在此时获取 zone 信息。该系列将:

  • sparse_init() 延迟到 zone 初始化之后("Defer sparse_init() until after zone initialization")
  • hugetlb reservation 同步延迟到 zone 初始化之后
  • 从 sparse_init() 中移除 set_pageblock_order() 调用
  • sparse_vmemmap_init_nid_late() 合并到 sparse_init_nid() 中

这确保了当 vmemmap 优化基础设施运行时,zone 和 pageblock 状态已完全可用。

第三层:通用 section-based vmemmap 优化基础设施(Patches 12-27)

这是整个系列的核心创新。引入了基于 mem_section 的通用 vmemmap 优化框架:

  1. 在 struct mem_section 中追踪 compound page order:新增 section_order 字段,由 vmemmap 优化用户(HugeTLB、DAX)在创建大页时设置。这使得 sparse-vmemmap 代码无需了解是大页子系统还是 DAX 在使用优化——统一通过 section 元数据来判断。

  2. vmemmap_page_optimizable() 函数:通用的判断 struct page 是否落在共享 tail vmemmap 范围内的辅助函数:

staticinlineboolvmemmap_page_optimizable(const struct page *page)
{
unsignedlong pfn = page_to_pfn(page);
unsignedlong nr_pages = 1UL << pfn_to_section_order(pfn);
if (!is_power_of_2(sizeof(struct page)))
returnfalse;
return (pfn & (nr_pages - 1)) >= OPTIMIZED_FOLIO_VMEMMAP_NR_STRUCT_PAGES;
}

该函数利用 pfn_to_section_order() 获取该 section 对应的 compound order,判断当前 pfn 是否落在头部的 OPTIMIZED_FOLIO_VMEMMAP_NR_STRUCT_PAGES 范围内(这部分需要实际映射的 struct page),还是落在尾部共享范围内。

  1. memmap_init_range() 跳过共享 tail page:在启动时的 memmap_init_range() 中,如果检测到 vmemmap_page_optimizable() 返回 true,则跳过该范围的 struct page 初始化,仅设置 pageblock migratetype。这既避免了冗余初始化工作,也防止覆盖已共享的 vmemmap tail page 内容。

  2. vmemmap_shared_tail_page() 通用辅助函数:提供一个通用的共享 tail page 获取接口,替代原来 HugeTLB 和 powerpc DAX 各自实现的 tail page 查找逻辑。该函数根据 order 从 per-zone 的预分配数组中找到对应的共享 tail page。

  3. **引入 CONFIG_SPARSEMEM_VMEMMAP_OPTIMIZATION**:新的通用 Kconfig 选项,替代原来的 CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP。当 HugeTLB 或 DAX 中任一需要 vmemmap 优化时自动选中。该选项控制通用基础设施的编译,而非绑定到特定子系统。

第四层:HugeTLB 切换至通用框架(Patches 28-36)

将 HugeTLB 从原有的专用 HVO 路径切换到新的 section-based 通用优化路径:

  • 删除 vmemmap_populate_hvo() 等 HugeTLB 专用的 pre-HVO 函数
  • HugeTLB 现在只需在分配 bootmem 大页时调用 section_set_order_range() 设置 section order,通用 sparse-vmemmap 填充路径会自动完成共享 tail page 的分配和映射
  • 将 HugeTLB 的 reserve 宏(HUGETLB_VMEMMAP_RESERVE_SIZE 等)替换为通用定义(OPTIMIZED_FOLIO_VMEMMAP_SIZE 等)
  • 删除 HUGE_BOOTMEM_HVO 和 HUGE_BOOTMEM_CMA 特殊标记,简化启动路径

第五层:device DAX 切换至通用框架(Patches 37-44)

将 device DAX 的 vmemmap 优化路径统一到相同的基础设施:

  • DAX 切换到 vmemmap_shared_tail_page() 获取共享 tail page,不再自己走页表查找
  • DAX 纳入 section-based 优化:memremap.c 中通过设置 section order 来标记 DAX 大页的 vmemmap 优化
  • 删除 DAX 的额外预留 tail page,进一步节省内存——原来 DAX 多预留了一个 page 的 struct page 空间
  • powerpc 的 vmemmap_populate_compound_pages() 变为 static,不再有外部调用者
  • 删除 powerpc 专用的 vmemmap_can_optimize(),统一使用通用检查
  • DAX 和 HugeTLB 的 vmemmap 填充路径完全统一

第六层:健壮性增强(Patches 45-47)

  • 共享 vmemmap tail page 映射为只读:通过 vmemmap_wrprotect_hvo() 将共享的 tail page 映射设为 read-only,防止意外写入破坏多个大页共享的 struct page 数据
  • 统一 HVO 启用检查:所有 HVO 相关决策收敛到通用框架中的 vmemmap_can_optimize() 和 section order 元数据
  • 删除 vmemmap_wrprotect_hvo() 的 HugeTLB 专用版本

文档重写:

将 Documentation/mm/vmemmap_dedup.rst 从 HugeTLB-only 视角重写为统一的 HVO 设计文档,同时删除 powerpc 专用的 Documentation/arch/powerpc/vmemmap_dedup.rst

收益

作者明确表示:"I have only built and tested this series on x86. I do not currently have a powerpc test environment, so any testing or feedback on powerpc would be much appreciated."

测试项
测试环境
结果
构建测试
x86_64
通过

作者未提供性能 benchmark 数据。从代码逻辑推断的预期收益:

  • 代码量净减少 1069 行(+743 / -1812),消除了 HugeTLB 和 DAX 之间的重复逻辑,长期维护成本显著降低
  • 启动路径简化:移除了 SPARSEMEM_VMEMMAP_PREINIT 整个概念和相关的 pre-HVO 路径,启动时的 vmemmap 处理逻辑更清晰
  • 当 CONFIG_DEFERRED_STRUCT_PAGE_INIT 禁用时,优化的 struct page 可以跳过 memmap_init() 初始化,减少启动开销
  • 所有支持 HVO 的架构自动受益于通用路径,无需各自维护架构特定的 preinit 代码
  • device DAX 的 struct page 节省进一步提升:通过删除额外预留的 tail page
  • 共享 vmemmap tail page 的只读映射提高了系统健壮性,防止内核 bug 导致的 vmemmap 数据损坏
  • 跨架构一致性:powerpc 原来有一整套专用的 vmemmap compound page 填充代码(~150 行),现在统一使用通用路径

2. KASAN HW_TAGS 微优化:消除 slab/vmalloc 路径中的重复 poison/unpoison 操作

系列[PATCH 0/3] kasan: hw_tags: some micro-optimizations作者: Dev Jain版本: v1(3 个 patch)

背景

硬件标签化 KASAN(KASAN_HW_TAGS,基于 Arm MTE 即 Memory Tagging Extension)使用硬件内存标签来检测内存越界访问和 use-after-free 错误。与软件 KASAN(Generic/Generic SW_TAGS)不同,硬件 KASAN 通过在分配时给内存区域设置特定标签(tag),在访问时由硬件自动检查标签匹配。

在硬件 KASAN 的工作流中,内存的 poison(投毒,设置为无效标签)和 unpoison(解毒,设置为有效标签)是关键操作。但当前的实现中存在若干不必要的重复操作——在某些路径中,内存被 unpoison 后又立即被 repunson,或在 buddy allocator 中 unpoison 的页面在 slab 分配器中立即再次 poison。这些冗余操作增加了不必要的指令开销。

作者在 cover letter 中简洁地描述了优化的目标:"Patch 1 uses GFP_SKIP_KASAN to skip unpoisoning of a slab page in the page allocator, since slab allocator itself poisons the slab page immediately. Patch 2 and 3 remove wasted work while poisoning the tail end of the vmalloc/slab allocation."

解决的问题

  • Buddy allocator 对 slab 页面执行冗余的 unpoison:当 slab 分配器从 buddy 获取新页面时,buddy 先 unpoison 整页,然后 slab 立即调用 kasan_poison_slab() 再次 poison 整个页面。两次操作结果抵消,unpoison 是浪费的
  • kmalloc 分配时重复的 redzone poison:原实现先 unpoison 整个 kmalloc cache object,然后再从 object + allocation_size 开始 poison redzone 区域。对于硬件标签 KASAN,free object 和 redzone 使用相同的无效标签(KASAN_TAG_INVALID),因此 unpoison 整个 object 后再 poison redzone 是多余的——只需 unpoison 到分配大小即可
  • vmalloc 小分配时重复的页面级 unpoison/poison:当 vmalloc 分配小于一个页面时,原实现先 unpoison 整个页面,然后再 poison 超出分配大小的 redzone 部分。对于硬件标签 KASAN,可以直接 unpoison 分配大小然后 poison redzone,避免中间的全页 unpoison

如何做

Patch 1:跳过 slab 页面的 buddy unpoison

利用现有的 __GFP_SKIP_KASAN 标志(此前已用于 vmalloc 路径),在 slab 分配器请求新页面时设置该标志:

// mm/slub.c: alloc_slab_page()
flags |= __GFP_SKIP_KASAN;

这使得 alloc_frozen_pages_nolock() 从 buddy 获取页面后跳过 kasan_unpoison_pages() 调用。关键前提是 slab 分配器在获取页面后会立即调用 kasan_poison_slab() 对整个 slab 页面进行 poison —— 因此 buddy 的 unpoison 在语义上是完全冗余的。

该 patch 还需要放宽 alloc_frozen_pages_nolock_noprof() 中对 gfp flag 的限制,原本只允许 __GFP_ACCOUNT,现在也需要允许 __GFP_SKIP_KASAN

Patch 2:优化 tag-based KASAN 的 kmalloc redzone 处理

这是三个 patch 中最复杂的优化,涉及 kasan 和 slab 接口的多个修改点:

  1. 新增 kasan_has_tag_based_kmalloc_redzones() 辅助函数
staticinlineboolkasan_has_tag_based_kmalloc_redzones(void)
{
return kasan_enabled() &&
           (IS_ENABLED(CONFIG_KASAN_SW_TAGS) || kasan_hw_tags_enabled());
}

该谓词的意义在于:SW_TAGS 和 HW_TAGS 都使用单一的无效标签值(而非 Generic KASAN 使用的区分 shadow byte 值)来表示 free 内存和 redzone。作者在注释中解释:"For tag-based modes, kmalloc redzones all use the same invalid tag." 因此无需在 unpoison 后再单独 poison redzone。

  1. 修改 kasan_slab_alloc() 接口:增加 size_t size 参数,传递实际分配大小(而不仅是 cache 的 object_size)。

  2. unpoison_slab_object() 新增 slab_unpoison_size() 逻辑

staticinlinesize_tslab_unpoison_size(struct kmem_cache *cache, size_t size)
{
if (kasan_has_tag_based_kmalloc_redzones() && is_kmalloc_cache(cache))
returnmin_t(size_t, size, cache->object_size);
return cache->object_size;
}

对于 tag-based KASAN 的 kmalloc cache:只 unpoison 到实际分配的 size 字节,后面的 redzone 区域保持 poison 状态。对于 Generic KASAN(使用不同的 shadow byte 值区分 free 和 redzone)以及非 kmalloc cache:保持原有行为,unpoison 整个 object。

  1. __kasan_kmalloc() 优化:对于 tag-based KASAN,不再调用 poison_kmalloc_redzone() 重新 poison 尾部,因为尾部从未被 unpoison。只需保存 alloc info。

  2. slab_post_alloc_hook() 修改:对于 tag-based KASAN 的 kmalloc cache,将 zero_size 设为 orig_size(实际分配大小)而非整个 object size,确保 memset(0) 不会触及 redzone 区域。

Patch 3:优化 vmalloc redzoning

修改 __kasan_unpoison_vmalloc() 的执行顺序。原实现:

1. kasan_unpoison(start, size)          // unpoison 整个分配区域+部分redzone
2. kasan_poison(redzone_start, ...)      // 再 poison redzone

优化后:

// 1. 计算 redzone 的起始和大小
redzone_start = round_up((unsignedlong)start + size, KASAN_GRANULE_SIZE);
redzone_size = round_up(redzone_start, PAGE_SIZE) - redzone_start;

// 2. 仅 unpoison 分配区域(到 redzone_start 为止)
kasan_unpoison(start, redzone_start - (unsignedlong)start, ...);

// 3. poison redzone
if (redzone_size)
    kasan_poison((void *)redzone_start, redzone_size, KASAN_TAG_INVALID, ...);

原始代码先 unpoison 了 start 到 start + size(可能跨越 tag granule 边界覆盖部分 redzone),然后在第二步才纠正。优化后直接精确到 redzone 边界,避免了中间的 unpoison + re-poison 往返。

收益

作者未提供性能数据。从代码逻辑推断的预期收益:

  • 每个 slab 页面分配节省一次 buddy unpoison 操作:在频繁分配/释放 slab 页面的高吞吐场景(如网络 I/O、文件系统元数据操作)中,跳过 buddy 的 kasan_unpoison_pages() 调用能减少指令数和 cache miss
  • 每个 kmalloc 分配节省 redzone re-poison 操作:对于 tag-based KASAN(Arm MTE 或 SW_TAGS),省去了 poison_kmalloc_redzone() 中的标签设置开销及相关的 kasan_save_alloc_info() 重复调用。在 kmalloc 密集型工作负载中,每次分配都可节省若干指令
  • 每个子页面 vmalloc 分配节省中间 unpoison 操作:对于小于一页的 vmalloc 分配(如内核模块的小型分配),优化后避免了先 unpoison 整个 page 再 poison 尾部的浪费
  • 改善 Data Cache 行为:减少不必要的内存写入(poison/unpoison 均为写操作),降低了 data cache 污染,对 cache-bound 的工作负载有间接帮助
  • 该系列优化仅针对 KASAN 启用时的开销,不影响 KASAN 关闭时的性能

3. HMM mmap lock-drop 支持:使 HMM 框架兼容 userfaultfd 映射

系列[PATCH v2 0/3] mm/hmm: Add mmap lock-drop support for userfaultfd-backed mappings作者: Stanislav Kinsburskii版本: v2(3 个 patch)

背景

HMM(Heterogeneous Memory Management)是 Linux 内核中用于异构内存管理的基础框架,允许设备驱动(如 GPU 驱动、FPGA 驱动)通过 hmm_range_fault() 将进程虚拟地址空间中的页面填充(fault in)并映射到设备页表中。这个框架在 GPU 计算(如 NVIDIA 的 nouveau 驱动、AMD GPU 驱动)和 CXL 设备等场景中广泛使用。

然而,hmm_range_fault() 的一个根本性限制是它在整个调用期间持有 mmap_read_lock,这与其调用 handle_mm_fault() 处理缺页的方式直接冲突。作者在封面信中解释了核心矛盾:"Some page fault handlers -- most notably userfaultfd -- require the mmap lock to be released so that userspace can resolve the fault. The current HMM interface never sets FAULT_FLAG_ALLOW_RETRY, making it impossible to fault in pages from userfaultfd-registered regions."

userfaultfd 是 Linux 的 user-space page fault 处理机制,允许用户态程序接管缺页处理(例如虚拟机迁移中的 post-copy 实时迁移、数据库的内存管理、容器检查点/恢复)。当 handle_mm_fault() 遇到 userfaultfd 注册的 VMA 时,会返回 VM_FAULT_RETRY 或 VM_FAULT_COMPLETED 并释放 mmap_lock,等待用户态程序解决缺页。但 HMM 框架从未设置 FAULT_FLAG_ALLOW_RETRY,意味着它无法从 userfaultfd 映射中获取页面。

解决的问题

  • HMM 无法在 userfaultfd 管理的 VMA 上进行 faulthmm_range_fault() 永远不在 fault flags 中设置 FAULT_FLAG_ALLOW_RETRY,而 userfaultfd 的缺页处理要求该 flag
  • HMM 的 walk callback 中直接调用 handle_mm_fault() 导致锁定层级问题:原有的 hmm_vma_fault() 在 page table walk 的中间层(可能持有 pte spinlock 或 hugetlb_vma_lock)调用 handle_mm_fault(),如果 mmap lock 在此被释放,walk 框架的后续 unlock 操作会因为 VMA 可能已被释放而导致 use-after-free
  • hugetlb 路径上的特殊处理脆弱:v1 中原有 "drop/retake hugetlb_vma_lock_read" 的舞蹈式处理来避免死锁,但这仅是权宜之计,无法扩展到 mmap lock drop 场景

如何做

该系列通过 3 个 patch 实现了 HMM 的 mmap lock-drop 支持,遵循了 mm/gup.c 中 get_user_pages_remote() 已经验证的 int *locked 模式。

Patch 1:将 page fault 处理移出 walk callback(重构)

这是使 Patch 2 成为可能的基础重构。核心思路是将 hmm_range_fault() 的职责清晰地分为两层:

  1. Walk callback 层(仅检测)hmm_vma_walk_pmd()hmm_vma_walk_pud()hmm_vma_walk_hugetlb_entry() 等 walk callback 不再直接调用 handle_mm_fault(),而是通过新的 hmm_record_fault() 在 struct hmm_vma_walk 中记录需要 fault 的范围和类型,然后返回私有的 HMM_FAULT_PENDING-EAGAIN)哨兵值。
staticinthmm_record_fault(unsignedlong addr, unsignedlong end,
unsignedint required_fault,
                            struct mm_walk *walk)

{
structhmm_vma_walk *hmm_vma_walk = walk->private;
    hmm_vma_walk->last = addr;
    hmm_vma_walk->end = end;
    hmm_vma_walk->required_fault = required_fault;
return HMM_FAULT_PENDING;
}
  1. Outer loop 层(执行 fault)hmm_range_fault() 的外层循环在收到 HMM_FAULT_PENDING 后,调用新的 hmm_do_fault() 函数。此时 walk_page_range() 已经返回,pte spinlock 和 hugetlb_vma_lock 均已释放,仅持有 mmap_read_lockhmm_do_fault() 在干净的锁定上下文中调用 handle_mm_fault()

这一拆分带来的直接好处包括:

  • Hugetlb 路径不再需要 "drop/retake hugetlb_vma_lock_read" 的特殊处理——原来的舞蹈式代码被完全删除
  • 所有 fault 路径的 pte spinlock 释放统一在 walk 框架中处理,不再由各个 callback 分别释放
  • 为 Patch 2 的 lock-drop 支持清除了锁定层级障碍

Patch 2:添加 hmm_range_fault_unlockable()(核心功能)

这是功能新增的核心 patch。新增的 hmm_range_fault_unlockable() 接受一个 int *locked 参数,遵循 GUP 的语义模式:

  • 调用者设置 *locked = 1 并持有 mmap_read_lock
  • 如果函数返回后 *locked == 1:锁仍被持有,返回值语义与 hmm_range_fault() 相同
  • 如果函数返回后 *locked == 0:mmap lock 在 fault 过程中被释放了(handle_mm_fault() 返回了 VM_FAULT_RETRY 或 VM_FAULT_COMPLETED),调用者需要重新获取锁并使用新的 notifier 序列号重新开始整个 walk

实现细节:

  1. hmm_do_fault() 扩展:当 locked 非 NULL 时,设置 FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE。当 handle_mm_fault() 返回 VM_FAULT_RETRY 或 VM_FAULT_COMPLETED 时,设置 *locked = 0 并返回私有哨兵值 HMM_FAULT_UNLOCKED-ENOLCK)。

  2. **outer loop 处理 HMM_FAULT_UNLOCKED**:

if (ret == HMM_FAULT_PENDING) {
    ret = hmm_do_fault(mm, &hmm_vma_walk);
if (ret == HMM_FAULT_UNLOCKED) {
if (fatal_signal_pending(current))
return -EINTR;
return0;     /* caller must restart */
    }
}

当收到 HMM_FAULT_UNLOCKED 时,检查是否有 fatal signal pending。有则返回 -EINTR;否则返回 0 表示调用者需要重新获取 lock 并重试。

  1. hmm_range_fault() 重构为薄 wrapper
inthmm_range_fault(struct hmm_range *range)
{
return hmm_range_fault_unlockable(range, NULL);
}

传入 NULL 的 locked 参数确保行为与原有实现完全一致,所有现有调用者均不受影响。

  1. 文档更新Documentation/mm/hmm.rst 新增了完整的调用模式示例代码,展示了驱动如何使用 hmm_range_fault_unlockable() —— 包括 notifier 序列号管理、锁的重新获取、以及 goto again 重试模式。

作者在 cover letter 中总结了 hugetlb 的兼容性:"Hugetlb regions therefore participate in the unlockable path uniformly with PTE- and PMD-level mappings; no special case is required."

Patch 3:userfaultfd + HMM unlockable 路径的 selftest

添加了一套完整的自测,验证 hmm_range_fault_unlockable() 在 userfaultfd 映射上的正确性:

  • 在 lib/test_hmm.c 中新增 dmirror_range_fault_unlockable()dmirror_fault_unlockable()dmirror_read_unlockable() 以及新的 HMM_DMIRROR_READ_UNLOCKABLE ioctl(0x09)
  • 在 tools/testing/selftests/mm/hmm-tests.c 中新增测试用例:创建匿名 mmap 区域 → 通过 UFFDIO_REGISTER_MODE_MISSING 注册到 userfaultfd → 启动 handler 线程用已知模式(0xAB)通过 UFFDIO_COPY 解决 page fault → 通过 unlockable ioctl 触发 HMM fault → 验证数据一致性

收益

作者未提供性能数据。从代码逻辑推断的预期收益:

  • HMM 框架首次支持 userfaultfd 映射:这是功能上的重要突破,使 GPU/FPGA 驱动能够在虚拟机实时迁移(post-copy)、数据库内存管理等使用 userfaultfd 的场景中正常工作
  • 与现有 GUP 模式一致int *locked 模式已在 get_user_pages_remote() 中广泛使用和验证,HMM 采用相同模式降低了驱动开发者的学习曲线
  • 重构降低了代码复杂度:Patch 1 删除了 hugetlb 路径中的特殊锁定处理,统一了 fault 执行路径,使整体代码结构更清晰
  • 向后兼容hmm_range_fault() 的语义和行为完全不变,所有现有调用者无需任何修改
  • Hugetlb 支持无缝:得益于 Patch 1 的重构,unlockable 路径对 hugetlb 区域开箱即用,无需额外处理
  • 完整的测试覆盖:自测覆盖了 userfaultfd + HMM unlockable 的端到端路径

4. mm/memory-failure: 为不可恢复页面添加 panic 选项

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

背景

硬件内存错误(如多比特 ECC 错误)命中内核页时,memory failure 处理器的默认行为是设置 PG_hwpoison 标志、记录事件日志,然后内核继续运行。但坏页仍可被内核访问,导致两种严重后果:"silent data corruption"——损坏数据被静默使用并可能传播到持久化存储;"delayed unattributable crash"——内核在数秒到数分钟后在完全无关的代码路径崩溃。在大规模集群中,这种延迟崩溃的根因分析需要大量工程投入:kdump 配置下,原始错误上下文(故障 PFN、MCE/GHES 记录、页面状态)在延迟崩溃发生时早已丢失。

作者明确指出:"In a large fleet that delayed, unattributable crash turns into significant engineering effort to root-cause."

解决的问题

  • 不可恢复内核页错误被静默吞没PG_hwpoison 设置后内核继续运行,损坏数据仍可访问,风险为静默数据损坏或延迟崩溃
  • 延迟崩溃丢失故障上下文:kdump vmcore 中只剩最终崩溃现场的栈回溯,原始硬件错误的 PFN、MCE 记录等信息已不可得
  • 运维无法选择"快速失败"策略:对于优先保证数据完整性而非可用性的场景,没有机制让内核在检测到不可恢复页时立即 panic

如何做

本系列方案分为三个层次:

第一层:清理死代码(Patch 1)

删除 error_states[] 表中第一项 { reserved, reserved, MF_MSG_KERNEL, me_kernel } 及其对应的 me_kernel() 函数。作者论证了该条目不可达:memory_failure() 到达 identify_page_state() 之前必须先通过 get_hwpoison_page() 返回 1,而 get_any_page() 中 HWPoisonHandlable() 拒绝 PG_reserved 页面,因此 PG_reserved 页在 identify_page_state() 之前就以 -EBUSY/-EIO 失败退出。保留 MF_MSG_KERNEL 枚举值用于后续复用。无功能改变。

第二层:区分不可恢复内核页(Patch 2-4)

Patch 2 是关键的重构:get_any_page() 原来将三种不同失败模式统一折叠为 -EIO 返回值:

  • 瞬时竞争(put_page race 在 !count_increased 路径)
  • HWPoisonHandlable() 拒绝(经 shake_page() 重试耗尽后)
  • 持有引用进入的 HWPoisonHandlable() 拒绝(count_increased=true 路径)

现在将它们区分:前两种保持返回 -EIO(无法证明页面永久属内核),第三种返回新的错误码 -ENOTRECOVERABLE——"the caller's reference is structural evidence that the page is owned by the kernel"。

Patch 3 在 memory_failure() 的 get_hwpoison_page() 返回码 switch 分支中,将 -ENOTRECOVERABLE 映射为 MF_MSG_KERNEL,使得 PG_reserved 页和 slab/vmalloc/page table/kernel stack 等内核页能被统一标记。

Patch 4 加入 PG_reserved 短路检查:在调用 get_hwpoison_page() 之前先判断 PageReserved(),避免对确定不可恢复的 reserved 页进行徒劳的 shake_page() 重试。

第三层:panic 机制(Patch 5-6)

新增 sysctl vm.panic_on_unrecoverable_memory_failure,默认值为 0(保持现有行为)。当值为 1 时,action_result() 中调用 panic_on_unrecoverable_mf() 判断是否应触发 panic。

Panic 判定条件采用保守策略,只覆盖 MF_MSG_KERNEL + MF_IGNORED 组合:

  • 排除了 MF_MSG_GET_HWPOISON:可能由瞬时 refcount 竞争触发,panic 会误杀可恢复的 userspace 页面
  • 排除了 MF_MSG_KERNEL_HIGH_ORDER:同理可被瞬时分配竞争触发
  • 排除了 MF_MSG_UNKNOWN:页面状态无法分类不能作为 panic 决策基础

文档(Patch 6)详细描述了四个使用场景:大规模集群延迟崩溃根因分析、kdump 环境保留原始故障上下文、高可用集群快速确定节点故障、内核/平台开发者使用 mce-inject 调试时立即可见问题。

收益

作者未提供量化的 benchmark 数据。从代码逻辑推断的预期收益:

  • 将不可恢复内核页错误的平均故障检测时间从"数秒到数分钟"降低为"即时"(硬件错误发生时刻立即 panic)
  • 在 kdump 配置下,vmcore 将保存故障 PFN、MCE/GHES 记录和完整的页面状态,使根因分析从"大量工程投入"变为"直接可读"
  • 默认关闭的设计确保现有工作负载行为不变,按需启用即可获得快速失败能力
  • 保守的 panic 触发条件(仅 MF_MSG_KERNEL + MF_IGNORED)将误panic 风险降至最低

5. arm64: 支持 FEAT_D128 128 位页表格式

系列[PATCH RFC V2 00/14] arm64/mm: Enable 128 bit page table entries作者: Anshuman Khandual, Linu Cherian版本: RFC V2(14 个 patch)

背景

FEAT_D128 是 ARMv9.3 引入的可选架构特性,新增了 VMSAv9-128 地址翻译系统。在此之前,arm64 平台始终使用 VMSAv8-64 翻译系统,页表描述符(page table descriptor)固定为 64 位宽。64 位页表项限制了物理地址空间和虚拟地址空间的进一步扩展能力,也限制了可用于硬件和软件管理的 MMU feature bit 数量。FEAT_D128 将页表项扩展至 128 位,使得平台可以支持更大的地址空间,同时为更多 MMU 管理功能位提供物理承载空间。

开启 FEAT_D128 后,arm64 平台可以同时拥有两套翻译系统——VMSAv8-64 和 VMSAv9-128——由内核通过 CONFIG_ARM64_D128 配置项选择启用哪一种。

解决的问题

  • 64 位页表项地址空间上限:现有 64 位 PTE 格式限制了 VA/PA 的进一步增长,128 位格式为未来的更大地址空间提供基础
  • 缺乏平台无关的页表读取抽象:内核中大量使用 READ_ONCE() 直接读取页表项,这在 64 位系统上是原子安全的,但 128 位页表项无法用单个 64-bit load 指令原子读取,需要平台特定的访问器来保证单次拷贝原子性(single copy atomicity)
  • vm_page_prot 的锁无关访问不兼容 128 位vma->vm_page_prot 当前通过 READ_ONCE()/WRITE_ONCE() 进行无锁读写,D128 下 pgprot_t 升级为 128 位后这些宏不再安全
  • 页表项打印格式固化__print_bad_page_map_pgtable() 等调试路径硬编码了 %08llx 格式,无法适配 128 位 PTE 值的打印

如何做

本系列的分层策略。

通用 mm 基础设施(Patch 1-2):

  1. 抽象 pxd_val() 打印:引入 pxdval_t 类型——当编译器支持 __SIZEOF_INT128__ 时定义为 u128,否则保持为 unsigned long long。同时引入 __PRIpxx 格式宏和 __PRIpxx_args() 参数宏,使得打印 PTE 值的代码可以通过平台重定义这些宏来适配不同位宽。__print_bad_page_map_pgtable() 和 print_bad_page_map() 中的变量类型及 pr_alert() 格式串全部切换为新的抽象。

  2. 抽象 vm_page_prot 访问:新增 pgprot_read() 和 pgprot_write() 内联函数,默认实现为 READ_ONCE() 和 WRITE_ONCE(),但通过 #ifndef 守卫允许平台按需覆盖。mm/memory.cmm/huge_memory.cmm/migrate.cmm/mmap.c 中所有对 vma->vm_page_prot 的直接 READ_ONCE()/WRITE_ONCE() 访问全部替换为这两个新访问器。

arm64 平台侧重构(Patch 3-13):

arm64 将各级页表读取统一路由到 pxxval_get() 宏——在未开启 D128 时等价于 READ_ONCE()。定义了 pmdp_get()pudp_get()p4dp_get()pgdp_get() 四个级别特定的访问器,并替换了 arm64 页表代码中所有对 READ_ONCE() 的直接调用。对称地定义了 pxxval_set() 用于写入,pxxval_cmpxchg_relaxed() 和 pxxval_xchg_relaxed() 用于原子操作,统一路由所有页表原子操作。新增 TLB 操作抽象层 tlbi_op 为后续引入 TLBIP 指令做准备。修复 5 级 fixmap 支持以适配 D128 下可能增加的页表层数。

FEAT_D128 核心实现(Patch 14):

这是系列的核心 patch(374 行新增),在 CONFIG_ARM64_D128 下:

  • PTE 位布局完全重定义:在 pgtable-hwdef.h 中新增整套 D128 格式的硬件定义。所有 PTE 属性位映射到 128 位空间中的新位置:PTE_VALID 仍在 bit[0],PTE_AF 在 bit[10],PTE_DBM 移至 bit[116],PTE_USER/PTE_PXN/PTE_UXN 移至 bit[115]/[117]/[118](通过 Permission Indirection Extension 的 PIIndex 机制),SW 定义位 PTE_DIRTY/PTE_SPECIAL 分别重定位到 bit[91]/[92]。PTE 地址掩码 PTE_ADDR_LOW 覆盖 bit[55:12]。

  • Permission Indirection 为强制要求:D128 格式独占地使用 permission indirection 风格管理页表项权限,因此 CONFIG_ARM64_D128 要求 FEAT_S1PIE 同时存在,启动时若硬件不满足则内核 panic。

  • 128 位原子读写pxxval_get() 在 D128 下展开为内联汇编 ldp(load pair),一次性加载 128 位值的高 64 位和低 64 位,保证单次拷贝原子性。pxxval_set() 对称地使用 stp(store pair)。pxxval_cmpxchg_relaxed() 调用 cmpxchg128_relaxed()pxxval_xchg_relaxed() 使用 LSE128 扩展的 swpp 指令。

  • 页表几何调整:由于每个 128 位的 PTE 占用空间翻倍,每级页表能容纳的表项数减半(PTRS_PER_PXX 相应调整)。各级页表的 leaf entry 覆盖范围变化显著——以 4K 页为例,PMD 映射从 2M 缩小到 1M,PUD 映射从 1G 缩小到 256M。Contiguous PTE/PMD 的覆盖范围也相应变化。

  • TLB 维护使用 TLBIP 指令:引入 __tlbip() 宏,针对 D128 使用 tlbip(TLB Invalidate with PA)指令替代传统 tlbi。TLB 刷新参数 tlbi_args_t 在 D128 下变为 union __u128_halves 以承载 128 位地址参数。

  • 寄存器访问适配TTBR0/1_EL1 和 PAR_EL1 在 D128 下变为 128 位宽,启动时通过 msrr 指令清零全部 128 位。由于当前 PA_BITS 仍限制在 52 位,对低 64 位的访问通过 mrs/msr 即可满足。

  • Kconfig 依赖链CONFIG_ARM64_D128 依赖编译器支持 __int128ARCH_SUPPORTS_INT128)、汇编器支持 LSE128 和 ARMv9.3-a、同时排除 KVM、KASAN 和 UNMAP_KERNEL_AT_EL0(这些功能暂不支持 D128)。

收益

作者未提供性能数据。从代码逻辑推断的预期收益:

  • 为未来 ARM 平台突破 52 位物理地址限制和 56 位虚拟地址限制提供了页表格式基础
  • 128 位 PTE 中充足的预留位空间可承载更多 MMU 功能扩展(硬件和软件侧)
  • 通用的 pxdval_t/__PRIpxx/pgprot_read|write 抽象层同时惠及其他架构未来可能的大位宽页表需求
  • 已通过 mm kselftests 测试(开启/关闭 CONFIG_ARM64_D128 均无问题),并在 x86、powerpc、riscv 等平台通过了编译构建测试

6. cgroup/dmem: 引入 dmem.peak 文件

系列[PATCH v2] cgroup/dmem: introduce a peak file作者: Thadeu Lima de Souza Cascardo版本: v2(1 个 patch)

背景

cgroup dmem(device memory)控制器用于管理和统计设备内存(如 GPU VRAM)的使用情况,模仿 memory cgroup 的接口设计。已有的 memory.peak 文件记录了 cgroup 自创建以来的内存使用峰值,对于容量规划和异常检测非常有用。但 dmem 控制器缺少对应的峰值统计接口,管理员无法了解设备内存使用的历史峰值。

解决的问题

  • dmem 控制器缺少峰值使用量(watermark)暴露接口,运维人员无法通过 cgroup 文件系统直接获取设备内存的历史最大使用量
  • 与 memory cgroup 的 memory.peak 接口不对称,降低了 dmem 控制器的可用性和一致性

如何做

本 patch 完全依托已有的 page_counter 基础设施。page_counter 内部已维护 watermark 字段,在每次 page_counter_try_charge() 成功后更新为 max(watermark, new_usage),无需额外维护开销。

实现要点:

  • 新增 get_resource_peak() 函数,通过 READ_ONCE(pool->cnt.watermark) 读取对应 dmem region 的 page_counter watermark
  • 新增 dmem_cgroup_region_peak_show() 回调,复用已有的 dmemcg_limit_show() 模板函数,将 get_resource_peak 作为函数指针传入
  • 在 files[] 数组中注册新的 cgroup 控制文件项,文件名为 "peak",标志位 CFTYPE_NOT_ON_ROOT(仅在非根 cgroup 上显示),回调设置为 dmem_cgroup_region_peak_show
  • 文件为只读(v2 变更),v1 版本包含写入功能但被调整为只读
  • 同步更新 Documentation/admin-guide/cgroup-v2.rst 中 dmem 接口文档

关键代码路径:dmem.peak 读取时进入 dmem_cgroup_region_peak_show(),该函数遍历 cgroup 的每个 dmem region,对每个 region 调用 dmemcg_limit_show(),后者按嵌套键(nested-keyed)格式输出 region ID 和对应的 get_resource_peak() 返回值。

收益

作者未提供性能数据。从代码逻辑推断的预期收益:

  • 零额外运行时开销:watermark 由 page_counter 原有计费路径维护,仅新增读路径
  • 与 memory.peak 接口一致,降低运维人员的学习成本和脚本适配成本
  • 为 dmem 容量规划和设备内存使用异常检测提供了基础数据源

总结

性能优化

#
系列
量化数据
1
HVO 泛化
 [v2, 47p]
代码净减少 1069 行(+743/-1812);消除 SPARSEMEM_VMEMMAP_PREINIT pre-HVO 路径减少启动开销;device DAX 额外节省一个尾页;共享 tail page 只读映射提升健壮性
2
KASAN HW_TAGS 微优化
 [v1, 3p]
每个 slab 页分配跳过一次 buddy unpoison;每个 tag-based kmalloc 减少 redzone re-poison;每个子页面 vmalloc 消除 unpoison+re-poison 往返。仅影响 KASAN 运行时开销
3
HMM mmap lock-drop
 [v2, 3p]
重构将 fault 处理移出 walk callback 消除 hugetlb 特殊锁定路径,新增 hmm_range_fault_unlockable() 采用 GUP int *locked 模式,首次支持 userfaultfd 映射

新机制 / 新接口

#
系列
要点
4
panic_on_unrecoverable_mf
 [v7, 6p]
新增 vm.panic_on_unrecoverable_memory_failure sysctl,遇到不可恢复内核页 hwpoison 时可立即 panic 保留故障现场;保守判定策略仅覆盖 MF_MSG_KERNEL + MF_IGNORED;默认关闭
5
arm64 D128 页表
 [RFC v2, 14p]
支持 ARMv9.3 FEAT_D128 128 位页表格式;通用 mm 层新增 pxdval_t/__PRIpxx/`pgprot_read
6
dmem.peak
 [v2, 1p]
为 cgroup dmem 控制器新增只读 peak 文件暴露设备内存使用历史峰值;依托 page_counter 已有 watermark,零额外运行时开销

Bug Fix

#
系列
影响
-
UFFDIO_COPY VMA panic
修复 UFFDIO_COPY retry 时 private/shmem VMA swap 导致的 BUG_ON(!anon_vma) 内核 panic
-
khugepaged underflow
修复 hstart >= hend 时无符号下溢导致返回错误超大值
-
hugetlb deadlock
修复 resv_map->rw_sema 与 mmap_lock 循环锁依赖死锁(syzbot)
-
memblock use-after-free
修复 memblock_free() 在 memblock_discard() 后被调用导致的 KASAN UAF
-
zram use-after-free
修复 zram writeback 中 kfree(wb_ctl) 的 UAF,改用 kfree_rcu()
-
swap extend table 泄漏
修复竞态条件导致分配了不再需要的 extend table
-
drivers/base/memory altmap
修复 __add_memory_block() 失败时 device_unregister() 触发 WARN_ON
-
lib/test_hmm kfree mismatch
修复 kvcalloc() 分配被 kfree() 释放的问题
-
userfaultfd mmap_changing 泄漏
修复 mremap 失败时 ctx->mmap_changing 未递减
-
hugetlb lockdep 假阳性
修复 locking model 改变后 hugetlb_vma_assert_locked() 的假阳性断言
-
selftests/mm MAP_FAILED
修复 mmap() 返回值用 !ptr 代替 MAP_FAILED 检查
-
selftests/cgroup leak
修复 test_percpu_basic 中 cg_name_indexed() 返回 NULL 时的资源泄漏
-
tools/mm/page-types bugs
修复 madvise 错误信息、sigbus 三元优先级、getopt 选项声明错误

内部优化 / 清理

#
系列
要点
-
mm/memory_failure bool 转化
 [v1]
将 try_memory_failure_hugetlb() 中 int 参数改为 bool,无功能变化
-
mm/shrinker guard() 重构
 [v2]
用 guard(mutex) 替代显式 mutex_lock/mutex_unlock 和 goto 错误路径
-
mm misc cleanups
 [v1, 4p]
for_each_free_list()
 迭代器、migratetype 重命名、pageblock 宏整理、移除 ifdef(均无功能变化)
-
landlock audit 计数
 [v1]
Landlock LSM 审计数据分配改用 GFP_KERNEL_ACCOUNT,与 mm 子系统无关

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-07-03 18:01:05 HTTP/2.0 GET : https://f.mffb.com.cn/a/493661.html
  2. 运行时间 : 0.122009s [ 吞吐率:8.20req/s ] 内存消耗:4,665.05kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=43ebb1639ee255503e958f1921ecb232
  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.000395s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000815s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000369s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000232s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000496s ]
  6. SELECT * FROM `set` [ RunTime:0.002319s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000639s ]
  8. SELECT * FROM `article` WHERE `id` = 493661 LIMIT 1 [ RunTime:0.002820s ]
  9. UPDATE `article` SET `lasttime` = 1783072865 WHERE `id` = 493661 [ RunTime:0.016459s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 67 LIMIT 1 [ RunTime:0.003207s ]
  11. SELECT * FROM `article` WHERE `id` < 493661 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.001643s ]
  12. SELECT * FROM `article` WHERE `id` > 493661 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.006471s ]
  13. SELECT * FROM `article` WHERE `id` < 493661 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.011245s ]
  14. SELECT * FROM `article` WHERE `id` < 493661 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.004002s ]
  15. SELECT * FROM `article` WHERE `id` < 493661 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.001234s ]
0.124628s