Linux内核源代码存放位置详解

老实说,说到Linux内核,光看文档我是无法理解的。
你必须自己做。
当我第一次接触内核源代码时,我被一堆文件夹压垮了。
后来我慢慢找到了方法。

我们先来说一下存储位置。
当我使用Debian系统时,默认路径是/usr/src/linux-5 .1 0.0。
此版本号随内核更新而更改。
然后我发现了一个有趣的现象。
如今许多发行版喜欢将内核源代码直接放入 /var/src/linux 中。
也许他们认为 /usr 太空了。
自定义管道仍然存在,特别是对于进行嵌入式开发的学生来说。
他们可以将内核源代码直接提取到项目文件夹中,以便于管理。
获取方式只有两种,要么使用apt安装linux源码包,要么访问kernel.org官方网站下载tarball。
解压时记得使用--strip-comComponents=1 ,否则文件权限会让你发疯。

我们来谈谈文件夹结构。
给我印象最深的是非常详细的Arch目录。
例如,Arch/x8 6 /kernel/ 中的大量内容与 CPU 相关,例如指令集和页表转换。
我曾经写过一个模块,想了解x8 6 架构的异常处理机制。
我花了两天时间研究它,终于发现密钥代码位于 arch/x8 6 /kernel/traps.c 中。
我通常进入块文件夹。
块设备驱动代码相当有趣,比如block/blk-core.c中的I/O调度算法。
我尝试更改截止日期时间表,但发现无论我如何调整CFQ,都没有用。
物理磁盘仍然无法呼吸。
至于fs目录,Ext4 中的代码量太大了。
我帮助一个朋友修复了一个文件系统挂载错误,这需要对mmap.c和inode.c有很多了解。

最让我头疼的是include文件夹里全是头文件,比如include/linux/sched.h,里面定义了task_struct结构体。
我每天写流程管理模块的时候都会看它。
kernel目录是内核的核心。
kernel/sched/core.c 中的代码,尤其是 CFS 调度程序实现,非常棒。
我尝试使用eBPF来监控其执行情况,但发现数据结构过于复杂,调试器卡住了。
更大的驱动程序目录。
我帮助公司修复了ARM平台的WiFi驱动程序,并更改了net/wireless/wl1 2 xx.c中的注册表值。
调试过程真是棒极了。

例如,在进程管理方面,kernel/pid.c中有find_get_pid函数。
当我第一次看到它时我惊呆了。
我不明白如何写rcu_read_lock。
经过查阅资料,我发现这是内核用来防止竞争条件的机制。
kernel/sched/core.c中还有一个wake_up_process函数,它使用set_task_state将进程状态更改为TASK_RUNNING。
我在写模块的时候用的最多的就是这个函数,但是一旦我改错了参数,系统就会疯狂的创建进程最终不得不重新启动。
调试时,我使用printk添加日志,发现内核日志比用户态日志丑陋得多。
它们都是十六进制地址和状态代码。

现在使用工具方便多了。
我一般使用cscope,在项目根目录下执行make cscope。
它将在当前目录中创建 cscope.out 文件。
检查函数调用之间的关系非常快。
还有kgdb。
我修复了一次内核堆栈溢出。
我连接了kgdb,直接按照步骤操作。
这比用gdb分析用户态程序有趣多了。
但需要注意的是,目录结构可能会随着内核版本的不同而变化。
例如,当从 4 .x 迁移到 5 .x 时,init 目录将消失,而将使用 initramfs。
在这种情况下,您必须阅读 Documentation/ 文件夹中的文档。
内核文档写得还是很好的。

说白了,内核源码就像一个迷宫,但是走多了就会习惯。
请记住,Arch 是关于硬件的,kernel 是关于核心功能的,drivers 是关于驱动程序的。
这三个块占了7 0%的内容。
如果你真的想深入挖掘,你应该从 Documentation/ 目录和 linus 邮件列表开始,其中有大佬的评论,比文档有趣得多。

带你详细了解Linux内核源码的构成及其作用

记得有一次我在宿舍调试嵌入式设备,旧的树莓派突然蓝屏了。
重启后系统报错,提示某个驱动加载失败。
那一刻我问自己:为什么这个东西突然不起作用了?后来经过排查,发现是更新内核后一些特定架构的代码出现了问题。
Linux内核源代码看起来相当复杂,但是如果你仔细想一想,你会发现每个文件夹都非常有讲究。
例如,arch/arm文件夹专门负责ARM架构,包括汇编代码、中断处理和内存管理。
另一个例子是drivers/net,其中存放着各种网卡的驱动程序。
想一想,树莓派采用ARM架构,网络驱动必须是特定的。
这些代码必须完美适配。
顺便说一句,还有一个加密文件夹。
之前做项目的时候,用的是AES加密,就是从这里加载的aes.ko模块。
这些小细节其实还是蛮有趣的。
等等,还有一件事。
上次我阅读 Documentation 中的文档时谈到了内核调度算法、CFQ 和 Deadline。
这相当复杂。
突然我想知道为什么有些设备更新后系统崩溃了?这和调度算法有关系吗?这个问题需要更详细地研究。