LWN.net Logo

Advertisement

GStreamer, Embedded Linux, Android, VoD, Smooth Streaming, DRM, RTSP, HEVC, PulseAudio, OpenGL. Register now to attend.

Advertise here

printk() problems

By Jonathan Corbet
June 26, 2012
The record-oriented logging patch set was pulled into the mainline during the 3.5 merge window. These changes are meant to make the processing of kernel messages generated by printk() and friends more reliable, more informative, and more easily consumed by automatic systems. But recently it has turned out that these changes make printk() less useful for kernel developers. Now there is some uncertainty as to whether this feature can be repaired in time, or whether it will be reverted back out of the 3.5 release.

One of the core design features of the new printk() is a change from byte-streamed output to record-oriented output. Current kernels can easily corrupt messages on their way to the log; for example, when the log buffer overflows, the kernel simply wraps around and partially overwrites older messages. Messages from multiple CPUs can also get confused, especially if one or more CPUs are using multiple printk() calls to output a single line of text. The switch to the record-oriented mechanism eliminates these problems; it also makes it possible to attach useful structured information to messages. As a whole, it looks like a solid improvement to the kernel logging subsystem.

There is just one little problem, though: when the kernel outputs a partial message (by passing a string to printk() that does not end with a newline), the logging system will buffer the text until the rest of the message arrives. The good news is that this buffering causes the full line to be output together once it's complete—if things go well. The situation when things do not go well was best summarized by Andrew Morton:

If a driver does

	printk("testing the frobnozzle ...");
	do_test();
	printk(" OK\n");

and do_test() hangs up, we really really want the user to know that there was a frobnozzle testing problem. Please tell me this isn't broken.

Not only is this behavior now broken, but it has also burned at least one developer who ended up spending a lot of time trying to figure out why the kernel was hanging. Kernel developers depend heavily on printk(), so this change has caused a fair amount of concern.

Bugs happen, of course; the important thing is to fix them. A number of possible fixes have been discussed on the list, including:

  • Leave printk() as it is, and change specific callers to output only full lines. Kay Sievers, the author of the printk() changes, suggested that approach, saying "We really should not optimize for cosmetics (full lines work reliably, they are not buffered) of self-tests, for the price of the reliability and integrity of all other users."

  • Adding a printk_flush() function to be called in places where it is important to see partial lines even if things go wrong before the newline character is printed. The problem with this approach is that, like printing full lines only, it requires changing every place in the code where the problem might hit. Experience says that many of those places can only be found the hard way.

  • Add a global knob by which buffering can be turned on or off; this knob might be set by either user space or the kernel. This idea was not particularly popular; it seems unlikely that the knob will be set for unbuffered output when it really matters.

  • Simply revert the printk() changes for 3.5 and try again for 3.6 or later. Ingo Molnar posted a patch to this effect, seemingly as a way of pressuring Kay to take the problem more seriously.

As of this writing, most of the discussion centers around this patch from Steven Rostedt which simply removes the buffering from printk(). For the most part, the advantages of the new code remain. But it is now possible that a single line of output created with multiple printk() calls may be split into multiple lines, with messages from other CPUs mixed in between. It seems to many to be a reasonable compromise fix.

Except that Kay still doesn't like the splitting of continuation lines. Andrew Morton is also concerned about where the printk() code is going, saying "The core printk code is starting to make one think of things like 'cleansing with fire'." Steven, meanwhile, is reconsidering the whole thing, saying that, perhaps, printk() is not the right tool for structured logging and other approaches should be considered. And Greg Kroah-Hartman has suggested that it might be better just to fix the call sites rather than further complicating the printk() code.

Linus, however, has argued strongly for the merging of Steven's patch. His view is that buffering at the logging level is fine, but text emitted with printk() has to get to the console immediately. So chances are that some version of Steven's fix will be applied for the 3.5 release. But it has become clear, again, that adding structured logging to the kernel while not making life harder for kernel developers is a difficult problem.


(Log in to post comments)

printk() problems

Posted Jun 28, 2012 5:19 UTC (Thu) by josh (subscriber, #17465) [Link]

Personally, I'd rather see printk just start saying "Oh, you didn't put a newline at the end of your line, I'll put one for you."

If printk exists for debugging, it doesn't need to do fancy things like "drivername: checking for whatever ... OK"; it can just as easily say "drivername: checking for whatever" and later "drivername: whatever OK\n

printk() problems

Posted Jun 28, 2012 11:54 UTC (Thu) by nix (subscriber, #2304) [Link]

The problem with that is that the people who wrote the printk()s meant there to be a distinction between those that ended in \n and those that did not: losing that destroys information. Now perhaps that information is not very valuable, but nonetheless it is notable that having printk() automatically append \n's would have made the boot messages on most x86-64 systems look quite horrible. If even the boot process is using this, what else is? ("A lot" is the answer.)

Linus is clearly right: the place to merge adjacent buffers when the earlier one does not end with a \n is in userspace, in the logging daemon. Logging daemons can already do duplicate elimination, rate-limiting and such things -- adjacent merging is trivial. (The kernel *also* implements a rate-limit mechanism, but that's because the buffer is limited in size and to avoid possible DoS attacks before the message ever reaches the logging daemon. Neither of these considerations apply to a trailing \n.)

printk() problems

Posted Jun 28, 2012 13:05 UTC (Thu) by cesarb (subscriber, #6266) [Link]

> Linus is clearly right: the place to merge adjacent buffers when the earlier one does not end with a \n is in userspace, in the logging daemon.

The way I read Linus' message, he is advocating merging the buffers in *kernel* space ("the stuff that actually makes it to dmesg" is still in the kernel), but at the same time sending an unbuffered copy to the console. Giving us the best of both worlds, at the small cost of the screen output and dmesg output being slightly different in case multiple CPUs interleave their messages (the screen would have them interleaved, the kernel log would have them separated correctly).

printk() problems

Posted Jun 28, 2012 16:09 UTC (Thu) by zlynx (subscriber, #2285) [Link]

There's a whole other problem here too. When a driver printk's some partial message and then goes off to wait on the hardware to come up, what is stopping the other driver which is running in parallel from printk'ing all over that line? Absolutely nothing, in fact.

Perhaps printk outputs need unique ID codes so the logging daemons know which bits to stick together.

Or just make each message a complete atomic entity.

printk() problems

Posted Jul 5, 2012 10:33 UTC (Thu) by incase (subscriber, #37115) [Link]

> Or just make each message a complete atomic entity.

In my opinion, this is the only sane approach. Makes boot logs longer with

xyz: initializing peripheral
abc: checking
xyz: peripheral OK
abc: Error
...

But doesn't interleave unrelated messages:

xyz: initializing abc: checking OK(from abc or xyz?)
Error (again: Which one?)

printk() problems

Posted Jun 28, 2012 14:12 UTC (Thu) by ortalo (subscriber, #4654) [Link]

Would simply also treating trailing '...' as a flush indication (like '\n') fix enough of the problematic call places to be worth considering?
(That's a workaround of course, but well... ;-)

Copyright © 2012, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds