* [PATCH v2 1/3] rust: helpers: Add list helpers for C linked list operations
@ 2025-11-11 17:13 Joel Fernandes
2025-11-11 17:13 ` [PATCH v2 2/3] rust: clist: Add basic list infrastructure and head iterator Joel Fernandes
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: Joel Fernandes @ 2025-11-11 17:13 UTC (permalink / raw)
To: linux-kernel, rust-for-linux, dri-devel, dakr, airlied
Cc: acourbot, apopple, ojeda, alex.gaynor, boqun.feng, gary,
bjorn3_gh, lossin, a.hindborg, aliceryhl, tmgross, simona,
maarten.lankhorst, mripard, tzimmermann, jhubbard, joelagnelf,
ttabi, joel, elle, daniel.almeida, arighi, phasta, nouveau
Add Rust helper functions for common C linked list operations
that are implemented as macros or inline functions and thus not
directly accessible from Rust.
Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com>
---
rust/helpers/helpers.c | 1 +
rust/helpers/list.c | 32 ++++++++++++++++++++++++++++++++
2 files changed, 33 insertions(+)
create mode 100644 rust/helpers/list.c
diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c
index 79c72762ad9c..634fa2386bbb 100644
--- a/rust/helpers/helpers.c
+++ b/rust/helpers/helpers.c
@@ -32,6 +32,7 @@
#include "io.c"
#include "jump_label.c"
#include "kunit.c"
+#include "list.c"
#include "maple_tree.c"
#include "mm.c"
#include "mutex.c"
diff --git a/rust/helpers/list.c b/rust/helpers/list.c
new file mode 100644
index 000000000000..fea2a18621da
--- /dev/null
+++ b/rust/helpers/list.c
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Helpers for C Circular doubly linked list implementation.
+ */
+
+#include <linux/list.h>
+
+bool rust_helper_list_empty(const struct list_head *head)
+{
+ return list_empty(head);
+}
+
+void rust_helper_list_del(struct list_head *entry)
+{
+ list_del(entry);
+}
+
+void rust_helper_INIT_LIST_HEAD(struct list_head *list)
+{
+ INIT_LIST_HEAD(list);
+}
+
+void rust_helper_list_add(struct list_head *new, struct list_head *head)
+{
+ list_add(new, head);
+}
+
+void rust_helper_list_add_tail(struct list_head *new, struct list_head *head)
+{
+ list_add_tail(new, head);
+}
--
2.34.1
^ permalink raw reply related [flat|nested] 8+ messages in thread* [PATCH v2 2/3] rust: clist: Add basic list infrastructure and head iterator 2025-11-11 17:13 [PATCH v2 1/3] rust: helpers: Add list helpers for C linked list operations Joel Fernandes @ 2025-11-11 17:13 ` Joel Fernandes 2025-11-24 3:47 ` Alexandre Courbot 2025-11-11 17:13 ` [PATCH v2 3/3] rust: clist: Add typed iteration with FromListHead trait Joel Fernandes 2025-11-11 17:13 ` [PATCH v2 0/3] rust: Introduce support for C linked list interfacing Joel Fernandes 2 siblings, 1 reply; 8+ messages in thread From: Joel Fernandes @ 2025-11-11 17:13 UTC (permalink / raw) To: linux-kernel, rust-for-linux, dri-devel, dakr, airlied Cc: acourbot, apopple, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh, lossin, a.hindborg, aliceryhl, tmgross, simona, maarten.lankhorst, mripard, tzimmermann, jhubbard, joelagnelf, ttabi, joel, elle, daniel.almeida, arighi, phasta, nouveau Add foundational types for working with C's doubly circular linked lists (list_head). Provide low-level iteration over list nodes. Typed iteration over actual items will be added in a follow-up commit using the FromListHead trait and ClistLink mechanism. Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com> --- rust/kernel/clist.rs | 190 +++++++++++++++++++++++++++++++++++++++++++ rust/kernel/lib.rs | 1 + 2 files changed, 191 insertions(+) create mode 100644 rust/kernel/clist.rs diff --git a/rust/kernel/clist.rs b/rust/kernel/clist.rs new file mode 100644 index 000000000000..5ea505d463ad --- /dev/null +++ b/rust/kernel/clist.rs @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! A C doubly circular intrusive linked list interface for rust code. +//! +//! TODO: Doctest example will be added in later commit in series due to dependencies. + +use crate::{ + bindings, + types::Opaque, // +}; + +/// A C linked list with a sentinel head +/// +/// A sentinel head is one which is not embedded in an item. It represents the entire +/// linked list and can be used for add, remove, empty operations etc. +/// +/// # Invariants +/// +/// - `Clist` wraps an allocated and valid C list_head structure that is the sentinel of a list. +/// - All the `list_head` nodes in the list are allocated and have valid next/prev pointers. +/// - The underlying `list_head` (and entire list) is not modified by C. +#[repr(transparent)] +pub struct Clist(ClistHead); + +// SAFETY: `Clist` can be sent to any thread. +unsafe impl Send for Clist {} +// SAFETY: `Clist` can be shared among threads as it is not modified by C per type invariants. +unsafe impl Sync for Clist {} + +impl Clist { + /// Create a `&Clist` from a raw sentinel `list_head` pointer. + /// + /// # Safety + /// + /// `ptr` must be a valid pointer to an allocated and initialized `list_head` structure + /// representing a list sentinel, and it must remain valid for the lifetime `'a`. + #[inline] + pub unsafe fn from_raw<'a>(ptr: *mut bindings::list_head) -> &'a Self { + // SAFETY: + // - `ClistHead` has same layout as `list_head`. + // - `ptr` is valid for 'a. + unsafe { &*ptr.cast() } + } + + /// Get the raw sentinel `list_head` pointer. + #[inline] + pub fn as_raw(&self) -> *mut bindings::list_head { + self.0.as_raw() + } + + /// Access the underlying `ClistHead`. + #[inline] + pub fn head(&self) -> &ClistHead { + &self.0 + } + + /// Check if the list is empty. + #[inline] + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + /// Create a low-level iterator over `ClistHead` nodes. Caller converts the returned + /// heads into items. + #[inline] + pub fn iter_heads(&self) -> ClistHeadIter<'_> { + ClistHeadIter { + current: &self.0, + head: &self.0, + } + } +} + +/// Wraps a non-sentinel C `list_head` node for use in intrusive linked lists. +/// +/// # Invariants +/// +/// - `ClistHead` represents an allocated and valid non-sentinel `list_head` structure. +/// - The underlying `list_head` (and entire list) is not modified by C. +#[repr(transparent)] +pub struct ClistHead(Opaque<bindings::list_head>); + +// SAFETY: `ClistHead` can be sent to any thread. +unsafe impl Send for ClistHead {} +// SAFETY: `ClistHead` can be shared among threads as it is not modified by C per type invariants. +unsafe impl Sync for ClistHead {} + +impl ClistHead { + /// Create a `&ClistHead` reference from a raw `list_head` pointer. + /// + /// # Safety + /// + /// `ptr` must be a valid pointer to an allocated and initialized `list_head` structure, + /// and it must remain valid for the lifetime `'a`. + #[inline] + pub unsafe fn from_raw<'a>(ptr: *mut bindings::list_head) -> &'a Self { + // SAFETY: + // - `ClistHead` has same layout as `list_head`. + // - `ptr` is valid for 'a. + unsafe { &*ptr.cast() } + } + + /// Get the raw `list_head` pointer. + #[inline] + pub fn as_raw(&self) -> *mut bindings::list_head { + self.0.get() + } + + /// Get the next `ClistHead` in the list. + #[inline] + pub fn next(&self) -> &Self { + // SAFETY: + // - `self.as_raw()` is valid per type invariants. + // - The `next` pointer is guaranteed to be non-NULL. + unsafe { + let raw = self.as_raw(); + Self::from_raw((*raw).next) + } + } + + /// Get the previous `ClistHead` in the list. + #[inline] + pub fn prev(&self) -> &Self { + // SAFETY: + // - self.as_raw() is valid per type invariants. + // - The `prev` pointer is guaranteed to be non-NULL. + unsafe { + let raw = self.as_raw(); + Self::from_raw((*raw).prev) + } + } + + /// Check if this node is linked in a list (not isolated). + #[inline] + pub fn is_in_list(&self) -> bool { + // SAFETY: self.as_raw() is valid per type invariants. + unsafe { + let raw = self.as_raw(); + (*raw).next != raw && (*raw).prev != raw + } + } + + /// Check if the list is empty. + #[inline] + pub fn is_empty(&self) -> bool { + // SAFETY: self.as_raw() is valid per type invariants. + unsafe { + let raw = self.as_raw(); + (*raw).next == raw + } + } +} + +/// Low-level iterator over `list_head` nodes. +/// +/// An iterator used to iterate over a C intrusive linked list (`list_head`). Caller has to +/// perform conversion of returned `ClistHead` to an item (typically using `container_of` macro). +/// +/// # Invariants +/// +/// `ClistHeadIter` is iterating over an allocated, initialized and valid `Clist`. +pub struct ClistHeadIter<'a> { + current: &'a ClistHead, + head: &'a ClistHead, +} + +// SAFETY: ClistHeadIter gives out immutable references to ClistHead, +// which is Send. +unsafe impl Send for ClistHeadIter<'_> {} + +// SAFETY: ClistHeadIter gives out immutable references to ClistHead, +// which is Sync. +unsafe impl Sync for ClistHeadIter<'_> {} + +impl<'a> Iterator for ClistHeadIter<'a> { + type Item = &'a ClistHead; + + #[inline] + fn next(&mut self) -> Option<Self::Item> { + // Advance to next node. + self.current = self.current.next(); + + // Check if we've circled back to HEAD. + if self.current.as_raw() == self.head.as_raw() { + return None; + } + + Some(self.current) + } +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index c2eea9a2a345..b69cc5ed3b59 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -72,6 +72,7 @@ pub mod bug; #[doc(hidden)] pub mod build_assert; +pub mod clist; pub mod clk; #[cfg(CONFIG_CONFIGFS_FS)] pub mod configfs; -- 2.34.1 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v2 2/3] rust: clist: Add basic list infrastructure and head iterator 2025-11-11 17:13 ` [PATCH v2 2/3] rust: clist: Add basic list infrastructure and head iterator Joel Fernandes @ 2025-11-24 3:47 ` Alexandre Courbot 0 siblings, 0 replies; 8+ messages in thread From: Alexandre Courbot @ 2025-11-24 3:47 UTC (permalink / raw) To: Joel Fernandes, linux-kernel, rust-for-linux, dri-devel, dakr, airlied Cc: acourbot, apopple, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh, lossin, a.hindborg, aliceryhl, tmgross, simona, maarten.lankhorst, mripard, tzimmermann, jhubbard, ttabi, joel, elle, daniel.almeida, arighi, phasta, nouveau, Nouveau Hi Joel, This low-level layer looks mostly ok to me, I will have more comments on the higher layer though. On Wed Nov 12, 2025 at 2:13 AM JST, Joel Fernandes wrote: > Add foundational types for working with C's doubly circular linked > lists (list_head). Provide low-level iteration over list nodes. > > Typed iteration over actual items will be added in a follow-up > commit using the FromListHead trait and ClistLink mechanism. > > Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com> > --- > rust/kernel/clist.rs | 190 +++++++++++++++++++++++++++++++++++++++++++ > rust/kernel/lib.rs | 1 + > 2 files changed, 191 insertions(+) > create mode 100644 rust/kernel/clist.rs > > diff --git a/rust/kernel/clist.rs b/rust/kernel/clist.rs > new file mode 100644 > index 000000000000..5ea505d463ad > --- /dev/null > +++ b/rust/kernel/clist.rs > @@ -0,0 +1,190 @@ > +// SPDX-License-Identifier: GPL-2.0 > + > +//! A C doubly circular intrusive linked list interface for rust code. > +//! > +//! TODO: Doctest example will be added in later commit in series due to dependencies. Since it is added in the following patch, I guess we can do without this very temporary TODO. :) > + > +use crate::{ > + bindings, > + types::Opaque, // > +}; > + > +/// A C linked list with a sentinel head Nit: '.' at end of sentence. > +/// > +/// A sentinel head is one which is not embedded in an item. It represents the entire > +/// linked list and can be used for add, remove, empty operations etc. > +/// > +/// # Invariants > +/// > +/// - `Clist` wraps an allocated and valid C list_head structure that is the sentinel of a list. > +/// - All the `list_head` nodes in the list are allocated and have valid next/prev pointers. > +/// - The underlying `list_head` (and entire list) is not modified by C. These last two ones look more like safety requirements to maintain for the life of a Clist than invariants. > +#[repr(transparent)] > +pub struct Clist(ClistHead); `ClistHead`'s definition should come before `Clist` for clarity. > + > +// SAFETY: `Clist` can be sent to any thread. > +unsafe impl Send for Clist {} > +// SAFETY: `Clist` can be shared among threads as it is not modified by C per type invariants. > +unsafe impl Sync for Clist {} These explicit impls should not be needed - as `ClistHead` implements `Send` and `Sync`, they will be automatically derived for `Clist` which just wraps it. > + > +impl Clist { > + /// Create a `&Clist` from a raw sentinel `list_head` pointer. > + /// > + /// # Safety > + /// > + /// `ptr` must be a valid pointer to an allocated and initialized `list_head` structure > + /// representing a list sentinel, and it must remain valid for the lifetime `'a`. > + #[inline] > + pub unsafe fn from_raw<'a>(ptr: *mut bindings::list_head) -> &'a Self { > + // SAFETY: > + // - `ClistHead` has same layout as `list_head`. > + // - `ptr` is valid for 'a. > + unsafe { &*ptr.cast() } Let's reuse `ClistHead::from_raw` here. > + } > + > + /// Get the raw sentinel `list_head` pointer. > + #[inline] > + pub fn as_raw(&self) -> *mut bindings::list_head { > + self.0.as_raw() > + } > + > + /// Access the underlying `ClistHead`. > + #[inline] > + pub fn head(&self) -> &ClistHead { > + &self.0 > + } > + > + /// Check if the list is empty. > + #[inline] > + pub fn is_empty(&self) -> bool { > + self.0.is_empty() > + } > + > + /// Create a low-level iterator over `ClistHead` nodes. Caller converts the returned > + /// heads into items. > + #[inline] > + pub fn iter_heads(&self) -> ClistHeadIter<'_> { > + ClistHeadIter { > + current: &self.0, > + head: &self.0, > + } > + } > +} > + > +/// Wraps a non-sentinel C `list_head` node for use in intrusive linked lists. This says "non-sentinel", but `Clist` embeds a `ClistHead` which wraps a sentinel node, so that statement does not seem to be true. > +/// > +/// # Invariants > +/// > +/// - `ClistHead` represents an allocated and valid non-sentinel `list_head` structure. > +/// - The underlying `list_head` (and entire list) is not modified by C. > +#[repr(transparent)] > +pub struct ClistHead(Opaque<bindings::list_head>); > + > +// SAFETY: `ClistHead` can be sent to any thread. > +unsafe impl Send for ClistHead {} > +// SAFETY: `ClistHead` can be shared among threads as it is not modified by C per type invariants. > +unsafe impl Sync for ClistHead {} > + > +impl ClistHead { > + /// Create a `&ClistHead` reference from a raw `list_head` pointer. > + /// > + /// # Safety > + /// > + /// `ptr` must be a valid pointer to an allocated and initialized `list_head` structure, > + /// and it must remain valid for the lifetime `'a`. > + #[inline] > + pub unsafe fn from_raw<'a>(ptr: *mut bindings::list_head) -> &'a Self { > + // SAFETY: > + // - `ClistHead` has same layout as `list_head`. > + // - `ptr` is valid for 'a. > + unsafe { &*ptr.cast() } > + } > + > + /// Get the raw `list_head` pointer. > + #[inline] > + pub fn as_raw(&self) -> *mut bindings::list_head { > + self.0.get() > + } > + > + /// Get the next `ClistHead` in the list. > + #[inline] > + pub fn next(&self) -> &Self { > + // SAFETY: > + // - `self.as_raw()` is valid per type invariants. > + // - The `next` pointer is guaranteed to be non-NULL. > + unsafe { > + let raw = self.as_raw(); This line doesn't need to be in the `unsafe` block (also applies to other methods). > + Self::from_raw((*raw).next) > + } > + } > + > + /// Get the previous `ClistHead` in the list. > + #[inline] > + pub fn prev(&self) -> &Self { > + // SAFETY: > + // - self.as_raw() is valid per type invariants. > + // - The `prev` pointer is guaranteed to be non-NULL. > + unsafe { > + let raw = self.as_raw(); > + Self::from_raw((*raw).prev) > + } > + } > + > + /// Check if this node is linked in a list (not isolated). > + #[inline] > + pub fn is_in_list(&self) -> bool { > + // SAFETY: self.as_raw() is valid per type invariants. > + unsafe { > + let raw = self.as_raw(); > + (*raw).next != raw && (*raw).prev != raw > + } > + } > + > + /// Check if the list is empty. > + #[inline] > + pub fn is_empty(&self) -> bool { > + // SAFETY: self.as_raw() is valid per type invariants. > + unsafe { > + let raw = self.as_raw(); > + (*raw).next == raw > + } > + } Does this method also apply to non-sentinel nodes? If not, should we move it to `Clist`? I am also wondering what the difference is with `is_in_list`. If `raw.next == raw`, then on a valid list `raw.prev == raw` as well, so it seems to be that `is_in_list()` is equivalent to `!is_empty()`. > +} > + > +/// Low-level iterator over `list_head` nodes. > +/// > +/// An iterator used to iterate over a C intrusive linked list (`list_head`). Caller has to > +/// perform conversion of returned `ClistHead` to an item (typically using `container_of` macro). > +/// > +/// # Invariants > +/// > +/// `ClistHeadIter` is iterating over an allocated, initialized and valid `Clist`. > +pub struct ClistHeadIter<'a> { > + current: &'a ClistHead, > + head: &'a ClistHead, IIUC `head` should probably be a `Clist`? > +} > + > +// SAFETY: ClistHeadIter gives out immutable references to ClistHead, > +// which is Send. > +unsafe impl Send for ClistHeadIter<'_> {} > + > +// SAFETY: ClistHeadIter gives out immutable references to ClistHead, > +// which is Sync. > +unsafe impl Sync for ClistHeadIter<'_> {} `Send` and `Sync` will also be auto-implemented here. > + > +impl<'a> Iterator for ClistHeadIter<'a> { > + type Item = &'a ClistHead; > + > + #[inline] > + fn next(&mut self) -> Option<Self::Item> { > + // Advance to next node. > + self.current = self.current.next(); > + > + // Check if we've circled back to HEAD. > + if self.current.as_raw() == self.head.as_raw() { Maybe derive/implement `PartialEq` so we can avoid calling `as_raw` when comparing nodes. ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 3/3] rust: clist: Add typed iteration with FromListHead trait 2025-11-11 17:13 [PATCH v2 1/3] rust: helpers: Add list helpers for C linked list operations Joel Fernandes 2025-11-11 17:13 ` [PATCH v2 2/3] rust: clist: Add basic list infrastructure and head iterator Joel Fernandes @ 2025-11-11 17:13 ` Joel Fernandes 2025-11-24 7:01 ` Alexandre Courbot 2025-11-11 17:13 ` [PATCH v2 0/3] rust: Introduce support for C linked list interfacing Joel Fernandes 2 siblings, 1 reply; 8+ messages in thread From: Joel Fernandes @ 2025-11-11 17:13 UTC (permalink / raw) To: linux-kernel, rust-for-linux, dri-devel, dakr, airlied Cc: acourbot, apopple, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh, lossin, a.hindborg, aliceryhl, tmgross, simona, maarten.lankhorst, mripard, tzimmermann, jhubbard, joelagnelf, ttabi, joel, elle, daniel.almeida, arighi, phasta, nouveau Add an iteration layer on top of the basic list infrastructure, enabling iteration over the actual container items. Enables users to iterate over actual items without manually performing container_of operations. Provide macros to make caller's life easier. Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com> --- rust/kernel/clist.rs | 210 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 207 insertions(+), 3 deletions(-) diff --git a/rust/kernel/clist.rs b/rust/kernel/clist.rs index 5ea505d463ad..01b78ba157a1 100644 --- a/rust/kernel/clist.rs +++ b/rust/kernel/clist.rs @@ -2,17 +2,104 @@ //! A C doubly circular intrusive linked list interface for rust code. //! -//! TODO: Doctest example will be added in later commit in series due to dependencies. +//! # Examples +//! +//! ``` +//! use kernel::{bindings, clist::Clist, clist_iterate, impl_from_list_head, types::Opaque}; +//! # // Create test list with values (0, 10, 20) - normally done by C code but it is +//! # // emulated here for doctests using the C bindings. +//! # use core::mem::MaybeUninit; +//! # +//! # /// C struct with embedded list_head (typically will be allocated by C code). +//! # #[repr(C)] +//! # pub(crate) struct SampleItemC { +//! # pub value: i32, +//! # pub link: bindings::list_head, +//! # } +//! # +//! # let mut head = MaybeUninit::<bindings::list_head>::uninit(); +//! # +//! # // SAFETY: head and all the items are test objects allocated in this scope. +//! # unsafe { bindings::INIT_LIST_HEAD(head.as_mut_ptr()) }; +//! # // SAFETY: head is a test object allocated in this scope. +//! # let mut head = unsafe { head.assume_init() }; +//! # let mut items = [ +//! # MaybeUninit::<SampleItemC>::uninit(), +//! # MaybeUninit::<SampleItemC>::uninit(), +//! # MaybeUninit::<SampleItemC>::uninit(), +//! # ]; +//! # +//! # for (i, item) in items.iter_mut().enumerate() { +//! # let ptr = item.as_mut_ptr(); +//! # // SAFETY: pointers are to allocated test objects with a list_head field. +//! # unsafe { +//! # (*ptr).value = i as i32 * 10; +//! # bindings::INIT_LIST_HEAD(&mut (*ptr).link); +//! # bindings::list_add_tail(&mut (*ptr).link, &mut head); +//! # } +//! # } +//! +//! // Rust wrapper for the C struct. +//! // The list item struct in this example is defined in C code as: +//! // struct SampleItemC { +//! // int value; +//! // struct list_head link; +//! // }; +//! // +//! #[repr(transparent)] +//! pub(crate) struct Item(Opaque<SampleItemC>); +//! +//! // Generate the link type. +//! impl_from_list_head!(pub(crate), Item, SampleItemC, link); +//! +//! impl Item { +//! pub(crate) fn value(&self) -> i32 { +//! // SAFETY: Item has same layout as SampleItemC. +//! unsafe { (*self.0.get()).value } +//! } +//! } +//! +//! // Create Clist (from a sentinel head). +//! // SAFETY: head is allocated by test code and Clist has the same layout. +//! let list = unsafe { Clist::from_raw(&mut head) }; +//! +//! // Now iterate using clist_iterate! macro. +//! let mut found_0 = false; +//! let mut found_10 = false; +//! let mut found_20 = false; +//! +//! for item in clist_iterate!(list, Item, link) { +//! let val = item.value(); +//! if val == 0 { found_0 = true; } +//! if val == 10 { found_10 = true; } +//! if val == 20 { found_20 = true; } +//! } +//! +//! assert!(found_0 && found_10 && found_20); +//! ``` use crate::{ bindings, types::Opaque, // }; +use core::marker::PhantomData; + +/// Trait for associating a link type with its container item type. +/// +/// Implemented by "field link types" that are `list_head` links embedded in intrusive +/// C linked lists. Each link type is unique to a specific item type and its `list_head` field, +/// making it possible for an item to be added to multiple lists. +pub trait ClistLink { + /// The item type that contains the `list_head` field linking to other items in the list. + type Item: FromListHead<Self> + where + Self: Sized; +} /// A C linked list with a sentinel head /// -/// A sentinel head is one which is not embedded in an item. It represents the entire -/// linked list and can be used for add, remove, empty operations etc. +/// Represents the entire linked list and can be used for add, remove, empty operations etc. +/// A sentinel head is one which is not embedded in an item. /// /// # Invariants /// @@ -69,6 +156,15 @@ pub fn iter_heads(&self) -> ClistHeadIter<'_> { head: &self.0, } } + + /// Create a high-level iterator over typed items. + #[inline] + pub fn iter<L: ClistLink>(&self) -> ClistIter<'_, L> { + ClistIter { + head_iter: self.iter_heads(), + _phantom: PhantomData, + } + } } /// Wraps a non-sentinel C `list_head` node for use in intrusive linked lists. @@ -188,3 +284,111 @@ fn next(&mut self) -> Option<Self::Item> { Some(self.current) } } + +/// High-level iterator over typed list items. +pub struct ClistIter<'a, L: ClistLink> { + head_iter: ClistHeadIter<'a>, + + /// The iterator yields immutable references to `L::Item`. + _phantom: PhantomData<&'a L::Item>, +} + +// SAFETY: ClistIter yields `&L::Item`, which is Send when `L::Item: Send`. +unsafe impl<L: ClistLink> Send for ClistIter<'_, L> where L::Item: Send {} + +// SAFETY: ClistIter yields &L::Item, which is Sync when `L::Item: Sync`. +unsafe impl<L: ClistLink> Sync for ClistIter<'_, L> where L::Item: Sync {} + +impl<'a, L: ClistLink> Iterator for ClistIter<'a, L> +where + L::Item: 'a, +{ + type Item = &'a L::Item; + + fn next(&mut self) -> Option<Self::Item> { + // Get next ClistHead. + let head = self.head_iter.next()?; + + // Convert to item using trait. + // SAFETY: FromListHead impl guarantees valid conversion. + Some(unsafe { L::Item::from_list_head(head) }) + } +} + +/// Trait for converting a `ClistHead` to an item reference. +pub trait FromListHead<Link>: Sized { + /// Convert a `ClistHead` node reference to an item reference. + /// + /// # Safety + /// + /// `head` must be a valid reference to an allocated and initialized `ClistHead` structure + /// valid for the lifetime `'a`. + unsafe fn from_list_head<'a>(head: &'a ClistHead) -> &'a Self; +} + +/// Macro to generate `FromListHead` implementations for C list integration. +/// +/// `FromListHead` trait is required to iterate over a C linked list using the `clist_iterate!` +/// macro which yields immutable references to the Rust item wrapper type. +/// +/// Also generates a link type named `Clist<ItemType><field>` implementing the `ClistLink` trait +/// that associates the list node with the item. The link type is used to iterate over the list +/// using the `clist_iterate!` macro. +/// +/// # Arguments +/// +/// - `$vis`: The visibility of the generated link type (e.g., `pub`, `pub(crate)`). +/// - `$item_type`: The Rust wrapper type for items in the list. +/// - `$c_type`: The C struct type that contains the embedded `list_head`. +/// - `$field`: The name of the `list_head` field within the C struct that links items. +/// +/// # Examples +/// +/// Refer to the comprehensive example in the [crate::clist] module documentation. +#[macro_export] +macro_rules! impl_from_list_head { + ($vis:vis, $item_type:ident, $c_type:ty, $field:ident) => { + $crate::macros::paste! { + /// Link type for associating list nodes with items. + $vis struct [<Clist $item_type $field>]; + + // Implement ClistLink trait to associate the link with its item type. + impl $crate::clist::ClistLink for [<Clist $item_type $field>] { + type Item = $item_type; + } + + impl $crate::clist::FromListHead<[<Clist $item_type $field>]> for $item_type { + unsafe fn from_list_head<'a>( + head: &'a $crate::clist::ClistHead, + ) -> &'a Self { + let ptr = $crate::container_of!(head.as_raw(), $c_type, $field); + // SAFETY: repr(transparent) makes item_type have same layout as c_type. + // Caller guarantees the container_of calculation is correct. + unsafe { &*ptr.cast::<Self>() } + } + } + } + }; +} + +/// Macro to assist with iterating over a C linked list. +/// +/// Returns a `ClistIter` iterator which yields immutable references to the `item_type` type. +/// +/// # Arguments +/// +/// - `$list`: The `Clist` instance to iterate over. +/// - `$item_type`: The Rust type of the item in the list with list_head embedded. +/// - `$field`: The name of the field in the `item_type` that links it to the list. +/// +/// # Examples +/// +/// Refer to the comprehensive example in the [crate::clist] module documentation. +#[macro_export] +macro_rules! clist_iterate { + ($list:expr, $item_type:ident, $field:ident) => { + $crate::macros::paste! { + $list.iter::<[<Clist $item_type $field>]>() + } + }; +} -- 2.34.1 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v2 3/3] rust: clist: Add typed iteration with FromListHead trait 2025-11-11 17:13 ` [PATCH v2 3/3] rust: clist: Add typed iteration with FromListHead trait Joel Fernandes @ 2025-11-24 7:01 ` Alexandre Courbot 0 siblings, 0 replies; 8+ messages in thread From: Alexandre Courbot @ 2025-11-24 7:01 UTC (permalink / raw) To: Joel Fernandes, linux-kernel, rust-for-linux, dri-devel, dakr, airlied Cc: acourbot, apopple, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh, lossin, a.hindborg, aliceryhl, tmgross, simona, maarten.lankhorst, mripard, tzimmermann, jhubbard, ttabi, joel, elle, daniel.almeida, arighi, phasta, nouveau, Nouveau On Wed Nov 12, 2025 at 2:13 AM JST, Joel Fernandes wrote: > Add an iteration layer on top of the basic list infrastructure, > enabling iteration over the actual container items. > > Enables users to iterate over actual items without manually performing > container_of operations. Provide macros to make caller's life easier. > > Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com> > --- > rust/kernel/clist.rs | 210 ++++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 207 insertions(+), 3 deletions(-) > > diff --git a/rust/kernel/clist.rs b/rust/kernel/clist.rs > index 5ea505d463ad..01b78ba157a1 100644 > --- a/rust/kernel/clist.rs > +++ b/rust/kernel/clist.rs > @@ -2,17 +2,104 @@ > > //! A C doubly circular intrusive linked list interface for rust code. > //! > -//! TODO: Doctest example will be added in later commit in series due to dependencies. > +//! # Examples > +//! > +//! ``` > +//! use kernel::{bindings, clist::Clist, clist_iterate, impl_from_list_head, types::Opaque}; > +//! # // Create test list with values (0, 10, 20) - normally done by C code but it is > +//! # // emulated here for doctests using the C bindings. > +//! # use core::mem::MaybeUninit; > +//! # > +//! # /// C struct with embedded list_head (typically will be allocated by C code). > +//! # #[repr(C)] > +//! # pub(crate) struct SampleItemC { > +//! # pub value: i32, > +//! # pub link: bindings::list_head, > +//! # } > +//! # > +//! # let mut head = MaybeUninit::<bindings::list_head>::uninit(); > +//! # > +//! # // SAFETY: head and all the items are test objects allocated in this scope. > +//! # unsafe { bindings::INIT_LIST_HEAD(head.as_mut_ptr()) }; > +//! # // SAFETY: head is a test object allocated in this scope. > +//! # let mut head = unsafe { head.assume_init() }; > +//! # let mut items = [ > +//! # MaybeUninit::<SampleItemC>::uninit(), > +//! # MaybeUninit::<SampleItemC>::uninit(), > +//! # MaybeUninit::<SampleItemC>::uninit(), > +//! # ]; > +//! # > +//! # for (i, item) in items.iter_mut().enumerate() { > +//! # let ptr = item.as_mut_ptr(); > +//! # // SAFETY: pointers are to allocated test objects with a list_head field. > +//! # unsafe { > +//! # (*ptr).value = i as i32 * 10; > +//! # bindings::INIT_LIST_HEAD(&mut (*ptr).link); > +//! # bindings::list_add_tail(&mut (*ptr).link, &mut head); > +//! # } > +//! # } > +//! > +//! // Rust wrapper for the C struct. > +//! // The list item struct in this example is defined in C code as: > +//! // struct SampleItemC { > +//! // int value; > +//! // struct list_head link; > +//! // }; > +//! // > +//! #[repr(transparent)] > +//! pub(crate) struct Item(Opaque<SampleItemC>); > +//! > +//! // Generate the link type. > +//! impl_from_list_head!(pub(crate), Item, SampleItemC, link); > +//! > +//! impl Item { > +//! pub(crate) fn value(&self) -> i32 { > +//! // SAFETY: Item has same layout as SampleItemC. > +//! unsafe { (*self.0.get()).value } > +//! } > +//! } > +//! > +//! // Create Clist (from a sentinel head). > +//! // SAFETY: head is allocated by test code and Clist has the same layout. > +//! let list = unsafe { Clist::from_raw(&mut head) }; > +//! > +//! // Now iterate using clist_iterate! macro. > +//! let mut found_0 = false; > +//! let mut found_10 = false; > +//! let mut found_20 = false; > +//! > +//! for item in clist_iterate!(list, Item, link) { > +//! let val = item.value(); > +//! if val == 0 { found_0 = true; } > +//! if val == 10 { found_10 = true; } > +//! if val == 20 { found_20 = true; } > +//! } > +//! > +//! assert!(found_0 && found_10 && found_20); > +//! ``` > > use crate::{ > bindings, > types::Opaque, // > }; > +use core::marker::PhantomData; IIUC the typical order of imports is `core`, then `kernel`, then `crate` (here crate == kernel though), with a space between them. > + > +/// Trait for associating a link type with its container item type. > +/// > +/// Implemented by "field link types" that are `list_head` links embedded in intrusive > +/// C linked lists. Each link type is unique to a specific item type and its `list_head` field, > +/// making it possible for an item to be added to multiple lists. > +pub trait ClistLink { > + /// The item type that contains the `list_head` field linking to other items in the list. > + type Item: FromListHead<Self> > + where > + Self: Sized; > +} > > /// A C linked list with a sentinel head > /// > -/// A sentinel head is one which is not embedded in an item. It represents the entire > -/// linked list and can be used for add, remove, empty operations etc. > +/// Represents the entire linked list and can be used for add, remove, empty operations etc. > +/// A sentinel head is one which is not embedded in an item. This comment changes, but its substance remains the same - let's get its final form in the previous patch? > /// > /// # Invariants > /// > @@ -69,6 +156,15 @@ pub fn iter_heads(&self) -> ClistHeadIter<'_> { > head: &self.0, > } > } > + > + /// Create a high-level iterator over typed items. > + #[inline] > + pub fn iter<L: ClistLink>(&self) -> ClistIter<'_, L> { > + ClistIter { > + head_iter: self.iter_heads(), > + _phantom: PhantomData, > + } > + } This looks very dangerous, as it gives any caller the freedom to specify the type they want to upcast the `Clist` to, without using unsafe code. One could easily invoke this with the wrong type and get no build error or warning whatsoever. A safer version would have the `Clist` generic over the kind of conversion that needs to be performed, using e.g. a closure: pub struct Clist<'a, T, C: Fn(*mut bindings::list_head) -> *mut T> { head: &'a ClistHead, conv: C, } `from_raw` would also take the closure as argument, which forces the creator of the list to both specify what that list is for, and use an `unsafe` statement for unsafe code. Here is a dummy example: let head: bindings::list_head = ...; // SAFETY: list_head always corresponds to the `list` member of // `type_embedding_list_head`. let conv = |head: *mut bindings::list_head| unsafe { crate::container_of!(head, type_embedding_list_head, list) }; // SAFETY: ... unsafe { Clist::from_raw(head, conv) } Then `conv` would be passed down to the `ClistIter` so it can return references to the correct type. By doing so you can remove the `ClinkList` and `FromListHead` traits, the `impl_from_list_head` and `clist_iterate` macros, as well as the hidden ad-hoc types these create. And importantly, all unsafe code must be explicitly specified in an `unsafe` block, nothing is hidden by macros. This approach works better imho because each `list_head` is unique in how it has to be iterated: there is no benefit in implementing things using types and traits that will only ever be used in a single place anyway. And if there was, we could always create a newtype for that. Also as I suspected in v1 `Clist` appears to do very little apart from providing an iterator, so I'm more convinced that the front type for this should be `ClistHead`. > } > > /// Wraps a non-sentinel C `list_head` node for use in intrusive linked lists. > @@ -188,3 +284,111 @@ fn next(&mut self) -> Option<Self::Item> { > Some(self.current) > } > } > + > +/// High-level iterator over typed list items. > +pub struct ClistIter<'a, L: ClistLink> { > + head_iter: ClistHeadIter<'a>, > + > + /// The iterator yields immutable references to `L::Item`. > + _phantom: PhantomData<&'a L::Item>, > +} > + > +// SAFETY: ClistIter yields `&L::Item`, which is Send when `L::Item: Send`. > +unsafe impl<L: ClistLink> Send for ClistIter<'_, L> where L::Item: Send {} > + > +// SAFETY: ClistIter yields &L::Item, which is Sync when `L::Item: Sync`. > +unsafe impl<L: ClistLink> Sync for ClistIter<'_, L> where L::Item: Sync {} These implementations should also be automatic. > + > +impl<'a, L: ClistLink> Iterator for ClistIter<'a, L> > +where > + L::Item: 'a, > +{ > + type Item = &'a L::Item; This is going to work well when we want to parse lists read-only. But I've also seen in some comments that you were considering supporting addition and deletion of items? In that case we will probably want to return some sort of guard type that derefs to `Item` (similar to a mutex guard), while also providing list management operations. We will probably also want distinct types for read-only and read-modify behavior. I think this can be done later, but better to keep this in mind when designing things. > + > + fn next(&mut self) -> Option<Self::Item> { > + // Get next ClistHead. > + let head = self.head_iter.next()?; > + > + // Convert to item using trait. > + // SAFETY: FromListHead impl guarantees valid conversion. > + Some(unsafe { L::Item::from_list_head(head) }) More idiomatic proposal: self.head_iter.next().map(|head| { // SAFETY: The FromListHead impl guarantees valid conversion. unsafe { L::Item::from_list_head(head) } }) Note that since kernel lists are bi-directional, you can also implement `DoubleEndedIterator`! ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v2 0/3] rust: Introduce support for C linked list interfacing 2025-11-11 17:13 [PATCH v2 1/3] rust: helpers: Add list helpers for C linked list operations Joel Fernandes 2025-11-11 17:13 ` [PATCH v2 2/3] rust: clist: Add basic list infrastructure and head iterator Joel Fernandes 2025-11-11 17:13 ` [PATCH v2 3/3] rust: clist: Add typed iteration with FromListHead trait Joel Fernandes @ 2025-11-11 17:13 ` Joel Fernandes 2025-11-11 19:54 ` Miguel Ojeda 2 siblings, 1 reply; 8+ messages in thread From: Joel Fernandes @ 2025-11-11 17:13 UTC (permalink / raw) To: linux-kernel, rust-for-linux, dri-devel, dakr, airlied Cc: acourbot, apopple, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh, lossin, a.hindborg, aliceryhl, tmgross, simona, maarten.lankhorst, mripard, tzimmermann, jhubbard, joelagnelf, ttabi, joel, elle, daniel.almeida, arighi, phasta, nouveau Changes from RFC to v2: - Dropped the DRM buddy allocator patches from this series. This series now focuses solely on the C linked list interfacing infrastructure (clist module). The DRM buddy allocator bindings will be sent separately once we agree on the clist abstraction. - Dropped samples and added doctests. - Added proper lifetime management similar to scatterlist. The git tree with all patches can be found at the tag: git://git.kernel.org/pub/scm/linux/kernel/git/jfern/linux.git (tag: clist-v2-checkpoint-6) Introduction ============ This patchset introduces an interface to iterate over doubly circular linked lists used in the kernel (allocated by C kernel code). The main usecase is iterating over the list of blocks provided by the DRM buddy allocator but there will certainly be others in the future. This series introduces a new rust module called clist with the necessary helpers and abstractions for safe iteration over C-allocated linked lists. Notes from earlier series: A question may arise: Why not use rust list.rs for this? ========================================================= Rust's list.rs is used to provide safe intrusive lists for Rust-allocated items. In doing so, it takes ownership of the items in the list and the links between list items. However, the usecase for DRM buddy allocator bindings, the C side allocates the items in the list, and also links the list together. Due to this, there is an ownership conflict making list.rs not the best abstraction for this usecase. What we need is a view of the list, not ownership of it. Further, the list links in a bindings usecase may come from C allocated objects, not from the Rust side. Other comments ============== I already presented the idea in Zulip and it seemed it mostly got agreements there. I rebased the patches on linux-next. I can also add MAINTAINER entries in a future version, if folks agree this should have its own MAINTAINER record. Link to RFC: https://lore.kernel.org/all/20251030190613.1224287-1-joelagnelf@nvidia.com/ Joel Fernandes (3): rust: helpers: Add list helpers for C linked list operations rust: clist: Add basic list infrastructure and head iterator rust: clist: Add typed iteration with FromListHead trait rust/helpers/helpers.c | 1 + rust/helpers/list.c | 32 ++++ rust/kernel/clist.rs | 394 +++++++++++++++++++++++++++++++++++++++++ rust/kernel/lib.rs | 1 + 4 files changed, 428 insertions(+) create mode 100644 rust/helpers/list.c create mode 100644 rust/kernel/clist.rs -- 2.34.1 ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 0/3] rust: Introduce support for C linked list interfacing 2025-11-11 17:13 ` [PATCH v2 0/3] rust: Introduce support for C linked list interfacing Joel Fernandes @ 2025-11-11 19:54 ` Miguel Ojeda 2025-11-11 21:52 ` Joel Fernandes 0 siblings, 1 reply; 8+ messages in thread From: Miguel Ojeda @ 2025-11-11 19:54 UTC (permalink / raw) To: Joel Fernandes Cc: linux-kernel, rust-for-linux, dri-devel, dakr, airlied, acourbot, apopple, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh, lossin, a.hindborg, aliceryhl, tmgross, simona, maarten.lankhorst, mripard, tzimmermann, jhubbard, ttabi, joel, elle, daniel.almeida, arighi, phasta, nouveau On Tue, Nov 11, 2025 at 6:13 PM Joel Fernandes <joelagnelf@nvidia.com> wrote: > > there. I rebased the patches on linux-next. I can also add MAINTAINER entries > in a future version, if folks agree this should have its own MAINTAINER > record. Yes, it sounds good to me to add one. Please do -- thanks! Cheers, Miguel ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v2 0/3] rust: Introduce support for C linked list interfacing 2025-11-11 19:54 ` Miguel Ojeda @ 2025-11-11 21:52 ` Joel Fernandes 0 siblings, 0 replies; 8+ messages in thread From: Joel Fernandes @ 2025-11-11 21:52 UTC (permalink / raw) To: Miguel Ojeda Cc: linux-kernel, rust-for-linux, dri-devel, dakr, airlied, acourbot, apopple, ojeda, alex.gaynor, boqun.feng, gary, bjorn3_gh, lossin, a.hindborg, aliceryhl, tmgross, simona, maarten.lankhorst, mripard, tzimmermann, jhubbard, ttabi, joel, elle, daniel.almeida, arighi, phasta, nouveau On 11/11/2025 2:54 PM, Miguel Ojeda wrote: > On Tue, Nov 11, 2025 at 6:13 PM Joel Fernandes <joelagnelf@nvidia.com> wrote: >> >> there. I rebased the patches on linux-next. I can also add MAINTAINER entries >> in a future version, if folks agree this should have its own MAINTAINER >> record. > > Yes, it sounds good to me to add one. Please do -- thanks! Ok, will do. Thanks! - Joel ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2025-11-24 7:02 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2025-11-11 17:13 [PATCH v2 1/3] rust: helpers: Add list helpers for C linked list operations Joel Fernandes 2025-11-11 17:13 ` [PATCH v2 2/3] rust: clist: Add basic list infrastructure and head iterator Joel Fernandes 2025-11-24 3:47 ` Alexandre Courbot 2025-11-11 17:13 ` [PATCH v2 3/3] rust: clist: Add typed iteration with FromListHead trait Joel Fernandes 2025-11-24 7:01 ` Alexandre Courbot 2025-11-11 17:13 ` [PATCH v2 0/3] rust: Introduce support for C linked list interfacing Joel Fernandes 2025-11-11 19:54 ` Miguel Ojeda 2025-11-11 21:52 ` Joel Fernandes
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).