重写 printk()
printk() 函数一直是内核开发者持续关注和担忧的主题。表面上看,它只是一个用于向控制台发送文本的输出例程。但与常规打印例程不同,printk() 必须能够在极端条件下工作,例如当发生可怕的事情并且系统需要在它咽下最后一口气时发出一些最后的线索。
这是一个英雄般的函数。并且像大多数英雄一样,它有很多内在的问题需要在许多冒险过程中解决。被派去与这些内在恶魔作斗争的实体之一是 John Ogness,他发布了一堆补丁。
printk() 的问题之一是它使用全局锁来保护其缓冲区。但这意味着内核中任何不能容忍锁的部分都不能使用 printk()。非屏蔽中断和递归上下文是必须推迟 printk() 使用的两个领域,直到执行上下文返回到正常空间。如果内核在此之前崩溃,它将无法说明出了什么问题。
还有其他问题——很多!由于延迟执行,有时缓冲区可能会变得非常大并且需要很长时间才能清空,这使得任何不喜欢不确定性的代码都难以预测执行时间。此外,出于同样的原因,时间戳可能非常不准确,这使得调试工作更加烦人。
John 希望通过重新实现 printk() 以不再需要锁来解决所有这些问题。在像 Peter Zijlstra 这样的人的分析帮助下,John 提出了一个实现方案,甚至可以在 NMI 上下文深处以及任何其他无法容忍等待的地方工作。
此外,John 的代码不是在过程结束时才获取时间戳,而是在执行时捕获它们,从而实现更准确的调试过程。
他的代码还引入了一个新想法——紧急情况的可能性,以便给定的 printk() 调用可以绕过整个缓冲区并立即将其消息写入控制台。因此,希望即使是最短的最后一口气也可以用来揭示反派的身份。
Sergey Senozhatsky 提出了一个存在性问题:如果新的 printk() 为了容忍在任何上下文中执行而要变为可抢占的,那么是什么阻止崩溃中断 printk() 以便死亡呢?
John 提供了技术解释,这似乎表明 “panic() 可以立即写入有保证的 NMI 安全的 write_atomic 控制台,而无需首先对其他 CPU(IPI、NMI、等待等)执行任何操作,并且不忽略锁。”
具体来说,John 认为他引入的紧急 printk() 消息将解决消息未能及时传达的问题。正如他所说,“只要所有关键消息都直接且立即打印到紧急控制台,那么如果发送到控制台的信息性消息有时会延迟或丢失,那又有什么问题呢?”
在某个时候,有人指出,尽管 John 的重新实现旨在总体上改进 printk(),但他表示,“实际上,我使用我的 printk-kthread 所做的最大设计更改是它仅适用于非关键消息。对于任何关键事项,用户都应该依赖紧急控制台。”
对话并没有持续很长时间,但看起来 John 新的 printk() 实现最终可能会引起争议。它消除了一些与现有实现相关的延迟,但这仅仅是通过将这些延迟降级为它认为不太重要的消息。我猜想,事实证明很难判断哪些消息真的比其他消息更重要。
注意:如果您在上面被提及并想在评论区上方发布回复,请将包含您的回复文本的消息发送至 ljeditor@linuxjournal.com。