如何进行 Linux 内核开发

这是关于此主题的终极文档。它包含关于如何成为 Linux 内核开发人员以及如何学习与 Linux 内核开发社区合作的说明。它尽量不包含任何与内核编程技术方面相关的内容,但会帮助您指出正确的方向。

如果本文档中的任何内容过时,请将补丁发送给本文档的维护者,维护者列在文档底部。

简介

那么,您想学习如何成为 Linux 内核开发人员吗?或者您的经理告诉您,“去为这个设备编写一个 Linux 驱动程序。”本文档的目标是通过描述您需要经历的过程以及有关如何与社区合作的提示,来教您实现此目标所需的一切知识。它还将尝试解释社区如此运作的一些原因。

内核主要用 C 编写,一些依赖于体系结构的部分用汇编编写。内核开发需要对 C 有很好的理解。除非您计划为该体系结构进行底层开发,否则不需要汇编(任何体系结构)。虽然它们不能很好地替代扎实的 C 教育和/或多年的经验,但以下书籍对于参考来说是不错的:

  • 《C 程序设计语言》 Kernighan 和 Ritchie 著 [Prentice Hall]

  • 《实用 C 编程》 Steve Oualline 著 [O’Reilly]

  • 《C:参考手册》 Harbison 和 Steele 著 [Prentice Hall]

内核使用 GNU C 和 GNU 工具链编写。虽然它遵循 ISO C11 标准,但它使用了标准中没有的许多扩展。内核是一个独立的 C 环境,不依赖于标准 C 库,因此不支持 C 标准的某些部分。不允许任意长的长整数除法和浮点运算。有时很难理解内核对工具链的假设及其使用的扩展,不幸的是,没有关于它们的明确参考。请查看 gcc 信息页面 (info gcc) 以获取有关它们的一些信息。

请记住,您正在尝试学习如何与现有的开发社区合作。这是一个由来自各行各业的人组成的多元化群体,他们对编码、风格和流程都有很高的标准。这些标准是随着时间的推移根据他们发现的对于如此庞大且地域分散的团队来说效果最佳的方式而创建的。请提前尽可能多地了解这些标准,因为它们有详细的文档记录;不要指望人们适应您或您公司的工作方式。

文档

Linux 内核源代码树有大量文档,对于学习如何与内核社区互动非常宝贵。当向内核添加新功能时,建议也添加新的文档文件,解释如何使用该功能。当内核更改导致内核暴露给用户空间的接口发生更改时,建议您将信息或补丁发送给手册页维护者 alx@kernel.org,并抄送列表 linux-api@vger.kernel.org,并在手册页中解释更改。

以下是内核源代码树中需要阅读的文件列表:

Documentation/admin-guide/README.rst

该文件简要介绍了 Linux 内核,并描述了配置和构建内核所必需的内容。刚接触内核的人应该从这里开始。

Documentation/process/changes.rst

此文件列出了成功构建和运行内核所需的各种软件包的最低级别。

Documentation/process/coding-style.rst

这描述了 Linux 内核编码风格及其背后的一些原理。所有新代码都应遵循本文档中的准则。大多数维护者只会在遵循这些规则的情况下接受补丁,许多人只会在代码采用适当的风格时才会审查代码。

Documentation/process/submitting-patches.rst

此文件详细描述了如何成功创建和发送补丁,包括(但不限于):

  • 电子邮件内容

  • 电子邮件格式

  • 发送给谁

遵循这些规则并不能保证成功(因为所有补丁都将受到内容和风格的审查),但不遵循这些规则几乎总会阻止成功。

其他关于如何正确创建补丁的优秀描述是:

Documentation/process/stable-api-nonsense.rst

此文件描述了内核中不具有稳定 API 的有意识决策背后的原理,包括以下内容:

  • 子系统 shim 层(为了兼容性?)

  • 操作系统之间的驱动程序可移植性。

  • 减轻内核源代码树内的快速变化(或阻止快速变化)

本文档对于理解 Linux 开发理念至关重要,对于从其他操作系统开发过渡到 Linux 的人员非常重要。

Documentation/process/security-bugs.rst

