当前位置:首页>Linux>Linux mm 2026-04-20 最新 Feature 分析报告

Linux mm 2026-04-20 最新 Feature 分析报告

  • 2026-07-03 03:38:21
Linux mm 2026-04-20 最新 Feature 分析报告
目录
  1. mm/virtio:跳过 host 已清零页的冗余再清零
  2. mm:folio refcount 伸缩性改进(基于专用 bit 的 refcount 锁)
  3. mm/mmu_gather:TLB flush 已发 IPI 时跳过冗余 sync IPI
  4. mm/vmalloc:vrealloc() 缩容时释放尾部物理页
  5. mm/alloc_tag:early PFN 固定数组替换为动态链表
  6. rust: maple_tree:为 MapleTree 实现 Send 与 Sync
  7. mm/page_alloc:修复 init_on_free 下 huge zero folio MTE tag 未清零
  8. mm/filemap:避免高阶 folio 分配进入昂贵回收路径
  9. vmalloc:修复 vrealloc_node_align() 缩容时 memcpy 越界写
  10. mm/damon/sysfs-schemes:修复 memcg_path 与 goal path 的 UAF/double-free

1. mm/virtio:跳过 host 已清零页的冗余再清零

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

背景

在 virtio-balloon 的 free page reporting 机制中,guest 会把空闲页报告给 hypervisor,host 通常通过 MADV_DONTNEED 之类的操作回收后端内存,并在此过程中把页面清零(KVM/QEMU 下匿名映射的 backing 被回收后,再次访问时内核会返回零页)。当 guest 再次分配这些页时,Linux 内核又会在分配路径上执行 folio_zero_user() 再次清零——同一份零数据被写了两遍,既浪费 CPU,又污染 cache。随着 THP 普及,一次 MADV_POPULATE_WRITE 里要对一个 2 MB 大页做清零,这种冗余更为显著。本系列(v2)来自 Michael S. Tsirkin 对 David Hildenbrand 意见的回应:放弃 __GFP_PREZEROED/page->private 的重载方式,改用一个新的 page flag 加上独立的 hint API,同时补上了 hugetlb、balloon deflate、page_reporting 侧的完整支持。

解决的问题

  • guest 在分配 host 已清零过的页时重复写零,浪费 task-clock、指令和 cache
  • 现有 __GFP_ZERO 语义无法跨 buddy allocator 持久表达"这个页已经是零"
  • THP/hugetlb 路径上一旦错过 pre-zero 信息,2 MB/1 GB 清零成本被平摊到用户分配时
  • balloon deflate 归还 guest 的页也是零页,但缺少机制把信息传到 buddy
  • 测试时 page reporting 有 2 秒延迟,不便做确定性 benchmark

如何做

核心是一条"host-zeroed"信息从 page_reporting 一路传播到页错误路径,关键数据结构与接口包括:

  • 新增 PG_zeroed,别名复用 PG_private,通过 __PAGEFLAG(Zeroed, zeroed, PF_NO_COMPOUND) 暴露,并从 PAGE_FLAGS_CHECK_AT_PREP 中排除 __PG_ZEROED,使其能在 free list 上存活到 post_alloc_hook()
  • 引入 pghint_t 位图类型与 PGHINT_ZEROED,提供 vma_alloc_folio_hints()__alloc_frozen_pages_hints() 等 _hints 变体,以输出参数返回"本次分配的页是否已清零",不侵入原有 GFP 语义。
  • 在 __free_one_page() 中跟踪 buddy merge:combined 页只有在两个 buddy 都带 PG_zeroed(或 reported 且 host 清零)时才保留该标志;expand() 在 split 时把标志传给被切分的尾页;try_to_claim_block() 在跨 migratetype 窃块时主动丢弃。
  • 在 page_reporting_drain() 里,如果 driver 声明 host_zeroes_pages,则在 __SetPageReported(page) 的同时 __SetPageZeroed(page),用 page_reporting_host_zeroes 静态键控制快路径开销。
  • post_alloc_hook() 增加 pghint_t *hints 参数,读到 PageZeroed 后清除该位、写回 PGHINT_ZEROED,并将 init 置为 false 让 kernel_init_pages() 跳过清零;prep_new_page() 和 get_page_from_freelist() 相应透传 hints。
  • Fault/分配路径上,vma_alloc_zeroed_movable_folioalloc_anon_foliovma_alloc_anon_folio_pmd 以及 memfd、hugetlb pool 代码使用 hints 跳过 folio_zero_user();balloon deflate 增加 free_frozen_pages_hint/put_page_hint 把 deflate 回来的零页标为 zeroed 再入 buddy。
  • virtio_balloon 增加 host_zeroes_pages 模块参数(feature flag 之前的测试接口),page_reporting 加 flush sysfs 参数绕过 2 秒延迟便于 benchmark。

收益

作者在 2 GB VM、1 vCPU、分配 256 MB 匿名页场景下给出了 perf stat 的结果:

场景
指标
baseline
optimized
delta
THP 匿名页
task-clock
191 ± 31 ms
60 ± 35 ms
-68%
THP 匿名页
cache-misses
1.10M ± 460K
269K ± 31K
-76%
THP 匿名页
instructions
4.54M ± 275K
4.10M ± 130K
-10%
hugetlb surplus
task-clock
183 ± 24 ms
45 ± 23 ms
-76%
hugetlb surplus
cache-misses
1.27M ± 544K
270K ± 16K
-79%
hugetlb surplus
instructions
5.37M ± 254K
4.94M ± 155K
-8%

作者说明最大收益来自 THP 场景——一次性分配 order-9 zeroed 块,2 MB 清零直接被省掉;order-0 路径因碎片化只有约 21% 分配来自 reported 页。持久 hugetlb pool 页不走 buddy 归还因此不受益。


