Rust 写进 Linux 内核之后

Linux 6.1 在 2022 年 12 月合并了第一批 Rust 代码。这件事发生时,内核社区里争论的声音几乎和支持的声音一样大。两年多过去了,尘埃并没有完全落定,但已经足够看清楚一些东西了。

Rust 进入 Linux 内核,不是一个关于编程语言的故事。它是一个关于如何在几千人同时参与的超大型系统里引入结构性变化的故事。


为什么是 Rust,为什么是现在

内核里的 C 代码已经有三十多年的历史。在这段时间里,内存安全漏洞构成了 Linux 安全问题的一大类——根据 Google 和微软分别发布的报告,生产系统中 70% 左右的严重安全漏洞可以追溯到内存安全问题。内核代码的特殊性在于:内核里没有保护网,一个 use-after-free 不是进程崩溃,是整个系统崩溃或被利用。

选择 Rust 的理由不复杂:Rust 的所有权系统在编译期强制检查内存安全,无需垃圾回收,没有运行时开销,和 C 的 FFI 互操作性可以接受。对内核这个场景来说,”在编译期排除一类错误”比”在运行期检测并处理错误”有根本性的优势。

为什么是现在?因为 Rust 的工具链和生态成熟到了一个临界点,Linux 内核社区里有人真的愿意把这件事推到落地,而 Linus Torvalds 也表达了谨慎的支持。这三个条件缺一不可。


实际合并了什么

两年多之后,内核里的 Rust 代码量和早期预期相比是克制的。已经合并的内容大致在这几个层面:

基础设施rust/ 目录下的内核 Rust 支持框架,包括内核数据结构的 Rust 绑定(kernel::preludekernel::synckernel::alloc 等),以及让 Rust 代码和内核 C 代码互操作的胶水层。这部分是其他所有工作的前提。

驱动程序:这是目前 Rust 代码最集中的区域。Apple M 系列芯片的 GPU 驱动(Nova GPU driver)选择了用 Rust 重写,这是迄今为止最受关注的 Rust 内核驱动项目。Nova 的开发者 Asahi Lina 在这个过程中提交了大量关于 Rust 绑定设计的改进,实际上推动了整个 Rust-for-Linux 框架的完善。

文件系统:一个实验性的 Rust 实现的文件系统抽象层正在推进中,但还没有合并到主线。

子系统绑定:内核 block 子系统、网络子系统的 Rust 绑定已经部分合并,让 Rust 驱动可以直接和这些子系统交互,而不需要每次都通过 C 胶水层。

代码量的数字不是最重要的。重要的是:这些代码在真实的内核版本里运行,被真实的用户使用,在真实的硬件上跑通。这和”实验性分支”是有本质区别的。


遇到了什么困难

困难比预想的多,而且大部分不是技术困难。

接受度的问题比技术本身更难解决。内核维护者里有人认为 Rust 是对现有代码库的不必要复杂化。一个具体的争议点:Rust 代码在同一个子系统里引入了新的错误处理模式(Result 类型),和现有 C 代码的 -ERRNO 返回值约定并存,让代码审查变得更复杂。

Rust 的 stable ABI 问题。内核内部没有稳定 ABI,但 Rust 本身没有稳定的 ABI 保证(#[repr(C)] 之外)。这意味着内核里的 Rust 绑定必须非常小心地处理跨越语言边界的数据结构。Rust-for-Linux 项目为此开发了大量包装类型和转换层,这些代码本身需要持续维护。

工具链绑定。内核现在对特定版本的 Rust 编译器有要求,因为内核用了一些 unstable 的 Rust 特性(主要是 const_generics 和部分 inline 相关 ABI)。这意味着每次 Rust 工具链更新,内核的 Rust 支持代码都需要跟着验证。对 C 内核来说,GCC 版本的要求宽松得多。

招募的困难。写 Rust 的人不一定懂内核,懂内核的人不一定写 Rust。这个交集比外部看起来小得多。Asahi Lina 的情况(既懂 ARM GPU 硬件、又能写高质量 Rust 内核代码)属于特例,不代表普遍供给。


什么是真实的收益

在 Nova GPU 驱动的开发过程中,出现了一个被广泛引用的事件:Asahi Lina 写的 Rust 驱动在早期测试中因为 GPU 固件的问题触发了一类竞争条件。在纯 C 实现里,这类问题通常会导致难以复现的内存损坏,排查成本极高。在 Rust 实现里,这个问题被编译器的借用检查器直接拒绝了——代码本身无法在存在竞争条件的情况下通过编译。

这个例子说明了 Rust 在内核里的核心收益:不是”消灭 bug”,而是”让某一类 bug 无法被写出来”

竞争条件和内存访问错误在内核里尤其危险,因为内核运行在 MMU 保护之外,错误的指针访问不会被隔离。Rust 的所有权模型和生命周期分析在这个场景下提供了传统 C 代码审查、静态分析工具都无法提供的保证。

另一个实际收益是:新驱动的开发体验有改善。内核 C API 有大量”约定俗成”的使用规范——某个函数返回的指针必须在某个条件下才是有效的,某段代码必须在中断上下文之外运行——这些约定在 C 里只能靠文档和代码审查来保证。Rust 的类型系统让一部分这类约定可以编码进类型里,违反约定就是编译错误。


什么没有改变

几件事比预想的改变得少:

内核主体还是 C,而且短期内不会变。几千万行的 C 代码不存在迁移的可能性。Rust 在内核里是”新增代码可以选择用 Rust 写”,不是”把 C 替换成 Rust”。这个定位本身是合理的,只是常被外界误读。

性能没有显著差异。这在预期之内,Rust 不引入运行时开销,生成的机器码质量和 C 相当。在某些场景下因为更积极的编译期优化有小幅提升,在某些场景下因为包装层有微小的额外开销。整体上,”Rust 会不会让内核变慢”的担忧在实测中基本没有出现。

安全漏洞不会消失。Rust 处理的是内存安全这一个类别,但内核的安全漏洞来源是多样的:逻辑漏洞、权限检查错误、驱动的协议实现问题——这些 Rust 都不负责。Rust 能做的是把内存安全这一项从漏洞来源列表里划去,或者大幅降低其概率。这已经是很大的价值,但不是银弹。


对工程决策的启示

从这件事里可以读出几个更普遍的工程判断:

在大型存量系统里引入新技术,边界清晰比全面替换更可行。Rust-for-Linux 成功的前提是它从来没有试图替换 C,而是在”新驱动”这个边界里找到了落脚点。存量代码的惯性是真实的,忽视它的改造计划很少能落地。

工具链的可维护性是长期成本。现在内核依赖特定的 Rust 编译器版本,这个依赖需要有人持续维护。开源项目引入新工具链,不只是引入”使用成本”,还有”跟进成本”——每次上游变更都可能产生适配工作。在决策时把这个成本算进去是必要的。

生态的建立是技术落地的前提。Rust-for-Linux 之所以能推进,是因为有 Rust-for-Linux 项目专门维护内核的 Rust 绑定,有社区在训练能写内核 Rust 代码的开发者,有文档在降低入门门槛。纯粹的技术优越性不会自动转化为落地,需要有人做生态建设。


Rust 进入 Linux 内核,两年多之后的状态大概是这样:比悲观者预期的要稳,比乐观者预期的要慢。

这大概是大型系统演化的正常节奏。


Rust 写进 Linux 内核之后
https://www.krli.org/2026/05/08/Rust-进入Linux内核之后/
作者
李科燃
发布于
2026年5月8日
许可协议