基于linux 6.1.12
files
/kernel/printk/printk.c
/include/linux/printk.h
/kernel/printk/printk_ringbuffer.c
/kernel/printk/printk_ringbuffer.h
data structure
![](https://img-blog.csdnimg.cn/img_convert/bf5befc5e54623e2dc6ae7b6efcc05df.png)
![](https://img-blog.csdnimg.cn/img_convert/c3ed1bd18d20261febfc73280a838e88.png)
3. overall call flow
3.1 write flow
![](https://img-blog.csdnimg.cn/img_convert/a23480ef972a6334460d125e58f1d028.png)
![](https://img-blog.csdnimg.cn/img_convert/480c349b5650851816a1877650880eaa.png)
(1)desc_reserve:从prb_desc数组中获取一个空闲的entry,若没有空闲的entry,则覆盖最老的entry。分配完成后将该描述符状态设置为desc_reserved
(2)设置该条log的seq序号
(3)data_alloc:从ring buffer中分配一段用于保存新log的空间,若空闲空间不足,则覆盖掉最老的数据,直到空间足够为止
(4)log data copy:将需要写入的数据拷贝到从log buffer中分配的空间中
(5)_prb_commit:将prb_desc的状态更新为desc_committed
(6)desc_make_final:将prb_desc的状态更新为desc_finalized,该操作后log写入完成且可被读取。
3.2 read flow
![](https://img-blog.csdnimg.cn/img_convert/c0d89882376294c23e763cf19e69a620.png)
读取log时以seq序号为参数,并调用prb_read读取该seq对应的log,若读取失败则调用prb_first_seq获取该seq之后第一条可读的log,并重新读取。
(1)desc_read_finalized_seq:读取该条log对应的状态,若状态合法,则执行下面的log数据和信息读取操作,否则表明该条log已被覆盖、正在被修改或其描述符是空闲的。数据读取完成后,再次执行本函数重新读取其状态和seq号,若状态合法且seq号未变,表明在读的过程中,数据未被写操作修改。否则,表明在读的过程中,该条log的信息或数据已被log写接口覆盖修改了。若整个读流程成功,则数据读取完成,否则调用prb_first_seq获取下一条可读的log
(2)prb_first_seq:由于buffer中尾节点是最老的log数据,因此若待读取数据比尾结点数据还老,则表明该数据已被覆盖,将尾结点作为first seq读取即可。若该节点合法,但数据读取失败,则将下一个节点作为first seq读取。若缓冲区中无有效数据,则返回错误
4. 设计思想
如何通过细化数据,分而治之,通过添加 prb_desc_ring,以及采用 atomic_t 变量等方法来去除锁的消耗。