LWN:初识6.1内核中的Rust!

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

A first look at Rust in the 6.1 kernel

By Jonathan Corbet
October 13, 2022
DeepL assisted translation
https://lwn.net/Articles/910762/

在 6.1 版本中有很多重要的改动被合并到 mainline 了,但是其中一个最受关注的改动,对内核用户的短期影响其实也最小,也就是引入了对 Rust 编程语言的支持。没有一个使用 6.1 版内核的系统会运行 Rust 内核代码,但是这个改动确实给了内核开发者机会,可以开始在内核环境中玩这种语言,并感受 Rust 开发。不过,对于大多数开发者来说,最可能得到的结论是,内核中的 Rust 还不足以做多少有趣的事情。

为 Linux 内核开发 Rust 的工作已经进行了几年,它已经产生了许多支持代码,以及一些有意思的驱动程序。还有其他一些正在进行的计划,包括用 Rust 语言编写 Apple 的图形驱动。不过,在最初并入 mainline kernel 时,Linus Torvalds 明确表示,应该尽可能少包含新功能。因此,这些驱动程序和它们的支持代码都被拿掉了,必须要等未来的内核再发布。现在有的功能,只够编译一个 loadable module 并加载到 kernel,以及一个很简单的 sample module。

Building Rust support

感兴趣的开发者会遇到的第一个挑战就是如何进行编译。内核配置过程会在 build 系统中寻找一些先决条件,如果不存在的话就会直接默默地禁用掉 Rust 相关的选项,因此它们甚至不会显示在 make menuconfig 中。尽管编者在系统上安装了 Rust,但还是遇到了这种情况,因此被迫进入了一个可耻的过程,开始实际去阅读文档来弄清还缺少什么。

构建 Rust 支持,需要特定版本的 Rust 编译器和 bindgen 工具——具体来说就是 Rust 1.62.0 和 bindgen 0.56.0。如果目标系统上有更加新的版本,config 的过程会给出 warning,但还是会继续。对于那些试图用发行版提供商所提供的 Rust toolchain 进行编译的人来说,更尴尬的是,这个编译过程还需要 Rust 标准库的源代码,这样才可以编译自己的 core crate 以及 alloc crate。在发行版提供商开始提供 "Rust for the kernel" 这样的 package 之前,想把这些代码加到 build 过程中可以找到的地方,还是有点困难的。

要想满足这个以来,一个简单的方法是干脆放弃发行版中提供的 toolchain,而从 Rust git 仓库来安装一切。"getting started" 页面描述了如何做到这一点;这里不可避免地需要去使用那些得很有信心才敢尝试的 "curl|bash" 操作。安装程序完全不关心一个人打算把 Rust 的东西安装在什么位置(它会直接选择 ~/.cargo),并且默默地修改掉用户的 Bash 启动脚本,把新增目录添加到 PATH 变量中。不过,最终这种做法可以奏效,并且也让安装所需的依赖工具的动作变得更容易了。

The sample module

在完成上述动作之后,内核配置系统就允许用户去打开 CONFIG_RUST 选项了。还有一个 config 选项可以用来 build 这个 sample module。该模块(samples/rust/rust_minimal.rs)确实是个最小版本了,但它足以让我们感受到 Rust 写的内核代码会是什么样子。它的开头就是 Rust 中的类似 #include 功能的一句话:

use kernel::prelude::*;

这就会把 rust/kernel/prelude.rs 中的声明内容都加进来,从而可以开始使用那些 type、function 和 macro。

用 C 语言编写的 kernel module 会包括对 MODULE_DESCRIPTION()和 MODULE_LICENSE()等宏的调用,这些宏会把 module 的 metadata 放在一个单独的 ELF section 里。module_init()和 module_exit() 宏分别标识了 module 的构造函数和析构函数。Rust 中的写法则是将这些程式化的内容的大部分都放到一个 macro 调用中:

module! {
    type: RustMinimal,
    name: b"rust_minimal",
    author: b"Rust for Linux Contributors",
    description: b"Rust minimal sample",
    license: b"GPL",
}

这个宏中各个字段的排序是很严格的,如果开发者顺序写错了就会看到抱怨。除了把所有这些信息放到一个调用中之外,module! 这个宏还包括一个 type: 项,这就是 module 实际代码的指针。开发者需要提供一个 type,来做具体的工作。在 sample module 中,这个 type 看起来像这样:

struct RustMinimal {
    numbers: Vec<i32>,
}

这是一个简单的结构,其中包含一个 32 位整数值的 Vec(基本上就是数组的意思)。这本身很简单,但 Rust 允许为 structure 这种类型添加一个接口("trait")的实现。因此,这个 sample module 为 RustMinimal type 实现了 kernel::Module trait:

impl kernel::Module for RustMinimal {
    fn init(_module: &'static ThisModule) -> Result<Self> {
        pr_info!("Rust minimal sample (init)\n");
        pr_info!("Am I built-in? {}\n", !cfg!(MODULE));

        let mut numbers = Vec::new();
        numbers.try_push(72)?;
        numbers.try_push(108)?;
        numbers.try_push(200)?;

        Ok(RustMinimal { numbers })
    }
}

init() 函数就应该做常规的 module 初始化的工作。在这个例子中,它会向系统日志唠叨几句(在这个过程中展示了可以用 cfg!() 宏在编译时查询内核 config 参数)。然后,它分配了一个 mutable (可变的) Vec,并试图将三个数字放进去。这里的 try_push() 很重要:一个 Vec 会在必要时调整自己的 size。这牵涉到内存分配,而在内核环境中这个动作可能会失败。在分配失败时,try_push() 会返回一个 failure status,这进而会导致 init() 也返回失败(这就是行末的"?"的用处)。

最后,如果一切顺利的话,就会返回一个 RustMinimal 结构,其中包含了分配的 Vec,以及一个成功完成的 status。由于这个模块没有跟其他任何内核子系统交互,它实际上不会做任何事,只是耐心地等待被删除。在 Kernel::Module trait 中没有删除模块的函数;相反,我们使用了 RustMinimal 类型的一个简单的 destructor(析构函数):

impl Drop for RustMinimal {
    fn drop(&mut self) {
        pr_info!("My numbers are {:?}\n", self.numbers);
        pr_info!("Rust minimal sample (exit)\n");
    }
}

这个函数打印出初始化时存储在 Vec 中的数字(从而确认数据这时还是存在的)然后就 return;之后,module 会被删除,释放掉相应的内存。似乎没有办法让 module 移除的动作失败,其实现实世界的 module 有时候还是会碰到这种情况的。

Beyond "hello world"

这就是在 6.1 kernel 中对 Rust 内核 module 可以做些什么的大致介绍了。Torvalds 要求能做 "hello world" 类型的东西,于是我们就得到了这些。这是一个可以用来尝试的版本,但目前还不能用来做真正意义上的内核编程。

希望这种情况在不久的将来会有所改变。Rust-for-Linux 开发者的下一步将会是开始添加他们所创建的一些基础设施,以与其他内核子系统对接。这就会使得人们可以真正开始写一些内核代码了,同样重要的是,可以展示与其他内核子系统配合需要给出怎样的抽象定义。这需要尽快实现;Rust in the kernel 现在劲头儿很足,但如果它只限于对内核的日志信息进行 print,那大家很快就没有动力了。如果幸运的话,6.2 版内核中的 Rust 将获得大量的功能。

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

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

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

format,png

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值