1、打印开关可随时控制,开机如果要修改是否打印日志的话,需要修改代码重新编译内核才行,其实如果真要搞,应该有其他方法;
2、打印次数,当前代码里边写的是1000次,其实可以根据传参动态修改打印日志次数,不过没有开发,只是大概展示了下;
3、函数未来可扩展;
运行效果:
linux_pr_info_self_哔哩哔哩_bilibililinux kernel 添加内核自定义日志后运行状态,代码地址:https://gitee.com/r77683962/linux-6.9.0内核版本6.9.0, 视频播放量 13、弹幕量 0、点赞数 0、投硬币枚数 0、收藏人数 0、转发人数 0, 视频作者 缘起性空aa, 作者简介 ,相关视频:2024版Linux内核源码分析(强烈推荐收藏!),三天让你学会Linux操作系统!,【网络安全】拜托三连了!这绝对是全B站最用心(没有之一)的Linux学习教程!,如何成为一名linux用户,B站强推!2024年最新Linux操作系统全套顶级天花板教程,血赚!学完即可上岸,拿走不谢!,【大佬秘籍】子牙老师告诉你,如何才能学会任何计算机技术,看懂任何代码:Java虚拟机、linux内核、redis、MySQL,【Linux虚拟机】wsl+ubuntu+vscode配置教程,请选择你的勾石操作系统,【操作系统】学起来,你就超过99%的人!保姆级教学,小白也可以轻松搞懂操作系统!,2024.6.22最新安卓【国际版抖音tiktok】iOS 免拔卡https://www.bilibili.com/video/BV1Bi421Y7UP/?vd_source=0578c14da2b84f0964bbee439d4fd921
代码:
include/linux/printk_self.h · r77683962/linux-6.9.0 - Gitee.comhttps://gitee.com/r77683962/linux-6.9.0/blob/70652d2129aae756fde3f9c440dd21177d9890cd/include/linux/printk_self.hinclude/linux/printk_self.h
#ifndef __KERNEL_PRINTK_SELF__
#define __KERNEL_PRINTK_SELF__
#include <linux/stdarg.h>
#include <linux/init.h>
#include <linux/kern_levels.h>
#include <linux/linkage.h>
#include <linux/ratelimit_types.h>
#include <linux/once_lite.h>
typedef enum
{
PRINT_LOG_STATE_NONE = 0,
PRINT_LOG_STATE_LESS,
PRINT_LOG_STATE_DEFAULT,
PRINT_LOG_STATE_MORE,
PRINT_LOG_STATE_TIMES
}PRINT_LOG_STATE_EN;
extern int iGlobalLogPrintLevel;
extern int iGlobalLogPrintTimes;
void GlobalLogPrintTimesSet(unsigned int value);
void GlobalLogPrintLevelSet(int value);
/**
* pr_info - Print an info-level message
* @fmt: format string
* @...: arguments for the format string
*
* This macro expands to a printk with KERN_INFO loglevel. It uses pr_fmt() to
* generate the format string.
*/
#define pr_info_self(fmt, ...) \
({ \
if (iGlobalLogPrintLevel == PRINT_LOG_STATE_DEFAULT) \
printk(KERN_INFO "[%s %s %d DEFAULT] "pr_fmt(fmt), __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
else if (iGlobalLogPrintLevel == PRINT_LOG_STATE_LESS) \
printk(KERN_INFO "[LESS] "pr_fmt(fmt), ##__VA_ARGS__); \
else if (iGlobalLogPrintLevel == PRINT_LOG_STATE_MORE) \
printk(KERN_INFO "[%s %s %d MORE] "pr_fmt(fmt), __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
else if (iGlobalLogPrintLevel == PRINT_LOG_STATE_TIMES && iGlobalLogPrintTimes > 0) \
{ \
printk(KERN_INFO "[%s %s %d TIMES: %d ] "pr_fmt(fmt), __FILE__, __FUNCTION__, __LINE__, iGlobalLogPrintTimes, ##__VA_ARGS__); \
iGlobalLogPrintTimes--; \
} \
})
#endif
这个枚举是可以扩展的,比如自己想添加其他类型的打印类型,像java log打印就比较复杂;
另外就是pr_info_self这里也可以扩展,不过这里的语法比较复杂,什么斜杠,fmt,双引号什么的,修改代码的时候要注意
kernel/printk/printk_self.c · r77683962/linux-6.9.0 - Gitee.comhttps://gitee.com/r77683962/linux-6.9.0/blob/master/kernel/printk/printk_self.c
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/stdarg.h>
#include <linux/init.h>
#include <linux/kern_levels.h>
#include <linux/linkage.h>
#include <linux/ratelimit_types.h>
#include <linux/once_lite.h>
#include <linux/printk_self.h>
int iGlobalLogPrintLevel;
EXPORT_SYMBOL(iGlobalLogPrintLevel);
int iGlobalLogPrintTimes;
EXPORT_SYMBOL(iGlobalLogPrintTimes);
void GlobalLogPrintTimesSet(unsigned int value)
{
iGlobalLogPrintTimes = value;
}
EXPORT_SYMBOL(GlobalLogPrintTimesSet);
void GlobalLogPrintLevelSet(int value)
{
iGlobalLogPrintLevel = value;
}
EXPORT_SYMBOL(GlobalLogPrintLevelSet);
这就是实现的一点点封装,类似面向对象编译的类。
这里要注意export_symbol这个宏不能少。
不然编译不会有问题,链接会报错。
fs/open.c · r77683962/linux-6.9.0 - Gitee.comhttps://gitee.com/r77683962/linux-6.9.0/blob/70652d2129aae756fde3f9c440dd21177d9890cd/fs/open.c
static long do_sys_openat2(int dfd, const char __user *filename,
struct open_how *how)
{
struct open_flags op;
int fd = build_open_flags(how, &op);
struct filename *tmp;
pr_info_self("");
if (fd)
return fd;
tmp = getname(filename);
if (IS_ERR(tmp))
return PTR_ERR(tmp);
if (strncmp_self(tmp->name, "log_none", 8) == 0)
{
GlobalLogPrintLevelSet(PRINT_LOG_STATE_NONE);
pr_info_self("log_none filename: %s", tmp->name);
}
else if (strncmp_self(tmp->name, "log_less", 8) == 0)
{
GlobalLogPrintLevelSet(PRINT_LOG_STATE_LESS);
pr_info_self("log_less filename: %s", tmp->name);
}
else if (strncmp_self(tmp->name, "log_default", 11) == 0)
{
GlobalLogPrintLevelSet(PRINT_LOG_STATE_DEFAULT);
pr_info_self("log_default filename: %s", tmp->name);
}
else if (strncmp_self(tmp->name, "log_more", 8) == 0)
{
GlobalLogPrintLevelSet(PRINT_LOG_STATE_MORE);
pr_info_self("log_more filename: %s", tmp->name);
}
else if (strncmp_self(tmp->name, "log_times", 9) == 0)
{
GlobalLogPrintTimesSet(1000);
GlobalLogPrintLevelSet(PRINT_LOG_STATE_TIMES);
pr_info_self("log_times filename: %s", tmp->name);
}
fd = get_unused_fd_flags(how->flags);
if (fd >= 0) {
struct file *f = do_filp_open(dfd, tmp, &op);
if (IS_ERR(f)) {
put_unused_fd(fd);
fd = PTR_ERR(f);
} else {
fd_install(fd, f);
}
}
putname(tmp);
return fd;
}
这里边就是根据文件名(其实视频里边操作的都是创建文件的文件名),来修改内核日志打印的状态。
初始化:
include/linux/printk.h · r77683962/linux-6.9.0 - Gitee.comhttps://gitee.com/r77683962/linux-6.9.0/blob/master/include/linux/printk.h如果想让内核在起动的时候就打开,需要修改iGlobalLogPrintLevel = PRINT_LOG_STATE_NONE;
static inline void setup_log_buf(int early)
{
iGlobalLogPrintLevel = PRINT_LOG_STATE_NONE;
iGlobalLogPrintTimes = 0;
}
这就是变量初始化。
kernel/printk/Makefile · r77683962/linux-6.9.0 - Gitee.comhttps://gitee.com/r77683962/linux-6.9.0/blob/master/kernel/printk/Makefile
# SPDX-License-Identifier: GPL-2.0-only
obj-y = printk.o printk_self.o
obj-$(CONFIG_PRINTK) += printk_safe.o nbcon.o
obj-$(CONFIG_A11Y_BRAILLE_CONSOLE) += braille.o
obj-$(CONFIG_PRINTK_INDEX) += index.o
obj-$(CONFIG_PRINTK) += printk_support.o
printk_support-y := printk_ringbuffer.o
printk_support-$(CONFIG_SYSCTL) += sysctl.o
这就是Makefile的第一行,因为我们新增了两个文件,要新生成对应的.o文件
代码比较简单。