On Tue Mar 17, 2026 at 8:17 PM GMT, Joel Fernandes wrote:
> Add a new module `kernel::interop::list` for working with C's doubly
> circular linked lists. Provide low-level iteration over list nodes.
>
> Typed iteration over actual items is provided with a `clist_create`
> macro to assist in creation of the `CList` type.
>
> Cc: Nikola Djukic <[email protected]>
> Reviewed-by: Daniel Almeida <[email protected]>
> Reviewed-by: Alexandre Courbot <[email protected]>
> Acked-by: Alexandre Courbot <[email protected]>
> Acked-by: Gary Guo <[email protected]>
> Acked-by: Miguel Ojeda <[email protected]>
> Signed-off-by: Joel Fernandes <[email protected]>
> ---
> MAINTAINERS | 8 +
> rust/helpers/helpers.c | 1 +
> rust/helpers/list.c | 17 ++
> rust/kernel/interop.rs | 9 +
> rust/kernel/interop/list.rs | 342 ++++++++++++++++++++++++++++++++++++
> rust/kernel/lib.rs | 2 +
> 6 files changed, 379 insertions(+)
> create mode 100644 rust/helpers/list.c
> create mode 100644 rust/kernel/interop.rs
> create mode 100644 rust/kernel/interop/list.rs
>
> +/// Create a C doubly-circular linked list interface [`CList`] from a raw
> `list_head` pointer.
> +///
> +/// This macro creates a `CList<T, OFFSET>` that can iterate over items of
> type `$rust_type`
> +/// linked via the `$field` field in the underlying C struct `$c_type`.
> +///
> +/// # Arguments
> +///
> +/// - `$head`: Raw pointer to the sentinel `list_head` object (`*mut
> bindings::list_head`).
> +/// - `$rust_type`: Each item's rust wrapper type.
> +/// - `$c_type`: Each item's C struct type that contains the embedded
> `list_head`.
> +/// - `$field`: The name of the `list_head` field within the C struct.
> +///
> +/// # Safety
> +///
> +/// The caller must ensure:
> +///
> +/// - `$head` is a valid, initialized sentinel `list_head` (e.g. via
> `INIT_LIST_HEAD()`)
> +/// pointing to a list that is not concurrently modified for the lifetime
> of the [`CList`].
> +/// - The list contains items of type `$c_type` linked via an embedded
> `$field`.
> +/// - `$rust_type` is `#[repr(transparent)]` over `$c_type` or has
> compatible layout.
> +///
> +/// # Examples
> +///
> +/// Refer to the examples in the [`crate::interop::list`] module
> documentation.
> +#[macro_export]
> +macro_rules! clist_create {
> + (unsafe { $head:ident, $rust_type:ty, $c_type:ty, $($field:tt).+ }) => {{
> + // Compile-time check that field path is a `list_head`.
> + // SAFETY: `p` is a valid pointer to `$c_type`.
> + let _: fn(*const $c_type) -> *const $crate::bindings::list_head =
> + |p| unsafe { &raw const (*p).$($field).+ };
Actually, this check is insufficient, you should create a reference instead
(just in case people put this inside `repr(packed)`.
This could be something like
let _ = |p: &$c_type| { _ = &p.$($field).+ }
?
> +
> + // Calculate offset and create `CList`.
> + const OFFSET: usize = ::core::mem::offset_of!($c_type, $($field).+);
> + // SAFETY: The caller of this macro is responsible for ensuring
> safety.
> + unsafe { $crate::interop::list::CList::<$rust_type,
> OFFSET>::from_raw($head) }
Given that this is unsafe, I am not sure why the macro should have unsafe
keyword in it, rather than just being `clist_create(a, b, c, d)` and just have
user write unsafe.
The offset could probably benefit from similar strategies we used for other
embedded data structure like Rust list and work items. Boqun has a series
unifying these and clist could probably use it, too. (As a follow-up)
Best,
Gary
> + }};
> +}
> diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
> index d93292d47420..bdcf632050ee 100644
> --- a/rust/kernel/lib.rs
> +++ b/rust/kernel/lib.rs
> @@ -29,6 +29,7 @@
> #![feature(lint_reasons)]
> //
> // Stable since Rust 1.82.0.
> +#![feature(offset_of_nested)]
> #![feature(raw_ref_op)]
> //
> // Stable since Rust 1.83.0.
> @@ -107,6 +108,7 @@
> #[doc(hidden)]
> pub mod impl_flags;
> pub mod init;
> +pub mod interop;
> pub mod io;
> pub mod ioctl;
> pub mod iommu;
G