在今天的Linux Plumbers Conference 2020大会上,Geoffery Thomas等人以“Barriers to in-tree Rust”为主题,讨论了想要把Rust引入到Linux内核项目中作为一种可选的开发语言,还需要解决的一些问题。
Rust适合作为内核开发语言主要有两点原因:
- Rust是一个C语言很好的替代,很符合Linux内核对编程语言的需求:没有垃圾回收,更符合内核的面向对象模型。
- 使用Rust更容易编写安全的代码。造成安全问题的use-after-free,缓存溢出,未初始化的内存等等的程序缺陷很容易避免。
Rust的优势让很多开发者感受到了吸引力。对新项目来说,选择Rust的技术困难可能不太大,但是对已有项目来说,到底有多可行呢?Linux社区已经在严肃的考虑这个问题。除了“可能没人懂Rust的patch怎么review因为没有用过Rust”这种鸡生蛋的问题以外,还有一些更加实际的项目框架问题需要考虑:
Cargo和库
Cargo是Rust官方的项目管理工具,可以安装和管理依赖,也可以控制构建过程。Geoffery认为虽然cargo的依赖管理对内核完全没有用(比如编译内核的过程不能依赖从网络上下载一个库,所有的代码都必须是in-tree的),但是使用cargo还是有一定的意义的(具体是什么并没有深入)。
Rust的语言的运行时包含core / alloc / std三个层级,其中core是最核心的,内核代码也需要用到。alloc需要运行时里包含动态内存管理,这个在内核里是有的(kmalloc),但是有人指出,内核GPF_*的API可能比较难适配。std库基本是封装操作系统的输入输出,文件操作等API,所以在内核里是用不到的。
跟C语言之间的ABI
两个语言之间如何互相调用?这个Rust是支持的,也不是Linux特有的问题,工具也有,但是如果大量的涉及到一些比较底层的操作,比如位操作、#ifdef检测config、以及各种C的预处理技巧,怎么在Rust里保持一致等等,可能会导致一些混乱。感觉像trace这样的框架,是不是需要用Rust重新实现一次呢?
RCU
内核使用了很多精细的同步机制,比如RCU。在讨论到怎么样从Rust访问RCU保护的数据时,Geoffery认为从语言层面是可行的,也有一些代码适配的进展。具体可以见
https://github.com/fishinabarrel/linux-kernel-module-rust/pull/250
除此之外,还有一些Rust语言特性导致的数据结构区别,比如双链表等,似乎也不是很大的困难——常见问题已经有一些可以参考的库和unsafe大法来解决(来自Rust社区的说法)。
GCC编译
rustc目前依赖LLVM作为编译工具,但是GCC仍然是内核的主流编译方式。使用LLVM编译整个内核可能是目前比较可行的做法,因为大家对混合LLVM+GCC的方式表示了一些担忧——使用两套编译器就无法做LTO,更重要的是,两个编译器的微妙差异可能会导致内部ABI不兼容问题。还有人提出,应该考虑给GCC添加一个Rust前端。
多平台支持
Linux支持的体系结构众多,Rust暂时还不能全部覆盖。(主要是arc, sparc32)
不过这个问题可以用“先让一部分人Rust起来”的思路解决。
mrustc
除了把Rust代码编译成.o再跟C语言的目标文件链接在一起,还有一种可能是用mrustc把Rust代码翻译成C,再进行编译。
https://github.com/thepowersgang/mrustc
Linus Torvalds的态度
https://lkml.org/lkml/2020/7/10/1261 I’d want the first rust driver (or whatever) to be introduced in such a simple format that failures will be obvious and simple.
总结
所谓魔鬼都在细节之中。对内核项目来说,要引入一个新的语言并不容易。即使没有致命的问题,也需要投入很多的精力来排除一些障碍,让双语言开发被流畅的支持。如果Linux真的能够采纳Rust,那对整个Rust生态必将是一个巨大的利好消息。
最后,这次虽然更多的是一个主题讨论,不过还是有一份演讲的slides可以看的:
https://linuxplumbersconf.org/event/7/contributions/804/attachments/641/1168/barriers-to-in-tree-rust.pdf