Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/DeelerDev/linux/llms.txt

Use this file to discover all available pages before exploring further.

Rust support was merged into the Linux kernel mainline in version 6.1. It gives kernel developers a second implementation language alongside C: one with a type system that eliminates entire classes of memory-safety bugs—use-after-free, null dereference, data races—at compile time. The Rust integration does not replace C; instead it provides an opt-in path for new drivers and subsystems, with a thin safe abstraction layer over the existing C kernel APIs.

Why Rust

Memory safety, no undefined behavior, zero-cost abstractions.

Toolchain setup

Install rustc, rust-src, bindgen, and LLVM.

The kernel crate

rust/kernel/ modules, the module! macro, and the Module trait.

Hello world module

A complete, annotated minimal Rust kernel module.

Available abstractions

Task, File, Mutex, SpinLock, workqueue, and more.

Building

CONFIG_RUST=y, make LLVM=1, and the rustdoc target.

What Rust brings to the kernel

Kernel code written in C has historically relied on programmer discipline to avoid memory errors. Rust’s ownership and borrowing rules enforce the same invariants mechanically:
  • No use-after-free: the borrow checker prevents accessing memory after the owning value is dropped.
  • No null-pointer dereferences: pointers in Rust are non-null by default; nullable pointers are wrapped in Option<*mut T>.
  • No data races: the Send and Sync marker traits prevent sharing mutable state across threads without synchronization.
  • No uninitialized memory reads: variables must be initialized before use; the compiler rejects programs that read from uninitialized memory.
  • Deterministic cleanup: destructors (Drop) run automatically and cannot be skipped, so resource leaks are a compiler error rather than a runtime bug.
Rust code in the kernel is written in #![no_std] mode. Only the core crate (a subset of the standard library with no heap dependency) is available by default. The kernel’s own kernel crate provides the allocator and kernel-specific wrappers.

Abstractions vs. bindings

The Rust-for-Linux architecture has two layers:
  1. Bindings (rust/bindings/): auto-generated by bindgen from C headers. Calling bindgen-generated functions is unsafe because C provides no safety guarantees the compiler can verify.
  2. Abstractions (rust/kernel/): hand-written, safe Rust wrappers around the bindings. A driver or file system written in Rust should call only abstraction APIs, never raw bindings directly.
my_driver.rs
    └─► kernel crate abstractions  (rust/kernel/)   ← safe
            └─► bindings crate     (rust/bindings/)  ← unsafe
                    └─► C kernel APIs               (include/)

Setting up the toolchain

Rust kernel development requires a recent stable rustc, the Rust standard library source, bindgen, and an LLVM toolchain.
pacman -S rust rust-src rust-bindgen
apt install rustc rust-src bindgen rustfmt rust-clippy
For Ubuntu, also export:
export RUST_LIB_SRC=/usr/src/rustc-$(rustc --version | cut -d' ' -f2)/library
dnf install rust rust-src bindgen-cli rustfmt clippy
# From inside the kernel source tree
rustup override set stable
rustup component add rust-src rustfmt clippy
cargo install --locked bindgen-cli

Verify the toolchain

# Run from the kernel source root
make LLVM=1 rustavailable
This runs the same logic Kconfig uses when deciding whether to offer CONFIG_RUST. If requirements are not met, it explains exactly what is missing.

The kernel crate

The kernel crate (source in rust/kernel/) is the primary API surface for Rust kernel code. It re-exports a curated set of abstractions through its prelude.

Key modules in rust/kernel/

ModuleContents
syncMutex, SpinLock, Arc, Completion, RcuData
taskTask — wraps struct task_struct
mmMemory management helpers
fsVirtual filesystem abstractions
netNetworking socket abstractions
workqueueWork, Queue — wraps kernel workqueues
errorError, Result — maps C errno values to Rust
strCStr, CString — kernel C-string types
printpr_info!, pr_err!, pr_debug!, dev_info!
allocKBox, KVec — kernel-allocator-backed collections
irqIRQ descriptor and handler abstractions
pci / platformBus driver abstractions

The prelude

use kernel::prelude::*;
This imports the most commonly needed items: module!, pr_info!, GFP_KERNEL, KBox, KVec, Arc, Result, Error, and others.

Writing a Rust kernel module

Every Rust kernel module uses the module! macro to declare its metadata and the kernel::Module trait to define its lifecycle. The module struct is instantiated on insmod and dropped on rmmod.

Minimal module

The following is the actual rust_minimal sample from samples/rust/rust_minimal.rs:
// SPDX-License-Identifier: GPL-2.0

//! Rust minimal sample.

use kernel::prelude::*;

module! {
    type: RustMinimal,
    name: "rust_minimal",
    authors: ["Rust for Linux Contributors"],
    description: "Rust minimal sample",
    license: "GPL",
    params: {
        test_parameter: i64 {
            default: 1,
            description: "This parameter has a default of 1",
        },
    },
}

struct RustMinimal {
    numbers: KVec<i32>,
}

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 = KVec::new();
        numbers.push(72, GFP_KERNEL)?;
        numbers.push(108, GFP_KERNEL)?;
        numbers.push(200, GFP_KERNEL)?;

        Ok(RustMinimal { numbers })
    }
}

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

Anatomy of a Rust module

