前言
在程序开发中最常用的调试手段就是打印,同时也可向我们输出提示消息。在应用层采用printf用于打印,
在内核开发中我们用printk来进行打印,而内核的打印是有等级的,本篇文章就是介绍内核的打印等级。
驱动
编写一个简单的驱动
打印等级的定义在kernel\include\linux\kern_levels.h
#include<linux/init.h>
#include<linux/module.h>
static int __init hello_init(void)
{
printk(KERN_EMERG "LOG level 0\r\n");
printk(KERN_ALERT "LOG level 1\r\n");
printk(KERN_CRIT "LOG level 2\r\n");
printk(KERN_ERR "LOG level 3\r\n");
printk(KERN_WARNING "LOG level 4\r\n");
printk(KERN_NOTICE "LOG level 5\r\n");
printk(KERN_INFO "LOG level 6\r\n");
printk(KERN_DEBUG "LOG level 7\r\n");
printk("-------------------\r\n");
printk("defaule LOG level\r\n");
return 0;
}
static void __exit hello_exit(void)
{
printk("--exit:----%s-------\r\n",__FUNCTION__);
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
驱动很简单insmod的时候打印一些信息在控制台上
printk的格式等级与msg之间用空格隔开
printk也可不加等级,内核将采用默认等级
makefile
MOD_NAME := akk_printk
obj-m += $(MOD_NAME).o
$(MOD_NAME)-objs += ko_printk_log_level.o
MAKE_ENV = ARCH=arm64 CROSS_COMPILE=aarch64-XXXX-linux-
KERNEL_DIR = XXX/kernel
.PHONY: all clean
all:
make -C $(KERNEL_DIR) M=`pwd` $(MAKE_ENV) modules
clean:
rm -rf .tmp_versions *.mod.* *.o .*.mod .*.ko.cmd .*.o.cmd Module.symvers modules.order *.ko
测试
将上述的驱动在内核下insmod你会发现并不是所有的printk都打印出来了。这里涉及到一个内核的打印策略
内核的printk模块它维护了一个数组,里面的值可以看做配置,这种配置指导打印哪些内容打印哪些内容不打印。
//\kernel\kernel\printk\printk.c
int console_printk[4] = {
CONSOLE_LOGLEVEL_DEFAULT, /* console_loglevel 7*/
MESSAGE_LOGLEVEL_DEFAULT, /* default_message_loglevel CONFIG_MESSAGE_LOGLEVEL_DEFAULT*/
CONSOLE_LOGLEVEL_MIN, /* minimum_console_loglevel 1*/
CONSOLE_LOGLEVEL_DEFAULT, /* default_console_loglevel 7*/
};
//\kernel\include\linux\printk.h
/* printk's without a loglevel use this.. */
#define MESSAGE_LOGLEVEL_DEFAULT CONFIG_MESSAGE_LOGLEVEL_DEFAULT
#define CONSOLE_LOGLEVEL_SILENT 0 /* Mum's the word */
#define CONSOLE_LOGLEVEL_MIN 1 /* Minimum loglevel we let people use */
#define CONSOLE_LOGLEVEL_QUIET 4 /* Shhh ..., when booted with "quiet" */
#define CONSOLE_LOGLEVEL_DEFAULT 7 /* anything MORE serious than KERN_DEBUG */
从上述可以看出数组中元素的含义为,控制台的打印等级、默认的打印等级、用户最小可配置打印等级、默认的控制台打印等级,后面这两个等级配置我到现在也不是很明白干嘛用的。
重点分析
这个配置数组console_printk的值可以在内核下看到命令
$ cat /proc/sys/kernel/printk
7 4 1 7
这个是内核代码中的默认配置值,第二个元素MESSAGE_LOGLEVEL_DEFAULT还可以在内核的menuconfig 中配置
同时也可以动态的修改内核当前的打印配置,echo后再次进行cat就能看到配置修改生效
echo “8 4 1 7” > /proc/sys/kernel/printk
这个时候再次挂载我们之前的驱动就能看到所有的打印了。
内核的打印策略,当消息的打印优先级大于我内核的控制台打印等级我就打印输出。否者不输出
这里数字越低表示优先级越高
可以类比代码,消息的打印等级值 < 控制台打印等级值 ? 输出 : 不输出;
可以看出与控制台的打印相等也不输出
这个时候可以回头来看配置的第一个值 7 表示当前内核打印输出的等级为7,只有等级0—6的消息才会输出到控制台,
这个配置可以用来控制内核的打印,有些场景不希望内核有打印那么就可以设置这个值来做。
疑问
那有些消息不打印出来的话,但我想看,那岂不是看不到了,放心,内核的消息肯定是能够看到的,
所有的内核打印以及printk的输出都会缓存到内核的一个console-buff中,上面的控制台消息打印配置,其实就是在这个buf中有哪些数据可以让你直接看到而已。
通过内核的命令dmesg就能看到所有的打印消息了。