内核漫游指南
Anakin Lv1

Eric Raymond 在《大教堂与集市》中曾言:

我认为,未来会更多地属于那些告别大教堂、拥抱集市的人们。

这不是说个人的远见和才华不再重要;而是在我看来,未来的成功者只是从自己的远见和才华开始工作,然后通过有效的社区合作,将其不断地放大。

开放式的文化会最终胜利,这或许不是因为”开放”在道德上正确,或者”封闭”在道德上错误,而只是因为开放式合作可以在一个问题上投入多几个数量级的技术工时,封闭的世界无法赢得这样的竞争。

本指南献给闯荡银河系的勇者们,愿他们也能领略到内核世界的绝美风光。

内核源码树

目录 内容 备注
kernel 内核核心组件 除非绝对必要,否则不要向该目录添加内容。
mm 架构无关的内存管理代码
fs 所有文件系统实现代码
init 内核初始化相关代码
ipc 进程间通信机制
block 块设备相关代码
drivers 各类驱动程序 源码中所占空间最大,但只有少量成员会编译到。
sound 声卡驱动程序 尽管有独立的目录,但和其他设备驱动程序类似。
net 网络实现代码 包括核心和各种协议两部分。
lib 通用库例程 包括各种数据结构和数据压缩的例程。
include 所有公开导出函数的头文件
usr cpio 相关实现
security 各类安全模块 主要包括 LSM 模块和密钥管理代码。
crypto 加密层文件 如各种加密算法的实现。
virt 内核虚拟化代码
arch 体系结构相关文件 每种体系结构都有独立子目录,内部类似于顶层目录。
samples 编程范例 包括内核和用户态编程。
scripts 脚本和使用程序 用于编译内核、检查补丁格式等任务。
tools 内核裁剪配置工具 将源码编译成目标文件,连接合并为可运行的 zImage。
Documentation 内核文档 虽然其中很多过时了。
LICENSES 各类相关开源许可证
MAINTAINERS 内核各模块维护者联系方式
Kconfig 编译配置文件 决定需要编译哪些代码。
Kbuild 组件式构建配置文件
Makefile 主 Makefile 定义 C 编译器、链接器的调用路径。

编译内核

Kconfig

Kbuild

内核开发

开发工作流

如何进行补丁移植

内核开发中一个常见的场景是补丁移植,将高版本内核的修复补丁或特性补丁回合到低版本内核中,往往因为补丁上下文的改动导致无法直接合入,这时候就需要我们手动进行移植。

  1. 使用 git am 尝试合入开源补丁:

    1
    $ git am xxx.patch

    该命令会尝试合入补丁,如果合入顺利,就直接根据补丁头的信息进行提交,如果有冲突,会回退所有的修改并告知哪里有冲突。

    你可以加上 -s 选项以在提交信息中附加自己的签名。

  2. 出现冲突时的处理。

    • 首先判断冲突是否是因为补丁内容已经存在于源码中,如果是,就直接跳过补丁:

      1
      $ git am --skip
    • 使用 git apply 合入未冲突的部分修改,并通过 --reject 选项导出冲突内容到一个 .rej 文件中:

      1
      $ git apply --reject xxx.patch
    • 使用 vim -O 同时打开 .rej 文件和源文件,以便手动适配合入:

      1
      $ vim -O crashfile.rej crashfile

      根据补丁上下文,从 .rej 文件复制对应的修改到原文件,删除应该删除的行。

    • 清理 .rej 文件并使用 git add 添加修改到文件,最后完成提交:

      1
      2
      3
      $ rm -f crashfile.rej
      $ git add --all
      $ git am --resolved
  3. 合入补丁后,根据需要补充补丁头信息:

    1
    $ git commit --amend
  4. 生成单个新补丁:

    1
    $ git format-patch --subject-prefix="PATCH version_prefix" -1

    一次生成完整的补丁集:

    1
    $ git format-patch --subject-prefix="PATCH version_prefix" --cover-letter [commit-ID]
  5. 检查补丁:

    1
    $ scripts/checkpatch.pl xxx.patch
  6. 发送补丁:

    1
    $ git send-email *.patch -to "maintainer email" --cc="kernel.openeuler@huawei.com" --from="your email" --suppress-cc=all

编码风格

可移植性

内核调测

数据交互

procfs

debugfs

常规调试

printk

kprobe

SystemTap

KGDB

KGTP

崩溃调试

kdump

kdump 是一种内核崩溃转储机制,能够在系统崩溃时自动转储内存,以用于后续分析。

kdump 工作过程如下:

  1. 系统内核启动的时候,为 capture 内核预留一块内存空间,该空间无法被当前内核访问;

    这块空间的大小及其在内存中的偏移可通过启动参数中的 crashkernel=size[@offset] 指定。

  2. 内核启动完成后,kdump 服务执行 kexec -p 把 capture 内核载入预留的内存;

  3. 如果当前内核发生崩溃,就自动把控制权交给 capture 内核(capture 内核仅使用预留内存,因此其余内存数据不会被改动),由该内核把崩溃内核内存中的数据写入到 dump 文件;

  4. 写完 dump 文件中,capture 内核自动重启。

这里不过多介绍 kdump 的设置,读者可以在各发行版的文档中找到(例如红帽),直接介绍如何通过 vmcore 文件获取系统崩溃信息。

SysRq 魔术键

性能调优

perf

性能分析的“瑞士军刀”。

总结

参考资料

变更记录

  • 2020.11.25:完成目录框架。
  • Post title:内核漫游指南
  • Post author:Anakin
  • Create time:2020-11-25 08:35:22
  • Post link:https://nettingsisyphus.tech/2020/11/25/kernel-diving-guide/
  • Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.