阅读内核源码技巧
内核代码非常大,大量的驱动代码文件,体系结构相关的文件,并且有很多重名文件,重名函数,大量的宏定义,还有一些函数是宏定义进行拼接,直接搜索,并不能直接找到函数定义等等,因为这些原因,造成入门读内核代码会有一定的困难,需要不断探索,不断总结看内核代码的一些技巧。
在线看内核代码的网站 bootlin
囊括了所有版本,tag的内核代码,在线阅读,可以跳转,可以看到相关的函数调用。 https://elixir.bootlin.com/linux/latest/source
搜索函数
-
SYSCALL_DEFINE 系统调用函数入口 搜索所有系统调用的入口,可以是正则表达式 SYSCALL_DEFINE, DEFINE后面的参数表示系统调用函数的参数。
-
EXPORT_SYMBOL 导出某个内核符号
查看各个系统的init函数
要了解各个子系统,响应的init函数是需要关注的,涉及到一些全局变量的初始化,可以看到数据结构是如何串联起来的,可能在看代码的过程中有一些迷惑,看了模块的初始化过程,就名表了 。 net/socket.c:socket_init net/ipv4/af_inet.c: inet_init net/socket.c 有关于socket编程的系统调用的入口
常见的数据结构
fs.h:struct file_operations
sock_fs_type socket也有一套文件系统sockfs
内核中的文件系统 pipefs,nsfs,sockfs
全局变量
内核中存在大量的全局变量,一是便于监控,二是便于寻址。
如tcp_hashinfo保存所有的tcp连接信息,
init_task可以遍历到所有的进程,
netns可以遍历到所有的命名空间,
mem_map可以遍历所有的page以及section。
全局变量 tcp_hashinfo 保存所有的tcp连接
inet_sk_listen_hashfn(sk)
hash函数 inet_hashinfo 好几个变量,不同状态的连接放在不同的hash桶中,如ehash,listening_hash等
记录重要函数
fib_lookup 路由表的查找
netif_receive_skb 由网卡驱动到内核协议栈的入口。
load_elf_binary 执行二进制程序的流程
arp子系统中arp_tbl neigh->arp_queue arp_ignore 和 arp_announce
概念
内核中也有大量的队列操作,需要大致明白队列的作用以及调用时机。
sk的队列 backlog队列
sk_receive_queue 队列
out_of_oder队列
sock_def_readable