How to write Rust in the kernel: part 3

发布于:2025-08-02 ⋅ 阅读:(11) ⋅ 点赞:(0)

The interfaces between C and Rust in the kernel have grown over time; any non-trivial Rust driver will use a number of these. Tasks like allocating memory, dealing with immovable structures, and interacting with locks are necessary for handling most devices. There are also many subsystem-specific bindings, but the focus of this third item in our series on writing Rust in the kernel will be on an overview of the bindings that all kernel Rust code can be expected to use.
随着时间的推移,内核中 C 与 Rust 之间的接口不断发展;任何非平凡的 Rust 驱动程序都会使用其中的若干接口。诸如内存分配、处理不可移动结构以及与锁交互等任务,对于大多数设备的处理来说都是必要的。虽然还有许多子系统特定的绑定,但我们这一系列“在内核中编写 Rust”文章的第三部分将重点介绍所有内核 Rust 代码都可能会使用的通用绑定接口。

Rust code can call C using the foreign function interface (FFI); given that, one potential way to integrate Rust into the kernel would have been to let Rust code call kernel C functions directly. There are a few problems with that approach, however: __always_inline functions, non-idiomatic APIs, etc. In particular, C and Rust have different approaches to freeing memory and locking.
Rust 代码可以通过外部函数接口(FFI)调用 C 代码;因此,一种将 Rust 集成进内核的潜在方式是让 Rust 代码直接调用内核的 C 函数。但这种方式存在一些问题:例如 __always_inline 函数、非惯用的 API 等。尤其值得注意的是,C 和 Rust 在内存释放和锁机制方面采用了不同的处理方式。

During the early planning phases, the project proposed adopting a rule that there should be a single, centralized set of Rust bindings for each subsystem, as explained in the kernel documentation. This has the disadvantage (compared to direct use of Rust's FFI) of creating some extra work for a Rust programmer who wishes to call into a new area of the kernel, but as more bindings are written that need should go away over time. The advantage of the approach is that there's a single set of standardized Rust interfaces to learn, with all of the documentation in one place, which should make building and understanding the bindings less work overall. The interfaces can also be reviewed by the Rust maintainers in one place for safety and quality.
在早期的规划阶段,该项目提议为每个子系统制定一套集中管理的 Rust 绑定接口,这一原则也在内核文档中有所说明。与直接使用 Rust FFI 相比,这种做法的缺点是当 Rust 程序员希望调用某个新的内核模块时,可能会多出一些额外的工作;但随着绑定的不断完善,这种负担会逐渐减轻。这种方式的优点是提供了一套统一标准的 Rust 接口,所有文档集中在一个地方,使得学习、构建和理解这些绑定变得更加高效。此外,这些接口也可以由 Rust 维护者集中审核,以保证其安全性和质量。

Allocating memory

分配内存

Like C, Rust puts local variables (including compound structures) on the stack by default. But most programs will eventually need the flexibility offered by heap allocation and the limitations on kernel-stack size mean that even purely local data may require heap-allocation. In user space, Rust programs use automatic heap allocations for some types — mainly Box (a smart pointer into the heap) and Vec (a growable, heap-allocated array). In the kernel, these interfaces would not provide nearly enough control. Instead, allocations are performed using the interfaces in the kernel::alloc module, which allow for specifying allocation flags and handling the possibility of failure.
与 C 类似,Rust 默认将局部变量(包括复合结构体)放置在栈上。但大多数程序最终都会需要堆分配所提供的灵活性,而内核栈大小有限,这意味着即使是纯粹的局部数据,也可能需要通过堆进行分配。在用户空间中,Rust 程序使用自动堆分配来处理某些类型——主要包括 Box(指向堆的智能指针)和 Vec(一个可增长的堆分配数组)。然而,在内核中,这些接口的控制能力远远不够。因此,内存分配是通过 kernel::alloc 模块中的接口完成的,这些接口允许指定分配标志并处理可能的分配失败情况。

The Rust interfaces support three ways to allocate kernel memory: Kmalloc, Vmalloc, and KVmalloc, corresponding to the memory-management API functions with similar names.


网站公告

今日签到

点亮在社区的每一天
去签到