如果您认为您在 Linux 内核中发现了安全问题,请按照本文档中的步骤帮助通知内核开发人员并帮助解决问题。

Documentation/process/management-style.rst

本文档描述了 Linux 内核维护人员如何运作以及其方法背后的共同精神。这对于任何刚接触内核开发的人员(或任何只是对此感到好奇的人员)来说都是重要的阅读材料,因为它解决了许多关于内核维护人员独特行为的常见误解和困惑。

Documentation/process/stable-kernel-rules.rst

此文件描述了有关如何发布稳定内核版本以及如果您想将更改纳入其中一个版本应执行的操作的规则。

Documentation/process/kernel-docs.rst

与内核开发相关的外部文档列表。如果您在内核文档中找不到您要查找的内容,请查阅此列表。

Documentation/process/applying-patches.rst

一篇好的介绍,确切描述了什么是补丁以及如何将其应用于内核的不同开发分支。

内核还有大量文档可以从源代码本身或 ReStructuredText 标记 (ReST) 自动生成,例如此文档。这包括对内核 API 的完整描述,以及关于如何正确处理锁定的规则。

所有此类文档都可以通过运行从主内核源代码目录分别生成为 PDF 或 HTML

make pdfdocs
make htmldocs

分别从主内核源代码目录生成。

使用 ReST 标记的文档将在 Documentation/output 中生成。它们也可以使用以下命令生成 LaTeX 和 ePub 格式:

make latexdocs
make epubdocs

成为内核开发人员

如果您对 Linux 内核开发一无所知,则应查看 Linux KernelNewbies 项目

它包含一个有用的邮件列表,您可以在其中提出几乎任何类型的基本内核开发问题(在提出过去已回答过的问题之前,请务必先搜索存档。)它还有一个 IRC 频道,您可以使用它实时提出问题,以及许多有用的文档,这些文档对于学习 Linux 内核开发很有用。

该网站包含有关代码组织、子系统和当前项目(包括树内和树外)的基本信息。它还描述了一些基本后勤信息,例如如何编译内核和应用补丁。

如果您不知道从哪里开始,但又想寻找一些开始做的事情以加入内核开发社区,请转到 Linux Kernel Janitor 的项目

这是一个很好的起点。它描述了一系列相对简单的问题,这些问题需要在 Linux 内核源代码树中进行清理和修复。通过与负责该项目的开发人员合作,您将学习如何将您的补丁提交到 Linux 内核树的基本知识,并且如果您还没有想法,可能会被引导到下一步的工作方向。

在对 Linux 内核代码进行任何实际修改之前,务必先了解相关代码的工作原理。为此,没有什么比直接阅读代码更好的方法了(大多数棘手的部分都有很好的注释),甚至可以使用专门的工具来辅助阅读。这里特别推荐的工具是 Linux 交叉引用项目,它能够以自引用、索引的网页格式呈现源代码。一个优秀的、最新的内核代码仓库可以在以下网址找到:

开发流程

Linux 内核的开发流程目前由几个不同的主要内核“分支”和许多不同的子系统特定的内核分支组成。这些不同的分支是:

  • Linus 的主线树

  • 具有多个主版本号的各种稳定树

  • 子系统特定的树

  • linux-next 集成测试树

主线树

