LWN: Linux kernel 中的Rust!

关注了就能看到更多这么棒的文章哦~

The Rust for Linux project

By Jonathan Corbet
September 16, 2021
Kangrejos
DeepL assisted translation
https://lwn.net/Articles/869145/

首届 Rust for Linux 会议,又名 Kangrejos,于 9 月 13 日正式开始了。组织者 Miguel Ojeda 在开幕演讲上概述了为什么希望在内核中使用 Rust、这里有哪些挑战、以及目前的状况如何。讲座以及后续讨论很好地概述了推动这一倡议的原因,以及可能存在的一些症结。

Why Rust?

他说,今年是 Linux 内核诞生 30 周年,但同时也是 C 语言的第一个 ISO 标准诞生 30 周年。C语言历史悠久,也有很多负担,但它仍然深度参与着如今的开发工作、并且也是很有意思的。Ojeda 说,他正在与 C 语言委员会合作来改进该语言,但就算它能取得成果的话,这一过程也需要很长的时间。

ce16fedc00bd5e98fa07d62bde3b1cae.png

C 语言用于内核开发的原因很多。它速度快,便于编写底层代码,简单,而且很适合 Linux kernel 这个环境。但是有一个小问题,就是有一些通常被人们称为 "undefined behavior" 的行为。Rust 的优势在于它消除了这类 undefined behavior,至少在 "safe" 代码中是这样的。事实上,Rust 开发者所说的 "safe" 的意思,就是指它消除了这些未明确定义情况下的行为,而跟 "safety-critical" 这类术语完全没有关系。根据这个定义来说的话,C语言中的 abort() 调用就是 safe 的,即使最后的结果是杀掉了一个进程。Ojeda 为 C 语言提出了一个 "[ [safty] ]" 属性,希望用它来标记所有那些需要避免 undefined behavior 的函数(并让编译器来强制保证这一点),但该提议没有取得多少进展。

那么按照 Rust 的标准,什么是不 "safe" 的呢?not-safe 行为的清单包括:在指针被释放后使用指针、访问 NULL 指针、两次释放一块内存、使用未初始化内存中的内容、内存访问越界、数据竞态行为(data race)等等。他断言,这些事情在 Rust 代码的 safe 部分都不会发生。这就是为什么他希望在内核中能使用 Rust 代码。他说,大约 70% 的 C 语言漏洞是由这些 undefined behavior 而导致的,而安卓多媒体和蓝牙组件中的漏洞中接近 90% 都是这类问题。Rust 就可以帮得上忙了。Rust 还提供了许多其他优势,包括更严格的 type 类型、module 模块、模式匹配原语、lifetime、一套完整的开发工具等等。

在内核中使用 Rust 的坏处是什么?他说,不可能对所有的东西都完成建模,所以还是有必要使用一些不安全的代码的。Rust 语言比 C 语言要复杂得多,其额外的 run-time check 会导致性能损失。当然,对于内核开发者和维护者来说,这又是一种需要学习的语言,这也是一个很大的成本。他说这是一个一次性的成本,会有很多回报,但这仍然得是要花精力的。Rust for Linux 的开发者们很乐意帮助开发者们来克服这个最初的学习障碍。

那么,作为一种系统编程语言,Rust 与 C 相比起来怎么样?和 C 语言一样,它的速度很快。它和 C 语言一样可以开发底层代码,但根据具体代码的情况可能有些不一样,开发者也许对有些代码不容易预测其所产生的汇编代码是什么样子的。Rust 绝对不像 C 那么简单。他认为,Rust 和 C 一样都适合这个领域,但其他人可能会有其他看法。

Rust support in the kernel

到目前为止,Rust 支持了五个体系架构:armv6、arm64、powerpc、riscv 和 x86-64。目前为止做这些工作的目的并不是要去支持所有架构,那会带来很多底层工作,而不一定能带来什么新的好处。相反,我们的目的是要证明 Rust 是可以支持各种架构的。目前有三个项目正在为内核编译 Rust 代码。其中两个使用了 "官方" 的 rustc 前端,然后使用 LLVM 或 GCC 来生成代码。rustc/LLVM 的组合是目前领先的 Rust 编译器方案。Ojeda 没有对 rustc/GCC 的搭配介绍。第三个项目正在为 GCC 开发 native Rust 编译器(gccrs),预计将在一两年内完成。

Rust for Linux 的工作分为 Rust 和内核两部分代码 tree。Rust 这一边有两个 crates,分别是 core(底层功能)和 alloc(数据结构等)。alloc crate 也是之前试图提交到内核里面的一部分代码,最终可能并不需要。这些 crate 被认为是 Rust 库的一部分,而不是内核的一部分。

