* [PATCH -next v7 0/2] rust: Add CList and GPU buddy allocator bindings
@ 2026-02-06 0:41 Joel Fernandes
2026-02-06 0:41 ` [PATCH -next v7 1/2] rust: clist: Add support to interface with C linked lists Joel Fernandes
2026-02-06 0:41 ` [PATCH -next v7 2/2] rust: gpu: Add GPU buddy allocator bindings Joel Fernandes
0 siblings, 2 replies; 23+ messages in thread
From: Joel Fernandes @ 2026-02-06 0:41 UTC (permalink / raw)
To: linux-kernel
Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Jonathan Corbet, Alex Deucher,
Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi,
Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost,
Lucas De Marchi, Thomas Hellström, Helge Deller,
Danilo Krummrich, Alice Ryhl, Miguel Ojeda, Alex Gaynor,
Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
Andreas Hindborg, Trevor Gross, John Hubbard, Alistair Popple,
Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi,
Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner,
Elle Rhumsaa, Daniel Almeida, joel, nouveau, dri-devel,
rust-for-linux, linux-doc, amd-gfx, intel-gfx, intel-xe,
linux-fbdev, Joel Fernandes
This series provides Rust bindings infrastructure needed for nova-core
memory management:
1. CList module for interfacing with C circular linked lists, required
for iterating over GPU buddy allocator blocks.
2. GPU buddy allocator bindings for physical memory management in
nova-core.
These patches are based on the RFC v6 nova-core memory management series:
https://lore.kernel.org/all/20260120204303.3229303-1-joelagnelf@nvidia.com/
Main changes from v6 are based on suggestions by Gary and Dave.
This patch requires the DRM buddy code movement patch as a prerequisite:
https://lore.kernel.org/all/20260206003451.1914130-1-joelagnelf@nvidia.com/
Rebased on linux-next commit 9845cf73f7db ("Add linux-next specific files
for 20260205").
Joel Fernandes (2):
rust: clist: Add support to interface with C linked lists
rust: gpu: Add GPU buddy allocator bindings
MAINTAINERS | 7 +
drivers/gpu/Kconfig | 7 +
rust/bindings/bindings_helper.h | 11 +
rust/helpers/gpu.c | 23 ++
rust/helpers/helpers.c | 2 +
rust/helpers/list.c | 21 ++
rust/kernel/clist.rs | 315 +++++++++++++++++++
rust/kernel/gpu/buddy.rs | 530 ++++++++++++++++++++++++++++++++
rust/kernel/gpu/mod.rs | 5 +
rust/kernel/lib.rs | 4 +
10 files changed, 925 insertions(+)
create mode 100644 rust/helpers/gpu.c
create mode 100644 rust/helpers/list.c
create mode 100644 rust/kernel/clist.rs
create mode 100644 rust/kernel/gpu/buddy.rs
create mode 100644 rust/kernel/gpu/mod.rs
--
2.34.1
^ permalink raw reply [flat|nested] 23+ messages in thread* [PATCH -next v7 1/2] rust: clist: Add support to interface with C linked lists 2026-02-06 0:41 [PATCH -next v7 0/2] rust: Add CList and GPU buddy allocator bindings Joel Fernandes @ 2026-02-06 0:41 ` Joel Fernandes 2026-02-06 15:25 ` Gary Guo 2026-02-06 17:49 ` Daniel Almeida 2026-02-06 0:41 ` [PATCH -next v7 2/2] rust: gpu: Add GPU buddy allocator bindings Joel Fernandes 1 sibling, 2 replies; 23+ messages in thread From: Joel Fernandes @ 2026-02-06 0:41 UTC (permalink / raw) To: linux-kernel Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Danilo Krummrich, Alice Ryhl, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Trevor Gross, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, Daniel Almeida, joel, nouveau, dri-devel, rust-for-linux, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev, Joel Fernandes Add a new module `clist` 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. Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com> --- MAINTAINERS | 7 + drivers/gpu/Kconfig | 7 + rust/helpers/helpers.c | 1 + rust/helpers/list.c | 21 +++ rust/kernel/clist.rs | 315 +++++++++++++++++++++++++++++++++++++++++ rust/kernel/lib.rs | 2 + 6 files changed, 353 insertions(+) create mode 100644 rust/helpers/list.c create mode 100644 rust/kernel/clist.rs diff --git a/MAINTAINERS b/MAINTAINERS index 900fc00b73e6..310bb479260c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -23204,6 +23204,13 @@ S: Maintained T: git https://github.com/Rust-for-Linux/linux.git rust-analyzer-next F: scripts/generate_rust_analyzer.py +RUST TO C LIST INTERFACES +M: Joel Fernandes <joelagnelf@nvidia.com> +M: Alexandre Courbot <acourbot@nvidia.com> +L: rust-for-linux@vger.kernel.org +S: Maintained +F: rust/kernel/clist.rs + RXRPC SOCKETS (AF_RXRPC) M: David Howells <dhowells@redhat.com> M: Marc Dionne <marc.dionne@auristor.com> diff --git a/drivers/gpu/Kconfig b/drivers/gpu/Kconfig index 22dd29cd50b5..2c3dec070645 100644 --- a/drivers/gpu/Kconfig +++ b/drivers/gpu/Kconfig @@ -1,7 +1,14 @@ # SPDX-License-Identifier: GPL-2.0 +config RUST_CLIST + bool + depends on RUST + help + Rust abstraction for interfacing with C linked lists. + config GPU_BUDDY bool + select RUST_CLIST if RUST help A page based buddy allocator for GPU memory. diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index a3c42e51f00a..724fcb8240ac 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -35,6 +35,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..3390b154fa36 --- /dev/null +++ b/rust/helpers/list.c @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Helpers for C Circular doubly linked list implementation. + */ + +#include <linux/list.h> + +#ifndef __rust_helper +#define __rust_helper +#endif + +__rust_helper void rust_helper_INIT_LIST_HEAD(struct list_head *list) +{ + INIT_LIST_HEAD(list); +} + +__rust_helper void rust_helper_list_add_tail(struct list_head *new, struct list_head *head) +{ + list_add_tail(new, head); +} diff --git a/rust/kernel/clist.rs b/rust/kernel/clist.rs new file mode 100644 index 000000000000..1f6d4db13c1d --- /dev/null +++ b/rust/kernel/clist.rs @@ -0,0 +1,315 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! A C doubly circular intrusive linked list interface for rust code. +//! +//! # Examples +//! +//! ``` +//! use kernel::{ +//! bindings, +//! clist_create, +//! 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(); +//! # +//! # let head = head.as_mut_ptr(); +//! # // SAFETY: head and all the items are test objects allocated in this scope. +//! # unsafe { bindings::INIT_LIST_HEAD(head) }; +//! # +//! # 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; +//! # // addr_of_mut!() computes address of link directly as link is uninitialized. +//! # bindings::INIT_LIST_HEAD(core::ptr::addr_of_mut!((*ptr).link)); +//! # bindings::list_add_tail(&mut (*ptr).link, 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>); +//! +//! impl Item { +//! pub(crate) fn value(&self) -> i32 { +//! // SAFETY: [`Item`] has same layout as [`SampleItemC`]. +//! unsafe { (*self.0.get()).value } +//! } +//! } +//! +//! // Create typed [`CList`] from sentinel head. +//! // SAFETY: head is valid, items are [`SampleItemC`] with embedded `link` field. +//! let list = unsafe { clist_create!(head, Item, SampleItemC, link) }; +//! +//! // Iterate directly over typed items. +//! let mut found_0 = false; +//! let mut found_10 = false; +//! let mut found_20 = false; +//! +//! for item in list.iter() { +//! 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 core::{ + iter::FusedIterator, + marker::PhantomData, // +}; + +use crate::{ + bindings, + types::Opaque, // +}; + +use pin_init::PinInit; + +/// Wraps a `list_head` object for use in intrusive linked lists. +/// +/// # Invariants +/// +/// - [`CListHead`] represents an allocated and valid `list_head` structure. +/// - Once a [`CListHead`] is created in Rust, it will not be modified by non-Rust code. +/// - All `list_head` for individual items are not modified for the lifetime of [`CListHead`]. +#[repr(transparent)] +pub(crate) struct CListHead(Opaque<bindings::list_head>); + +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. + /// - `ptr` must remain valid and unmodified for the lifetime `'a`. + #[inline] + pub(crate) unsafe fn from_raw<'a>(ptr: *mut bindings::list_head) -> &'a Self { + // SAFETY: + // - [`CListHead`] has same layout as `list_head`. + // - `ptr` is valid and unmodified for 'a. + unsafe { &*ptr.cast() } + } + + /// Get the raw `list_head` pointer. + #[inline] + pub(crate) fn as_raw(&self) -> *mut bindings::list_head { + self.0.get() + } + + /// Get the next [`CListHead`] in the list. + #[inline] + pub(crate) fn next(&self) -> &Self { + let raw = self.as_raw(); + // SAFETY: + // - `self.as_raw()` is valid per type invariants. + // - The `next` pointer is guaranteed to be non-NULL. + unsafe { Self::from_raw((*raw).next) } + } + + /// Check if this node is linked in a list (not isolated). + #[inline] + pub(crate) fn is_linked(&self) -> bool { + let raw = self.as_raw(); + // SAFETY: self.as_raw() is valid per type invariants. + unsafe { (*raw).next != raw && (*raw).prev != raw } + } + + /// Pin-initializer that initializes the list head. + pub(crate) fn new() -> impl PinInit<Self> { + // SAFETY: `INIT_LIST_HEAD` initializes `slot` to a valid empty list. + unsafe { + pin_init::pin_init_from_closure(move |slot: *mut Self| { + bindings::INIT_LIST_HEAD(slot.cast()); + Ok(()) + }) + } + } +} + +// 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 non-Rust code per type invariants. +unsafe impl Sync for CListHead {} + +impl PartialEq for CListHead { + fn eq(&self, other: &Self) -> bool { + core::ptr::eq(self, other) + } +} + +impl Eq for CListHead {} + +/// 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 (using `container_of` macro or similar). +/// +/// # Invariants +/// +/// [`CListHeadIter`] is iterating over an allocated, initialized and valid list. +struct CListHeadIter<'a> { + /// Current position in the list. + current: &'a CListHead, + /// The sentinel head (used to detect end of iteration). + sentinel: &'a CListHead, +} + +impl<'a> Iterator for CListHeadIter<'a> { + type Item = &'a CListHead; + + #[inline] + fn next(&mut self) -> Option<Self::Item> { + // Check if we've reached the sentinel (end of list). + if core::ptr::eq(self.current, self.sentinel) { + return None; + } + + let item = self.current; + self.current = item.next(); + Some(item) + } +} + +impl<'a> FusedIterator for CListHeadIter<'a> {} + +/// A typed C linked list with a sentinel head. +/// +/// A sentinel head represents the entire linked list and can be used for +/// iteration over items of type `T`, it is not associated with a specific item. +/// +/// The const generic `OFFSET` specifies the byte offset of the `list_head` field within +/// the struct that `T` wraps. +/// +/// # Invariants +/// +/// - The [`CListHead`] is an allocated and valid sentinel C `list_head` structure. +/// - `OFFSET` is the byte offset of the `list_head` field within the struct that `T` wraps. +/// - All the list's `list_head` nodes are allocated and have valid next/prev pointers. +#[repr(transparent)] +pub(crate) struct CList<T, const OFFSET: usize>(CListHead, PhantomData<T>); + +impl<T, const OFFSET: usize> CList<T, OFFSET> { + /// Create a typed [`CList`] reference 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. + /// - `ptr` must remain valid and unmodified for the lifetime `'a`. + /// - The list must contain items where the `list_head` field is at byte offset `OFFSET`. + /// - `T` must be `#[repr(transparent)]` over the C struct. + #[inline] + pub(crate) unsafe fn from_raw<'a>(ptr: *mut bindings::list_head) -> &'a Self { + // SAFETY: + // - [`CList`] has same layout as [`CListHead`] due to repr(transparent). + // - Caller guarantees `ptr` is a valid, sentinel `list_head` object. + unsafe { &*ptr.cast() } + } + + /// Check if the list is empty. + #[inline] + #[expect(dead_code)] + pub(crate) fn is_empty(&self) -> bool { + !self.0.is_linked() + } + + /// Create an iterator over typed items. + #[inline] + pub(crate) fn iter(&self) -> CListIter<'_, T, OFFSET> { + let head = &self.0; + CListIter { + head_iter: CListHeadIter { + current: head.next(), + sentinel: head, + }, + _phantom: PhantomData, + } + } +} + +/// High-level iterator over typed list items. +pub(crate) struct CListIter<'a, T, const OFFSET: usize> { + head_iter: CListHeadIter<'a>, + _phantom: PhantomData<&'a T>, +} + +impl<'a, T, const OFFSET: usize> Iterator for CListIter<'a, T, OFFSET> { + type Item = &'a T; + + fn next(&mut self) -> Option<Self::Item> { + let head = self.head_iter.next()?; + + // Convert to item using OFFSET. + // SAFETY: `item_ptr` calculation from `OFFSET` (calculated using offset_of!) + // is valid per invariants. + Some(unsafe { &*head.as_raw().byte_sub(OFFSET).cast::<T>() }) + } +} + +impl<'a, T, const OFFSET: usize> FusedIterator for CListIter<'a, T, OFFSET> {} + +/// 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 +/// +/// This is an unsafe macro. The caller must ensure: +/// +/// - `$head` is a valid, initialized sentinel `list_head` pointing to a list that remains +/// unmodified for the lifetime of the rust `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 this module's documentation. +#[macro_export] +macro_rules! clist_create { + ($head:expr, $rust_type:ty, $c_type:ty, $($field:tt).+) => {{ + // Compile-time check that field path is a list_head. + let _: fn(*const $c_type) -> *const $crate::bindings::list_head = + |p| &raw const (*p).$($field).+; + + // Calculate offset and create `CList`. + const OFFSET: usize = ::core::mem::offset_of!($c_type, $($field).+); + $crate::clist::CList::<$rust_type, OFFSET>::from_raw($head) + }}; +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 3da92f18f4ee..8439c30f40b5 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -75,6 +75,8 @@ pub mod bug; #[doc(hidden)] pub mod build_assert; +#[cfg(CONFIG_RUST_CLIST)] +pub(crate) mod clist; pub mod clk; #[cfg(CONFIG_CONFIGFS_FS)] pub mod configfs; -- 2.34.1 ^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: [PATCH -next v7 1/2] rust: clist: Add support to interface with C linked lists 2026-02-06 0:41 ` [PATCH -next v7 1/2] rust: clist: Add support to interface with C linked lists Joel Fernandes @ 2026-02-06 15:25 ` Gary Guo 2026-02-06 15:53 ` Danilo Krummrich 2026-02-09 19:41 ` Joel Fernandes 2026-02-06 17:49 ` Daniel Almeida 1 sibling, 2 replies; 23+ messages in thread From: Gary Guo @ 2026-02-06 15:25 UTC (permalink / raw) To: Joel Fernandes, linux-kernel Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Danilo Krummrich, Alice Ryhl, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Trevor Gross, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, Daniel Almeida, joel, nouveau, dri-devel, rust-for-linux, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev On Fri Feb 6, 2026 at 12:41 AM GMT, Joel Fernandes wrote: > Add a new module `clist` 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. > > Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com> > --- > MAINTAINERS | 7 + > drivers/gpu/Kconfig | 7 + > rust/helpers/helpers.c | 1 + > rust/helpers/list.c | 21 +++ > rust/kernel/clist.rs | 315 +++++++++++++++++++++++++++++++++++++++++ > rust/kernel/lib.rs | 2 + > 6 files changed, 353 insertions(+) > create mode 100644 rust/helpers/list.c > create mode 100644 rust/kernel/clist.rs > > diff --git a/MAINTAINERS b/MAINTAINERS > index 900fc00b73e6..310bb479260c 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -23204,6 +23204,13 @@ S: Maintained > T: git https://github.com/Rust-for-Linux/linux.git rust-analyzer-next > F: scripts/generate_rust_analyzer.py > > +RUST TO C LIST INTERFACES > +M: Joel Fernandes <joelagnelf@nvidia.com> > +M: Alexandre Courbot <acourbot@nvidia.com> > +L: rust-for-linux@vger.kernel.org > +S: Maintained > +F: rust/kernel/clist.rs I still think we should try to work on a more powerful list infra that works for both C and Rust, but I reckon that is a longer term effort, and shouldn't prevent a simpler version from getting in and be used by abstractions that need it. So Acked-by: Gary Guo <gary@garyguo.net> Some nits below: > + > RXRPC SOCKETS (AF_RXRPC) > M: David Howells <dhowells@redhat.com> > M: Marc Dionne <marc.dionne@auristor.com> > diff --git a/drivers/gpu/Kconfig b/drivers/gpu/Kconfig > index 22dd29cd50b5..2c3dec070645 100644 > --- a/drivers/gpu/Kconfig > +++ b/drivers/gpu/Kconfig > @@ -1,7 +1,14 @@ > # SPDX-License-Identifier: GPL-2.0 > > +config RUST_CLIST > + bool > + depends on RUST > + help > + Rust abstraction for interfacing with C linked lists. I am not sure if we need extra config entry. This is fully generic so shouldn't generate any code unless there is an user. > + > config GPU_BUDDY > bool > + select RUST_CLIST if RUST > help > A page based buddy allocator for GPU memory. > > diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c > index a3c42e51f00a..724fcb8240ac 100644 > --- a/rust/helpers/helpers.c > +++ b/rust/helpers/helpers.c > @@ -35,6 +35,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..3390b154fa36 > --- /dev/null > +++ b/rust/helpers/list.c > @@ -0,0 +1,21 @@ > +// SPDX-License-Identifier: GPL-2.0 > + > +/* > + * Helpers for C Circular doubly linked list implementation. > + */ > + > +#include <linux/list.h> > + > +#ifndef __rust_helper > +#define __rust_helper > +#endif This shouldn't be needed. > + > +__rust_helper void rust_helper_INIT_LIST_HEAD(struct list_head *list) > +{ > + INIT_LIST_HEAD(list); > +} > + > +__rust_helper void rust_helper_list_add_tail(struct list_head *new, struct list_head *head) > +{ > + list_add_tail(new, head); > +} > diff --git a/rust/kernel/clist.rs b/rust/kernel/clist.rs > new file mode 100644 > index 000000000000..1f6d4db13c1d > --- /dev/null > +++ b/rust/kernel/clist.rs > @@ -0,0 +1,315 @@ > +// SPDX-License-Identifier: GPL-2.0 > + > +//! A C doubly circular intrusive linked list interface for rust code. > +//! > +//! # Examples > +//! > +//! ``` > +//! use kernel::{ > +//! bindings, > +//! clist_create, > +//! 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(); > +//! # > +//! # let head = head.as_mut_ptr(); > +//! # // SAFETY: head and all the items are test objects allocated in this scope. > +//! # unsafe { bindings::INIT_LIST_HEAD(head) }; > +//! # > +//! # 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; > +//! # // addr_of_mut!() computes address of link directly as link is uninitialized. > +//! # bindings::INIT_LIST_HEAD(core::ptr::addr_of_mut!((*ptr).link)); > +//! # bindings::list_add_tail(&mut (*ptr).link, 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>); > +//! > +//! impl Item { > +//! pub(crate) fn value(&self) -> i32 { > +//! // SAFETY: [`Item`] has same layout as [`SampleItemC`]. > +//! unsafe { (*self.0.get()).value } > +//! } > +//! } > +//! > +//! // Create typed [`CList`] from sentinel head. > +//! // SAFETY: head is valid, items are [`SampleItemC`] with embedded `link` field. > +//! let list = unsafe { clist_create!(head, Item, SampleItemC, link) }; > +//! > +//! // Iterate directly over typed items. > +//! let mut found_0 = false; > +//! let mut found_10 = false; > +//! let mut found_20 = false; > +//! > +//! for item in list.iter() { > +//! 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 core::{ > + iter::FusedIterator, > + marker::PhantomData, // > +}; > + > +use crate::{ > + bindings, > + types::Opaque, // > +}; > + > +use pin_init::PinInit; > + > +/// Wraps a `list_head` object for use in intrusive linked lists. > +/// > +/// # Invariants > +/// > +/// - [`CListHead`] represents an allocated and valid `list_head` structure. > +/// - Once a [`CListHead`] is created in Rust, it will not be modified by non-Rust code. > +/// - All `list_head` for individual items are not modified for the lifetime of [`CListHead`]. > +#[repr(transparent)] > +pub(crate) struct CListHead(Opaque<bindings::list_head>); > + > +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. > + /// - `ptr` must remain valid and unmodified for the lifetime `'a`. > + #[inline] > + pub(crate) unsafe fn from_raw<'a>(ptr: *mut bindings::list_head) -> &'a Self { > + // SAFETY: > + // - [`CListHead`] has same layout as `list_head`. > + // - `ptr` is valid and unmodified for 'a. > + unsafe { &*ptr.cast() } > + } > + > + /// Get the raw `list_head` pointer. > + #[inline] > + pub(crate) fn as_raw(&self) -> *mut bindings::list_head { > + self.0.get() > + } > + > + /// Get the next [`CListHead`] in the list. > + #[inline] > + pub(crate) fn next(&self) -> &Self { > + let raw = self.as_raw(); > + // SAFETY: > + // - `self.as_raw()` is valid per type invariants. > + // - The `next` pointer is guaranteed to be non-NULL. > + unsafe { Self::from_raw((*raw).next) } > + } > + > + /// Check if this node is linked in a list (not isolated). > + #[inline] > + pub(crate) fn is_linked(&self) -> bool { > + let raw = self.as_raw(); > + // SAFETY: self.as_raw() is valid per type invariants. > + unsafe { (*raw).next != raw && (*raw).prev != raw } > + } > + > + /// Pin-initializer that initializes the list head. > + pub(crate) fn new() -> impl PinInit<Self> { > + // SAFETY: `INIT_LIST_HEAD` initializes `slot` to a valid empty list. > + unsafe { > + pin_init::pin_init_from_closure(move |slot: *mut Self| { pin_init::ffi_init should be used for this. > + bindings::INIT_LIST_HEAD(slot.cast()); > + Ok(()) > + }) > + } > + } > +} > + > +// 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 non-Rust code per type invariants. > +unsafe impl Sync for CListHead {} > + > +impl PartialEq for CListHead { #[inline] > + fn eq(&self, other: &Self) -> bool { > + core::ptr::eq(self, other) > + } > +} > + > +impl Eq for CListHead {} ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH -next v7 1/2] rust: clist: Add support to interface with C linked lists 2026-02-06 15:25 ` Gary Guo @ 2026-02-06 15:53 ` Danilo Krummrich 2026-02-06 16:05 ` Joel Fernandes 2026-02-09 19:41 ` Joel Fernandes 1 sibling, 1 reply; 23+ messages in thread From: Danilo Krummrich @ 2026-02-06 15:53 UTC (permalink / raw) To: Gary Guo Cc: Joel Fernandes, linux-kernel, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Alice Ryhl, Miguel Ojeda, Alex Gaynor, Boqun Feng, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Trevor Gross, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, Daniel Almeida, joel, nouveau, dri-devel, rust-for-linux, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev On Fri Feb 6, 2026 at 4:25 PM CET, Gary Guo wrote: > On Fri Feb 6, 2026 at 12:41 AM GMT, Joel Fernandes wrote: >> diff --git a/drivers/gpu/Kconfig b/drivers/gpu/Kconfig >> index 22dd29cd50b5..2c3dec070645 100644 >> --- a/drivers/gpu/Kconfig >> +++ b/drivers/gpu/Kconfig >> @@ -1,7 +1,14 @@ >> # SPDX-License-Identifier: GPL-2.0 >> >> +config RUST_CLIST >> + bool >> + depends on RUST >> + help >> + Rust abstraction for interfacing with C linked lists. > > I am not sure if we need extra config entry. This is fully generic so shouldn't > generate any code unless there is an user. I also don't think we need a Kconfig for this. In any case, it shouln't be in drivers/gpu/Kconfig. >> + >> config GPU_BUDDY >> bool >> + select RUST_CLIST if RUST If we will have a Kconfig for this, this belongs in the GPU buddy patch. >> help >> A page based buddy allocator for GPU memory. ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH -next v7 1/2] rust: clist: Add support to interface with C linked lists 2026-02-06 15:53 ` Danilo Krummrich @ 2026-02-06 16:05 ` Joel Fernandes 2026-02-06 16:13 ` Gary Guo 0 siblings, 1 reply; 23+ messages in thread From: Joel Fernandes @ 2026-02-06 16:05 UTC (permalink / raw) To: Danilo Krummrich, Gary Guo Cc: linux-kernel, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Alice Ryhl, Miguel Ojeda, Alex Gaynor, Boqun Feng, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Trevor Gross, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, Daniel Almeida, joel, nouveau, dri-devel, rust-for-linux, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev On 2/6/2026 10:53 AM, Danilo Krummrich wrote: > On Fri Feb 6, 2026 at 4:25 PM CET, Gary Guo wrote: >> On Fri Feb 6, 2026 at 12:41 AM GMT, Joel Fernandes wrote: >>> diff --git a/drivers/gpu/Kconfig b/drivers/gpu/Kconfig >>> index 22dd29cd50b5..2c3dec070645 100644 >>> --- a/drivers/gpu/Kconfig >>> +++ b/drivers/gpu/Kconfig >>> @@ -1,7 +1,14 @@ >>> # SPDX-License-Identifier: GPL-2.0 >>> >>> +config RUST_CLIST >>> + bool >>> + depends on RUST >>> + help >>> + Rust abstraction for interfacing with C linked lists. >> >> I am not sure if we need extra config entry. This is fully generic so shouldn't >> generate any code unless there is an user. > > I also don't think we need a Kconfig for this. > > In any case, it shouln't be in drivers/gpu/Kconfig. Fair point, I believe I was having trouble compiling this into the kernel crate without warnings (I believe if !GPU_BUDDY). I'll try to drop it and see if we can get rid of it. > >>> + >>> config GPU_BUDDY >>> bool >>> + select RUST_CLIST if RUST > > If we will have a Kconfig for this, this belongs in the GPU buddy patch. You mean, in the GPU buddy bindings patch right? If so, yes, I will move it there. Thanks. -- Joel Fernandes ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH -next v7 1/2] rust: clist: Add support to interface with C linked lists 2026-02-06 16:05 ` Joel Fernandes @ 2026-02-06 16:13 ` Gary Guo 2026-02-06 17:13 ` Danilo Krummrich 0 siblings, 1 reply; 23+ messages in thread From: Gary Guo @ 2026-02-06 16:13 UTC (permalink / raw) To: Joel Fernandes, Danilo Krummrich, Gary Guo Cc: linux-kernel, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Alice Ryhl, Miguel Ojeda, Alex Gaynor, Boqun Feng, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Trevor Gross, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, Daniel Almeida, joel, nouveau, dri-devel, rust-for-linux, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev On Fri Feb 6, 2026 at 4:05 PM GMT, Joel Fernandes wrote: > > > On 2/6/2026 10:53 AM, Danilo Krummrich wrote: >> On Fri Feb 6, 2026 at 4:25 PM CET, Gary Guo wrote: >>> On Fri Feb 6, 2026 at 12:41 AM GMT, Joel Fernandes wrote: >>>> diff --git a/drivers/gpu/Kconfig b/drivers/gpu/Kconfig >>>> index 22dd29cd50b5..2c3dec070645 100644 >>>> --- a/drivers/gpu/Kconfig >>>> +++ b/drivers/gpu/Kconfig >>>> @@ -1,7 +1,14 @@ >>>> # SPDX-License-Identifier: GPL-2.0 >>>> >>>> +config RUST_CLIST >>>> + bool >>>> + depends on RUST >>>> + help >>>> + Rust abstraction for interfacing with C linked lists. >>> >>> I am not sure if we need extra config entry. This is fully generic so shouldn't >>> generate any code unless there is an user. >> >> I also don't think we need a Kconfig for this. >> >> In any case, it shouln't be in drivers/gpu/Kconfig. > > Fair point, I believe I was having trouble compiling this into the kernel crate > without warnings (I believe if !GPU_BUDDY). I'll try to drop it and see if we > can get rid of it. If you run into dead code warnings, I think it is fine to just #[allow(dead_code, reason = "all users might be cfg-ed out")] the overhead of just let rustc type-checking this module isn't worth the extra Kconfig plumbing, I think. Best, Gary > >> >>>> + >>>> config GPU_BUDDY >>>> bool >>>> + select RUST_CLIST if RUST >> >> If we will have a Kconfig for this, this belongs in the GPU buddy patch. > > You mean, in the GPU buddy bindings patch right? If so, yes, I will move it there. > > Thanks. ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH -next v7 1/2] rust: clist: Add support to interface with C linked lists 2026-02-06 16:13 ` Gary Guo @ 2026-02-06 17:13 ` Danilo Krummrich 2026-02-06 17:20 ` Gary Guo 2026-02-06 20:44 ` Joel Fernandes 0 siblings, 2 replies; 23+ messages in thread From: Danilo Krummrich @ 2026-02-06 17:13 UTC (permalink / raw) To: Gary Guo Cc: Joel Fernandes, linux-kernel, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Alice Ryhl, Miguel Ojeda, Alex Gaynor, Boqun Feng, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Trevor Gross, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, Daniel Almeida, joel, nouveau, dri-devel, rust-for-linux, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev On Fri Feb 6, 2026 at 5:13 PM CET, Gary Guo wrote: > On Fri Feb 6, 2026 at 4:05 PM GMT, Joel Fernandes wrote: >> >> >> On 2/6/2026 10:53 AM, Danilo Krummrich wrote: >>> On Fri Feb 6, 2026 at 4:25 PM CET, Gary Guo wrote: >>>> On Fri Feb 6, 2026 at 12:41 AM GMT, Joel Fernandes wrote: >>>>> diff --git a/drivers/gpu/Kconfig b/drivers/gpu/Kconfig >>>>> index 22dd29cd50b5..2c3dec070645 100644 >>>>> --- a/drivers/gpu/Kconfig >>>>> +++ b/drivers/gpu/Kconfig >>>>> @@ -1,7 +1,14 @@ >>>>> # SPDX-License-Identifier: GPL-2.0 >>>>> >>>>> +config RUST_CLIST >>>>> + bool >>>>> + depends on RUST >>>>> + help >>>>> + Rust abstraction for interfacing with C linked lists. >>>> >>>> I am not sure if we need extra config entry. This is fully generic so shouldn't >>>> generate any code unless there is an user. >>> >>> I also don't think we need a Kconfig for this. >>> >>> In any case, it shouln't be in drivers/gpu/Kconfig. >> >> Fair point, I believe I was having trouble compiling this into the kernel crate >> without warnings (I believe if !GPU_BUDDY). I'll try to drop it and see if we >> can get rid of it. > > If you run into dead code warnings, I think it is fine to just > > #[allow(dead_code, reason = "all users might be cfg-ed out")] > > the overhead of just let rustc type-checking this module isn't worth the extra > Kconfig plumbing, I think. You mean because there are pub(crate) in clist.rs? I don't think the Kconfig would help with that, nothing prevents people from enabling RUST_CLIST, but none of the users. Besides that, once we have the new build system, the users of CList are likely in other crates anyways, so I think we should just change things to pub. ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH -next v7 1/2] rust: clist: Add support to interface with C linked lists 2026-02-06 17:13 ` Danilo Krummrich @ 2026-02-06 17:20 ` Gary Guo 2026-02-06 17:27 ` Danilo Krummrich 2026-02-06 20:44 ` Joel Fernandes 1 sibling, 1 reply; 23+ messages in thread From: Gary Guo @ 2026-02-06 17:20 UTC (permalink / raw) To: Danilo Krummrich, Gary Guo Cc: Joel Fernandes, linux-kernel, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Alice Ryhl, Miguel Ojeda, Alex Gaynor, Boqun Feng, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Trevor Gross, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, Daniel Almeida, joel, nouveau, dri-devel, rust-for-linux, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev On Fri Feb 6, 2026 at 5:13 PM GMT, Danilo Krummrich wrote: > On Fri Feb 6, 2026 at 5:13 PM CET, Gary Guo wrote: >> On Fri Feb 6, 2026 at 4:05 PM GMT, Joel Fernandes wrote: >>> >>> >>> On 2/6/2026 10:53 AM, Danilo Krummrich wrote: >>>> On Fri Feb 6, 2026 at 4:25 PM CET, Gary Guo wrote: >>>>> On Fri Feb 6, 2026 at 12:41 AM GMT, Joel Fernandes wrote: >>>>>> diff --git a/drivers/gpu/Kconfig b/drivers/gpu/Kconfig >>>>>> index 22dd29cd50b5..2c3dec070645 100644 >>>>>> --- a/drivers/gpu/Kconfig >>>>>> +++ b/drivers/gpu/Kconfig >>>>>> @@ -1,7 +1,14 @@ >>>>>> # SPDX-License-Identifier: GPL-2.0 >>>>>> >>>>>> +config RUST_CLIST >>>>>> + bool >>>>>> + depends on RUST >>>>>> + help >>>>>> + Rust abstraction for interfacing with C linked lists. >>>>> >>>>> I am not sure if we need extra config entry. This is fully generic so shouldn't >>>>> generate any code unless there is an user. >>>> >>>> I also don't think we need a Kconfig for this. >>>> >>>> In any case, it shouln't be in drivers/gpu/Kconfig. >>> >>> Fair point, I believe I was having trouble compiling this into the kernel crate >>> without warnings (I believe if !GPU_BUDDY). I'll try to drop it and see if we >>> can get rid of it. >> >> If you run into dead code warnings, I think it is fine to just >> >> #[allow(dead_code, reason = "all users might be cfg-ed out")] >> >> the overhead of just let rustc type-checking this module isn't worth the extra >> Kconfig plumbing, I think. > > You mean because there are pub(crate) in clist.rs? I don't think the Kconfig > would help with that, nothing prevents people from enabling RUST_CLIST, but none > of the users. > > Besides that, once we have the new build system, the users of CList are likely > in other crates anyways, so I think we should just change things to pub. I asked for this to be changed to `pub(crate)` because I think this isn't something that should be used by drivers. As you said, tt might be tricky to enforce that with new build system when subsystems are inside different crates. But until then I think it's better to limit visibility. Best, Gary ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH -next v7 1/2] rust: clist: Add support to interface with C linked lists 2026-02-06 17:20 ` Gary Guo @ 2026-02-06 17:27 ` Danilo Krummrich 2026-02-06 21:30 ` Daniel Almeida 0 siblings, 1 reply; 23+ messages in thread From: Danilo Krummrich @ 2026-02-06 17:27 UTC (permalink / raw) To: Gary Guo Cc: Joel Fernandes, linux-kernel, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Alice Ryhl, Miguel Ojeda, Alex Gaynor, Boqun Feng, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Trevor Gross, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, Daniel Almeida, joel, nouveau, dri-devel, rust-for-linux, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev On Fri Feb 6, 2026 at 6:20 PM CET, Gary Guo wrote: > I asked for this to be changed to `pub(crate)` because I think this isn't > something that should be used by drivers. > > As you said, tt might be tricky to enforce that with new build system when > subsystems are inside different crates. But until then I think it's better to > limit visibility. It should *usually* not be used by drivers, but there are exceptions. For instance, it is perfectly valid to be used by Rust drivers that interact with C drivers. Besides that, my take on this is that we know that the new build system will come and that pub(crate) won't work in the long term, so why bother. I'd only use it in cases where you want to keep things local to the subsystem. ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH -next v7 1/2] rust: clist: Add support to interface with C linked lists 2026-02-06 17:27 ` Danilo Krummrich @ 2026-02-06 21:30 ` Daniel Almeida 2026-02-09 19:42 ` Joel Fernandes 0 siblings, 1 reply; 23+ messages in thread From: Daniel Almeida @ 2026-02-06 21:30 UTC (permalink / raw) To: Danilo Krummrich Cc: Gary Guo, Joel Fernandes, linux-kernel, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Alice Ryhl, Miguel Ojeda, Alex Gaynor, Boqun Feng, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Trevor Gross, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, joel, nouveau, dri-devel, rust-for-linux, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev > On 6 Feb 2026, at 14:27, Danilo Krummrich <dakr@kernel.org> wrote: > > On Fri Feb 6, 2026 at 6:20 PM CET, Gary Guo wrote: >> I asked for this to be changed to `pub(crate)` because I think this isn't >> something that should be used by drivers. >> >> As you said, tt might be tricky to enforce that with new build system when >> subsystems are inside different crates. But until then I think it's better to >> limit visibility. > > It should *usually* not be used by drivers, but there are exceptions. For > instance, it is perfectly valid to be used by Rust drivers that interact with C > drivers. I agree with what Danilo said here. I don’t see a reason to forbid drivers from using this. If the reason is the unsafe bits, then isn’t it the same pattern used by impl_has_work!() anyways? i.e.: a macro that implements an unsafe trait so long as the driver gives it the right Work field. Seems equivalent in spirit to the clist_create macro introduced by this patch. — Daniel ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH -next v7 1/2] rust: clist: Add support to interface with C linked lists 2026-02-06 21:30 ` Daniel Almeida @ 2026-02-09 19:42 ` Joel Fernandes 0 siblings, 0 replies; 23+ messages in thread From: Joel Fernandes @ 2026-02-09 19:42 UTC (permalink / raw) To: Daniel Almeida, Danilo Krummrich Cc: Gary Guo, linux-kernel, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Alice Ryhl, Miguel Ojeda, Alex Gaynor, Boqun Feng, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Trevor Gross, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, joel, nouveau, dri-devel, rust-for-linux, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev On 2/6/2026 4:30 PM, Daniel Almeida wrote: > > >> On 6 Feb 2026, at 14:27, Danilo Krummrich <dakr@kernel.org> wrote: >> >> On Fri Feb 6, 2026 at 6:20 PM CET, Gary Guo wrote: >>> I asked for this to be changed to `pub(crate)` because I think this isn't >>> something that should be used by drivers. >>> >>> As you said, tt might be tricky to enforce that with new build system when >>> subsystems are inside different crates. But until then I think it's better to >>> limit visibility. >> >> It should *usually* not be used by drivers, but there are exceptions. For >> instance, it is perfectly valid to be used by Rust drivers that interact with C >> drivers. > > I agree with what Danilo said here. > > I don’t see a reason to forbid drivers from using this. If the reason is > the unsafe bits, then isn’t it the same pattern used by impl_has_work!() > anyways? i.e.: a macro that implements an unsafe trait so long as the driver > gives it the right Work field. Seems equivalent in spirit to the clist_create macro > introduced by this patch. > Thank you for this suggestion. As I discussed on the other thread, I think the consensus is to change the module level to "pub" and all the items in it to "pub" as well. So I will do so. -- Joel Fernandes ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH -next v7 1/2] rust: clist: Add support to interface with C linked lists 2026-02-06 17:13 ` Danilo Krummrich 2026-02-06 17:20 ` Gary Guo @ 2026-02-06 20:44 ` Joel Fernandes 1 sibling, 0 replies; 23+ messages in thread From: Joel Fernandes @ 2026-02-06 20:44 UTC (permalink / raw) To: Danilo Krummrich, Gary Guo Cc: linux-kernel, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Alice Ryhl, Miguel Ojeda, Alex Gaynor, Boqun Feng, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Trevor Gross, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, Daniel Almeida, joel, nouveau, dri-devel, rust-for-linux, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev On 2/6/2026 12:13 PM, Danilo Krummrich wrote: > On Fri Feb 6, 2026 at 5:13 PM CET, Gary Guo wrote: >> On Fri Feb 6, 2026 at 4:05 PM GMT, Joel Fernandes wrote: >>> >>> >>> On 2/6/2026 10:53 AM, Danilo Krummrich wrote: >>>> On Fri Feb 6, 2026 at 4:25 PM CET, Gary Guo wrote: >>>>> On Fri Feb 6, 2026 at 12:41 AM GMT, Joel Fernandes wrote: >>>>>> diff --git a/drivers/gpu/Kconfig b/drivers/gpu/Kconfig >>>>>> index 22dd29cd50b5..2c3dec070645 100644 >>>>>> --- a/drivers/gpu/Kconfig >>>>>> +++ b/drivers/gpu/Kconfig >>>>>> @@ -1,7 +1,14 @@ >>>>>> # SPDX-License-Identifier: GPL-2.0 >>>>>> >>>>>> +config RUST_CLIST >>>>>> + bool >>>>>> + depends on RUST >>>>>> + help >>>>>> + Rust abstraction for interfacing with C linked lists. >>>>> >>>>> I am not sure if we need extra config entry. This is fully generic so shouldn't >>>>> generate any code unless there is an user. >>>> >>>> I also don't think we need a Kconfig for this. >>>> >>>> In any case, it shouln't be in drivers/gpu/Kconfig. >>> >>> Fair point, I believe I was having trouble compiling this into the kernel crate >>> without warnings (I believe if !GPU_BUDDY). I'll try to drop it and see if we >>> can get rid of it. >> >> If you run into dead code warnings, I think it is fine to just >> >> #[allow(dead_code, reason = "all users might be cfg-ed out")] >> >> the overhead of just let rustc type-checking this module isn't worth the extra >> Kconfig plumbing, I think. > > You mean because there are pub(crate) in clist.rs? I don't think the Kconfig > would help with that, nothing prevents people from enabling RUST_CLIST, but none > of the users. I think he means add the alloc annotation to suppress deadcode warnings and get rid of the Kconfig? > Besides that, once we have the new build system, the users of CList are likely > in other crates anyways, so I think we should just change things to pub. I agree with both approaches. Perhaps changing to pub is better to avoid churn in the future when other crates use it. -- Joel Fernandes ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH -next v7 1/2] rust: clist: Add support to interface with C linked lists 2026-02-06 15:25 ` Gary Guo 2026-02-06 15:53 ` Danilo Krummrich @ 2026-02-09 19:41 ` Joel Fernandes 1 sibling, 0 replies; 23+ messages in thread From: Joel Fernandes @ 2026-02-09 19:41 UTC (permalink / raw) To: Gary Guo, linux-kernel Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Danilo Krummrich, Alice Ryhl, Miguel Ojeda, Alex Gaynor, Boqun Feng, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Trevor Gross, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, Daniel Almeida, joel, nouveau, dri-devel, rust-for-linux, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev On 2/6/2026 10:25 AM, Gary Guo wrote: > On Fri Feb 6, 2026 at 12:41 AM GMT, Joel Fernandes wrote: >> Add a new module `clist` 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. >> >> Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com> >> --- >> MAINTAINERS | 7 + >> drivers/gpu/Kconfig | 7 + >> rust/helpers/helpers.c | 1 + >> rust/helpers/list.c | 21 +++ >> rust/kernel/clist.rs | 315 +++++++++++++++++++++++++++++++++++++++++ >> rust/kernel/lib.rs | 2 + >> 6 files changed, 353 insertions(+) >> create mode 100644 rust/helpers/list.c >> create mode 100644 rust/kernel/clist.rs >> >> diff --git a/MAINTAINERS b/MAINTAINERS >> index 900fc00b73e6..310bb479260c 100644 >> --- a/MAINTAINERS >> +++ b/MAINTAINERS >> @@ -23204,6 +23204,13 @@ S: Maintained >> T: git https://github.com/Rust-for-Linux/linux.git rust-analyzer-next >> F: scripts/generate_rust_analyzer.py >> >> +RUST TO C LIST INTERFACES >> +M: Joel Fernandes <joelagnelf@nvidia.com> >> +M: Alexandre Courbot <acourbot@nvidia.com> >> +L: rust-for-linux@vger.kernel.org >> +S: Maintained >> +F: rust/kernel/clist.rs > > I still think we should try to work on a more powerful list infra that works for > both C and Rust, but I reckon that is a longer term effort, and shouldn't > prevent a simpler version from getting in and be used by abstractions that need > it. So > > Acked-by: Gary Guo <gary@garyguo.net> Thanks! I also replied below. > > Some nits below: > >> + >> RXRPC SOCKETS (AF_RXRPC) >> M: David Howells <dhowells@redhat.com> >> M: Marc Dionne <marc.dionne@auristor.com> >> diff --git a/drivers/gpu/Kconfig b/drivers/gpu/Kconfig >> index 22dd29cd50b5..2c3dec070645 100644 >> --- a/drivers/gpu/Kconfig >> +++ b/drivers/gpu/Kconfig >> @@ -1,7 +1,14 @@ >> # SPDX-License-Identifier: GPL-2.0 >> >> +config RUST_CLIST >> + bool >> + depends on RUST >> + help >> + Rust abstraction for interfacing with C linked lists. > > I am not sure if we need extra config entry. This is fully generic so shouldn't > generate any code unless there is an user. Yes, I am dropping it now. As per the other discussions, I will change the module level and all the items in the module to pub. And then we will not need this config. > >> + >> config GPU_BUDDY >> bool >> + select RUST_CLIST if RUST >> help >> A page based buddy allocator for GPU memory. >> >> diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c >> index a3c42e51f00a..724fcb8240ac 100644 >> --- a/rust/helpers/helpers.c >> +++ b/rust/helpers/helpers.c >> @@ -35,6 +35,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..3390b154fa36 >> --- /dev/null >> +++ b/rust/helpers/list.c >> @@ -0,0 +1,21 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> + >> +/* >> + * Helpers for C Circular doubly linked list implementation. >> + */ >> + >> +#include <linux/list.h> >> + >> +#ifndef __rust_helper >> +#define __rust_helper >> +#endif > > This shouldn't be needed. I had to add this because a patch was missing in the DRM tree it depended on. I believe I should not need it anymore, so I will drop it. Thank you for pointing that out. >> + >> +__rust_helper void rust_helper_INIT_LIST_HEAD(struct list_head *list) >> +{ >> + INIT_LIST_HEAD(list); >> +} >> + >> +__rust_helper void rust_helper_list_add_tail(struct list_head *new, struct list_head *head) >> +{ >> + list_add_tail(new, head); >> +} >> diff --git a/rust/kernel/clist.rs b/rust/kernel/clist.rs >> new file mode 100644 >> index 000000000000..1f6d4db13c1d >> --- /dev/null >> +++ b/rust/kernel/clist.rs >> @@ -0,0 +1,315 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> + >> +//! A C doubly circular intrusive linked list interface for rust code. >> +//! >> +//! # Examples >> +//! >> +//! ``` >> +//! use kernel::{ >> +//! bindings, >> +//! clist_create, >> +//! 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(); >> +//! # >> +//! # let head = head.as_mut_ptr(); >> +//! # // SAFETY: head and all the items are test objects allocated in this scope. >> +//! # unsafe { bindings::INIT_LIST_HEAD(head) }; >> +//! # >> +//! # 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; >> +//! # // addr_of_mut!() computes address of link directly as link is uninitialized. >> +//! # bindings::INIT_LIST_HEAD(core::ptr::addr_of_mut!((*ptr).link)); >> +//! # bindings::list_add_tail(&mut (*ptr).link, 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>); >> +//! >> +//! impl Item { >> +//! pub(crate) fn value(&self) -> i32 { >> +//! // SAFETY: [`Item`] has same layout as [`SampleItemC`]. >> +//! unsafe { (*self.0.get()).value } >> +//! } >> +//! } >> +//! >> +//! // Create typed [`CList`] from sentinel head. >> +//! // SAFETY: head is valid, items are [`SampleItemC`] with embedded `link` field. >> +//! let list = unsafe { clist_create!(head, Item, SampleItemC, link) }; >> +//! >> +//! // Iterate directly over typed items. >> +//! let mut found_0 = false; >> +//! let mut found_10 = false; >> +//! let mut found_20 = false; >> +//! >> +//! for item in list.iter() { >> +//! 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 core::{ >> + iter::FusedIterator, >> + marker::PhantomData, // >> +}; >> + >> +use crate::{ >> + bindings, >> + types::Opaque, // >> +}; >> + >> +use pin_init::PinInit; >> + >> +/// Wraps a `list_head` object for use in intrusive linked lists. >> +/// >> +/// # Invariants >> +/// >> +/// - [`CListHead`] represents an allocated and valid `list_head` structure. >> +/// - Once a [`CListHead`] is created in Rust, it will not be modified by non-Rust code. >> +/// - All `list_head` for individual items are not modified for the lifetime of [`CListHead`]. >> +#[repr(transparent)] >> +pub(crate) struct CListHead(Opaque<bindings::list_head>); >> + >> +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. >> + /// - `ptr` must remain valid and unmodified for the lifetime `'a`. >> + #[inline] >> + pub(crate) unsafe fn from_raw<'a>(ptr: *mut bindings::list_head) -> &'a Self { >> + // SAFETY: >> + // - [`CListHead`] has same layout as `list_head`. >> + // - `ptr` is valid and unmodified for 'a. >> + unsafe { &*ptr.cast() } >> + } >> + >> + /// Get the raw `list_head` pointer. >> + #[inline] >> + pub(crate) fn as_raw(&self) -> *mut bindings::list_head { >> + self.0.get() >> + } >> + >> + /// Get the next [`CListHead`] in the list. >> + #[inline] >> + pub(crate) fn next(&self) -> &Self { >> + let raw = self.as_raw(); >> + // SAFETY: >> + // - `self.as_raw()` is valid per type invariants. >> + // - The `next` pointer is guaranteed to be non-NULL. >> + unsafe { Self::from_raw((*raw).next) } >> + } >> + >> + /// Check if this node is linked in a list (not isolated). >> + #[inline] >> + pub(crate) fn is_linked(&self) -> bool { >> + let raw = self.as_raw(); >> + // SAFETY: self.as_raw() is valid per type invariants. >> + unsafe { (*raw).next != raw && (*raw).prev != raw } >> + } >> + >> + /// Pin-initializer that initializes the list head. >> + pub(crate) fn new() -> impl PinInit<Self> { >> + // SAFETY: `INIT_LIST_HEAD` initializes `slot` to a valid empty list. >> + unsafe { >> + pin_init::pin_init_from_closure(move |slot: *mut Self| { > > pin_init::ffi_init should be used for this. > Will do, thanks. >> + bindings::INIT_LIST_HEAD(slot.cast()); >> + Ok(()) >> + }) >> + } >> + } >> +} >> + >> +// 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 non-Rust code per type invariants. >> +unsafe impl Sync for CListHead {} >> + >> +impl PartialEq for CListHead { > > #[inline] Will do. Thanks, -- Joel Fernandes ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH -next v7 1/2] rust: clist: Add support to interface with C linked lists 2026-02-06 0:41 ` [PATCH -next v7 1/2] rust: clist: Add support to interface with C linked lists Joel Fernandes 2026-02-06 15:25 ` Gary Guo @ 2026-02-06 17:49 ` Daniel Almeida 2026-02-06 20:46 ` Joel Fernandes 2026-02-06 20:51 ` Joel Fernandes 1 sibling, 2 replies; 23+ messages in thread From: Daniel Almeida @ 2026-02-06 17:49 UTC (permalink / raw) To: Joel Fernandes Cc: linux-kernel, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Danilo Krummrich, Alice Ryhl, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Trevor Gross, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, joel, nouveau, dri-devel, rust-for-linux, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev Hi Joel, > On 5 Feb 2026, at 21:41, Joel Fernandes <joelagnelf@nvidia.com> wrote: > > Add a new module `clist` 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. > > Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com> > --- > MAINTAINERS | 7 + > drivers/gpu/Kconfig | 7 + > rust/helpers/helpers.c | 1 + > rust/helpers/list.c | 21 +++ > rust/kernel/clist.rs | 315 +++++++++++++++++++++++++++++++++++++++++ > rust/kernel/lib.rs | 2 + > 6 files changed, 353 insertions(+) > create mode 100644 rust/helpers/list.c > create mode 100644 rust/kernel/clist.rs > > diff --git a/MAINTAINERS b/MAINTAINERS > index 900fc00b73e6..310bb479260c 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -23204,6 +23204,13 @@ S: Maintained > T: git https://github.com/Rust-for-Linux/linux.git rust-analyzer-next > F: scripts/generate_rust_analyzer.py > > +RUST TO C LIST INTERFACES > +M: Joel Fernandes <joelagnelf@nvidia.com> > +M: Alexandre Courbot <acourbot@nvidia.com> > +L: rust-for-linux@vger.kernel.org > +S: Maintained > +F: rust/kernel/clist.rs > + > RXRPC SOCKETS (AF_RXRPC) > M: David Howells <dhowells@redhat.com> > M: Marc Dionne <marc.dionne@auristor.com> > diff --git a/drivers/gpu/Kconfig b/drivers/gpu/Kconfig > index 22dd29cd50b5..2c3dec070645 100644 > --- a/drivers/gpu/Kconfig > +++ b/drivers/gpu/Kconfig > @@ -1,7 +1,14 @@ > # SPDX-License-Identifier: GPL-2.0 > > +config RUST_CLIST > + bool > + depends on RUST > + help > + Rust abstraction for interfacing with C linked lists. > + > config GPU_BUDDY > bool > + select RUST_CLIST if RUST > help > A page based buddy allocator for GPU memory. > > diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c > index a3c42e51f00a..724fcb8240ac 100644 > --- a/rust/helpers/helpers.c > +++ b/rust/helpers/helpers.c > @@ -35,6 +35,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..3390b154fa36 > --- /dev/null > +++ b/rust/helpers/list.c > @@ -0,0 +1,21 @@ > +// SPDX-License-Identifier: GPL-2.0 > + > +/* > + * Helpers for C Circular doubly linked list implementation. > + */ > + > +#include <linux/list.h> > + > +#ifndef __rust_helper > +#define __rust_helper > +#endif > + > +__rust_helper void rust_helper_INIT_LIST_HEAD(struct list_head *list) > +{ > + INIT_LIST_HEAD(list); > +} > + > +__rust_helper void rust_helper_list_add_tail(struct list_head *new, struct list_head *head) > +{ > + list_add_tail(new, head); > +} > diff --git a/rust/kernel/clist.rs b/rust/kernel/clist.rs > new file mode 100644 > index 000000000000..1f6d4db13c1d > --- /dev/null > +++ b/rust/kernel/clist.rs > @@ -0,0 +1,315 @@ > +// SPDX-License-Identifier: GPL-2.0 > + > +//! A C doubly circular intrusive linked list interface for rust code. > +//! > +//! # Examples > +//! > +//! ``` > +//! use kernel::{ > +//! bindings, > +//! clist_create, > +//! 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(); > +//! # > +//! # let head = head.as_mut_ptr(); > +//! # // SAFETY: head and all the items are test objects allocated in this scope. > +//! # unsafe { bindings::INIT_LIST_HEAD(head) }; > +//! # > +//! # 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; > +//! # // addr_of_mut!() computes address of link directly as link is uninitialized. > +//! # bindings::INIT_LIST_HEAD(core::ptr::addr_of_mut!((*ptr).link)); Shoudn’t this be &raw mut? > +//! # bindings::list_add_tail(&mut (*ptr).link, 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>); > +//! > +//! impl Item { > +//! pub(crate) fn value(&self) -> i32 { > +//! // SAFETY: [`Item`] has same layout as [`SampleItemC`]. > +//! unsafe { (*self.0.get()).value } > +//! } > +//! } > +//! > +//! // Create typed [`CList`] from sentinel head. > +//! // SAFETY: head is valid, items are [`SampleItemC`] with embedded `link` field. > +//! let list = unsafe { clist_create!(head, Item, SampleItemC, link) }; > +//! > +//! // Iterate directly over typed items. > +//! let mut found_0 = false; > +//! let mut found_10 = false; > +//! let mut found_20 = false; > +//! > +//! for item in list.iter() { > +//! 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 core::{ > + iter::FusedIterator, > + marker::PhantomData, // > +}; > + > +use crate::{ > + bindings, > + types::Opaque, // > +}; > + > +use pin_init::PinInit; > + > +/// Wraps a `list_head` object for use in intrusive linked lists. > +/// > +/// # Invariants > +/// > +/// - [`CListHead`] represents an allocated and valid `list_head` structure. > +/// - Once a [`CListHead`] is created in Rust, it will not be modified by non-Rust code. > +/// - All `list_head` for individual items are not modified for the lifetime of [`CListHead`]. Can you expand on the two points above? > +#[repr(transparent)] > +pub(crate) struct CListHead(Opaque<bindings::list_head>); > + > +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. > + /// - `ptr` must remain valid and unmodified for the lifetime `'a`. > + #[inline] > + pub(crate) unsafe fn from_raw<'a>(ptr: *mut bindings::list_head) -> &'a Self { > + // SAFETY: > + // - [`CListHead`] has same layout as `list_head`. > + // - `ptr` is valid and unmodified for 'a. > + unsafe { &*ptr.cast() } > + } > + > + /// Get the raw `list_head` pointer. > + #[inline] > + pub(crate) fn as_raw(&self) -> *mut bindings::list_head { > + self.0.get() > + } > + > + /// Get the next [`CListHead`] in the list. > + #[inline] > + pub(crate) fn next(&self) -> &Self { > + let raw = self.as_raw(); > + // SAFETY: > + // - `self.as_raw()` is valid per type invariants. > + // - The `next` pointer is guaranteed to be non-NULL. > + unsafe { Self::from_raw((*raw).next) } > + } > + > + /// Check if this node is linked in a list (not isolated). > + #[inline] > + pub(crate) fn is_linked(&self) -> bool { > + let raw = self.as_raw(); > + // SAFETY: self.as_raw() is valid per type invariants. > + unsafe { (*raw).next != raw && (*raw).prev != raw } I wonder if this is duplicating some C helper? > + } > + > + /// Pin-initializer that initializes the list head. > + pub(crate) fn new() -> impl PinInit<Self> { > + // SAFETY: `INIT_LIST_HEAD` initializes `slot` to a valid empty list. > + unsafe { > + pin_init::pin_init_from_closure(move |slot: *mut Self| { > + bindings::INIT_LIST_HEAD(slot.cast()); > + Ok(()) > + }) > + } > + } > +} > + > +// 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 non-Rust code per type invariants. > +unsafe impl Sync for CListHead {} > + > +impl PartialEq for CListHead { > + fn eq(&self, other: &Self) -> bool { > + core::ptr::eq(self, other) > + } > +} > + > +impl Eq for CListHead {} > + > +/// 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 (using `container_of` macro or similar). > +/// > +/// # Invariants > +/// > +/// [`CListHeadIter`] is iterating over an allocated, initialized and valid list. > +struct CListHeadIter<'a> { > + /// Current position in the list. > + current: &'a CListHead, > + /// The sentinel head (used to detect end of iteration). > + sentinel: &'a CListHead, > +} > + > +impl<'a> Iterator for CListHeadIter<'a> { > + type Item = &'a CListHead; > + > + #[inline] > + fn next(&mut self) -> Option<Self::Item> { > + // Check if we've reached the sentinel (end of list). > + if core::ptr::eq(self.current, self.sentinel) { > + return None; > + } I was under the impression that CListHeads implemented PartialEq/Eq? > + > + let item = self.current; > + self.current = item.next(); > + Some(item) > + } > +} > + > +impl<'a> FusedIterator for CListHeadIter<'a> {} > + > +/// A typed C linked list with a sentinel head. > +/// > +/// A sentinel head represents the entire linked list and can be used for > +/// iteration over items of type `T`, it is not associated with a specific item. > +/// > +/// The const generic `OFFSET` specifies the byte offset of the `list_head` field within > +/// the struct that `T` wraps. > +/// > +/// # Invariants > +/// > +/// - The [`CListHead`] is an allocated and valid sentinel C `list_head` structure. > +/// - `OFFSET` is the byte offset of the `list_head` field within the struct that `T` wraps. > +/// - All the list's `list_head` nodes are allocated and have valid next/prev pointers. > +#[repr(transparent)] > +pub(crate) struct CList<T, const OFFSET: usize>(CListHead, PhantomData<T>); > + > +impl<T, const OFFSET: usize> CList<T, OFFSET> { > + /// Create a typed [`CList`] reference 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. > + /// - `ptr` must remain valid and unmodified for the lifetime `'a`. > + /// - The list must contain items where the `list_head` field is at byte offset `OFFSET`. > + /// - `T` must be `#[repr(transparent)]` over the C struct. > + #[inline] > + pub(crate) unsafe fn from_raw<'a>(ptr: *mut bindings::list_head) -> &'a Self { > + // SAFETY: > + // - [`CList`] has same layout as [`CListHead`] due to repr(transparent). > + // - Caller guarantees `ptr` is a valid, sentinel `list_head` object. > + unsafe { &*ptr.cast() } > + } > + > + /// Check if the list is empty. > + #[inline] > + #[expect(dead_code)] > + pub(crate) fn is_empty(&self) -> bool { Why can’t this be pub? > + !self.0.is_linked() > + } > + > + /// Create an iterator over typed items. > + #[inline] > + pub(crate) fn iter(&self) -> CListIter<'_, T, OFFSET> { > + let head = &self.0; > + CListIter { > + head_iter: CListHeadIter { > + current: head.next(), > + sentinel: head, > + }, > + _phantom: PhantomData, > + } > + } > +} > + > +/// High-level iterator over typed list items. > +pub(crate) struct CListIter<'a, T, const OFFSET: usize> { > + head_iter: CListHeadIter<'a>, > + _phantom: PhantomData<&'a T>, > +} > + > +impl<'a, T, const OFFSET: usize> Iterator for CListIter<'a, T, OFFSET> { > + type Item = &'a T; > + > + fn next(&mut self) -> Option<Self::Item> { > + let head = self.head_iter.next()?; > + > + // Convert to item using OFFSET. > + // SAFETY: `item_ptr` calculation from `OFFSET` (calculated using offset_of!) > + // is valid per invariants. > + Some(unsafe { &*head.as_raw().byte_sub(OFFSET).cast::<T>() }) > + } > +} > + > +impl<'a, T, const OFFSET: usize> FusedIterator for CListIter<'a, T, OFFSET> {} > + > +/// 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 > +/// > +/// This is an unsafe macro. The caller must ensure: > +/// > +/// - `$head` is a valid, initialized sentinel `list_head` pointing to a list that remains > +/// unmodified for the lifetime of the rust `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 this module's documentation. > +#[macro_export] > +macro_rules! clist_create { > + ($head:expr, $rust_type:ty, $c_type:ty, $($field:tt).+) => {{ > + // Compile-time check that field path is a list_head. > + let _: fn(*const $c_type) -> *const $crate::bindings::list_head = > + |p| &raw const (*p).$($field).+; > + > + // Calculate offset and create `CList`. > + const OFFSET: usize = ::core::mem::offset_of!($c_type, $($field).+); > + $crate::clist::CList::<$rust_type, OFFSET>::from_raw($head) > + }}; > +} > diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs > index 3da92f18f4ee..8439c30f40b5 100644 > --- a/rust/kernel/lib.rs > +++ b/rust/kernel/lib.rs > @@ -75,6 +75,8 @@ > pub mod bug; > #[doc(hidden)] > pub mod build_assert; > +#[cfg(CONFIG_RUST_CLIST)] > +pub(crate) mod clist; > pub mod clk; > #[cfg(CONFIG_CONFIGFS_FS)] > pub mod configfs; > -- > 2.34.1 > > ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH -next v7 1/2] rust: clist: Add support to interface with C linked lists 2026-02-06 17:49 ` Daniel Almeida @ 2026-02-06 20:46 ` Joel Fernandes 2026-02-06 20:51 ` Gary Guo 2026-02-06 20:51 ` Joel Fernandes 1 sibling, 1 reply; 23+ messages in thread From: Joel Fernandes @ 2026-02-06 20:46 UTC (permalink / raw) To: Daniel Almeida Cc: linux-kernel, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Danilo Krummrich, Alice Ryhl, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Trevor Gross, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, joel, nouveau, dri-devel, rust-for-linux, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev On 2/6/2026 12:49 PM, Daniel Almeida wrote: >> +#[repr(transparent)] >> +pub(crate) struct CList<T, const OFFSET: usize>(CListHead, PhantomData<T>); >> + >> +impl<T, const OFFSET: usize> CList<T, OFFSET> { >> + /// Create a typed [`CList`] reference 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. >> + /// - `ptr` must remain valid and unmodified for the lifetime `'a`. >> + /// - The list must contain items where the `list_head` field is at byte offset `OFFSET`. >> + /// - `T` must be `#[repr(transparent)]` over the C struct. >> + #[inline] >> + pub(crate) unsafe fn from_raw<'a>(ptr: *mut bindings::list_head) -> &'a Self { >> + // SAFETY: >> + // - [`CList`] has same layout as [`CListHead`] due to repr(transparent). >> + // - Caller guarantees `ptr` is a valid, sentinel `list_head` object. >> + unsafe { &*ptr.cast() } >> + } >> + >> + /// Check if the list is empty. >> + #[inline] >> + #[expect(dead_code)] >> + pub(crate) fn is_empty(&self) -> bool { > > Why can’t this be pub? I believe this was suggested by Gary. See the other thread where we are discussing it (with Gary and Danilo) and let us discuss there. -- Joel Fernandes ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH -next v7 1/2] rust: clist: Add support to interface with C linked lists 2026-02-06 20:46 ` Joel Fernandes @ 2026-02-06 20:51 ` Gary Guo 2026-02-06 21:12 ` Joel Fernandes 0 siblings, 1 reply; 23+ messages in thread From: Gary Guo @ 2026-02-06 20:51 UTC (permalink / raw) To: Joel Fernandes, Daniel Almeida Cc: linux-kernel, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Danilo Krummrich, Alice Ryhl, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Trevor Gross, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, joel, nouveau, dri-devel, rust-for-linux, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev On Fri Feb 6, 2026 at 8:46 PM GMT, Joel Fernandes wrote: > On 2/6/2026 12:49 PM, Daniel Almeida wrote: >>> +#[repr(transparent)] >>> +pub(crate) struct CList<T, const OFFSET: usize>(CListHead, PhantomData<T>); >>> + >>> +impl<T, const OFFSET: usize> CList<T, OFFSET> { >>> + /// Create a typed [`CList`] reference 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. >>> + /// - `ptr` must remain valid and unmodified for the lifetime `'a`. >>> + /// - The list must contain items where the `list_head` field is at byte offset `OFFSET`. >>> + /// - `T` must be `#[repr(transparent)]` over the C struct. >>> + #[inline] >>> + pub(crate) unsafe fn from_raw<'a>(ptr: *mut bindings::list_head) -> &'a Self { >>> + // SAFETY: >>> + // - [`CList`] has same layout as [`CListHead`] due to repr(transparent). >>> + // - Caller guarantees `ptr` is a valid, sentinel `list_head` object. >>> + unsafe { &*ptr.cast() } >>> + } >>> + >>> + /// Check if the list is empty. >>> + #[inline] >>> + #[expect(dead_code)] >>> + pub(crate) fn is_empty(&self) -> bool { >> >> Why can’t this be pub? > > I believe this was suggested by Gary. See the other thread where we are > discussing it (with Gary and Danilo) and let us discuss there. I suggested the module to be `pub(crate)`. For the individual item it is not necessary if the module itself already have limited visibility. Best, Gary ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH -next v7 1/2] rust: clist: Add support to interface with C linked lists 2026-02-06 20:51 ` Gary Guo @ 2026-02-06 21:12 ` Joel Fernandes 0 siblings, 0 replies; 23+ messages in thread From: Joel Fernandes @ 2026-02-06 21:12 UTC (permalink / raw) To: Gary Guo, Daniel Almeida Cc: linux-kernel, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Danilo Krummrich, Alice Ryhl, Miguel Ojeda, Alex Gaynor, Boqun Feng, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Trevor Gross, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, joel, nouveau, dri-devel, rust-for-linux, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev On 2/6/2026 3:51 PM, Gary Guo wrote: > On Fri Feb 6, 2026 at 8:46 PM GMT, Joel Fernandes wrote: >> On 2/6/2026 12:49 PM, Daniel Almeida wrote: >>>> +#[repr(transparent)] >>>> +pub(crate) struct CList<T, const OFFSET: usize>(CListHead, PhantomData<T>); >>>> + >>>> +impl<T, const OFFSET: usize> CList<T, OFFSET> { >>>> + /// Create a typed [`CList`] reference 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. >>>> + /// - `ptr` must remain valid and unmodified for the lifetime `'a`. >>>> + /// - The list must contain items where the `list_head` field is at byte offset `OFFSET`. >>>> + /// - `T` must be `#[repr(transparent)]` over the C struct. >>>> + #[inline] >>>> + pub(crate) unsafe fn from_raw<'a>(ptr: *mut bindings::list_head) -> &'a Self { >>>> + // SAFETY: >>>> + // - [`CList`] has same layout as [`CListHead`] due to repr(transparent). >>>> + // - Caller guarantees `ptr` is a valid, sentinel `list_head` object. >>>> + unsafe { &*ptr.cast() } >>>> + } >>>> + >>>> + /// Check if the list is empty. >>>> + #[inline] >>>> + #[expect(dead_code)] >>>> + pub(crate) fn is_empty(&self) -> bool { >>> >>> Why can’t this be pub? >> >> I believe this was suggested by Gary. See the other thread where we are >> discussing it (with Gary and Danilo) and let us discuss there. > > I suggested the module to be `pub(crate)`. For the individual item it is not > necessary if the module itself already have limited visibility. > Sure, I can change it to module-level pub then, and drop the pub(crate) if everyone agrees. -- Joel Fernandes ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH -next v7 1/2] rust: clist: Add support to interface with C linked lists 2026-02-06 17:49 ` Daniel Almeida 2026-02-06 20:46 ` Joel Fernandes @ 2026-02-06 20:51 ` Joel Fernandes 2026-02-06 21:21 ` Daniel Almeida 1 sibling, 1 reply; 23+ messages in thread From: Joel Fernandes @ 2026-02-06 20:51 UTC (permalink / raw) To: Daniel Almeida Cc: linux-kernel, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Danilo Krummrich, Alice Ryhl, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Trevor Gross, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, joel, nouveau, dri-devel, rust-for-linux, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev Hi Daniel, Hope you do not mind me replying piecemeal as I can reply more quickly. Thank you for all the comments. On 2/6/2026 12:49 PM, Daniel Almeida wrote: >> +use crate::{ >> + bindings, >> + types::Opaque, // >> +}; >> + >> +use pin_init::PinInit; >> + >> +/// Wraps a `list_head` object for use in intrusive linked lists. >> +/// >> +/// # Invariants >> +/// >> +/// - [`CListHead`] represents an allocated and valid `list_head` structure. >> +/// - Once a [`CListHead`] is created in Rust, it will not be modified by non-Rust code. >> +/// - All `list_head` for individual items are not modified for the lifetime of [`CListHead`]. > > Can you expand on the two points above? This is basically saying that a C `list_head` that is wrapped by a `CListHead` is read-only for the lifetime of `ClistHead`. modifying the pointers anymore. That is the invariant. Or did I miss something? -- Joel Fernandes ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH -next v7 1/2] rust: clist: Add support to interface with C linked lists 2026-02-06 20:51 ` Joel Fernandes @ 2026-02-06 21:21 ` Daniel Almeida 2026-02-06 21:26 ` Joel Fernandes 0 siblings, 1 reply; 23+ messages in thread From: Daniel Almeida @ 2026-02-06 21:21 UTC (permalink / raw) To: Joel Fernandes Cc: linux-kernel, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Danilo Krummrich, Alice Ryhl, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Trevor Gross, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, joel, nouveau, dri-devel, rust-for-linux, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev > On 6 Feb 2026, at 17:51, Joel Fernandes <joelagnelf@nvidia.com> wrote: > > Hi Daniel, > Hope you do not mind me replying piecemeal as I can reply more quickly. Thank > you for all the comments. > > On 2/6/2026 12:49 PM, Daniel Almeida wrote: >>> +use crate::{ >>> + bindings, >>> + types::Opaque, // >>> +}; >>> + >>> +use pin_init::PinInit; >>> + >>> +/// Wraps a `list_head` object for use in intrusive linked lists. >>> +/// >>> +/// # Invariants >>> +/// >>> +/// - [`CListHead`] represents an allocated and valid `list_head` structure. >>> +/// - Once a [`CListHead`] is created in Rust, it will not be modified by non-Rust code. >>> +/// - All `list_head` for individual items are not modified for the lifetime of [`CListHead`]. >> >> Can you expand on the two points above? > > This is basically saying that a C `list_head` that is wrapped by a `CListHead` > is read-only for the lifetime of `ClistHead`. modifying the pointers anymore. > That is the invariant. > > Or did I miss something? > > -- > Joel Fernandes > > Yeah, but my point being: is there a reason why the underlying list has to remain read-only? Is this a safety requirement or an invariant that is established by the code above? — Daniel ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH -next v7 1/2] rust: clist: Add support to interface with C linked lists 2026-02-06 21:21 ` Daniel Almeida @ 2026-02-06 21:26 ` Joel Fernandes 2026-02-06 22:33 ` Daniel Almeida 0 siblings, 1 reply; 23+ messages in thread From: Joel Fernandes @ 2026-02-06 21:26 UTC (permalink / raw) To: Daniel Almeida Cc: linux-kernel, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Danilo Krummrich, Alice Ryhl, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Trevor Gross, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, joel, nouveau, dri-devel, rust-for-linux, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev On 2/6/2026 4:21 PM, Daniel Almeida wrote: > > >> On 6 Feb 2026, at 17:51, Joel Fernandes <joelagnelf@nvidia.com> wrote: >> >> Hi Daniel, >> Hope you do not mind me replying piecemeal as I can reply more quickly. Thank >> you for all the comments. >> >> On 2/6/2026 12:49 PM, Daniel Almeida wrote: >>>> +use crate::{ >>>> + bindings, >>>> + types::Opaque, // >>>> +}; >>>> + >>>> +use pin_init::PinInit; >>>> + >>>> +/// Wraps a `list_head` object for use in intrusive linked lists. >>>> +/// >>>> +/// # Invariants >>>> +/// >>>> +/// - [`CListHead`] represents an allocated and valid `list_head` structure. >>>> +/// - Once a [`CListHead`] is created in Rust, it will not be modified by non-Rust code. >>>> +/// - All `list_head` for individual items are not modified for the lifetime of [`CListHead`]. >>> >>> Can you expand on the two points above? >> >> This is basically saying that a C `list_head` that is wrapped by a `CListHead` >> is read-only for the lifetime of `ClistHead`. modifying the pointers anymore. >> That is the invariant. >> >> Or did I miss something? >> >> -- >> Joel Fernandes >> >> > > > Yeah, but my point being: is there a reason why the underlying list has to > remain read-only? Is this a safety requirement or an invariant that is established > by the code above? I'm not fully sure if it's an invariant or a safety requirement, but anyone creating a C list head on the rust side must guarantee that it is not modified. Since rust has no visibility on the C side, I believe it is a Rust invariant here that the existence of CListHead assumes that the list cannot be modified once Rust has access over it. That is up to the creator (user) of the CListHead to guarantee. In the DRM buddy case, once the list is allocated and accessible from Rust, C code will not modify it while the Rust object exists. Does that make sense, or is there a better way to document this? -- Joel Fernandes ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH -next v7 1/2] rust: clist: Add support to interface with C linked lists 2026-02-06 21:26 ` Joel Fernandes @ 2026-02-06 22:33 ` Daniel Almeida 2026-02-09 17:02 ` Joel Fernandes 0 siblings, 1 reply; 23+ messages in thread From: Daniel Almeida @ 2026-02-06 22:33 UTC (permalink / raw) To: Joel Fernandes Cc: linux-kernel, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Danilo Krummrich, Alice Ryhl, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Trevor Gross, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, joel, nouveau, dri-devel, rust-for-linux, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev >> >> >> Yeah, but my point being: is there a reason why the underlying list has to >> remain read-only? Is this a safety requirement or an invariant that is established >> by the code above? > I'm not fully sure if it's an invariant or a safety requirement, but anyone > creating a C list head on the rust side must guarantee that it is not modified. > Since rust has no visibility on the C side, I believe it is a Rust invariant > here that the existence of CListHead assumes that the list cannot be modified > once Rust has access over it. That is up to the creator (user) of the CListHead > to guarantee. In the DRM buddy case, once the list is allocated and accessible > from Rust, C code will not modify it while the Rust object exists. > > Does that make sense, or is there a better way to document this? > > -- > Joel Fernandes In which case, I recommend moving this to a safety requirement when creating the list. I assume the purpose of not modifying the list on the C side is to avoid corrupting the list in Rust somehow? — Daniel ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH -next v7 1/2] rust: clist: Add support to interface with C linked lists 2026-02-06 22:33 ` Daniel Almeida @ 2026-02-09 17:02 ` Joel Fernandes 0 siblings, 0 replies; 23+ messages in thread From: Joel Fernandes @ 2026-02-09 17:02 UTC (permalink / raw) To: Daniel Almeida Cc: linux-kernel, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Danilo Krummrich, Alice Ryhl, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Trevor Gross, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, joel, nouveau, dri-devel, rust-for-linux, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev On 2/6/2026 5:33 PM, Daniel Almeida wrote: >>> >>> >>> Yeah, but my point being: is there a reason why the underlying list has to >>> remain read-only? Is this a safety requirement or an invariant that is established >>> by the code above? >> I'm not fully sure if it's an invariant or a safety requirement, but anyone >> creating a C list head on the rust side must guarantee that it is not modified. >> Since rust has no visibility on the C side, I believe it is a Rust invariant >> here that the existence of CListHead assumes that the list cannot be modified >> once Rust has access over it. That is up to the creator (user) of the CListHead >> to guarantee. In the DRM buddy case, once the list is allocated and accessible >> from Rust, C code will not modify it while the Rust object exists. >> >> Does that make sense, or is there a better way to document this? >> >> -- >> Joel Fernandes > > > In which case, I recommend moving this to a safety requirement when > creating the list. Ok, will do. > I assume the purpose of not modifying the list on the C side is to avoid > corrupting the list in Rust somehow? Yes. Thanks, -- Joel Fernandes ^ permalink raw reply [flat|nested] 23+ messages in thread
* [PATCH -next v7 2/2] rust: gpu: Add GPU buddy allocator bindings 2026-02-06 0:41 [PATCH -next v7 0/2] rust: Add CList and GPU buddy allocator bindings Joel Fernandes 2026-02-06 0:41 ` [PATCH -next v7 1/2] rust: clist: Add support to interface with C linked lists Joel Fernandes @ 2026-02-06 0:41 ` Joel Fernandes 1 sibling, 0 replies; 23+ messages in thread From: Joel Fernandes @ 2026-02-06 0:41 UTC (permalink / raw) To: linux-kernel Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie, Simona Vetter, Jonathan Corbet, Alex Deucher, Christian König, Jani Nikula, Joonas Lahtinen, Rodrigo Vivi, Tvrtko Ursulin, Huang Rui, Matthew Auld, Matthew Brost, Lucas De Marchi, Thomas Hellström, Helge Deller, Danilo Krummrich, Alice Ryhl, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin, Andreas Hindborg, Trevor Gross, John Hubbard, Alistair Popple, Timur Tabi, Edwin Peer, Alexandre Courbot, Andrea Righi, Andy Ritger, Zhi Wang, Balbir Singh, Philipp Stanner, Elle Rhumsaa, Daniel Almeida, joel, nouveau, dri-devel, rust-for-linux, linux-doc, amd-gfx, intel-gfx, intel-xe, linux-fbdev, Joel Fernandes Add safe Rust abstractions over the Linux kernel's GPU buddy allocator for physical memory management. The GPU buddy allocator implements a binary buddy system useful for GPU physical memory allocation. nova-core will use it for physical memory allocation. Signed-off-by: Joel Fernandes <joelagnelf@nvidia.com> --- rust/bindings/bindings_helper.h | 11 + rust/helpers/gpu.c | 23 ++ rust/helpers/helpers.c | 1 + rust/kernel/gpu/buddy.rs | 530 ++++++++++++++++++++++++++++++++ rust/kernel/gpu/mod.rs | 5 + rust/kernel/lib.rs | 2 + 6 files changed, 572 insertions(+) create mode 100644 rust/helpers/gpu.c create mode 100644 rust/kernel/gpu/buddy.rs create mode 100644 rust/kernel/gpu/mod.rs diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h index 083cc44aa952..dbb765a9fdbd 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -29,6 +29,7 @@ #include <linux/hrtimer_types.h> #include <linux/acpi.h> +#include <linux/gpu_buddy.h> #include <drm/drm_device.h> #include <drm/drm_drv.h> #include <drm/drm_file.h> @@ -146,6 +147,16 @@ const vm_flags_t RUST_CONST_HELPER_VM_MIXEDMAP = VM_MIXEDMAP; const vm_flags_t RUST_CONST_HELPER_VM_HUGEPAGE = VM_HUGEPAGE; const vm_flags_t RUST_CONST_HELPER_VM_NOHUGEPAGE = VM_NOHUGEPAGE; +#if IS_ENABLED(CONFIG_GPU_BUDDY) +const unsigned long RUST_CONST_HELPER_GPU_BUDDY_RANGE_ALLOCATION = GPU_BUDDY_RANGE_ALLOCATION; +const unsigned long RUST_CONST_HELPER_GPU_BUDDY_TOPDOWN_ALLOCATION = GPU_BUDDY_TOPDOWN_ALLOCATION; +const unsigned long RUST_CONST_HELPER_GPU_BUDDY_CONTIGUOUS_ALLOCATION = + GPU_BUDDY_CONTIGUOUS_ALLOCATION; +const unsigned long RUST_CONST_HELPER_GPU_BUDDY_CLEAR_ALLOCATION = GPU_BUDDY_CLEAR_ALLOCATION; +const unsigned long RUST_CONST_HELPER_GPU_BUDDY_CLEARED = GPU_BUDDY_CLEARED; +const unsigned long RUST_CONST_HELPER_GPU_BUDDY_TRIM_DISABLE = GPU_BUDDY_TRIM_DISABLE; +#endif + #if IS_ENABLED(CONFIG_ANDROID_BINDER_IPC_RUST) #include "../../drivers/android/binder/rust_binder.h" #include "../../drivers/android/binder/rust_binder_events.h" diff --git a/rust/helpers/gpu.c b/rust/helpers/gpu.c new file mode 100644 index 000000000000..38b1a4e6bef8 --- /dev/null +++ b/rust/helpers/gpu.c @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/gpu_buddy.h> + +#ifdef CONFIG_GPU_BUDDY + +__rust_helper u64 rust_helper_gpu_buddy_block_offset(const struct gpu_buddy_block *block) +{ + return gpu_buddy_block_offset(block); +} + +__rust_helper unsigned int rust_helper_gpu_buddy_block_order(struct gpu_buddy_block *block) +{ + return gpu_buddy_block_order(block); +} + +__rust_helper u64 rust_helper_gpu_buddy_block_size(struct gpu_buddy *mm, + struct gpu_buddy_block *block) +{ + return gpu_buddy_block_size(mm, block); +} + +#endif /* CONFIG_GPU_BUDDY */ diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index 724fcb8240ac..a53929ce52a3 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -32,6 +32,7 @@ #include "err.c" #include "irq.c" #include "fs.c" +#include "gpu.c" #include "io.c" #include "jump_label.c" #include "kunit.c" diff --git a/rust/kernel/gpu/buddy.rs b/rust/kernel/gpu/buddy.rs new file mode 100644 index 000000000000..00290ce53aeb --- /dev/null +++ b/rust/kernel/gpu/buddy.rs @@ -0,0 +1,530 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! GPU buddy allocator bindings. +//! +//! C header: [`include/linux/gpu_buddy.h`](srctree/include/linux/gpu_buddy.h) +//! +//! This module provides Rust abstractions over the Linux kernel's GPU buddy +//! allocator, which implements a binary buddy memory allocator. +//! +//! The buddy allocator manages a contiguous address space and allocates blocks +//! in power-of-two sizes, useful for GPU physical memory management. +//! +//! # Examples +//! +//! ``` +//! use kernel::{ +//! gpu::buddy::{BuddyFlags, GpuBuddy, GpuBuddyAllocParams, GpuBuddyParams}, +//! prelude::*, +//! sizes::*, // +//! }; +//! +//! // Create a 1GB buddy allocator with 4KB minimum chunk size. +//! let buddy = GpuBuddy::new(&GpuBuddyParams { +//! base_offset_bytes: 0, +//! physical_memory_size_bytes: SZ_1G as u64, +//! chunk_size_bytes: SZ_4K as u64, +//! })?; +//! +//! // Verify initial state. +//! assert_eq!(buddy.size(), SZ_1G as u64); +//! assert_eq!(buddy.chunk_size(), SZ_4K as u64); +//! let initial_free = buddy.free_memory_bytes(); +//! +//! // Base allocation params - mutated between calls for field overrides. +//! let mut params = GpuBuddyAllocParams { +//! start_range_address: 0, +//! end_range_address: 0, // Entire range. +//! size_bytes: SZ_16M as u64, +//! min_block_size_bytes: SZ_16M as u64, +//! buddy_flags: BuddyFlags::try_new(BuddyFlags::RANGE_ALLOCATION)?, +//! }; +//! +//! // Test top-down allocation (allocates from highest addresses). +//! params.buddy_flags = BuddyFlags::try_new(BuddyFlags::TOPDOWN_ALLOCATION)?; +//! let topdown = buddy.alloc_blocks(¶ms)?; +//! assert_eq!(buddy.free_memory_bytes(), initial_free - SZ_16M as u64); +//! +//! for block in topdown.iter() { +//! assert_eq!(block.offset(), (SZ_1G - SZ_16M) as u64); +//! assert_eq!(block.order(), 12); // 2^12 pages +//! assert_eq!(block.size(), SZ_16M as u64); +//! } +//! drop(topdown); +//! assert_eq!(buddy.free_memory_bytes(), initial_free); +//! +//! // Allocate 16MB - should result in a single 16MB block at offset 0. +//! params.buddy_flags = BuddyFlags::try_new(BuddyFlags::RANGE_ALLOCATION)?; +//! let allocated = buddy.alloc_blocks(¶ms)?; +//! assert_eq!(buddy.free_memory_bytes(), initial_free - SZ_16M as u64); +//! +//! for block in allocated.iter() { +//! assert_eq!(block.offset(), 0); +//! assert_eq!(block.order(), 12); // 2^12 pages +//! assert_eq!(block.size(), SZ_16M as u64); +//! } +//! drop(allocated); +//! assert_eq!(buddy.free_memory_bytes(), initial_free); +//! +//! // Test non-contiguous allocation with fragmented memory. +//! // Create fragmentation by allocating 4MB blocks at [0,4M) and [8M,12M). +//! params.end_range_address = SZ_4M as u64; +//! params.size_bytes = SZ_4M as u64; +//! params.min_block_size_bytes = SZ_4M as u64; +//! let frag1 = buddy.alloc_blocks(¶ms)?; +//! assert_eq!(buddy.free_memory_bytes(), initial_free - SZ_4M as u64); +//! +//! params.start_range_address = SZ_8M as u64; +//! params.end_range_address = (SZ_8M + SZ_4M) as u64; +//! let frag2 = buddy.alloc_blocks(¶ms)?; +//! assert_eq!(buddy.free_memory_bytes(), initial_free - SZ_8M as u64); +//! +//! // Allocate 8MB without CONTIGUOUS - should return 2 blocks from the holes. +//! params.start_range_address = 0; +//! params.end_range_address = SZ_16M as u64; +//! params.size_bytes = SZ_8M as u64; +//! let fragmented = buddy.alloc_blocks(¶ms)?; +//! assert_eq!(buddy.free_memory_bytes(), initial_free - (SZ_16M) as u64); +//! +//! let (mut count, mut total) = (0u32, 0u64); +//! for block in fragmented.iter() { +//! // The 8MB allocation should return 2 blocks, each 4MB. +//! assert_eq!(block.size(), SZ_4M as u64); +//! total += block.size(); +//! count += 1; +//! } +//! assert_eq!(total, SZ_8M as u64); +//! assert_eq!(count, 2); +//! drop(fragmented); +//! drop(frag2); +//! drop(frag1); +//! assert_eq!(buddy.free_memory_bytes(), initial_free); +//! +//! // Test CONTIGUOUS failure when only fragmented space available. +//! // Create a small buddy allocator with only 16MB of memory. +//! let small = GpuBuddy::new(&GpuBuddyParams { +//! base_offset_bytes: 0, +//! physical_memory_size_bytes: SZ_16M as u64, +//! chunk_size_bytes: SZ_4K as u64, +//! })?; +//! +//! // Allocate 4MB blocks at [0,4M) and [8M,12M) to create fragmented memory. +//! params.start_range_address = 0; +//! params.end_range_address = SZ_4M as u64; +//! params.size_bytes = SZ_4M as u64; +//! let hole1 = small.alloc_blocks(¶ms)?; +//! +//! params.start_range_address = SZ_8M as u64; +//! params.end_range_address = (SZ_8M + SZ_4M) as u64; +//! let hole2 = small.alloc_blocks(¶ms)?; +//! +//! // 8MB contiguous should fail - only two non-contiguous 4MB holes exist. +//! params.start_range_address = 0; +//! params.end_range_address = 0; +//! params.size_bytes = SZ_8M as u64; +//! params.buddy_flags = BuddyFlags::try_new(BuddyFlags::CONTIGUOUS_ALLOCATION)?; +//! let result = small.alloc_blocks(¶ms); +//! assert!(result.is_err()); +//! drop(hole2); +//! drop(hole1); +//! +//! # Ok::<(), Error>(()) +//! ``` + +use crate::{ + bindings, + clist::CListHead, + clist_create, + error::to_result, + new_mutex, + prelude::*, + sync::{ + lock::mutex::MutexGuard, + Arc, + Mutex, // + }, + types::Opaque, +}; + +/// Flags for GPU buddy allocator operations. +/// +/// These flags control the allocation behavior of the buddy allocator. +#[derive(Clone, Copy, Default, PartialEq, Eq)] +pub struct BuddyFlags(usize); + +impl BuddyFlags { + /// Range-based allocation from start to end addresses. + pub const RANGE_ALLOCATION: usize = bindings::GPU_BUDDY_RANGE_ALLOCATION; + + /// Allocate from top of address space downward. + pub const TOPDOWN_ALLOCATION: usize = bindings::GPU_BUDDY_TOPDOWN_ALLOCATION; + + /// Allocate physically contiguous blocks. + pub const CONTIGUOUS_ALLOCATION: usize = bindings::GPU_BUDDY_CONTIGUOUS_ALLOCATION; + + /// Request allocation from the cleared (zeroed) memory. The zero'ing is not + /// done by the allocator, but by the caller before freeing old blocks. + pub const CLEAR_ALLOCATION: usize = bindings::GPU_BUDDY_CLEAR_ALLOCATION; + + /// Disable trimming of partially used blocks. + pub const TRIM_DISABLE: usize = bindings::GPU_BUDDY_TRIM_DISABLE; + + /// Mark blocks as cleared (zeroed) when freeing. When set during free, + /// indicates that the caller has already zeroed the memory. + pub const CLEARED: usize = bindings::GPU_BUDDY_CLEARED; + + /// Create [`BuddyFlags`] from a raw value with validation. + /// + /// Use `|` operator to combine flags if needed, before calling this method. + pub fn try_new(flags: usize) -> Result<Self> { + // Flags must not exceed u32::MAX to satisfy the GPU buddy allocator C API. + if flags > u32::MAX as usize { + return Err(EINVAL); + } + + // `TOPDOWN_ALLOCATION` only works without `RANGE_ALLOCATION`. When both are + // set, `TOPDOWN_ALLOCATION` is silently ignored by the allocator. Reject this. + if (flags & Self::RANGE_ALLOCATION) != 0 && (flags & Self::TOPDOWN_ALLOCATION) != 0 { + return Err(EINVAL); + } + + Ok(Self(flags)) + } + + /// Get raw value of the flags. + pub(crate) fn as_raw(self) -> usize { + self.0 + } +} + +/// Parameters for creating a GPU buddy allocator. +pub struct GpuBuddyParams { + /// Base offset in bytes where the managed memory region starts. + /// Allocations will be offset by this value. + pub base_offset_bytes: u64, + /// Total physical memory size managed by the allocator in bytes. + pub physical_memory_size_bytes: u64, + /// Minimum allocation unit / chunk size in bytes, must be >= 4KB. + pub chunk_size_bytes: u64, +} + +/// Parameters for allocating blocks from a GPU buddy allocator. +pub struct GpuBuddyAllocParams { + /// Start of allocation range in bytes. Use 0 for beginning. + pub start_range_address: u64, + /// End of allocation range in bytes. Use 0 for entire range. + pub end_range_address: u64, + /// Total size to allocate in bytes. + pub size_bytes: u64, + /// Minimum block size for fragmented allocations in bytes. + pub min_block_size_bytes: u64, + /// Buddy allocator behavior flags. + pub buddy_flags: BuddyFlags, +} + +/// Inner structure holding the actual buddy allocator. +/// +/// # Synchronization +/// +/// The C `gpu_buddy` API requires synchronization (see `include/linux/gpu_buddy.h`). +/// The internal [`GpuBuddyGuard`] ensures that the lock is held for all +/// allocator and free operations, preventing races between concurrent allocations +/// and the freeing that occurs when [`AllocatedBlocks`] is dropped. +/// +/// # Invariants +/// +/// The inner [`Opaque`] contains a valid, initialized buddy allocator. +#[pin_data(PinnedDrop)] +struct GpuBuddyInner { + #[pin] + inner: Opaque<bindings::gpu_buddy>, + #[pin] + lock: Mutex<()>, + /// Base offset for all allocations (does not change after init). + base_offset: u64, + /// Cached chunk size (does not change after init). + chunk_size: u64, + /// Cached total size (does not change after init). + size: u64, +} + +impl GpuBuddyInner { + /// Create a pin-initializer for the buddy allocator. + fn new(params: &GpuBuddyParams) -> impl PinInit<Self, Error> { + let base_offset = params.base_offset_bytes; + let size = params.physical_memory_size_bytes; + let chunk_size = params.chunk_size_bytes; + + try_pin_init!(Self { + inner <- Opaque::try_ffi_init(|ptr| { + // SAFETY: ptr points to valid uninitialized memory from the pin-init + // infrastructure. gpu_buddy_init will initialize the structure. + to_result(unsafe { bindings::gpu_buddy_init(ptr, size, chunk_size) }) + }), + lock <- new_mutex!(()), + base_offset: base_offset, + chunk_size: chunk_size, + size: size, + }) + } + + /// Lock the mutex and return a guard for accessing the allocator. + fn lock(&self) -> GpuBuddyGuard<'_> { + GpuBuddyGuard { + inner: self, + _guard: self.lock.lock(), + } + } +} + +#[pinned_drop] +impl PinnedDrop for GpuBuddyInner { + fn drop(self: Pin<&mut Self>) { + let guard = self.lock(); + + // SAFETY: guard provides exclusive access to the allocator. + unsafe { + bindings::gpu_buddy_fini(guard.as_raw()); + } + } +} + +// SAFETY: [`GpuBuddyInner`] can be sent between threads. +unsafe impl Send for GpuBuddyInner {} + +// SAFETY: [`GpuBuddyInner`] is `Sync` because the internal [`GpuBuddyGuard`] +// serializes all access to the C allocator, preventing data races. +unsafe impl Sync for GpuBuddyInner {} + +/// Guard that proves the lock is held, enabling access to the allocator. +/// +/// # Invariants +/// +/// The inner `_guard` holds the lock for the duration of this guard's lifetime. +pub(crate) struct GpuBuddyGuard<'a> { + inner: &'a GpuBuddyInner, + _guard: MutexGuard<'a, ()>, +} + +impl GpuBuddyGuard<'_> { + /// Get a raw pointer to the underlying C `gpu_buddy` structure. + fn as_raw(&self) -> *mut bindings::gpu_buddy { + self.inner.inner.get() + } +} + +/// GPU buddy allocator instance. +/// +/// This structure wraps the C `gpu_buddy` allocator using reference counting. +/// The allocator is automatically cleaned up when all references are dropped. +/// +/// # Invariants +/// +/// The inner [`Arc`] points to a valid, initialized GPU buddy allocator. +pub struct GpuBuddy(Arc<GpuBuddyInner>); + +impl GpuBuddy { + /// Create a new buddy allocator. + /// + /// Creates a buddy allocator that manages a contiguous address space of the given + /// size, with the specified minimum allocation unit (chunk_size must be at least 4KB). + pub fn new(params: &GpuBuddyParams) -> Result<Self> { + Ok(Self(Arc::pin_init( + GpuBuddyInner::new(params), + GFP_KERNEL, + )?)) + } + + /// Get the base offset for allocations. + pub fn base_offset(&self) -> u64 { + self.0.base_offset + } + + /// Get the chunk size (minimum allocation unit). + pub fn chunk_size(&self) -> u64 { + self.0.chunk_size + } + + /// Get the total managed size. + pub fn size(&self) -> u64 { + self.0.size + } + + /// Get the available (free) memory in bytes. + pub fn free_memory_bytes(&self) -> u64 { + let guard = self.0.lock(); + // SAFETY: guard provides exclusive access to the allocator. + unsafe { (*guard.as_raw()).avail } + } + + /// Allocate blocks from the buddy allocator. + /// + /// Returns an [`Arc<AllocatedBlocks>`] structure that owns the allocated blocks + /// and automatically frees them when all references are dropped. + /// + /// Takes `&self` instead of `&mut self` because the internal [`Mutex`] provides + /// synchronization - no external `&mut` exclusivity needed. + pub fn alloc_blocks(&self, params: &GpuBuddyAllocParams) -> Result<Arc<AllocatedBlocks>> { + let buddy_arc = Arc::clone(&self.0); + + // Create pin-initializer that initializes list and allocates blocks. + let init = try_pin_init!(AllocatedBlocks { + buddy: Arc::clone(&buddy_arc), + list <- CListHead::new(), + flags: params.buddy_flags, + _: { + // Lock while allocating to serialize with concurrent frees. + let guard = buddy.lock(); + + // SAFETY: `guard` provides exclusive access to the buddy allocator. + to_result(unsafe { + bindings::gpu_buddy_alloc_blocks( + guard.as_raw(), + params.start_range_address, + params.end_range_address, + params.size_bytes, + params.min_block_size_bytes, + list.as_raw(), + params.buddy_flags.as_raw(), + ) + })? + } + }); + + Arc::pin_init(init, GFP_KERNEL) + } +} + +/// Allocated blocks from the buddy allocator with automatic cleanup. +/// +/// This structure owns a list of allocated blocks and ensures they are +/// automatically freed when dropped. Use `iter()` to iterate over all +/// allocated [`Block`] structures. +/// +/// # Invariants +/// +/// - `list` is an initialized, valid list head containing allocated blocks. +/// - `buddy` references a valid [`GpuBuddyInner`]. +#[pin_data(PinnedDrop)] +pub struct AllocatedBlocks { + #[pin] + list: CListHead, + buddy: Arc<GpuBuddyInner>, + flags: BuddyFlags, +} + +impl AllocatedBlocks { + /// Check if the block list is empty. + pub fn is_empty(&self) -> bool { + // An empty list head points to itself. + !self.list.is_linked() + } + + /// Iterate over allocated blocks. + /// + /// Returns an iterator yielding [`AllocatedBlock`] references. The blocks + /// are only valid for the duration of the borrow of `self`. + pub fn iter(&self) -> impl Iterator<Item = AllocatedBlock<'_>> + '_ { + // SAFETY: list contains gpu_buddy_block items linked via __bindgen_anon_1.link. + let clist = unsafe { + clist_create!( + self.list.as_raw(), + Block, + bindings::gpu_buddy_block, + __bindgen_anon_1.link + ) + }; + + clist + .iter() + .map(|block| AllocatedBlock { block, alloc: self }) + } +} + +#[pinned_drop] +impl PinnedDrop for AllocatedBlocks { + fn drop(self: Pin<&mut Self>) { + let guard = self.buddy.lock(); + + // SAFETY: + // - list is valid per the type's invariants. + // - guard provides exclusive access to the allocator. + // CAST: BuddyFlags were validated to fit in u32 at construction. + unsafe { + bindings::gpu_buddy_free_list( + guard.as_raw(), + self.list.as_raw(), + self.flags.as_raw() as u32, + ); + } + } +} + +/// A GPU buddy block. +/// +/// Transparent wrapper over C `gpu_buddy_block` structure. This type is returned +/// as references from [`CListIter`] during iteration over [`AllocatedBlocks`]. +/// +/// # Invariants +/// +/// The inner [`Opaque`] contains a valid, allocated `gpu_buddy_block`. +#[repr(transparent)] +pub struct Block(Opaque<bindings::gpu_buddy_block>); + +impl Block { + /// Get a raw pointer to the underlying C block. + fn as_raw(&self) -> *mut bindings::gpu_buddy_block { + self.0.get() + } + + /// Get the block's offset in the address space. + pub(crate) fn offset(&self) -> u64 { + // SAFETY: self.as_raw() is valid per the type's invariants. + unsafe { bindings::gpu_buddy_block_offset(self.as_raw()) } + } + + /// Get the block order. + pub(crate) fn order(&self) -> u32 { + // SAFETY: self.as_raw() is valid per the type's invariants. + unsafe { bindings::gpu_buddy_block_order(self.as_raw()) } + } +} + +// SAFETY: `Block` is a transparent wrapper over `gpu_buddy_block` which is not +// modified after allocation. It can be safely sent between threads. +unsafe impl Send for Block {} + +// SAFETY: `Block` is a transparent wrapper over `gpu_buddy_block` which is not +// modified after allocation. It can be safely shared among threads. +unsafe impl Sync for Block {} + +/// An allocated block with access to the allocation list. +/// +/// # Invariants +/// +/// - `block` is a valid reference to an allocated [`Block`]. +/// - `alloc` is a valid reference to the [`AllocatedBlocks`] that owns this block. +pub struct AllocatedBlock<'a> { + block: &'a Block, + alloc: &'a AllocatedBlocks, +} + +impl AllocatedBlock<'_> { + /// Get the block's offset in the address space. + /// + /// Returns the absolute offset including the allocator's base offset. + /// This is the actual address to use for accessing the allocated memory. + pub fn offset(&self) -> u64 { + self.alloc.buddy.base_offset + self.block.offset() + } + + /// Get the block order (size = chunk_size << order). + pub fn order(&self) -> u32 { + self.block.order() + } + + /// Get the block's size in bytes. + pub fn size(&self) -> u64 { + self.alloc.buddy.chunk_size << self.block.order() + } +} diff --git a/rust/kernel/gpu/mod.rs b/rust/kernel/gpu/mod.rs new file mode 100644 index 000000000000..8f25e6367edc --- /dev/null +++ b/rust/kernel/gpu/mod.rs @@ -0,0 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! GPU subsystem abstractions. + +pub mod buddy; diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 8439c30f40b5..e30faa5ca8f4 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -99,6 +99,8 @@ pub mod firmware; pub mod fmt; pub mod fs; +#[cfg(CONFIG_GPU_BUDDY)] +pub mod gpu; #[cfg(CONFIG_I2C = "y")] pub mod i2c; pub mod id_pool; -- 2.34.1 ^ permalink raw reply related [flat|nested] 23+ messages in thread
end of thread, other threads:[~2026-02-09 19:42 UTC | newest] Thread overview: 23+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-02-06 0:41 [PATCH -next v7 0/2] rust: Add CList and GPU buddy allocator bindings Joel Fernandes 2026-02-06 0:41 ` [PATCH -next v7 1/2] rust: clist: Add support to interface with C linked lists Joel Fernandes 2026-02-06 15:25 ` Gary Guo 2026-02-06 15:53 ` Danilo Krummrich 2026-02-06 16:05 ` Joel Fernandes 2026-02-06 16:13 ` Gary Guo 2026-02-06 17:13 ` Danilo Krummrich 2026-02-06 17:20 ` Gary Guo 2026-02-06 17:27 ` Danilo Krummrich 2026-02-06 21:30 ` Daniel Almeida 2026-02-09 19:42 ` Joel Fernandes 2026-02-06 20:44 ` Joel Fernandes 2026-02-09 19:41 ` Joel Fernandes 2026-02-06 17:49 ` Daniel Almeida 2026-02-06 20:46 ` Joel Fernandes 2026-02-06 20:51 ` Gary Guo 2026-02-06 21:12 ` Joel Fernandes 2026-02-06 20:51 ` Joel Fernandes 2026-02-06 21:21 ` Daniel Almeida 2026-02-06 21:26 ` Joel Fernandes 2026-02-06 22:33 ` Daniel Almeida 2026-02-09 17:02 ` Joel Fernandes 2026-02-06 0:41 ` [PATCH -next v7 2/2] rust: gpu: Add GPU buddy allocator bindings Joel Fernandes
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox