printk 将内核信息输出到内核信息缓冲区中,内核缓冲区在 kernel/printk/printk.c
中定义,内核信息缓冲区是一个环形缓冲区(Ring Buffer),如果dmesg消息过多,会将之前的消息冲掉。
static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN);
1. 修改printk打印等级
调试内核模块时候,若调试信息太多可以通过修改/proc/sys/kernel/printk
文件内容来控制。
查看当前printk打印消息的log等级:
$ cat /proc/sys/kernel/printk
1 4 1 7
#| | | |-默认的控制台日志级别:控制台日志级别的缺省值
#| | |
#| | |--最低的控制台日志级别:控制台日志级别可被设置的最小值(最高优先级)
#| |
#| |---默认的消息日志级别:将用该优先级来打印没有优先级的消息
#|
#|----控制台日志级别:优先级高于该值的消息将被打印至控制台
改变printk打印等级(需要管理员权限):修改后将dmesg中信息直接打印到串口中。
$ echo "7 4 1 7" > /proc/sys/kernel/printk
这四个值是在kernel/printk.c
中被定义:
int console_printk[4] = {
CONSOLE_LOGLEVEL_DEFAULT, /* console_loglevel */
MESSAGE_LOGLEVEL_DEFAULT, /* default_message_loglevel */
CONSOLE_LOGLEVEL_MIN, /* minimum_console_loglevel */
CONSOLE_LOGLEVEL_DEFAULT, /* default_console_loglevel */
};
内核中共提供了八种不同的日志级别,在 linux/kernel.h
中有相应的宏对应。
#define KERN_EMERG KERN_SOH "0" /* system is unusable */
#define KERN_ALERT KERN_SOH "1" /* action must be taken immediately */
#define KERN_CRIT KERN_SOH "2" /* critical conditions */
#define KERN_ERR KERN_SOH "3" /* error conditions */
#define KERN_WARNING KERN_SOH "4" /* warning conditions */
#define KERN_NOTICE KERN_SOH "5" /* normal but significant condition */
#define KERN_INFO KERN_SOH "6" /* informational */
#define KERN_DEBUG KERN_SOH "7" /* debug-level messages */
#define KERN_DEFAULT "" /* the default kernel loglevel */
内核通过printk()
输出的信息具有日志级别,所以printk()
可以这样用:printk(KERN_INFO"Hello, world!\n");
。
未指定日志级别采用的默认级别是DEFAULT_MESSAGE_LOGLEVEL
,该宏在kernel/printk.c
中被定义为整数4,即对应KERN_WARNING
。
#define default_message_loglevel (console_printk[1])
如果要想在内核启动过程中打印少的信息,就可以根据自己的需要在kernel/printk.c
中修改以上数值(重新编译)。
/* printk's without a loglevel use this.. */
#define MESSAGE_LOGLEVEL_DEFAULT CONFIG_MESSAGE_LOGLEVEL_DEFAULT #默认为0
2. 修改dmesg环形缓冲区大小
代码路径:/kernel/printk/printk.c
/* record buffer */
#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)
#define LOG_ALIGN 4
#else
#define LOG_ALIGN __alignof__(struct printk_log)
#endif
#define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT) /*---->由此控制其缓冲区大小*/
static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN);
static char *log_buf = __log_buf;
static u32 log_buf_len = __LOG_BUF_LEN;
/* Return log buffer address */
char *log_buf_addr_get(void)
{
return log_buf;
}
由以上可看出,dmesg缓冲区的大小由 CONFIG_LOG_BUF_SHIFT
控制,其规律为:size = 2 ^ CONFIG_LOG_BUF_SHIFT
,因此修改这个宏就可以更改dmesg缓冲区的大小。
这个宏在内核编译时由配置文件定义,如X86_64位的CPU配置文件路径为:\arch\x86\configs\x86_64_defconfig
。
...
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
CONFIG_LOG_BUF_SHIFT=18 ###########
CONFIG_CGROUPS=y
CONFIG_CGROUP_FREEZER=y
CONFIG_CPUSETS=y
...