[PATCH v4 03/11] rust: xarray: add `XArrayState`
From: Andreas Hindborg
Date: Thu Jun 04 2026 - 16:01:39 EST
Add `XArrayState` as internal state for XArray iteration and entry
operations. This struct wraps the C `xa_state` structure and holds a
reference to a `Guard` to ensure exclusive access to the XArray for the
lifetime of the state object.
The `XAS_RESTART` constant is also exposed through the bindings helper
to properly initialize the `xa_node` field.
The struct and its constructor are marked with `#[expect(dead_code)]` as
there are no users yet. We will remove this annotation in a later patch.
Signed-off-by: Andreas Hindborg <a.hindborg@xxxxxxxxxx>
---
rust/bindings/bindings_helper.h | 7 +++++
rust/kernel/xarray.rs | 66 ++++++++++++++++++++++++++++++++++++++++-
2 files changed, 72 insertions(+), 1 deletion(-)
diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 446dbeaf0866..d4093367a4a8 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -123,6 +123,13 @@ const xa_mark_t RUST_CONST_HELPER_XA_PRESENT = XA_PRESENT;
const gfp_t RUST_CONST_HELPER_XA_FLAGS_ALLOC = XA_FLAGS_ALLOC;
const gfp_t RUST_CONST_HELPER_XA_FLAGS_ALLOC1 = XA_FLAGS_ALLOC1;
+/*
+ * `XAS_RESTART` is `((struct xa_node *)3UL)` -- a sentinel pointer value, not
+ * an address. Cast to `size_t` so bindgen emits a plain `usize` constant; for
+ * pointer-typed macro values bindgen otherwise generates a `pub static mut`,
+ * see https://github.com/rust-lang/rust-bindgen/issues/3347.
+ */
+const size_t RUST_CONST_HELPER_XAS_RESTART = (size_t)XAS_RESTART;
const vm_flags_t RUST_CONST_HELPER_VM_MERGEABLE = VM_MERGEABLE;
const vm_flags_t RUST_CONST_HELPER_VM_READ = VM_READ;
diff --git a/rust/kernel/xarray.rs b/rust/kernel/xarray.rs
index d54942aeb201..6d0d4905004a 100644
--- a/rust/kernel/xarray.rs
+++ b/rust/kernel/xarray.rs
@@ -8,7 +8,10 @@
iter,
marker::PhantomData,
pin::Pin,
- ptr::NonNull, //
+ ptr::{
+ null_mut,
+ NonNull, //
+ },
};
use kernel::{
alloc,
@@ -299,6 +302,67 @@ pub fn store(
}
}
+/// A reference to a [`Guard`], either shared or mutable, that exposes the
+/// underlying xarray pointer and the value type stored in the array.
+pub(crate) trait GuardRef {
+ type Value: ForeignOwnable;
+ fn xa_ptr(&self) -> *mut bindings::xarray;
+}
+
+impl<'a, T: ForeignOwnable> GuardRef for &Guard<'a, T> {
+ type Value = T;
+ fn xa_ptr(&self) -> *mut bindings::xarray {
+ self.xa.xa.get()
+ }
+}
+
+impl<'a, T: ForeignOwnable> GuardRef for &mut Guard<'a, T> {
+ type Value = T;
+ fn xa_ptr(&self) -> *mut bindings::xarray {
+ self.xa.xa.get()
+ }
+}
+
+/// Internal state for XArray iteration and entry operations.
+///
+/// `R` is the borrow held on the guard: either `&Guard` for read-only callers
+/// or `&mut Guard` for entry-style APIs that need to surrender the borrow back
+/// via [`XArrayState::into_guard`].
+///
+/// # Invariants
+///
+/// - `state` is always a valid `bindings::xa_state`.
+/// - `state.xa` aliases the xarray reachable through `guard`.
+#[expect(dead_code)]
+pub(crate) struct XArrayState<R: GuardRef> {
+ guard: R,
+ state: bindings::xa_state,
+}
+
+impl<R: GuardRef> XArrayState<R> {
+ #[expect(dead_code)]
+ fn new(guard: R, index: usize) -> Self {
+ let xa_ptr = guard.xa_ptr();
+ // INVARIANT: `state` is initialized to a valid `xa_state` whose `xa` field aliases the
+ // xarray reachable through `guard`.
+ Self {
+ guard,
+ state: bindings::xa_state {
+ xa: xa_ptr,
+ xa_index: index,
+ xa_shift: 0,
+ xa_sibs: 0,
+ xa_offset: 0,
+ xa_pad: 0,
+ xa_node: bindings::XAS_RESTART as *mut bindings::xa_node,
+ xa_alloc: null_mut(),
+ xa_update: None,
+ xa_lru: null_mut(),
+ },
+ }
+ }
+}
+
// SAFETY: `XArray<T>` has no shared mutable state so it is `Send` iff `T` is `Send`.
unsafe impl<T: ForeignOwnable + Send> Send for XArray<T> {}
--
2.51.2