2. mm:folio refcount 伸缩性改进(基于专用 bit 的 refcount 锁)

系列[PATCH v2 0/2] mm: improve folio refcount scalability作者: Gorbunov Ivan / Gladyshev Ilya版本: v2(2 个 patch)

背景

Linux 的 folio/page 引用计数目前用"0 = dead/frozen"的约定。folio_try_get()/page_ref_add_unless_zero() 因此必须用 atomic_add_unless(&_refcount, nr, 0),其内部是一个 CAS 循环:读 → 检查是否为 0 → CAS。对只读 page cache 上的高频并发读,这种 "do-not-touch-if-zero" 的 CAS 构成一个显著的串行化点——多核同时 try_get 同一 folio 时彼此反复失败-重试,伸缩性很差。同时,"0 = frozen" 的语义把"临时归零(正在 dec_and_test)"与"永久冻结(待释放)"两种状态混在一起,一旦想让 frozen 页也保留非零计数就会产生歧义。这套 v2 修订基于 Andrew 和 Linus 在 v1 的反馈,补齐了 frozen 页初始化、page_ref_count 语义和 debug 断言。

解决的问题

  • folio_try_get 的 CAS 循环在高并发读场景成为 hot path 瓶颈
  • 0 值同时表示"未被持有的合法页"和"已冻结的死页",语义混淆
  • page_ref_add/page_ref_inc 等修改接口可被误用于 frozen 页,无法用编译/运行时手段检测

如何做

方案分两步,由两个 patch 实现:

  1. **"drop page refcount zero state semantics"**(Gorbunov Ivan)先剥离"0 == frozen"的不变量。引入 set_page_count_as_frozen(page) 替换所有 set_page_count(p, 0) 位点(p2pdmakexec_handoverhugetlb tail vmemmap、zone device page、CMA、__free_pages_core 等),语义上明确"这是故意冻结而非计数归零"。同时在 page_ref_addpage_ref_subpage_ref_incpage_ref_decpage_ref_inc_returnpage_ref_dec_returnfolio_ref_sub_return 等所有修改接口里加 VM_BUG_ON(__page_count_is_frozen(...)),debug 内核下自动抓"修改 frozen 页计数"的调用者。page_ref_count 继续对 frozen 页返回 0,保持对旧调用方的兼容。

  2. **"implement page refcount locking via dedicated bit"**(Gladyshev Ilya,Linus 已 Ack)把 frozen 状态编码进 _refcount 的专用位 PAGEREF_FROZEN_BIT = BIT(31)。新的四态模型:

    page_ref_add_unless_zero() 因此改成乐观路径

    int val = atomic_add_return(nr, &page->_refcount);
    ret = !(val & PAGEREF_FROZEN_BIT);
    while (unlikely((unsigned int)val >= _PAGEREF_FROZEN_LIMIT))
        val = atomic_cmpxchg_relaxed(&page->_refcount, val, PAGEREF_FROZEN_BIT);

    即直接 atomic_add_return消除 CAS 循环;只有在事后检查 FROZEN_BIT 命中(极罕见)时才用 CAS 把计数回滚到 PAGEREF_FROZEN_BIT,同时保护高位不被溢出。page_ref_freeze() 改为 CAS 到 PAGEREF_FROZEN_BIT 而非 0;page_ref_count() 读到 FROZEN_BIT 时仍对外返回 0,避免破坏其他地方的假设;page_ref_dec_and_test/page_ref_sub_and_test 在测到 0 后额外 cmpxchg(0 → PAGEREF_FROZEN_BIT) 完成从"无 owner"到 frozen 的一步转换。

    • 有 owner:1…INT_MAX
    • 无 owner(仅 dec_and_test 瞬时):0
    • frozen:INT_MIN…-1

收益

封面信未给出具体的 benchmark 数字,作者在改动描述里指出"CAS 循环在高频文件读操作中构成瓶颈",可推断预期收益为:

  • page cache 高并发读(多核同一 folio get/put)减少 CAS 重试,吞吐提升
  • folio_try_get() 快路径从一次可能重试的 CAS 变成一次无条件 atomic_add_return 加位检查,单次成本下降
  • 理论上消除了分支预测不稳定导致的 jitter,对实时/低延迟路径更友好

Linus 已对 refcount locking patch 给出 Acked-by,Andrew Morton 在 v1 讨论中也表态支持,说明核心思路已获得共识,具体性能数据留待合入后的 kernel test robot 或作者后续补充。


3. mm/mmu_gather:TLB flush 已发 IPI 时跳过冗余 sync IPI

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

背景

mmu_gather 子系统在释放/解除共享页表时,除了 TLB flush 还会调用 tlb_remove_table_sync_one()smp_call_function 广播 IPI)或 tlb_remove_table_sync_rcu()synchronize_rcu)来同步软件/无锁页表遍历者(主要是 GUP-fast)。两个核心场景依赖这个同步:hugetlb PMD unshare 时要防止 last user 把 PMD 页表重用于其他用途;khugepaged collapse 时要阻止并发 GUP-fast 拿到即将被折叠/重新 deposit 的页表。问题是,x86 native 的 flush_tlb_multi() 在没有 INVLPGB 时本身已经给所有相关 CPU 发了 IPI——这些 IPI 会推动目标 CPU 退出 IRQ-disabled 区,等价于广播同步。紧接着再发一轮 sync IPI 就是冗余,而且会干扰所有 CPU,在大服务器和 RT workload 上都被观测到有明显代价(cover letter 引用了 RT 子系统针对该问题的报告)。David Hildenbrand 最初提出两步方案,Lance Yang 在此基础上经过 v1–v9 多轮迭代落地第一步。

解决的问题

  • 大核心数机器上 tlb_remove_table_sync_one() 的 IPI 广播打断所有 CPU,即使操作是单进程 hugetlb/khugepaged
  • RT workload 被这些冗余 IPI 破坏延迟预算
  • 现有 PV 抽象里 hypervisor 后端的 flush 实现不保证 IPI,无法简单"一刀切"跳过

如何做

核心是在前置 TLB flush 确认已发 IPI 时,让后续 sync 早退出

  • 在通用层 include/asm-generic/tlb.h 新增弱钩子 tlb_table_flush_implies_ipi_broadcast(),默认 return falsemm/mmu_gather.c 的 tlb_remove_table_sync_one() 与 tlb_remove_table_sync_rcu() 各加一个 early-return 判断——前者跳过 smp_call_function(tlb_remove_table_smp_sync, ...),后者跳过 synchronize_rcu()
  • x86 下用静态键 DEFINE_STATIC_KEY_FALSE(tlb_ipi_broadcast_key) 做零开销判定。native_pv_tlb_init() 在 native_smp_prepare_boot_cpu() 里一次性决策:如果 pv_ops.mmu.flush_tlb_multi == native_flush_tlb_multi 且 !cpu_feature_enabled(X86_FEATURE_INVLPGB),则 static_branch_enable(&tlb_ipi_broadcast_key)。PV 后端(KVM、Xen、Hyper-V)不被信任;INVLPGB 不保证 IPI,主动排除。
  • arch/x86/include/asm/tlb.h 的 tlb_flush() 改为把 tlb->unshared_tables 当作 freed_tables 一起处理:flush_tlb_mm_range(mm, start, end, stride, tlb->freed_tables || tlb->unshared_tables),确保 unsharing 路径也会给 lazy-TLB CPU 发 IPI,才能安全地让 tlb_table_flush_implies_ipi_broadcast() 返回 true。
  • David 最初构想的"仅对正在做 lockless walk 的 CPU 发定向 IPI"被拆成 Step 2(早期原型显示约 3% 的 GUP-fast 开销,需要继续调优),本系列只做 Step 1。

版本演进也值得注意:v1–v3 用动态 IPI 跟踪;v4 改为 David 的两步方案;v5 保持 PV 后端属性为 false;v6 引入 static_branch 消除分支开销(Peter Zijlstra 建议);v7 清理 PV backend 属性;v8 加 CAL 中断数据(Andrew 要求);v9 仅 rebase 到 mm-new。

收益

作者在 64-core Intel x86 服务器上用 khugepaged collapse 20 GiB 范围作为 workload,对比 /proc/interrupts 里的 CAL(Function call interrupts) 条目:

指标
baseline CAL 中断
646,316
应用本系列后 CAL 中断
785
削减幅度
约 823 倍(-99.88%)

这个数字直接量化了"冗余 sync IPI"的实际成本:一次 20 GiB collapse 本身只涉及少量 CPU 的页表,却触发了近 65 万次 function-call IPI 广播。去除后除了降低发起者自身的 sync 延迟,更重要的是消除了对其他 63 个 CPU 的干扰,对 RT workload 与大规模共托管场景都有明确收益。David Hildenbrand 已给出 Acked-by。


4. mm/vmalloc:vrealloc() 缩容时释放尾部物理页

系列[PATCH v11 0/5] mm/vmalloc: free unused pages on vrealloc() shrink作者: Shivam Kalra版本: v11(5 个 patch)

背景

vrealloc() 是 vmalloc 家族中类似 krealloc() 的接口,用于在保持原有虚拟地址的前提下对 vmalloc 区域进行扩缩。然而长期以来,当 vrealloc() 被要求缩小一个分配时,它只更新簿记信息(requested_size、KASAN shadow),并不真正释放底层的物理页。原始代码中甚至留有一条 TODO:

"TODO: Shrink the vm_area, i.e. unmap and free unused pages. What would be a good heuristic for when to shrink the vm_area?"

这意味着调用者逻辑上"释放"的这部分物理内存,会在整个 allocation 的生命周期里一直被占用,造成持续的内存浪费。一个具体且即将上游的真实用户是 Rust binder 驱动的 KVVec::shrink_to,它显式依赖 vrealloc() 收缩来做内存回收,但目前该路径等价于 no-op。

解决的问题

  • vrealloc() 缩小分配时尾部物理页无法归还 buddy allocator,导致进程/内核模块在 vmalloc 上的实际 RSS 只增不减。
  • 原来的 grow-in-place 判断基于 alloced_size = get_vm_area_size(vm),一旦支持 shrink 后,虚拟保留不变但物理页已减少,这个判断会错误地放过对已释放页的访问。
  • vread_iter()/proc/vmallocinfo 等读者依赖 vm->size 反映实际可访问的页数,shrink 后需要新的真实来源。
  • 缺少覆盖 grow-realloc / 跨页 shrink / 页内 shrink / in-place grow 四条路径的回归测试。

如何做

整套方案以"保留虚拟地址保留区,只在跨越 page 边界时释放尾部物理页"为核心。Patch 1 从 vfree() 中抽出一个通用辅助 vm_area_free_pages(vm, start_idx, end_idx),集中处理 NR_VMALLOC 统计、VM_MAP_PUT_PAGES 语义与 cond_resched(),并把 vm->pages[i] = NULL 写入以防止 vm_struct 存活时残留悬空指针。Patch 2、3 是前置条件:grow-in-place 的判断改为 size <= vm->nr_pages << PAGE_SHIFTvread_iter() 的边界也从 get_vm_area_size() 切换到 vm->nr_pages,把"物理页数"确立为唯一事实源。

