printk源码分析

printk 源码

之前我们讲了整个调用过程,本章从源码进行分析。

1
2
3
4
5
6
7
8
9
10
11
12
asmlinkage __visible int _printk(const char *fmt, ...)
{
va_list args;
int r;

va_start(args, fmt);
r = vprintk(fmt, args);
va_end(args);

return r;
}
EXPORT_SYMBOL(_printk);

上面 const char *fmt 是格式化字符串,... 是变长参数,借用 C 语言的变长参数机制。
把打包好的 fmtargs 一起传入到 vprintk 中。

继续向下,vprintk 会调用 vprintk_default 函数,随后会调用 vprintk_emit

1
2
3
4
int vprintk_default(const char *fmt, va_list args)
{
return vprintk_emit(0, LOGLEVEL_DEFAULT, NULL, fmt, args);
}

会调用 vprintk_store 写入 ring buffer,其作用就是把格式化后的内容写入缓冲区,我们看一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
int vprintk_store(int facility, int level,
const struct dev_printk_info *dev_info,
const char *fmt, va_list args)
{
struct prb_reserved_entry e;
struct printk_record r;

u16 reserve_size;
u16 text_len;

...

/* 1. 计算格式化后的日志需要多少空间 */
reserve_size = vsnprintf(prefix_buf,
sizeof(prefix_buf),
fmt, args2) + 1;

...

/* 2. 初始化一条待写入的日志记录 */
prb_rec_init_wr(&r, reserve_size);

/* 3. 在 printk Ring Buffer 中申请空间 */
if (!prb_reserve(&e, prb, &r)) {
...
}

/* 4. 格式化日志正文,并写入申请到的空间 */
text_len = printk_sprint(r.text_buf,
reserve_size,
facility,
&flags,
fmt, args);

/* 5. 填写日志元数据 */
r.info->text_len = text_len;
r.info->facility = facility;
r.info->level = level;
r.info->flags = flags;
r.info->ts_nsec = ts_nsec;
r.info->caller_id = caller_id;

/* 6. 提交记录,使其正式可读 */
prb_final_commit(&e);

...

return text_len;
}

上面有三个核心数据结构,第一个是 printk_record

1
2
3
4
5
struct printk_record {
struct printk_info *info; /* 指向日志的元数据信息 */
char *text_buf; /* 指向格式化后的日志文本缓冲区 */
unsigned int text_buf_size; /* 日志文本缓冲区的大小 */
};

表示构造一条日志记录。

prb_reserved_entry 指向本次申请的 Ring Buffer 记录位置;

1
struct printk_ringbuffer *prb = &printk_rb_static;

这是 printk 使用的全局环形缓冲区 printk_ringbuffer

上面大致做的就是首先计算日志所需空间,初始化日志记录结构体 printk_record,向 ring buffer 申请空间,写入日志正文,填写日志的信息,提交日志。

未完待续……


printk源码分析
https://cj0510.github.io/2026/08/16/Linux Kernel/Logging subsystem/printk源码分析/
作者
CJ1018
发布于
2026年8月16日
许可协议
CC BY-NC-SA 4.0