在内核这一边有 kernel 和 builtins crates。kernel crate 抽象了跟内核其他部分的接口。利用了 bindgen 工具来生成 binding,从而允许从 Rust 调用内核函数。目前看来还没有需要从 C 语言调用到 Rust 的情况。他认为有一个问题仍然需要完整的解决方案,那就是如何保持 C 语言和 Rust 两边同步。也就是要让 Rust 成为内核中的一等公民,如果开发者做了一个导致 Rust 代码被破坏的改动,那么他们就得负责 fix 这个问题,也就是跟内核的 C 代码待遇要一样。不过,目前还不清楚如何能达到这个效果。

驱动程序作者的观点就很有趣了。他们希望能为驱动通常需要调用的所有内核函数都创建好 Rust binding,打通这一使用场景,但 Rust-on-Linux 开发者的计划不是这样的。相反,他介绍说他们正在扩充 kernel crate 来添加针对一些子系统的抽象层以及接口,希望能在编写驱动程序时不再有任何不 safe 的代码。

Discussion

此时有些人提出了自己的担忧,认为这会要求维护者需要学习 Rust。Ojeda 承认这确实会是有必要的。最终维护者总是需要能够对他们的子系统负责的,尽管 Rust 开发者最初会帮助他们。Laurent Pinchart 说,可能需要很长一段时间的帮助,他没有办法找到时间能停下手头的工作来学习 Rust,所以他将很难对他的子系统中的 Rust 代码负责。

Ojeda 回答说,Rust 的开发者已经意识到了这一点,他们一直在着重挑选那些有时间和兴趣接受这一挑战的维护者的子系统来作为开始。希望这样能创造出足够的例子和经验来对今后引入其他子系统提供帮助。但他重申,维护者需要加入进来。如果 Rust 不是内核中的一等公民,那么这个实验就不会成功。他还说,早一点加入 Rust 的维护者可能会比晚一点加入的维护者能得到更多的帮助,这也是半开玩笑的说法。

708f1c2c140f66a42bdd81114a75340e.png

Ojeda 说,虽然子系统维护者可能会增加一些困难,但对于驱动程序开发者来说生活会更加容易,他们只需要使用提供给他们的(safe)接口就好。Pinchart 反对说,驱动程序编写者经常发现他们需要对核心子系统进行修改,这样才能正确支持他们的设备,所以生活并不是想象的那么简单。他说,如果对驱动程序作者的要求提高到需要精通 Rust,这将会真正阻碍一些人参与进来。

Paolo Bonzini 担心 Rust 代码会抑制 internal kernel API 的改动。开发者可能会发现 Rust 代码是某个 API 的唯一使用者了,但此时可能会懒的修复这部分代码(或者也是没有能力去做这个),所以旧 API 就将继续存在。他问道:Rust 开发者打算为核心内核 API 增加多少个 wrapper?例如,如果 file_operations 结构中只有一些成员变量在 Rust 代码中使用到了,那么是否还会对所有成员变量都生成 binding?如果增加了不必要的 binding 的话可能会导致将来改变这些 operation 的时候变得更加困难。Ojeda 回答说,对于像 file_operations 这么核心的东西,他们可能会把所有成员变量都加进去,因为最终总是都会被使用的。其他情况下,只会实现 Rust 代码实际使用到的接口。

讨论接下来来到了工具链(toolchain),Ojeda 说,Linux 的 Rust 开发者目前只支持某一个特定版本的 Rust 编译器来编译任何一个内核版本。其他版本的编译器可能可以用,但不能保证。最终将有可能只会使用稳定的 Rust 特性来编译内核,那时就有可能支持更多的编译器版本了。他补充说,有人对 Rust 语言的总体稳定性表示担忧,但他认为这不是一个问题。这个语言现在很稳定,而且变得越来越稳定。现在编写的内核代码,即使是使用不稳定功能的代码,"大部分" 在今后也都可以继续使用。

正在开发 gccrs 的 Philip Herron 问道:Linux 的 Rust 开发者特别希望看到用 Rust 编写哪些部分的代码?Ojeda 的观点是文件系统以及其他一些包含大量状态的子系统将是很好的选择。Herron 接着问到,是否有计划挑选 Rust 语言的一个特定子集来用在内核中。他具体谈到了常量泛型(const generics),他说,这将是一个很适合在内核环境中使用的功能。但是会不会有一天会变得必须禁用这个功能从而减少维护者的负担?Ojeda 说,一些更高级的功能在 core 代码中可能是有用的,但他更希望看到驱动程序使用 Rust 语言中比较小的一个子集,避免像 "crazy metaprogramming" 之类的东西。

此时,会议的时间已经用完了,与会者们去喝咖啡了。更深入的讨论就放到了接下来的两天时间里。超过 30 名开发者参加了这次会议,这表明人们对用 Rust 编写内核代码这个想法有相当大的兴趣,即使这个功能目前还不在 mainline kernel 中。Rust in kernel 不是一个可以容易让人们接受方案,但就算它最终失败了,也不用后悔,毕竟都努力尝试过了。

全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。

欢迎分享、转载及基于现有协议再创作~

长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~

9b71a822774d80e892b78d5d19aa6423.png

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值