[lkml]   [2007]   [Sep]   [21]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
Messages in this thread
    SubjectRe: [Announce] Linux-tiny project revival
    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.

    Kyle Moffett

    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to
    More majordomo info at
    Please read the FAQ at

     \ /
      Last update: 2007-09-21 23:37    [W:0.026 / U:110.200 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site