Patch 4 在 vrealloc_node_align_noprof() 中替换掉 TODO:只有当 new_nr_pages < vm->nr_pages 且 page_order == 0 时才走 shrink,并在下列任一条件下保守跳过:VM_FLUSH_RESET_PERMS(需要先 reset 直接映射权限)、VM_USERMAPremap_vmalloc_range_partial 用 vm->size 做校验)、以及 !gfp_has_io_fs(flags)kmemleak_free_part 内部用 GFP_KERNEL 会触发文件系统/IO 回收递归)。临界区取 addr_to_node(addr)->busy.lock 保护 vm->nr_pages 的写入以同步并发读者,然后依次调用 kmemleak_free_part()vunmap_range()vm_area_free_pages()。值得注意的是 addr 先经过 kasan_reset_tag()——这是 v8 修掉 "获取错误 node 锁" bug 的关键点。Patch 5 在 lib/test_vmalloc.c 加上 vrealloc_testrun_test_mask bit 12 = 4096),每轮 PAGE_SIZE → 4*PAGE_SIZE → PAGE_SIZE → PAGE_SIZE/2 → PAGE_SIZE 覆盖四条路径,并通过首字节 'a' 验证跨 realloc 数据完整性。

收益

作者未提供 throughput/latency benchmark,但从代码语义可精确推断收益:对于任意一次跨页 shrink(从 old_nr_pages 降到 new_nr_pages),可立即向 buddy 归还 (old_nr_pages - new_nr_pages) * PAGE_SIZE 字节物理内存;原本这部分内存要等到整个分配 vfree() 时才能释放。典型用户如 Rust binder KVVec::shrink_to 以及任何基于 vrealloc 的动态缓冲区,内存占用将严格跟随逻辑使用量。测试覆盖:KASAN KUnit vmalloc_oob 通过;lib/test_vmalloc 3/3 stress 各 100 万迭代;checkpatch、sparse、W=1 allmodconfig、coccicheck 全部 clean。


5. mm/alloc_tag:early PFN 固定数组替换为动态链表

系列[PATCH v1] mm/alloc_tag: replace fixed-size early PFN array with dynamic linked list作者: Hao Ge版本: v1(1 个 patch)

背景

内存分配性能分析(CONFIG_MEM_ALLOC_PROFILING)依赖给每页打 codetag,记录 allocation site。然而有一类页在 page_ext 初始化之前就被分配出来(CPU hotplug 回调中的 tracing ring buffer、scheduler per-CPU 数据等),这些页的 codetag ref 未被初始化,如果将来被 free 会触发 alloc_tag_sub_check() 的 "alloc_tag was not set" 警告。现有机制是:用一个 __initdata 静态数组 early_pfns[EARLY_ALLOC_PFN_MAX] 记录这些 PFN,page_ext 上线后在 clear_early_alloc_pfn_tag_refs() 里把它们的 codetag 清成 CODETAG_EMPTY。问题出在那个 8192 的常量:early 分配数与 CPU 数量线性相关,在大核机器上会超过这个上限,触发 pr_warn_once("Early page allocations before page_ext init exceeded EARLY_ALLOC_PFN_MAX (%d)\n", ...) 并漏记录,随后在 free 时抛出告警。之前代码里已经有一条 TODO:

"TODO: Replace fixed-size array with dynamic allocation using a GFP flag similar to ___GFP_NO_OBJ_EXT to avoid recursion."

本 patch 就是落地这个 TODO。

解决的问题

  • 固定 8192 条目的 early_pfns[] 在大 CPU 核数机器上会溢出,漏记录 PFN 并产生后续误报警告。
  • 直接改成 alloc_page() 动态扩容会递归:alloc_page() 本身会进入 __pgalloc_tag_add() -> alloc_tag_add_early_pfn() -> alloc_page(),无限递归。
  • 需要一条能从 gfp 层一路传到 __pgalloc_tag_add() 的"跳过 early PFN 记录"通道。

如何做

核心是两件事:gfp flag 通路 + 自举式 slab-of-nodes。首先新增语义 flag __GFP_NO_CODETAG(为了不占新 bit,别名复用 __GFP_NO_OBJ_EXT),并提供 should_record_early_pfn(gfp_t) inline helper。然后把 gfp_flags 一路加到函数签名:__pgalloc_tag_add(page, task, nr, gfp_flags) 与 pgalloc_tag_add(...)post_alloc_hook() 调用点更新为 pgalloc_tag_add(page, current, 1 << order, gfp_flags)。在 __pgalloc_tag_add() 的 else 分支(page_ext 尚未就绪时),先 alloc_tag_set_inaccurate(task->alloc_tag),再 if (unlikely(!should_record_early_pfn(gfp_flags))) return;——这是递归截断点。

数据结构侧,early_pfns[] 静态数组被换成:

structearly_pfn_node {structearly_pfn_node *next;unsignedlong pfn; };
#define NODES_PER_PAGE (PAGE_SIZE / sizeof(struct early_pfn_node))
staticstructearly_pfn_node *early_pfn_list __initdata;
staticstructearly_pfn_node *early_pfn_freelist __initdata;
staticstructpage *early_pfn_pages __initdata;

alloc_early_pfn_node() 是自举核心:先用 try_cmpxchg 从 early_pfn_freelist 无锁弹一个 node;freelist 空则 alloc_page(GFP_ATOMIC | __GFP_NO_CODETAG | __GFP_ZERO),把整页切成 NODES_PER_PAGE 个 node 串成 freelist;同时用 page->private 把这些承载页自己串成 early_pfn_pages 链表,方便清理阶段一并 free。由于承载页本身带 __GFP_NO_CODETAG__pgalloc_tag_add() 不会递归记录它们。__alloc_tag_add_early_pfn() 随后把新节点 try_cmpxchg 进 early_pfn_list 头部。

清理阶段 clear_early_alloc_pfn_tag_refs() 改为遍历链表:for (ep = early_pfn_list; ep; ep = ep->next),逐一 pfn_valid 检查并 update_page_tag_ref;最后新增一段循环遍历 early_pfn_pages,对承载页 clear_page_tag_ref() 再 __free_page()——因为这些承载页当初以 __GFP_NO_CODETAG 分配、ref 未设置,必须先主动 CODETAG_EMPTY 化避免 free 时告警。

收益

作者未提供 benchmark 数字,但实际收益精确可推:(1) early PFN 记录容量从硬上限 8192 变为受可用物理内存限制——在 PAGE_SIZE = 4096 下每页承载 NODES_PER_PAGE = 4096 / 16 = 256 个节点,扩容粒度 4KB,可无声扩展到百万级 early allocation,彻底消除大核数机器上的溢出告警与 "alloc_tag was not set" 误报;(2) 稳态内存占用反而更低——先前 8192 项数组固定占用 8192 * sizeof(unsigned long) = 64 KB __initdata,新方案按实际数量动态分配承载页,典型机器 early 分配远少于 8192,实际占用只需一到若干 4 KB 页;(3) 所有 __initdata 状态在 clear_early_alloc_pfn_tag_refs() 末尾被 __free_page() 归还,init 结束后内存占用归零。整体效果是用一个 gfp flag 的"自举跳过"技巧,把固定数组换成了零额外成本、无上限的动态结构。


6. rust: maple_tree:为 MapleTree 实现 Send 与 Sync

系列[PATCH RFC v1] rust: maple_tree: implement Send and Sync for MapleTree作者: Joel Fernandes(NVIDIA)版本: RFC v1(1 个 patch)

背景

Rust for Linux 的 MapleTree<T> 抽象层建立在 C 侧 struct maple_tree 之上,而该 C 结构体内部字段包含 *mut c_void(裸指针)。按照 Rust 编译器规则,原始指针默认既不实现 Send 也不实现 Sync,于是所有包含 Opaque<bindings::maple_tree> 的 Rust 类型都会自动丧失 Send/Sync 能力。这种自动传播沿着类型嵌套链一路向上扩散:MapleTree<T> → MapleTreeAlloc<T> → Pin<Box<MapleTreeAlloc<()>, Kmalloc>> → 驱动侧的 Vmm → BarUser → Gpu → NovaCore。而 pci::Driver trait(见 rust/kernel/pci.rs:294)要求 implementor 类型必须满足 Send bound,于是 nova-core GPU 驱动在编译期就彻底无法通过检查。本 patch 虽然没有打 Fixes: tag(属于 RFC,补齐 Rust 抽象而非修一个已上游的 C bug),但解决的是 Rust 内核驱动端一个立刻阻塞编译的实际问题。

解决的问题

  • nova-core 驱动(drivers/gpu/nova-core/driver.rs:77)由于 MapleTree<T> 不满足 Send 而无法被 impl pci::Driver for NovaCore 接受,编译期报错 error[E0277]: *mut c_void cannot be sent between threads safely
  • 任何在 PCI/平台驱动中持有 MapleTree 的 Rust 抽象都被阻塞,无法进入多线程上下文。
  • MapleGuard 原本是 tuple struct,不显式阻止 Send,但 spinlock 必须由获取它的同一 CPU 释放,跨 CPU 传递 guard 会造成 UB 风险。

如何做

核心做法是显式手动 unsafe impl

unsafeimpl<T: ForeignOwnable + SendSendfor MapleTree<T> {}
unsafeimpl<T: ForeignOwnable + SendSyncfor MapleTree<T> {}

安全性论证基于两个不变式——所有对内部树的访问必须通过 ma_lock 自旋锁,或者通过独占的 &mut MapleTree;trait bound T: Send 保证内部存储的值本身也能跨线程传递。与此同时,MapleGuard 被从元组结构体重构为带命名字段的结构体,并新增 _not_send: NotThreadSafe(即 PhantomData<*mut ()>,定义于 rust/kernel/types.rs:435)以显式禁用自动派生的 Send。这是内核 Rust 抽象层的标准惯用法,seq_file.rsxarray.rs 都采用同一模式阻止 guard 跨 CPU 迁移。随之而来的细节调整:旧的 self.0 字段访问一律改写为 self.tree,覆盖 Drop::dropma_stateload 等方法。

收益

修复后,任何 T: Send + ForeignOwnable 类型参数化的 MapleTree<T> 都可以跨线程传递与共享引用,nova-core 立即能够满足 pci::Driver 的 Send bound 并通过编译;同时 MapleGuard 仍然被严格绑定到获取 spinlock 的 CPU 上,保证了 spinlock 释放的 locality 语义。这是让内核 Rust 子系统生态(存储 GPU VMM 地址区间、跟踪驱动资源等场景都需要 MapleTree)向前迈进的必要一步。


7. mm/page_alloc:修复 init_on_free 下 huge zero folio MTE tag 未清零

系列[PATCH v1] mm/page_alloc: fix initialization of tags of the huge zero folio with init_on_free作者: David Hildenbrand(Arm)版本: v1(1 个 patch,Cc stable)

背景

arm64 MTE(Memory Tagging Extension)通过为每 16 字节物理内存附加一个 4-bit tag 来做硬件内存安全检查。架构文档 Documentation/arch/arm64/memory-tagging-extension.rst 明确保证:"allocation tags are set to 0 when a page is first mapped to user space"。该保证在常规 user PTE 路径上由 set_pte_at() 系列检测 PG_mte_tagged 未置位时完成 tag 初始化;但透明大页 zero folio(huge zero folio)通过一个带 special 标记的 PMD 映射到用户空间,完全绕过了上述 PTE 路径,因此 tag 必须在分配时就通过 __GFP_ZEROTAGS 预先清零。本 patch 修复 Fixes: adfb6609c680 ("mm/huge_memory: initialise the tags of the huge zero folio") 引入的一个边缘场景缺陷——当系统同时开启 init_on_free 时,原有路径不会再走 tag 清零分支,结果 huge zero folio 向用户空间暴露了残留 tag。

解决的问题

  • post_alloc_hook() 中旧代码 bool zero_tags = init && (gfp_flags & __GFP_ZEROTAGS),而 init_on_free 开启时 want_init_on_alloc() 返回 true 但 want_init_on_free() 同时为 true,导致 init 为 false,从而 zero_tags 也为 false,MTE tag 不会被清零。
  • 作者修改 arm64 MTE selftest check_buffer_fill 使其使用 2 MiB 区域(触发 huge zero folio),并在释放时确保 pages 带有非 0 tag,复现出:

    not ok 17 Check initial tags with private mapping, sync error mode and mmap memory not ok 18 Check initial tags with private mapping, sync error mode and mmap/mprotect memory

  • 违反架构文档承诺,用户空间可能读到前任 owner 的 MTE tag,产生错误的 tag check fault 或安全风险。

如何做

patch 在语义层面将 __GFP_ZEROTAGS 与 __GFP_ZERO/init 解耦:

constbool zero_tags = kasan_hw_tags_enabled() && (gfp_flags & __GFP_ZEROTAGS);
...
if (zero_tags) {
    tag_clear_highpages(page, 1 << order, /* clear_pages= */init);
    init = false;
}

zero_tags 的判定不再依赖 init,只要 HW tags 启用且 caller 请求 __GFP_ZEROTAGS,就无条件清 tag。tag_clear_highpages() 的 arm64 实现新增 clear_pages 参数:当 clear_pages=true 时调用 mte_zero_clear_page_tags()(同时清 tag 与页内容),false 时调用 mte_clear_page_tags()(只清 tag)。这样无论 init_on_free 是否已把页清零,tag 初始化都不会漏掉。顺带做的清理:删掉通用 #ifndef __HAVE_ARCH_TAG_CLEAR_HIGHPAGES stub 和返回值,改为由 post_alloc_hook() 直接判断 kasan_hw_tags_enabled() 再调用,让调用路径更清晰。gfp_types.h 的注释也同步更新,明确 __GFP_ZEROTAGS 现在在 init_on_free 场景下仍会清 tag。

收益

修复后,init_on_free=1 + arm64 MTE + THP 三个特性共存的场景下,huge zero folio 首次映射到用户空间时 allocation tag 一定为 0,恢复了 Documentation/arch/arm64/memory-tagging-extension.rst 的架构保证;重新跑 MTE selftest check_buffer_fill 的 test 17/18 应通过。因为带 stable tag,该修复会回合到 LTS 内核,避免生产环境上带 MTE 的 arm64 服务器(AWS Graviton 等)出现间歇性用户态 tag check fault。作者也预告了后续 cleanup 方向——继续解耦 __GFP_ZEROTAGS 与 __GFP_SKIP_KASAN、将 KASAN 魔术抽到独立 helper。


8. mm/filemap:避免高阶 folio 分配进入昂贵回收路径

系列[PATCH v2] mm/filemap: avoid costly reclaim for high-order folio allocations作者: Salvatore Dipietro(Amazon Development Center Italy)版本: v2(1 个 patch,Cc stable)

背景

本 patch 修复 Fixes: 5d8edfb900d5 ("iomap: Copy larger chunks from userspace") 引入的严重性能回归。该提交将 iomap buffered write 路径升级为尝试分配高阶 folio(high-order folio)以一次拷贝更大块用户态数据,本意是减少 page 数量与提升吞吐。然而 __filemap_get_folio() 在碎片化内存下反复尝试超过 PAGE_ALLOC_COSTLY_ORDER(order=3,即 8 pages/32KiB)的分配时,每次失败都会触发 __alloc_pages_slowpath() 中的 direct compaction 与 drain_all_pages() 的昂贵路径。v1 版本作者曾试图在 iomap 层修,v2 把修复下沉到 mm/filemap 层,使修复覆盖所有复用 __filemap_get_folio() 的调用者。

解决的问题

  • iomap 高阶 folio 分配在内存碎片化场景下进入反复 compaction + drain 路径,造成 pgbench simple-update 吞吐在 96-vCPU arm64 系统、1024 并发客户端下出现 0.75x 的回归(即下降到基线 75%)。
  • 原始代码 if (order > min_order) alloc_gfp |= __GFP_NORETRY | __GFP_NOWARN; 对所有超过 min_order 的 order 一视同仁,但对 costly order 而言 __GFP_NORETRY 仍允许进入 direct reclaim / compaction,成本过高且收益微乎其微。
  • 任何频繁触发高阶 buffered write 的负载(数据库 OLTP、日志密集写入)都在此类碎片化内存场景下受影响。

如何做

核心改动仅 7 行,按 order cost 分级处理:

if (order > min_order) {
    alloc_gfp |= __GFP_NOWARN;
if (order > PAGE_ALLOC_COSTLY_ORDER)
        alloc_gfp &= ~__GFP_DIRECT_RECLAIM;
else
        alloc_gfp |= __GFP_NORETRY;
}

分级策略的设计逻辑:

  • order > PAGE_ALLOC_COSTLY_ORDER(>3,即 >32KiB):剥掉 __GFP_DIRECT_RECLAIM,让分配变成纯粹 opportunistic——只扫 freelist,空即立刻返回 NULL。由外层循环降阶重试(order = max(min_order, order / 2) 之类逻辑)或 fallback 到更小 folio。
  • **min_order < order ≤ PAGE_ALLOC_COSTLY_ORDER**:保留 __GFP_NORETRY,允许一次轻量级 direct reclaim 但不做重试,不调用重 compaction。

这种分层避开了 __alloc_pages_slowpath() 对 costly order 反复 compaction 的热点,同时保留非 costly order 的回收机会。

收益

作者在提交信息中明确引用了基准数据(精确原文保留):

  • 平台:96-vCPU arm64 系统
  • 负载:pgbench simple-update,1024 并发 clients
  • 回归场景5d8edfb900d5 引入后出现 0.75x 吞吐下降
  • 修复后:throughput 恢复到 148k TPS,相对 regressed baseline 改进 +67%
  • 稳定性:stable across all iterations(多轮迭代间无抖动)

带 Cc: stable@vger.kernel.org,意味着将回合到 LTS 分支修复线上生产环境(亚马逊等云厂商的 Graviton 机型是典型受影响平台)。从架构角度看,这个 patch 也为 mm/filemap 的高阶 folio 分配确立了"opportunistic fast path + lightweight slow path"的分层惯例,对未来 large folio 在 page cache 的全面铺开有借鉴意义。


9. vmalloc:修复 vrealloc_node_align() 缩容时 memcpy 越界写

系列[PATCH] vmalloc: fix buffer overflow in vrealloc_node_align()作者: Marco Elver(Google)版本: v1(1 个 patch,Cc stable)

背景

本 patch 修复的问题由 Fixes: 4c5d3365882d ("mm/vmalloc: allow to set node and align in vrealloc") 引入。该前置 commit 给 vrealloc() 增加了 NUMA node 指定与 alignment 约束能力:当用户请求的 node 不匹配当前分配所在 node,或指定的 align 与现有对象不兼容时,即便用户只是想"缩小"这个对象,代码也会走 need_realloc 路径,强制重新分配一块新的 vmalloc 区域,再把旧内容拷贝过去。问题在于拷贝长度没有按新的目标 size 做 clamp,仍然按 old_size 进行 memcpy。当 size < old_size(缩容)且 need_realloc 触发时,就会从源拷贝比目标缓冲区更多的字节,形成对新分配缓冲区的越界写。漏洞由 Harry Yoo(Oracle)发现并报告。

解决的问题

  • vrealloc_node_align_noprof() 在 need_realloc(node/align 不兼容)+ 缩容(size < old_size)路径下触发堆越界写。
  • 越界写越过目标分配区域,可能破坏相邻 vmalloc 映射或其 guard page 语义。
  • 作为 vrealloc 缩容路径语义错误,任何调用 vrealloc(p, size) 并尝试 shrink 的 caller(例如 Rust binder 的 KVVec::shrink_to 一旦落在 need_realloc 分支上)都可能触发。

如何做

修复极简(单行),核心是把 memcpy 的长度由 old_size 改为 min(size, old_size)

if (p) {
-    memcpy(n, p, old_size);
+    memcpy(n, p, min(size, old_size));
     vfree(p);
 }

逻辑上:need_realloc 路径会先 __vmalloc_node() 分配一块新的 vmalloc 对象 n(大小严格等于用户请求的 size),然后从旧对象 p 拷贝到 n。当 size >= old_size(扩容或等大),仍然拷贝 old_size 字节即可(剩余部分由新分配完成);当 size < old_size(缩容),则只能拷贝目标能容纳的 size 字节。用 min(size, old_size) 一步覆盖两种方向,简单正确。修复后旧对象保持完整、vfree(p) 正常归还。

收益

修复了一条真实的堆越界写通道。带 Cc: stable@vger.kernel.org,将回合到包含 4c5d3365882d 的所有 LTS/发布版本。相关联的 "mm/vmalloc: free unused pages on vrealloc() shrink"(本期 #4)在 vrealloc 缩容语义成立后会频繁走 shrink 路径,该修复与之是刚性前置依赖——若未 fix,#4 的工作在 NUMA/对齐不匹配场景下会立即暴露此越界写。作者未提供 exploit 或性能数据(bug fix 本身不需要),修复后的正确性收益可直接由代码推断。


10. mm/damon/sysfs-schemes:修复 memcg_path 与 goal path 的 UAF/double-free

系列[PATCH v2] mm/damon/sysfs-schemes: fix use-after-free on memcg_path and goal path作者: Junxi Qian版本: v2(1 个 patch)

背景

DAMON(Data Access MONitor)通过 sysfs 向用户空间暴露 scheme filter 的 memcg_path 和 quota goal 的 path 两个字符串属性。这些字符串写入后会被 kdamond 工作线程在 damon_sysfs_add_scheme_filters() 与 damos_sysfs_add_quota_score() 中通过 damon_call() 异步读取并解析(例如 damon_sysfs_memcg_path_to_id() 里把 memcg_path 转成 cgroup ID)。按设计,"commit" 操作由 damon_sysfs_lock 保护;可问题是 memcg_path_store() 与 path_store() 本身没有持 damon_sysfs_lock 就 kfree(filter->memcg_path) 再替换指针,与 kdamond 线程侧的读形成竞争。Fixes: 490a43d07f16 ("mm/damon/sysfs-schemes: free old damon_sysfs_scheme_filter->memcg_path on write")——正是该 commit 加入了 free-and-replace 逻辑但遗漏了锁保护。

解决的问题

  • 竞争窗口:
    • Thread A(commit)持 damon_sysfs_lock,触发 damon_call()
    • kdamond 线程在 damon_sysfs_memcg_path_to_id() 中读 sysfs_filter->memcg_path
    • Thread B(sysfs write)不持锁调用 memcg_path_store()kfree(filter->memcg_path) 并替换指针
  • kdamond 观察到被释放的指针,damon_sysfs_memcg_path_eq() 解引用触发 UAF。
  • 同理 memcg_path_show()/path_show() 无锁读指针,与并发 store 的 kfree 相撞,sysfs_emit() 解引用已释放串。
  • KASAN 在 v7.0.0-rc5 复现出 double-free 于 memcg_path_store+0x6e/0xc0,addr ffff888100a086c0(kmalloc-8 cache):分配由 cpu0 task 147 完成,释放由 cpu0 task 150 完成,随后 task 149 再次释放,栈依次是 kfree → memcg_path_store → kernfs_fop_write_iter → vfs_write → ksys_write

如何做

本质是把"分配新串 → 替换指针 → 释放旧串"三步重排为先在锁内原子替换,再在锁外释放,避免 kfree 持锁过久:

mutex_lock(&damon_sysfs_lock);
old = filter->memcg_path;
filter->memcg_path = path;
mutex_unlock(&damon_sysfs_lock);

kfree(old);

具体改动覆盖四个对称点:

  • memcg_path_store()path_store() 把 kfree(old) 移到锁外。
  • memcg_path_show()path_show() 在锁保护下调用 sysfs_emit(),防止 show 与 store 并发时读到 dangling pointer。

收益

修复了 DAMON sysfs 的 UAF + double-free 双重漏洞。带 Fixes: 标签,KASAN 复现路径明确(reproducer "exp" 程序反复从两个 task 并发写同一 memcg_path 节点即可触发)。对启用 CONFIG_DAMON_SYSFS 且用户态允许非特权进程写 DAMON 控制面的场景尤其重要——UAF 在 kmalloc-8 slab 上高频触发可能被作为提权原语。修复后两类 store/show 并发模式下指针一致性得到保证,kdamond 线程不会再观察到 partial-freed 状态。


总结

新机制 / 新接口

#
系列
要点
1
mm/virtio: skip redundant zeroing of host-zeroed reported pages
 [RFC v2, 18p]
新增 PG_zeroed flag + pghint_t hint API,把 host 已清零信息从 page_reporting 传播到 fault/分配路径
6
rust: maple_tree: implement Send and Sync for MapleTree
 [RFC v1]
为 Rust MapleTree<T> 手动实现 Send/Sync,解除 nova-core GPU 等 PCI Rust 驱动的编译阻塞

性能优化

#
系列
量化数据
1
mm/virtio: skip redundant zeroing
 [RFC v2, 18p]
2 GB VM / 256 MB 匿名 THP:task-clock -68%、cache-misses -76%;hugetlb surplus:task-clock -76%、cache-misses -79%
2
mm: improve folio refcount scalability
 [v2, 2p]
消除 folio_try_get CAS 循环,改为 atomic_add_return+bit 检查的乐观路径;Linus Acked-by,无具体数字
3
skip redundant sync IPIs when TLB flush sent them
 [v9, 2p]
64-core Intel,20 GiB khugepaged collapse:CAL 中断 646,316 → 785(约 823 倍削减,-99.88%)
4
mm/vmalloc: free unused pages on vrealloc() shrink
 [v11, 5p]
vrealloc
 缩容按 page 边界即时归还 (old_nr_pages-new_nr_pages)*PAGE_SIZE 物理内存;Rust binder KVVec::shrink_to 真实用户
5
mm/alloc_tag: replace fixed-size early PFN array with dynamic linked list
 [v1]
容量上限从 8192 解除为受内存限制;__initdata 静态占用从 64 KB 降为按实际分配页数,init 后全归零
8
mm/filemap: avoid costly reclaim for high-order folio allocations
 [v2]
96-vCPU arm64 pgbench/1024 clients:回归 0.75x 被修复,吞吐恢复到 148k TPS,相对 regressed baseline +67%

Bug Fix

#
系列
影响
7
mm/page_alloc: fix tags of huge zero folio with init_on_free
 [v1]
init_on_free
+MTE+THP 场景下用户态可见残留 MTE tag,违反架构保证;Fixes: adfb6609c680,Cc stable
8
mm/filemap: avoid costly reclaim
 [v2]
iomap buffered write 在碎片化内存下触发 compaction/drain,造成 pgbench 0.75x 回归;Fixes: 5d8edfb900d5,Cc stable
9
vmalloc: fix buffer overflow in vrealloc_node_align()
 [v1]
need_realloc
+缩容路径 memcpy 越界写;Fixes: 4c5d3365882d,Reported-by Harry Yoo,Cc stable
10
mm/damon/sysfs-schemes: fix UAF on memcg_path and goal path
 [v2]
sysfs store/show 无锁访问字符串指针,KASAN 复现 double-free;Fixes: 490a43d07f16

内部优化 / 清理

#
系列
要点
mm/gup: pgtable entry accessors cleanup [RFC v1, 2p]
pte = *ptep
 → ptep_get(ptep) 为未来 KASAN PTE 检查器铺路(本期已排除)
docs/mm: clarify no LLM generated content [v1]
仅文档说明,无代码改动(本期已排除)

最新文章

随机文章

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-07-04 09:33:49 HTTP/2.0 GET : https://f.mffb.com.cn/a/488306.html
  2. 运行时间 : 0.151752s [ 吞吐率:6.59req/s ] 内存消耗:4,635.26kb 文件加载:140
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=2ed1b8cffdc60c6f3fbbd91b3f7cae2e
  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.000585s ] mysql:host=127.0.0.1;port=3306;dbname=f_mffb;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.000736s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.043252s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000429s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000683s ]
  6. SELECT * FROM `set` [ RunTime:0.000205s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000608s ]
  8. SELECT * FROM `article` WHERE `id` = 488306 LIMIT 1 [ RunTime:0.001362s ]
  9. UPDATE `article` SET `lasttime` = 1783128829 WHERE `id` = 488306 [ RunTime:0.022939s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 67 LIMIT 1 [ RunTime:0.003517s ]
  11. SELECT * FROM `article` WHERE `id` < 488306 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.004359s ]
  12. SELECT * FROM `article` WHERE `id` > 488306 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.000485s ]
  13. SELECT * FROM `article` WHERE `id` < 488306 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.004190s ]
  14. SELECT * FROM `article` WHERE `id` < 488306 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.001521s ]
  15. SELECT * FROM `article` WHERE `id` < 488306 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.000826s ]
0.153315s