处理 printk()

作者:Zack Brown

考虑到 printk() 本质上只是 printf() 的替代品,并且不需要将标准的 C 库 链接到内核中,因此 printk() 会给内核开发带来如此多的问题,这很奇怪。

然而,众所周知,它一团糟,充满了边缘情况、极端情况、死锁、竞争条件以及各种其他难以解决的问题。 原因是,与 printf() 不同,printk() 系统调用即使在整个系统崩溃时也必须产生合理的行为。 这才是重点——printk() 需要报告错误和警告,这些错误和警告可用于调试刚刚袭击运行系统的任何奇怪和意外的灾难。

同时尝试修复所有死锁和其他问题对于任何人来说都是一项过于庞大的任务,尤其因为每个问题都是由 printk() 调用出现的特定上下文定义的特殊情况。 但是,有时可以一起解决特定代码区域中的一堆实例。

Sergey Senozhatsky 最近试图解决一些 printk() 死锁问题,尽管他承认他不会解决任何由 printk() 代码本身触发单独的递归 printk() 调用引起的实例。 他只想关注非递归的死锁。

Sergey 专注于控制台代码,printk() 通常将其输出发送到该代码,并且控制台代码是 printk() 可能发生死锁的一个地方。 他向代码添加了一个非常小的保护措施,但结果似乎是整个内核中的驱动程序都必须更新以使用新的保护措施。

他的代码并没有得到普遍赞扬。 Alan Cox 注意到 Sergey 的保护措施向“快速路径”添加了代码——快速路径是需要尽可能快速和高效的代码区域,因为它一直运行,每秒多次运行。 减慢快速路径会减慢整个系统。 Alan 建议,与其这样做,不如让内核在控制台代码处于可能发生死锁的位置时简单地不调用 printk()。

然而,Sergey 对此并不满意。 他指出,他的补丁解决了用户报告直接遇到的实际问题。 他不明白仅仅删除触发问题的 printk() 实例会有什么帮助,特别是如果这些实例正在做重要工作,例如报告系统崩溃的真正原因等等。

Sergey 希望保留 printk() 实例并实施保护措施来保护它们。 然而,此时 Linus Torvalds 加入了讨论,并说

规则很简单:那就不要那样做。

不要进行递归锁。 不要制造随机的复杂性。 停止做那些有害的事情。

UART 驱动程序在控制台锁定的关键区域内进行任何类型的 printk() 都是没有正当理由的。

只需删除这些 printk,不要添加新的疯狂锁定。

如果您的自旋锁因为在已经自旋锁定的区域内而死锁,您会说“那是错误”。

这正是同样的问题。 我们不解决有缺陷的垃圾。 我们通过删除有问题的 printk 来修复错误。

Sergey 指出,printk() 实例是从他想要更改的所有驱动程序中调用的。 这不是内核的某些简单部分有额外的 printk() 的情况。 所有驱动程序都需要使用保护措施进行更新,否则它们将继续报告错误的内容。

对话在没有结论的情况下结束。 很难知道何时应该修复某些东西而不是删除它。 会出现各种各样的技术问题,包括想知道修复是否值得所有麻烦。

注意:如果您在上面被提及并想在评论部分上方发布回复,请将包含您的回复文本的消息发送至 ljeditor@linuxjournal.com。

Zack Brown 是 Linux JournalLinux Magazine 的科技记者,并且是“Kernel Traffic”每周新闻通讯和“Learn Plover”速记打字教程的前作者。 他于 1993 年在他的 386 电脑上首次安装了 Slackware Linux,配备 8 兆内存,并被开源社区永久震撼。 他是 Crumble 纯策略棋盘游戏的创造者,您可以用几块纸板自己制作。 他还喜欢写小说、尝试动画、改革拉班舞谱、设计和缝制自己的衣服、学习法语以及与朋友和家人共度时光。

加载 Disqus 评论