Re: [Announce] Linux-tiny project revival

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sep 20, 2007, at 19:18:41, Rob Landley wrote:
On Thursday 20 September 2007 4:26:13 pm Indan Zupancic wrote:
But the problem remains that there are printk's which don't have a KERN_* as the first argument. Those are also impossible to get rid off in this way, as the loglevel is unknown (and you don't want partially printed messages).

So adding the comma is really needed and in addition all printk's without a loglevel should get one. Which clutters the code and may increase codesize.

It's ok to _explicitly_ not have a loglevel, and thus take a known default. The problem is printing out less than a full line, continuing it later, and not making obvious at compile time what the level of this chunk is.

That's actually a fairly straightforward problem to solve. Really we ought to be able to guarantee that lines from different CPUs are not intermixed. This can end up in a log like this:

info: Current device state: <1>netdev watchdog timeout: eth0
reg1=0xABCD reg2=0xDEADBEEF

Clearly unpleasant, no? Really any logging which wants to print out a bunch of stuff with multiple printk()s should use an API something like this:

Option 1: Buffer allocated with kmalloc(). Sleep-ish context, can handle failures easily
struct printk_queue qpk;
if (qprintk_kmalloc(&qpk, level, GFP_KERNEL))
	return -ENOMEM;

qprintk(&qpk, "Some string here:");
qprintk(&qpk, " %d, %s, %d", 4, some_string, 42);
qprintk_finish(&qpk);


Option 2: Preallocated per-cpu buffer.  preempt_disable()d
struct printk_queue qpk;
qprintk_percpu(&qpk, level);
[...]
qprintk_finish(&qpk);


Option 3: Preallocated per-cpu interrupts-only buffer. Only from code which may interrupt a preempt_disable() section
struct printk_queue qpk;
qprintk_irq(&pqk, level)
[...]
qprintk_finish(&qpk);


For all of the above, the final "qprintk_finish()" call would essentially take the printk spinlock and write the contents of the qpk->buffer into the dmesg ringbuffer, inserting ("<%d>", level) at the beginning and after each newline. The buffers would all be some useful fixed size (a page?); if you need more than that then you are probably trying to queue too much and excess data would be truncated.

Since the level would be a constant passed to qprintk_ {kmalloc,percpu,irq} in almost every case, you could easily do something like this:

static inline int qprintk_kmalloc(struct printk_queue *qpk,
		unsigned int level, gfp_t gfp)
{
	if (level > CONFIG_MAX_LOG_LEVEL) {
		qpk->type = QPRINTK_TYPE_NONE; /* also 0 */
		qpk->buffer = NULL;
		return 0;
	}

	_qprintk_kmalloc(qpk, level, gfp);
}

#define qprintk(QPK, FMT...) do { \
		if ((QPK)->type)
			_qprintk(QPK, FMT);
	} while(0)


With a bit more glue that would cause GCC to notice that for a given qprintk_kmalloc the "qpk->type" is always zero because the level is too high, and therefore it would optimize out *ALL* of the _qprintk_kmalloc(), _qprintk(), and _qprintk_finish() calls.

Cheers,
Kyle Moffett

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux