The printk() function is a subject of much ongoing consternation among kernel developers. Ostensibly, it's just an output routine for sending text to the console. But unlike a regular print routine, printk() has to be able to work even under extreme conditions, like when something horrible is going on and the system needs to utter a few last clues as it breathes its final breath.
It's a heroic function. And like most heroes, it has a lot of inner problems that need to be worked out over the course of many adventures. One of the entities sent down to battle those inner demons has been John Ogness, who posted a bunch of patches.
One of the problems with printk() is that it uses a global lock to protect its buffer. But this means any parts of the kernel that can't tolerate locks can't use printk(). Nonmasking interrupts and recursive contexts are two areas that have to defer printk() usage until execution context returns to normal space. If the kernel dies before that happens, it simply won't be able to say anything about what went wrong.
There were other problems—lots! Because of deferred execution, sometimes the buffer could grow really big and take a long time to empty out, making execution time hard to predict for any code that disliked uncertainty. Also, the timestamps could be wildly inaccurate for the same reason, making debugging efforts more annoying.
John wanted to address all this by re-implementing printk() to no longer require a lock. With analysis help from people like Peter Zijlstra, John had come up with an implementation that even could work deep in NMI context and anywhere else that couldn't tolerate waiting.
Additionally, instead of having timestamps arrive at the end of the process, John's code captured them at execution time, for a much more accurate debugging process.
His code also introduced a new idea—the possibility of an emergency situation, so that a given printk() invocation could bypass the entire buffer and write its message to the console immediately. Thus, hopefully, even the shortest of final breaths could be used to reveal the villain's identity.
Sergey Senozhatsky had an existential question: if the new printk() was going to be preemptible in order to tolerate execution in any context, then what would stop a crash from interrupting printk() in order to die?
John offered a technical explanation, which seemed to indicate that "panic() can write immediately to the guaranteed NMI-safe write_atomic console without having to first do anything with other CPUs (IPIs, NMIs, waiting, whatever) and without ignoring locks."
Specifically, John felt that his introduction of emergency printk() messages would handle the problem of messages failing to get out in time. And as he put it, "As long as all critical messages are printed directly and immediately to an emergency console, why is it a problem if the informational messages to consoles are sometimes delayed or lost?"
At some point, it came out that although John's reimplementation was intended to improve printk() in general, he said, "Really the big design change I make with my printk-kthread is that it is only for non-critical messages. For anything critical, users should rely on an emergency console."
The conversation did not go on very long, but it does seem as though John's new printk() implementation may end up being controversial. It eliminates some of the delays associated with the existing implementation, but only by relegating those delays to messages it regards as less important. I would guess it'll turn out to be hard to tell which messages are really more important than others.
Note: if you're mentioned above and want to post a response above the comment section, send a message with your response text to [email protected].