在 Linux 内核开发中,如何处理“理论上绝不应该发生、但一旦发生就意味着严重错误”的异常条件,一直是社区争论不休的话题。从最初被滥用的 BUG_ON(),到后来作为替代品推行的 WARN_ON(),再到如今针对 WARN_ON() 的限制与反思,内核开发者们在“保持系统可用性”与“暴露严重隐患”之间展开了一场长达数年的博弈。
一、 从被摒弃的 BUG_ON() 到替代者 WARN_ON()
长期以来,内核开发者习惯使用 BUG_ON() 来捕捉不可恢复的异常状态:
/* 这绝不可能发生,说实话,我怎么会骗你呢? */
BUG_ON(foo_ptr == NULL);
然而,BUG_ON() 会直接引发内核恐慌(kernel panic),导致系统立即崩溃或重启。这种“一言不合就宕机”的做法剥夺了用户保存工作和响应错误的最后机会,同时也让问题根源的追踪变得极其困难。
因此,内核社区早早明确了立场:严禁在新增代码中使用任何 BUG() 变体。内核代码风格文档明确指示,开发者应当使用 WARN*() 变体(尤其是 WARN_ON_ONCE()),并在可能的情况下编写恢复代码(Recovery Code)。
然而,随着时间推移,替代者 WARN_ON() 自身也陷入了尴尬境地。
二、 WARN_ON() 遭遇的新困境与 panic_on_warn
排斥使用 WARN_ON() 的声音主要来自两个层面:
-
用户空间滥用与日志刷屏:任何能从用户空间触发的
WARN_ON(),都可能被恶意利用来刷爆 syslog,引发性能下降或掩盖其他关键日志。 -
panic_on_warn机制的倒逼:内核提供了一个名为panic_on_warn的 sysctl 控制节点。一旦启用该选项,任何触发的WARN_ON()都会直接升级为系统 panic。
在许多 Android 设备以及各大云服务提供商的宿主内核中,panic_on_warn 被默认开启。对于这些使用者而言,任何警示都意味着潜在的安全风险,宁可干掉系统重新开始,也不愿带病运行。这就导致在实际生产环境中,WARN_ON() 产生的后果与被禁用的 BUG_ON() 毫无二致。
为此,Alex Elder 曾提议修改代码风格文档,建议开发者改用 dev_warn*() 或 pr_warn*() 等不会触发 panic 的纯日志打印函数。但这一提议迅速引发了剧烈反弹:
-
Christoph Hellwig 批驳该修改“错得离谱”。
-
Laurent Pinchart 指出,纯日志函数极易被忽视,无法有效督促开发者修复根本问题。
-
Greg Kroah-Hartman 则支持这一改变,认为既然
panic_on_warn用户无视了警告建议,就不应再继续增加新的WARN_ON()。
三、 两种生态的碰撞:Linus Torvalds 的视角
面对这场争论,Linus Torvalds 给出了极具代表性的点评:“如果你设置了 'panic_on_warn',那么出问题时系统碎成什么样你都得自己收拾(get to keep both pieces)。”
Linus 深刻剖析了内核使用场景的差异与对立:
| 场景类型 | 代表环境 | 宕机后果 | 核心诉求与应对 |
| 自动化/虚拟化环境 | 大型云厂商服务器集群、CI 测试(如 syzkaller)、虚拟机 | 宕机影响可控,有完善设施导出调试信息 | 偏好立刻中止,panic_on_warn 是合理的工具。 |
| 真实硬件/桌面环境 | 笔记本电脑、电源管理驱动、实体终端设备 | 无串口输出,宕机即变成“无法调试的死砖” | 绝对承担不起直接干掉机器的后果,BUG_ON() 几乎永远不可接受。 |
Linus 特别强调,自动化测试集群并不能涵盖所有边缘场景。他在日常运行真实硬件时,几乎每个合并窗口都能遇到在测试集群(如 linux-next)中从未露头的异常。在真实硬件场景下,盲目崩溃只会让调测陷入绝境。
四、 核心维护者的回应与当前共识
针对试图因 panic_on_warn 的存在而全面限制 WARN_ON() 的提议,内核内存管理(MM)子系统核心维护者 David Hildenbrand 明确给予了 NACK(拒绝)。
David 引用了他在 2022 年提交的经典 commit(1cfd9d7e43d5a1cf739d1420b10b1e65feb02f88),并强调:
-
原则未变:彻底禁止
BUG_ON(),但依然支持克制、审慎地使用WARN_ON_ONCE()。 -
责任归属:启用
panic_on_warn是运维或厂商的主动选择。他们既然主动要求内核在 Warning 发生时崩溃,就必须承担由此带来的系统易宕机后果,而不能倒逼内核开发者不敢在代码中加入合理的警告逻辑。
这场围绕 WARN_ON() 的讨论,本质上是内核在“虚拟化自动化集群”与“真实硬件终端用户”两种不同使用哲学之间的碰撞。虽然文档变更尚未达成完全共识,但社区的核心基调依然明朗:坚决杜绝 BUG_ON(),克制使用 WARN_ON_ONCE();至于开启了 panic_on_warn 的使用者——既然选择这项配置,就得做好收拾残局的准备。


13万+

被折叠的 条评论
为什么被折叠?