主线树由 Linus Torvalds 维护,可以在 https://linuxkernel.org.cn 或仓库中找到。其开发流程如下:

  • 一旦发布新的内核,就会打开一个为期两周的窗口,在此期间,维护人员可以将大的差异提交给 Linus,通常是那些已经包含在 linux-next 中几周的补丁。提交大的更改的首选方法是使用 git(内核的源代码管理工具,更多信息可以在 https://git-scm.cn/ 中找到),但普通的补丁也可以。

  • 两周后,将发布一个 -rc1 内核,重点是使新内核尽可能稳定。此时的大多数补丁应该修复回归问题。一直存在的错误不是回归,因此只有在它们很重要的情况下才推送这些类型的修复。请注意,在 -rc1 之后,可能会接受一个全新的驱动程序(或文件系统),因为只要更改是独立的且不影响正在添加的代码之外的区域,这种更改就不会导致回归的风险。在发布 -rc1 之后,可以使用 git 将补丁发送给 Linus,但补丁还需要发送到公共邮件列表以供审核。

  • 每当 Linus 认为当前的 git 树处于足够合理的、适合测试的状态时,就会发布一个新的 -rc 版本。目标是每周发布一个新的 -rc 内核。

  • 此过程会持续到内核被认为“准备就绪”,该过程应该持续大约 6 周。

值得一提的是 Andrew Morton 在 linux-kernel 邮件列表上关于内核发布的言论:

“没有人知道内核何时会发布,因为它是根据感知的错误状态而不是根据预先设定的时间表发布的。”

具有多个主版本号的各种稳定树

具有 3 部分版本的内核是 -stable 内核。它们包含针对安全问题或在给定主线版本中发现的重大回归的相对较小和关键的修复。主要稳定系列中的每个版本都会增加版本号的第三部分,保持前两部分不变。

对于那些想要最新的稳定内核并且不热衷于帮助测试开发/实验版本的用户,这是推荐的分支。

稳定树由“stable”团队 <stable@vger.kernel.org> 维护,并根据需要发布。正常的发布周期约为两周,但如果没有紧急问题,可能会更长。相反,一个与安全相关的问题可能会导致几乎立即发布。

内核树中的文件 Documentation/process/stable-kernel-rules.rst 记录了哪些类型的更改对 -stable 树是可接受的,以及发布过程如何运作。

子系统特定的树

各种内核子系统的维护人员,以及许多内核子系统开发人员,在其源代码仓库中公开其当前的开发状态。这样,其他人就可以看到内核不同区域正在发生的事情。在开发迅速的领域,可能会要求开发人员将其提交基于此类子系统内核树,以避免提交与其他已经进行的工作之间的冲突。

这些仓库大多数是 git 树,但也使用了其他 SCM,或者作为 quilt 系列发布补丁队列。这些子系统仓库的地址列在 MAINTAINERS 文件中。它们中的许多可以在 https://git.kernel.org/ 中浏览。

在将建议的补丁提交到此类子系统树之前,它会受到审核,该审核主要在邮件列表中进行(请参阅下面的相应部分)。对于几个内核子系统,此审核过程通过工具 patchwork 进行跟踪。Patchwork 提供了一个 Web 界面,显示补丁发布、对补丁的任何评论或修订,维护人员可以将补丁标记为正在审核、已接受或已拒绝。这些 patchwork 站点中的大多数都列在 https://patchwork.kernel.org/ 中。

linux-next 集成测试树

在将子系统树中的更新合并到主线树之前,需要对其进行集成测试。为此,存在一个特殊的测试仓库,几乎所有子系统树每天都会被拉入其中。

通过这种方式,linux-next 概述了在下一个合并期间预计会进入主线内核的内容。非常欢迎喜欢冒险的测试人员对 linux-next 进行运行时测试。

错误报告

主内核源代码目录中的文件 '报告问题' 描述了如何报告可能的内核错误,并详细说明了内核开发人员需要哪些类型的信息来帮助追踪问题。

管理错误报告

实践你的黑客技能的最佳方法之一是修复其他人报告的错误。你不仅会帮助内核更加稳定,而且你还会学习如何修复现实世界中的问题,你会提高你的技能,其他开发人员也会意识到你的存在。修复错误是获得其他开发人员认可的最佳方法之一,因为没有多少人喜欢浪费时间修复其他人的错误。

要处理已经报告的错误报告,请找到你感兴趣的子系统。检查 MAINTAINERS 文件,该子系统的错误报告会发送到哪里;通常它是一个邮件列表,很少是一个错误跟踪器。搜索该地方的存档,查找最近的报告,并在你认为合适的地方提供帮助。你可能还想查看 https://bugzilla.kernel.org 以获取错误报告;只有少数内核子系统积极使用它进行报告或跟踪,尽管如此,整个内核的错误都会在那里存档。

邮件列表

正如上述一些文档所述,大多数核心内核开发人员都参与了 Linux 内核邮件列表。有关如何订阅和取消订阅该列表的详细信息,请访问

网络上有很多不同的地方都有邮件列表的存档。使用搜索引擎查找这些存档。例如:

强烈建议你在将要提出的主题发布到列表之前,搜索有关该主题的存档。许多已详细讨论过的内容仅记录在邮件列表存档中。

大多数单独的内核子系统也有自己单独的邮件列表,他们在那里进行开发工作。请参阅 MAINTAINERS 文件,了解不同组的列表是什么。

许多列表都托管在 kernel.org 上。有关它们的信息,请访问

请记住在使用列表时遵循良好的行为习惯。尽管有点老套,以下 URL 提供了一些与列表(或任何列表)交互的简单准则:

如果有多人回复你的邮件,收件人的抄送:列表可能会变得很大。如果没有充分的理由,请不要从抄送:列表中删除任何人,或者不要仅回复列表地址。习惯于收到两次邮件,一次来自发件人,一次来自列表,不要试图通过添加花哨的邮件标头来调整它,人们不会喜欢它。

请记住保持上下文和回复的归属完整,将“John Kernelhacker wrote ...:” 行保留在回复的顶部,并在各个引用的部分之间添加你的陈述,而不是在邮件顶部书写。

如果将补丁添加到邮件中,请确保它们是纯文本格式,如 Documentation/process/submitting-patches.rst 中所述。内核开发人员不想处理附件或压缩补丁;他们可能想评论你补丁的各个行,而这只有通过这种方式才有效。请确保你使用的邮件程序不会破坏空格和制表符。一个好的第一步测试是将邮件发送给自己,并尝试自己应用你的补丁。如果不起作用,请修复你的邮件程序或更改它,直到它可以工作为止。

最重要的是,请记住尊重其他订阅者。

与社区合作

内核社区的目标是提供最好的内核。当你提交补丁以供接受时,它将仅根据其技术优点进行审查。那么,你应该期待什么?

  • 批评

  • 评论

  • 更改请求

  • 理由请求

  • 沉默

请记住,这是将你的补丁加入内核的一部分。你必须能够接受对你的补丁的批评和评论,在技术层面上评估它们,并重做你的补丁或提供清晰简洁的理由来说明为什么不应该进行这些更改。如果没有人回复你的帖子,请等待几天再试一次,有时事情会在大量信息中丢失。

你不应该做什么?

  • 期望你的补丁在没有质疑的情况下被接受

  • 变得防御性

  • 忽略评论

  • 在没有进行任何请求的更改的情况下重新提交补丁

在一个追求最佳技术解决方案的社区中,对于一个补丁的益处总会有不同的意见。你必须具有合作精神,并愿意调整你的想法以适应内核。或者至少愿意证明你的想法是值得的。记住,犯错是可以接受的,只要你愿意朝着正确的解决方案努力。

你的第一个补丁得到的回复很可能只是一列你需要纠正的十几个问题。这意味着你的补丁不会被接受,也是针对你个人的。只需纠正针对你的补丁提出的所有问题并重新发送即可。

内核社区与公司结构的差异

内核社区的运作方式与大多数传统的公司开发环境不同。以下是一些你可以尝试避免问题的方法:

关于你提出的更改,应该说的好话

  • “这解决了多个问题。”

  • “这删除了 2000 行代码。”

  • “这是一个补丁,解释了我试图描述的内容。”

  • “我在 5 种不同的架构上测试过它...”

  • “这是一系列小补丁,它们...”

  • “这提高了典型机器的性能...”

你应该避免说的坏话

  • “我们在 AIX/ptx/Solaris 中是这样做的,所以它一定是好的...”

  • “我已经做了 20 年了,所以...”

  • “这对我们公司赚钱是必要的”

  • “这是为我们的企业产品线准备的。”

  • “这是我的 1000 页设计文档,描述了我的想法”

  • “我为此工作了 6 个月...”

  • “这是一个 5000 行的补丁,它...”

  • “我重写了所有当前的混乱代码,这就是结果...”

  • “我有一个截止日期,这个补丁需要立即应用。”

内核社区与大多数传统软件工程工作环境的另一个不同之处在于交互的无脸性。使用电子邮件和 IRC 作为主要沟通形式的一个好处是,它消除了基于性别或种族的歧视。Linux 内核的工作环境接受女性和少数群体,因为你只是一个电子邮件地址。国际化方面也有助于创造公平的竞争环境,因为你无法根据一个人的名字来猜测性别。一个男人可能叫 Andrea,一个女人可能叫 Pat。大多数在 Linux 内核中工作并表达过意见的女性都有过积极的体验。

对于一些不习惯英语的人来说,语言障碍可能会导致问题。为了在邮件列表中正确表达你的想法,需要掌握良好的英语,因此建议你在发送电子邮件之前检查一下,确保它们在英语中是有意义的。

分解你的更改

Linux 内核社区不乐于接受一次性丢给它的大段代码。更改需要被适当地引入、讨论并分解成小的、独立的片段。这几乎与公司通常的做法完全相反。你的提案也应该在开发的早期阶段就提出,以便你可以收到关于你正在做的事情的反馈。这也让社区感觉你是在和他们一起工作,而不是仅仅把他们当作你功能的倾倒场。然而,不要一次向邮件列表发送 50 封电子邮件,你的补丁系列通常应该比这小得多。

分解更改的原因如下:

  1. 小补丁增加了你的补丁被应用的可能性,因为它们不需要花费太多时间或精力来验证其正确性。一个 5 行的补丁可以被维护者看一眼就应用。然而,一个 500 行的补丁可能需要几个小时来审查其正确性(所需时间与补丁大小成指数比例,或类似)。

    小补丁也使得在出现问题时很容易调试。逐个回滚补丁比在应用(并破坏了某些东西)之后剖析一个非常大的补丁要容易得多。

  2. 不仅发送小补丁很重要,在提交之前重写和简化(或简单地重新排序)补丁也很重要。

以下是来自内核开发人员 Al Viro 的一个类比:

“想象一位老师在给数学学生的作业评分。老师不想看到学生在得出解决方案之前所做的尝试和错误。他们想看到最简洁、最优雅的答案。一个好学生知道这一点,并且永远不会在最终解决方案之前提交她的中间过程。

内核开发也是如此。维护者和审查者不想看到解决问题背后思考过程。他们希望看到一个简单而优雅的解决方案。”

在呈现优雅的解决方案与与社区合作并讨论你未完成的工作之间保持平衡可能具有挑战性。因此,最好在早期阶段获得反馈以改进你的工作,同时也要保持你的更改在小块中,这样它们可能会被立即接受,即使你的整个任务现在还没有准备好包含在内。

还要意识到,发送未完成且将在“以后修复”的补丁是不可以接受的。

证明你的更改是合理的

在分解你的补丁的同时,让你 Linux 社区知道为什么他们应该添加此更改非常重要。新功能必须被证明是需要和有用的。

记录你的更改

在发送你的补丁时,请特别注意你在电子邮件文本中说的话。此信息将成为补丁的 ChangeLog 信息,并将永久保留供所有人查看。它应该完整地描述补丁,包括:

  • 为什么需要此更改

  • 补丁的总体设计方法

  • 实现细节

  • 测试结果

有关所有这些内容的更多详细信息,请参阅文档的 ChangeLog 部分

所有这些事情有时都很难做到。可能需要数年才能完善这些实践(如果有的话)。这是一个持续改进的过程,需要大量的耐心和决心。但不要放弃,这是可能的。很多人以前都做到了,而且每个人都必须从你现在的位置开始。


感谢 Paolo Ciarrocchi 允许基于他撰写的文本来撰写“开发过程”(https://lwn.net/Articles/94386/)部分,并感谢 Randy Dunlap 和 Gerrit Huizenga 提供了一些关于你应该和不应该说的事情的清单。还要感谢 Pat Mochel、Hanna Linder、Randy Dunlap、Kay Sievers、Vojtech Pavlik、Jan Kara、Josh Boyer、Kees Cook、Andrew Morton、Andi Kleen、Vadim Lobanov、Jesper Juhl、Adrian Bunk、Keri Harris、Frans Pop、David A. Wheeler、Junio Hamano、Michael Kerrisk 和 Alex Shepard 的审查、评论和贡献。没有他们的帮助,这份文档是不可能完成的。

维护者:Greg Kroah-Hartman <greg@kroah.com>