From: Andreas Hindborg <a.hindborg@kernel.org>
To: "Tamir Duberstein" <tamird@kernel.org>,
"Miguel Ojeda" <ojeda@kernel.org>,
"Boqun Feng" <boqun@kernel.org>, "Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Benno Lossin" <lossin@kernel.org>,
"Alice Ryhl" <aliceryhl@google.com>,
"Trevor Gross" <tmgross@umich.edu>,
"Danilo Krummrich" <dakr@kernel.org>,
"Daniel Almeida" <daniel.almeida@collabora.com>,
"Alexandre Courbot" <acourbot@nvidia.com>,
"Onur Özkan" <work@onurozkan.dev>,
"Matthew Wilcox" <willy@infradead.org>,
"Andrew Morton" <akpm@linux-foundation.org>,
"Lorenzo Stoakes" <ljs@kernel.org>,
"Liam R. Howlett" <liam@infradead.org>,
"Vlastimil Babka" <vbabka@kernel.org>,
"Harry Yoo" <harry@kernel.org>, "Hao Li" <hao.li@linux.dev>,
"Christoph Lameter" <cl@gentwo.org>,
"David Rientjes" <rientjes@google.com>,
"Roman Gushchin" <roman.gushchin@linux.dev>
Cc: Andreas Hindborg <a.hindborg@kernel.org>,
rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-fsdevel@vger.kernel.org, linux-mm@kvack.org
Subject: [PATCH v5 04/12] rust: xarray: add `XArrayState`
Date: Wed, 02 Sep 2026 15:26:00 +0200 [thread overview]
Message-ID: <20260902-xarray-entry-send-v5-4-d18adae40708@kernel.org> (raw)
In-Reply-To: <20260902-xarray-entry-send-v5-0-d18adae40708@kernel.org>
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. `XArrayState` is generic over the guard
borrow through a `Deref` bound, so it can hold either a shared or a
mutable reference to the guard.
Use the new state in `Guard::load` by replacing the call to `xa_load`
with `xas_load`. The `xa_load` function takes the RCU lock internally,
which we do not need, since the `Guard` already holds an exclusive lock
on the `XArray`. The `xas_load` function operates on `xa_state` and
assumes the required locks are already held.
Unlike `xa_load`, `xas_load` does not filter out internal entries.
Arrays created with `AllocKind::Alloc1` store `XA_ZERO_ENTRY` at index
0 when they are expanded from empty, so convert zero entries to `NULL`
like the C normal API does, exposing the `xa_zero_to_null` helper for
this purpose.
The `XAS_RESTART` constant is also exposed through the bindings helper
to properly initialize the `xa_node` field.
The `guard` field of `XArrayState` is not read until a later patch
adds `into_guard`, so it is annotated with `#[expect(dead_code)]`
until then.
Assisted-by: LLM
Signed-off-by: Andreas Hindborg <a.hindborg@kernel.org>
---
rust/bindings/bindings_helper.h | 7 ++++
rust/helpers/xarray.c | 5 +++
rust/kernel/xarray.rs | 74 ++++++++++++++++++++++++++++++++++++++---
3 files changed, 81 insertions(+), 5 deletions(-)
diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 1124785e210b3..419e6b74fedc3 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -124,6 +124,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/helpers/xarray.c b/rust/helpers/xarray.c
index 08979b3043410..79799c55c3d73 100644
--- a/rust/helpers/xarray.c
+++ b/rust/helpers/xarray.c
@@ -26,3 +26,8 @@ __rust_helper void rust_helper_xa_unlock(struct xarray *xa)
{
return xa_unlock(xa);
}
+
+__rust_helper void *rust_helper_xa_zero_to_null(void *entry)
+{
+ return xa_zero_to_null(entry);
+}
diff --git a/rust/kernel/xarray.rs b/rust/kernel/xarray.rs
index 4335caab8ccae..e8082df2b4797 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,
@@ -214,10 +217,8 @@ fn load<F, U>(&self, index: usize, f: F) -> Option<U>
where
F: FnOnce(NonNull<c_void>) -> U,
{
- // SAFETY: `self.xa.xa` is always valid by the type invariant.
- let ptr = unsafe { bindings::xa_load(self.xa.xa.get(), index) };
- let ptr = NonNull::new(ptr.cast())?;
- Some(f(ptr))
+ let mut state = XArrayState::new(self, index);
+ Some(f(state.load()?))
}
/// Provides a reference to the element at the given index.
@@ -300,6 +301,69 @@ pub fn store(
}
}
+/// 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`.
+pub(crate) struct XArrayState<R> {
+ // The borrow is held to guarantee exclusive access to the array. It is
+ // not read until a later patch adds `into_guard`, so silence the dead
+ // code warning until then.
+ #[expect(dead_code)]
+ guard: R,
+ state: bindings::xa_state,
+}
+
+impl<'a, R, T> XArrayState<R>
+where
+ T: ForeignOwnable + 'a,
+ R: core::ops::Deref<Target = Guard<'a, T>>,
+{
+ #[inline]
+ fn new(guard: R, index: usize) -> Self {
+ let xa_ptr = guard.xa.xa.get();
+ // 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(),
+ },
+ }
+ }
+
+ fn load(&mut self) -> Option<NonNull<c_void>> {
+ // SAFETY: `self.state` is a valid `xa_state` by the type invariant. By the same
+ // invariant, `self.state.xa` aliases the xarray reachable through `self.guard`, whose
+ // lock we hold.
+ let ptr = unsafe { bindings::xas_load(&raw mut self.state) };
+
+ // Unlike the normal API, `xas_load` does not filter out internal entries. Arrays
+ // created with [`AllocKind::Alloc1`] store `XA_ZERO_ENTRY` at index 0 when they are
+ // expanded from empty, so convert zero entries to `NULL` like `xa_load` does. Retry
+ // entries cannot be observed here because they require concurrent modification of the
+ // array, and we hold the lock.
+ //
+ // SAFETY: `xa_zero_to_null` only inspects the value of `ptr`.
+ NonNull::new(unsafe { bindings::xa_zero_to_null(ptr) }.cast())
+ }
+}
+
// 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
next prev parent reply other threads:[~2026-09-02 13:27 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-02 13:25 [PATCH v5 00/12] rust: xarray: add entry API with preloading Andreas Hindborg
2026-09-02 13:25 ` [PATCH v5 01/12] rust: xarray: minor formatting fixes Andreas Hindborg
2026-09-02 13:25 ` [PATCH v5 02/12] rust: xarray: add debug format for `StoreError` Andreas Hindborg
2026-09-02 13:25 ` [PATCH v5 03/12] xarray: move xas_result() and xa_zero_to_null() to the header Andreas Hindborg
2026-09-02 13:26 ` Andreas Hindborg [this message]
2026-09-02 13:26 ` [PATCH v5 05/12] rust: xarray: simplify `Guard::load` Andreas Hindborg
2026-09-02 13:26 ` [PATCH v5 06/12] rust: xarray: add `find_next` and `find_next_mut` Andreas Hindborg
2026-09-02 13:26 ` [PATCH v5 07/12] rust: xarray: add entry API Andreas Hindborg
2026-09-02 13:26 ` [PATCH v5 08/12] rust: mm: add abstractions for allocating from a `sheaf` Andreas Hindborg
2026-09-03 10:09 ` Vlastimil Babka (SUSE)
2026-09-02 13:26 ` [PATCH v5 09/12] rust: mm: sheaf: allow use of C initialized static caches Andreas Hindborg
2026-09-03 10:11 ` Vlastimil Babka (SUSE)
2026-09-02 13:26 ` [PATCH v5 10/12] xarray, radix-tree: enable sheaf support for kmem_cache Andreas Hindborg
2026-09-02 13:26 ` [PATCH v5 11/12] rust: xarray: add preload API Andreas Hindborg
2026-09-02 13:26 ` [PATCH v5 12/12] rust: xarray: document `Guard` lock drop semantics Andreas Hindborg
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260902-xarray-entry-send-v5-4-d18adae40708@kernel.org \
--to=a.hindborg@kernel.org \
--cc=acourbot@nvidia.com \
--cc=akpm@linux-foundation.org \
--cc=aliceryhl@google.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun@kernel.org \
--cc=cl@gentwo.org \
--cc=dakr@kernel.org \
--cc=daniel.almeida@collabora.com \
--cc=gary@garyguo.net \
--cc=hao.li@linux.dev \
--cc=harry@kernel.org \
--cc=liam@infradead.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=ljs@kernel.org \
--cc=lossin@kernel.org \
--cc=ojeda@kernel.org \
--cc=rientjes@google.com \
--cc=roman.gushchin@linux.dev \
--cc=rust-for-linux@vger.kernel.org \
--cc=tamird@kernel.org \
--cc=tmgross@umich.edu \
--cc=vbabka@kernel.org \
--cc=willy@infradead.org \
--cc=work@onurozkan.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.