lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-Id: <DEGQCMSX1SGZ.2NQDPG5KUNA9D@nvidia.com>
Date: Mon, 24 Nov 2025 16:01:06 +0900
From: "Alexandre Courbot" <acourbot@...dia.com>
To: "Joel Fernandes" <joelagnelf@...dia.com>,
 <linux-kernel@...r.kernel.org>, <rust-for-linux@...r.kernel.org>,
 <dri-devel@...ts.freedesktop.org>, <dakr@...nel.org>, <airlied@...il.com>
Cc: <acourbot@...dia.com>, <apopple@...dia.com>, <ojeda@...nel.org>,
 <alex.gaynor@...il.com>, <boqun.feng@...il.com>, <gary@...yguo.net>,
 <bjorn3_gh@...tonmail.com>, <lossin@...nel.org>, <a.hindborg@...nel.org>,
 <aliceryhl@...gle.com>, <tmgross@...ch.edu>, <simona@...ll.ch>,
 <maarten.lankhorst@...ux.intel.com>, <mripard@...nel.org>,
 <tzimmermann@...e.de>, <jhubbard@...dia.com>, <ttabi@...dia.com>,
 <joel@...lfernandes.org>, <elle@...thered-steel.dev>,
 <daniel.almeida@...labora.com>, <arighi@...dia.com>, <phasta@...nel.org>,
 <nouveau@...ts.freedesktop.org>, "Nouveau"
 <nouveau-bounces@...ts.freedesktop.org>
Subject: Re: [PATCH v2 3/3] rust: clist: Add typed iteration with
 FromListHead trait

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@...dia.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`!

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