module! {
    type: MyDriver,      // The struct that implements kernel::Module
    name: "my_driver",  // Module name (equivalent of MODULE_NAME)
    authors: ["Your Name <email@example.com>"],
    description: "My driver description",
    license: "GPL",     // Must be a GPL-compatible license string
}
The module! macro generates the C-visible init_module() and cleanup_module() symbols. It calls MyDriver::init() on load and drop() on unload.
impl kernel::Module for MyDriver {
    fn init(_module: &'static ThisModule) -> Result<Self> {
        // Returning Err(...) causes insmod to fail
        // Returning Ok(Self { ... }) completes the load
        Ok(MyDriver { /* ... */ })
    }
}
// Drop is the exit function — no module_exit() needed
Error propagation uses Rust’s ? operator. Result<T> in the kernel maps to Result<T, kernel::error::Error> where Error wraps a C errno integer. ENOMEM, EIO, EINVAL, and the rest are available as kernel::error::code::ENOMEM, etc., or via the prelude.

Available abstractions

Logging

Rust provides the same pr_* family as C, as macros that forward to the C printk implementation:
pr_info!("device found at IRQ {}\n", irq_num);
pr_err!("initialization failed: {}\n", err);
pr_warn!("deprecated configuration option set\n");
pr_debug!("entering {}\n", core::any::type_name::<Self>());

Synchronization: Mutex and SpinLock

use kernel::sync::{Mutex, SpinLock, Arc};
use kernel::prelude::*;

// Mutex wraps struct mutex; holds data T and provides RAII guard
let protected: Arc<Mutex<u32>> = Arc::pin_init(
    kernel::new_mutex!(0u32, "my_mutex"),
    GFP_KERNEL,
)?;

{
    let mut guard = protected.lock();  // returns MutexGuard<u32>
    *guard = 42;
}  // guard drops here, mutex is released

// SpinLock wraps spinlock_t
let spin: Arc<SpinLock<u32>> = Arc::pin_init(
    kernel::new_spinlock!(0u32, "my_spinlock"),
    GFP_KERNEL,
)?;

{
    let mut guard = spin.lock();  // returns SpinLockGuard<u32>
    *guard += 1;
}  // released here

Task

use kernel::task::Task;

// Get a reference to the current task
let current = Task::current();
pr_info!("running as pid {}\n", current.pid());

Work queues

use kernel::workqueue;

// Create a work item that runs my_work_fn on the system workqueue
let work = workqueue::Work::new(my_work_fn);
workqueue::system().enqueue(work);

Memory: KBox and KVec

KBox and KVec are kernel-allocator-backed equivalents of Box and Vec. They require a GFP flag to allow the caller to control whether the allocation may sleep.
use kernel::alloc::{KBox, KVec};

// KBox: heap-allocate a single value
let val: KBox<u64> = KBox::new(0u64, GFP_KERNEL)?;

// KVec: growable array
let mut v: KVec<i32> = KVec::new();
v.push(1, GFP_KERNEL)?;
v.push(2, GFP_KERNEL)?;

Building Rust modules

Enabling Rust support

# In the kernel configuration menu:
#   General setup → Rust support → CONFIG_RUST=y
make LLVM=1 menuconfig
Rust is available only when a suitable toolchain is detected. make LLVM=1 rustavailable confirms this.

Building the kernel and Rust samples

# Build the full kernel with LLVM (required for Rust)
make LLVM=1 -j$(nproc)

# Enable and build the Rust samples
make LLVM=1 menuconfig   # Kernel hacking → Sample kernel code → Rust samples
make LLVM=1 -j$(nproc)

Building an out-of-tree Rust module

Out-of-tree Rust modules use the same Makefile structure as C modules:
obj-m := my_driver.o
my_driver-objs := src/my_driver.o

KDIR ?= /lib/modules/$(shell uname -r)/build

all:
	$(MAKE) -C $(KDIR) M=$(PWD) LLVM=1 modules

clean:
	$(MAKE) -C $(KDIR) M=$(PWD) LLVM=1 clean

Generating Rust API documentation

# Generates HTML documentation for all kernel Rust code
make LLVM=1 rustdoc

# Open in browser
xdg-open Documentation/output/rust/rustdoc/kernel/index.html
Pre-generated docs are also available online at https://rust.docs.kernel.org.

Checking style

make LLVM=1 rustfmt          # auto-format all Rust kernel sources
make LLVM=1 rustfmtcheck     # check formatting without modifying files
make LLVM=1 CLIPPY=1         # run Clippy linter (development only)
Do not enable CLIPPY=1 when building a production kernel. Clippy can alter code generation in ways that affect runtime behavior.

SAFETY comments and unsafe code

Rust’s unsafe keyword is not banned in kernel Rust code, but its use must be minimal, well-justified, and auditable. Every unsafe block must be preceded by a // SAFETY: comment explaining why the code is correct:
// SAFETY: `ptr` is a valid, non-null pointer obtained from `kmalloc()` above
// and has not been freed. The pointee outlives this reference.
let val = unsafe { *ptr };
// SAFETY: We hold `my_lock` (acquired above), which is required by the
// safety contract of `inner_fn()`.
unsafe { inner_fn(data) };
The // SAFETY: comment is not optional. Reviewers will reject unsafe blocks without them, and the kernel CI checks for their presence. This discipline is what makes the safety guarantees of Rust abstractions trustworthy.

Build docs developers (and LLMs) love