Re: [PATCH v11 2/2] rust: clist: Add support to interface with C linked lists
From: Joel Fernandes
Date: Thu Feb 26 2026 - 14:40:02 EST
On Fri, 27 Feb 2026, Alvin Sun wrote:
> Thanks for the clist abstraction. The Tyr debugfs [1] I'm implementing
> needs to iterate over a GpuVm's VA list, and I'd like to switch that to
> a CList-based implementation.
Thanks for looking into using CList for this!
> Could you make CListHeadIter public and expose a public constructor?
> Or do you have a better suggestion?
I think this can be handled without exposing CListHeadIter. See below.
> The VA list mixes two node types in one list — GpuVa (with driver-specific
> data) and KernelGpuVa — so we have to filter/skip nodes and can't use
> CList as-is. With a public CListHeadIter and new(), we can implement a
> custom iterator (like our current GpuVaIter) on top of CListHeadIter and
> then migrate that code to clist instead of hand-rolled list traversal.
Looking at the Tyr code, both GpuVa and KernelGpuVa are
#[repr(transparent)] wrappers over the same C struct (drm_gpuva), linked
through the same list_head field at the same offset. The "two types" are
a Rust-level modeling choice for safety, not a structural difference in
the list — every node in that list is a drm_gpuva.
So CList's typed iteration already works here. You can iterate over all
nodes using a common Rust wrapper type (like a #[repr(transparent)]
wrapper over drm_gpuva), and then skip the kernel-reserved node by
pointer identity — since drm_gpuvm has its kernel_alloc_node as a named
field, its address is known. Something like:
// Iterate all nodes as a common base type.
let list = clist_create!(unsafe { head, RawGpuVa, drm_gpuva, rb.entry });
let kernel_ptr = unsafe { &raw mut (*gpuvm_raw).kernel_alloc_node };
for va in list.iter() {
if va.as_raw() == kernel_ptr {
continue; // skip
}
// Cast to &GpuVa
let gpu_va = unsafe { GpuVa::from_raw(va.as_raw()) };
...
}
If you need a named iterator type (e.g. for returning from a method),
you can wrap CListIter in your own GpuVaIter struct that stores the
kernel node pointer and filters in its Iterator::next() impl. That would
probably also be cleaner.
OTOH, with CListHeadIter you'd need to do container_of manually on each node,
which might be more erroneous code, whereas CListIter handles that for you.
And anyway, the pointer comparison needed to skip the kernel node is the same
in both approaches.
Would this work for the Tyr debugfs use case?
--
Joel Fernandes