linux之printk

今天和同事在遇到一个在内核中用printk打印log发现在一个printk里面,最后的log无法输出,如果去掉前面的一些log之后则可以显示后面的一些log信息,最后跟代码发现是由于在vprintk_store()函数内部的textbuf[LOG_LINE_MAX]限制了一次允许输出log的最大长度。也就是说printk一次输出的log长度不能大于LOG_LINE_MAX的长度。

kernel/printk/printk.c

#ifdef  CONFIG_PRINTK_CALLER                                                                                                                   
#define PREFIX_MAX      48
#else
#define PREFIX_MAX      32
#endif
#define LOG_LINE_MAX        (1024 - PREFIX_MAX)

/* Must be called under logbuf_lock. */                                                                                                       
int vprintk_store(int facility, int level,
          const char *dict, size_t dictlen,
          const char *fmt, va_list args)
{
    static char textbuf[LOG_LINE_MAX];
    char *text = textbuf;
    size_t text_len;
    enum log_flags lflags = 0;

    /*
     * The printf needs to come first; we need the syslog
     * prefix which might be passed-in as a parameter.
     */
    text_len = vscnprintf(text, sizeof(textbuf), fmt, args);

    /* mark and strip a trailing newline */
    if (text_len && text[text_len-1] == '\n') {
        text_len--;
        lflags |= LOG_NEWLINE;
    }

    /* strip kernel syslog prefix and extract log level or control flags */
    if (facility == 0) {
        int kern_level;

        while ((kern_level = printk_get_level(text)) != 0) {
            switch (kern_level) {                                                                                                             
            case '0' ... '7':
                if (level == LOGLEVEL_DEFAULT)
                    level = kern_level - '0';
                break;
            case 'c':   /* KERN_CONT */
                lflags |= LOG_CONT;
            }

            text_len -= 2;
            text += 2;
        }
    }

    if (level == LOGLEVEL_DEFAULT)
        level = default_message_loglevel;

    if (dict)
        lflags |= LOG_NEWLINE;

    return log_output(facility, level, lflags,
              dict, dictlen, text, text_len);
}

asmlinkage int vprintk_emit(int facility, int level,
                const char *dict, size_t dictlen,
                const char *fmt, va_list args)
{
    int printed_len;
    bool in_sched = false, pending_output;
    unsigned long flags;
    u64 curr_log_seq;

    /* Suppress unimportant messages after panic happens */
    if (unlikely(suppress_printk))
        return 0;
    
    if (level == LOGLEVEL_SCHED) {
        level = LOGLEVEL_DEFAULT;
        in_sched = true;
    }
            
    boot_delay_msec(level);
    printk_delay();
 
    /* This stops the holder of console_sem just where we want him */                                                                         
    logbuf_lock_irqsave(flags);
    curr_log_seq = log_next_seq;
    printed_len = vprintk_store(facility, level, dict, dictlen, fmt, args);
    pending_output = (curr_log_seq != log_next_seq);
    logbuf_unlock_irqrestore(flags);
        
    /* If called from the scheduler, we can not call up(). */
    if (!in_sched && pending_output) {
        /*
         * Disable preemption to avoid being preempted while holding
         * console_sem which would prevent anyone from printing to
         * console
         */                                                                                                                                   
        preempt_disable();
        /*
         * Try to acquire and then immediately release the console
         * semaphore.  The release will print out buffers and wake up
         * /dev/kmsg and syslog() users.
         */
        if (console_trylock_spinning())
            console_unlock();
        preempt_enable();
    }

    if (pending_output)
        wake_up_klogd();
    return printed_len;
}
EXPORT_SYMBOL(vprintk_emit);

int vprintk_default(const char *fmt, va_list args)
{
    int r; 

#ifdef CONFIG_KGDB_KDB
    /* Allow to pass printk() to kdb but avoid a recursion. */
    if (unlikely(kdb_trap_printk && kdb_printf_cpu < 0)) {
        r = vkdb_printf(KDB_MSGSRC_PRINTK, fmt, args);
        return r; 
    }
#endif
    r = vprintk_emit(0, LOGLEVEL_DEFAULT, NULL, 0, fmt, args);                                                                                
    
    return r;
}
EXPORT_SYMBOL_GPL(vprintk_default);

kernel/printk/printk_safe.c

__printf(1, 0) int vprintk_func(const char *fmt, va_list args)
{
    /*  
     * Try to use the main logbuf even in NMI. But avoid calling console
     * drivers that might have their own locks.
     */
    if ((this_cpu_read(printk_context) & PRINTK_NMI_DIRECT_CONTEXT_MASK) &&
        raw_spin_trylock(&logbuf_lock)) {
        int len;

        len = vprintk_store(0, LOGLEVEL_DEFAULT, NULL, 0, fmt, args);
        raw_spin_unlock(&logbuf_lock);
        defer_console_output();
        return len;
    }   

    /* Use extra buffer in NMI when logbuf_lock is taken or in safe mode. */
    if (this_cpu_read(printk_context) & PRINTK_NMI_CONTEXT_MASK)
        return vprintk_nmi(fmt, args);
                                                                                                                                              
    /* Use extra buffer to prevent a recursion deadlock in safe mode. */
    if (this_cpu_read(printk_context) & PRINTK_SAFE_CONTEXT_MASK)
        return vprintk_safe(fmt, args);

    /* No obstacles. */
    return vprintk_default(fmt, args);
}

asmlinkage __visible int printk(const char *fmt, ...)
{       
    va_list args;
    int r;
        
    va_start(args, fmt);
    r = vprintk_func(fmt, args);                                                                                                              
    va_end(args);

    return r;
}   
EXPORT_SYMBOL(printk);
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值