6.6.110-42.4 loongarch64 hung_task / dio_sparse 分析记录
1. 问题背景
- 缺陷描述来自
bugzilla.txt - 环境:TencentOS Server 4.4
- 内核:
6.6.110-42.4.tl4.loongarch64 - 触发方式:
ts_reliability长时间压力测试 - 最终现象:
Kernel panic - not syncing: hung_task: blocked tasks
相关文件:
bugzilla.txttk5_6.6.110-42.4.tl4.loongarch64_hungtash_20251229_1766999502/vmcoretk5_6.6.110-42.4.tl4.loongarch64_hungtash_20251229_1766999502/vmcore-dmesg.txttk5_6.6.110-42.4.tl4.loongarch64_hungtash_20251229_1766999502/vmlinux-6.6.110-42.4.tl4.loongarch64
2. 初始日志结论
2.1 panic 不是根因,只是结果
ts_reliability/stress.sh 中周期性开启:
kernel.hung_task_panic=1kernel.softlockup_panic=1kernel.hardlockup_panic=1kernel.panic_on_oops=1- 以及其它 panic 开关
因此 hung task 一旦出现,会被放大成 panic。
而 ts_reliability/tst_frame/ts_reliability.c 的 init_os_env() 实际上尝试关闭 hung_task_panic。两者存在策略冲突,stress.sh 覆盖了框架初始化。
2.2 dmesg 中的直接症状
hung 任务为一批 dio_sparse 进程,典型栈:
rwsem_down_write_slowpathdown_writeunlink_anon_vmasfree_pgtablesexit_mmap__mmputexit_mmdo_exit
另有至少一个 dio_sparse 进程更深一层卡在:
__put_anon_vmaunlink_anon_vmasfree_pgtablesexit_mmap
说明问题发生在进程退出时的 mm/rmap 清理路径,而不是普通业务逻辑路径。
3. 测试用例关联
从 vmcore-dmesg.txt 的时间线可确认:
- 多个
dio_sparse系列用例在同一轮压力测试中反复运行 - 最后触发现场的是
DS003 (dio_sparse)启动后约 311 秒出现 hung mem_process/memcg_control的 OOM 是同轮压力中的并发事件,但从时间线看并不是dio_sparse卡死的直接原因
结论:
dio_sparse是触发exit_mmap -> unlink_anon_vmas问题的直接场景memcgOOM 更像背景噪声/压力放大因素
4. 代码树排查结论
4.1 OpenCloudOS vendor 树
代码服务器路径:
/home/robin/Gitee/opencloudos-kernel
已确认 6.6.110-42 版本已经包含较早的修复:
d8ab9f7b644amm: lock VMA in dup_anon_vma() before setting ->anon_vma824135c46b00mmap: fix error paths with dup_anon_vma()ee8ab1903e3dmm: rmap: explicitly reset vma->anon_vma in unlink_anon_vmas()2555283eb40dmm/rmap: Fix anon_vma->degree ambiguity leading to double-reuse
因此,当前问题不是“缺少这几个老补丁”的简单情况。
4.2 主线内核树
主线代码服务器路径:
/home/robin/Kernel/linux
主线中发现了更晚、且更接近现场问题域的提交:
61f67c230a5emm/vma: fix anon_vma UAF on mremap() faulted, unfaulted merge91901a441fa1mm/rmap: eliminate partial anon_vma tear-down in anon_vma_fork()69e945845585mm/rmap: skip unfaulted VMAs on anon_vma clone, unlink535f6b8df17dmm/rmap: remove unnecessary root lock dance in anon_vma clone, unmap3a206a8649f8mm/rmap: clear vma->anon_vma on errora222439e1e27mm/rmap: add anon_vma lifetime debug check
这些提交说明:
- 上游到 2025-2026 仍在继续修
anon_vma生命周期、unlink、error path、UAF 问题 - 当前现场与上游持续修复的问题域高度一致
5. loongarch 机器上的 vmcore 现场分析
分析环境:
- 机器:
robin@10.180.13.141 - 架构:
loongarch64 crash可用vmcore与vmlinux匹配
5.1 关键 backtrace
dio_sparse 进程 2501700:
unlink_anon_vmas -> down_write
dio_sparse 进程 2501708:
unlink_anon_vmas -> __put_anon_vma -> down_write
结论:
- 不只是单点锁竞争
- 至少有不同进程在
unlink_anon_vmas()的不同阶段卡住
5.2 关键异常对象
通过 crash 反查 down_write() 的等待地址后发现:
- 某个等待地址
0x900000014a1b4b40 - 按预期应是
anon_vma->root->rwsem - 但对该地址附近做结构体解析后发现,它实际落在一个
anon_vma_chain对象内部
原始内存显示:
- vma = 0x900000011f567780 - anon_vma = 0x9000000108ffd2b0
0x900000014a1b4b50可被合理解释为anon_vma_chain.same_vma- 该对象中同时能解析出:
而如果强行把 0x900000014a1b4b38 当成 anon_vma 看:
root = 0x2rwsem.wait_list.next = 0x900000011f5677c8
这明显不是合法的 anon_vma->root->rwsem 状态。
5.3 由现场推导出的核心结论
结论不是“正常 rwsem 竞争太久”,而是:
unlink_anon_vmas()路径中使用的anon_vma/root相关对象已经损坏- 内核随后把错误地址当成
rwsem去down_write() - 最终导致多个
dio_sparse进程永久 D 状态
也就是说,问题更像:
anon_vmaanon_vma_chainvma->anon_vmaanon_vma->root
这些对象/指针/生命周期关系在更早阶段已经被破坏。
6. 当前技术判断
按概率排序:
- 内核公共
mm/rmap路径问题 - LoongArch 架构侧放大/触发某个公共问题
- 硬件问题概率最低
目前没有证据表明这是:
- 纯硬件随机比特翻转
- 纯 LoongArch 专属代码 bug
当前最像的是:
anon_vma生命周期anon_vma_chain链接关系unlink_anon_vmas()清理路径- 并发退出场景下的对象错连/UAF/错误恢复缺陷
7. 后续分析方向
下一步建议聚焦主线补丁短名单:
61f67c230a5e91901a441fa169e945845585535f6b8df17d3a206a8649f8a222439e1e27
重点看这些补丁是否解释:
anon_vma提前部分 tear-downunlink_anon_vmas()仍处理不该处理的 VMA- error path 未清空
vma->anon_vma - 某些 faulted/unfaulted VMA merge/fork/unmap 场景导致
anon_vma引用关系错误
8. 主线补丁与现场的进一步对照
8.1 vendor 6.6 树当前仍是旧实现
在 /home/robin/Gitee/opencloudos-kernel 当前 mm/rmap.c 中:
- out_error: - unlink_anon_vmas(vma);
- root = lock_anon_vma_root(root, anon_vma);
anon_vma_fork()在分配anon_vma/anon_vma_chain失败时仍走:unlink_anon_vmas()仍采用:
这与现场卡住栈完全一致:
unlink_anon_vmas()down_write()lock_anon_vma_root()
说明现场路径与旧实现高度吻合。
8.2 主线后续补丁的直接意义
91901a441fa1
该补丁的核心是:
- 避免在
anon_vma_fork()分配失败时 - 把“部分建立完成但无效”的 VMA 再送入
unlink_anon_vmas()
补丁说明里明确写到:
- 老实现会把 partially set up / invalid VMA 传给
unlink_anon_vmas() - 这样危险且容易引入 subtle bugs
这与当前现场非常接近,因为我们现场中:
unlink_anon_vmas()路径里拿到的anon_vma/root已经不是可信对象- 进而对错误地址执行
down_write()
69e945845585
该补丁让以下场景直接返回 no-op:
anon_vma_clone()面对!vma->anon_vmaunlink_anon_vmas()面对!vma->anon_vma
也就是上游进一步明确:
- unfaulted / 未正确接入 anon_vma 的 VMA,不应该继续走 unlink 清理逻辑
这同样在收紧“无效 VMA 被送入 unlink_anon_vmas()”的问题面。
535f6b8df17d
该补丁把 unlink_anon_vmas() 从旧逻辑:
- 逐个
lock_anon_vma_root(root, anon_vma)
改成新逻辑:
- 直接取
active_anon_vma = vma->anon_vma anon_vma_lock_write(active_anon_vma)
也就是不再在 unlink 过程中反复依据链上对象切换/比较 root 锁。
这点和现场尤其贴近,因为现场最强证据就是:
- 某个
down_write()等待地址并不落在合法anon_vma->root->rwsem - 而是落进了一个
anon_vma_chain对象内部
因此,这个补丁虽然未必是唯一修复,但它确实绕开了现场当前最可疑的坏指针使用点。
3a206a8649f8
该补丁在 cleanup_partial_anon_vmas() 结束后明确增加:
vma->anon_vma = NULL;
目的就是避免:
- VMA 部分清理后仍残留一个无效
vma->anon_vma - 从而导致后续 unlink / reuse / num_active_vmas 统计进入不一致状态
这与我们当前“对象关系先坏、后续 unlink 再踩中”的模型也是一致的。
8.3 当前最像的根因模型
结合现场与上游补丁,当前最像的模型是:
- 某个 VMA 在
anon_vma_fork()/ clone / error unwind / cleanup_partial_anon_vmas()` 这类路径上进入了部分建立或部分清理状态。 - 该 VMA 的
anon_vma、anon_vma_chain、root 关系没有被正确清理或保持一致。 - 之后在进程退出的
unlink_anon_vmas()中,旧实现仍继续依据这些不一致对象去lock_anon_vma_root()。 - 最终把错误内存当成
rwsem,造成永久阻塞。
8.4 现阶段最值得优先关注的上游补丁
按与现场贴近程度排序,当前最值得优先关注的是:
91901a441fa1mm/rmap: eliminate partial anon_vma tear-down in anon_vma_fork()69e945845585mm/rmap: skip unfaulted VMAs on anon_vma clone, unlink535f6b8df17dmm/rmap: remove unnecessary root lock dance in anon_vma clone, unmap3a206a8649f8mm/rmap: clear vma->anon_vma on error
补充判断:
- 这几笔修复在主线可见,但在当前 vendor 树里没有检到。
- 因此现场问题很可能属于主线后续已经识别并逐步修正的同类缺陷。
9. 按上游补丁序列回移到 vendor 树
根据用户要求,未再采用“直接魔改”的方式,而是在代码服务器上尽量按上游补丁序列回移。
远端分支信息:
- 仓库:
/home/robin/Gitee/opencloudos-kernel - 基线:
devel分支b1f001b202a1 - 测试分支:
codex/anon_vma_backport_test
已回移的上游补丁主题:
542eda1a8329mm/rmap: improve anon_vma_clone(), unlink_anon_vmas() comments, add asserts91901a441fa1mm/rmap: eliminate partial anon_vma tear-down in anon_vma_fork()69e945845585mm/rmap: skip unfaulted VMAs on anon_vma clone, unlink535f6b8df17dmm/rmap: remove unnecessary root lock dance in anon_vma clone, unmapbfc2b13b05a1mm/rmap: allocate anon_vma_chain objects unlocked when possible3a206a8649f8mm/rmap: clear vma->anon_vma on error
回移方式说明:
- 先将主线补丁导出为 patch。
- 在 vendor 测试分支上优先尝试
git am -3。 542eda1a8329、91901a441fa1、69e945845585可直接应用。535f6b8df17d与bfc2b13b05a1因上下文差异无法自动构造 fake ancestor,采用最小冲突解决后继续git am --continue。3a206a8649f8在前置语义补齐后可直接应用。
最终状态:
- 测试分支最近 6 个提交均为上述 backport 结果。
- 当前改动集中在
mm/rmap.c单文件。 - 相对基线
b1f001b202a1,mm/rmap.c统计为163 insertions(+), 102 deletions(-)。
当前可用于测试的分支:
codex/anon_vma_backport_test
评论