kernel/rxarray.rs
1// SPDX-License-Identifier: GPL-2.0
2
3//! Rust XArray implementation.
4//!
5//! This module implements an extensible array (aka XArray) via the [`XArray`] type. See [`XArray4`]
6//! and [`XArray6`] for common configurations.
7//!
8//! The array can hold two types of entries at the same time where each index independently stores
9//! either an owned pointer (`T: ForeignOwnable`) or a bounded integer up to `usize::MAX >> 1`
10//! backed by [`Bounded`]. Users insert entries via the [`Entry`] type. References to entries in
11//! the tree are handled by the [`BorrowedEntry`] and [`BorrowedEntryMut`] types.
12//!
13//! # Differences from C XArray
14//!
15//! The C XArray uses RCU for lock-free reads and an internal spinlock for writes. This
16//! implementation does not provide internal locking. A mutable reference is required for writes, a
17//! shared reference for reads. Locking can be applied externally. RCU support is planned.
18//!
19//! This implementation allocates during store. `xa_reserve()` and `xas_nomem()` are not yet
20//! supported.
21//!
22//! C `xa_destroy()` frees only internal nodes; callers must free their own stored values. Dropping
23//! [`XArray`] also frees all stored entries.
24//!
25//! C `xa_mk_value()` issues `WARN_ON` if the value exceeds `LONG_MAX`; the left shift overflows,
26//! producing a wrong entry.
27//! Rust [`Entry::int()`] rejects out-of-range values at compile time via `Bounded`, and
28//! [`Entry::try_int()`] returns [`None`] at runtime.
29//!
30//! The C XArray grows in depth on demand to be efficient for small indices, creating a short tree
31//! whenever possible and adding levels as larger indices appear. This implementation always walks
32//! the full levels, whatever the largest stored index is. Variable height is planned.
33//!
34//! C XArray features like search marks, multi-index entries, advanced API, etc. are not yet
35//! implemented.
36//!
37//! This implementation aims for full feature parity with the C XArray; any gap not covered above is
38//! a defect in this list.
39//!
40//! # Data structure
41//!
42//! The XArray is a radix tree that maps `usize` indices to [`Entry`] values. Each node holds an
43//! array of `SIZE` slots (where `SIZE = 1 << SHIFT`), and the tree depth is
44//! `ceil(usize::BITS / SHIFT)`. Indices are decomposed so that each chunk indexes a slot in a
45//! node at the corresponding level.
46//!
47//! ```text
48//! XArray
49//! │
50//! ▼
51//! ┌────────────────┐
52//! │ Root Node │ Level = levels-1
53//! │ slots[0..SIZE] │
54//! └────────────────┘
55//! / | \
56//! ┌───────────┘ │ └───────────┐
57//! ▼ ▼ ▼
58//! ┌────────────────┐ ┌────────┐ ┌────────────────┐
59//! │ Node │ │ Empty │ │ Node │
60//! │ slots[0..SIZE] │ └────────┘ │ slots[0..SIZE] │
61//! └────────────────┘ └────────────────┘
62//! / \ |
63//! ▼ ▼ ▼
64//! ... ... ┌────────────────┐
65//! │ Leaf Node │ Level = 0
66//! │ slots[0..SIZE] │
67//! └────────────────┘
68//! / | \
69//! ▼ ▼ ▼
70//! Entry Empty Entry
71//! (Int) (Ptr)
72//! ```
73//!
74//! Index decomposition for [`XArray6`] (SHIFT=6, 64 slots per node, 11 levels on 64-bit):
75//!
76//! ```text
77//! ┌─────────────────────────────────────────────────────────────────┐
78//! │ index │
79//! ├─────────┬─────────┬───────────────┬─────────┬─────────┬─────────┤
80//! │ level10 │ level 9 │ ... │ level 2 │ level 1 │ level 0 │
81//! │ [63:60] │ [59:54] │ │ [17:12] │ [11:6] │ [5:0] │
82//! └─────────┴─────────┴───────────────┴─────────┴─────────┴─────────┘
83//! ```
84//!
85//! At each level, the slot offset is: `(index >> (level * SHIFT)) & (SIZE - 1)`.
86//!
87//! # C API
88//!
89//! This implementation does not have a C API yet. When one is added, its FFI layer must validate
90//! at runtime what the Rust API enforces at compile or construction time:
91//!
92//! - **Int values**: use [`Entry::try_int()`]; reject [`None`] as `-EINVAL`. C has no [`Bounded`],
93//! so the FFI wrapper is the enforcement point.
94//! - **Pointers**: validate 4-byte alignment and non-null at runtime.
95//! `const_assert!(T::FOREIGN_ALIGN >= 4)` only covers Rust callers.
96//! - **NULL pointers**: dispatch as erase (`xa_store(NULL) == xa_erase`) or reserve
97//! (`XA_FLAGS_ALLOC`) before reaching [`XArray::store()`].
98//! - **Error entries**: reject `xa_is_err()` values; Rust would misclassify them as node pointers
99//! (see `Slot` invariants).
100
101use crate::{
102 alloc::Flags,
103 fmt,
104 num::Bounded,
105 prelude::*,
106 types::ForeignOwnable, //
107};
108use core::{
109 marker::PhantomData,
110 mem, //
111};
112
113/// Type alias for [`XArray`] with a shift of 4 and 16 slots per node.
114pub type XArray4<T> = XArray<T, 4, 16>;
115
116/// Type alias for [`XArray`] with a shift of 6 and 64 slots per node.
117pub type XArray6<T> = XArray<T, 6, 64>;
118
119/// Type alias for [`Entry::Int`] values. Integers that fit in `usize::BITS - 1` bits
120/// (`0..=usize::MAX >> 1`).
121pub type Value = Bounded<usize, { usize::BITS - 1 }>;
122
123/// An entry is either an [`Entry::Int`] integer (`0..=usize::MAX >> 1`) or an owned
124/// [`Entry::Pointer`].
125///
126/// Empty slots are represented by [`None`], not a separate variant.
127///
128/// Integer values are validated by [`Value`]. Pointer alignment (`T::FOREIGN_ALIGN >= 4`) is a
129/// requirement of the slot encoding, enforced at compile time when an [`XArray`] over `T` is
130/// constructed (see the [`XArray`] invariants); [`Entry`] itself carries no invariants.
131pub enum Entry<T: ForeignOwnable> {
132 /// Integer value (`0..=usize::MAX >> 1`).
133 Int(Value),
134 /// Pointer payload. Owned (`T`).
135 Pointer(T),
136}
137
138impl<T: ForeignOwnable> Entry<T> {
139 /// Creates an [`Entry::Int`] validated at compile time.
140 ///
141 /// Fails to compile if `V > usize::MAX >> 1`.
142 pub const fn int<const V: usize>() -> Self {
143 Entry::Int(Value::new::<V>())
144 }
145
146 /// Creates an [`Entry::Int`] validated at runtime.
147 ///
148 /// Returns [`None`] if `v > usize::MAX >> 1`.
149 pub fn try_int(v: usize) -> Option<Self> {
150 Value::try_new(v).map(Entry::Int)
151 }
152}
153
154/// A borrowed entry returned by [`XArray::load()`], containing either an integer or a borrowed
155/// pointer.
156pub enum BorrowedEntry<'a, T: ForeignOwnable + 'a> {
157 /// Integer value (`0..=usize::MAX >> 1`).
158 Int(Value),
159 /// Pointer payload `T::Borrowed<'_>`.
160 Pointer(T::Borrowed<'a>),
161}
162
163/// A mutably borrowed entry returned by [`XArray::load_mut()`], containing either an integer or a
164/// borrowed pointer.
165pub enum BorrowedEntryMut<'a, T: ForeignOwnable + 'a> {
166 /// Integer value (`0..=usize::MAX >> 1`).
167 Int(Value),
168 /// Pointer payload `T::BorrowedMut<'_>`.
169 Pointer(T::BorrowedMut<'a>),
170}
171
172/// The error returned by [`XArray::store()`].
173///
174/// Contains the underlying error and the entry that was not stored.
175pub struct StoreError<T: ForeignOwnable> {
176 /// The error that occurred.
177 pub error: Error,
178 /// The entry that was not stored.
179 pub entry: Entry<T>,
180}
181
182impl<T: ForeignOwnable> fmt::Debug for StoreError<T> {
183 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184 f.debug_struct("StoreError")
185 .field("error", &self.error)
186 .finish()
187 }
188}
189
190impl<T: ForeignOwnable> From<StoreError<T>> for Error {
191 #[inline]
192 fn from(value: StoreError<T>) -> Self {
193 value.error
194 }
195}
196
197/// An extensible array backed by a radix tree, mapping `usize` indices to [`Entry`] values.
198///
199/// `T` must be a [`ForeignOwnable`] whose `FOREIGN_ALIGN` is at least 4. The type can be named with
200/// any other `T`, but constructing a value of it fails to compile.
201///
202/// # Ownership
203///
204/// When an [`XArray`] is dropped, all stored [`Entry::Pointer`] entries are freed via
205/// [`ForeignOwnable::from_foreign()`]. This differs from the C `xa_destroy()`, which only frees
206/// internal nodes and requires callers to free stored pointers themselves. [`Entry::Int`] entries
207/// are encoded integers with no backing allocation and need no cleanup.
208///
209/// # Examples
210///
211/// ```
212/// use kernel::alloc::{flags, KBox};
213/// use kernel::rxarray::{BorrowedEntry, Entry, XArray6};
214///
215/// let mut xa = XArray6::<KBox<u64>>::new();
216/// assert!(xa.is_empty());
217///
218/// // Store a pointer entry at index 1.
219/// let boxed = KBox::new(0xbeef_u64, flags::GFP_KERNEL)?;
220/// xa.store(1, Entry::Pointer(boxed), flags::GFP_KERNEL)?;
221/// match xa.load(1) {
222/// Some(BorrowedEntry::Pointer(val)) => assert_eq!(*val, 0xbeef_u64),
223/// _ => panic!("expected Pointer"),
224/// }
225///
226/// // Store a value entry at index 0.
227/// let old = xa.store(0, Entry::int::<0xdead>(), flags::GFP_KERNEL)?;
228/// assert!(old.is_none());
229/// assert!(!xa.is_empty());
230///
231/// match xa.load(0) {
232/// Some(BorrowedEntry::Int(v)) => assert_eq!(v, 0xdead),
233/// _ => panic!("expected Int"),
234/// }
235///
236/// let old = xa.store(0, Entry::int::<0xcafe>(), flags::GFP_KERNEL)?;
237/// match old {
238/// Some(Entry::Int(v)) => assert_eq!(v, 0xdead),
239/// _ => panic!("expected old Int"),
240/// }
241///
242/// match xa.erase(0) {
243/// Some(Entry::Int(v)) => assert_eq!(v, 0xcafe),
244/// _ => panic!("expected erased Int"),
245/// }
246/// assert!(xa.erase(1).is_some());
247/// assert!(xa.is_empty());
248///
249/// # Ok::<(), Error>(())
250/// ```
251///
252/// # Invariants
253///
254/// - `T::FOREIGN_ALIGN >= 4`, ensuring pointer entries do not collide with the integer or internal
255/// entry encoding.
256/// - `SHIFT > 0` and `SIZE == 1 << SHIFT`.
257/// - Every slot in every node satisfies the `Slot` invariants.
258/// - Interior levels (level > 0) contain only empty or node slots. Leaf level (level 0) contains
259/// only empty, `Int`, or `Pointer` slots.
260/// - The subtree below every node slot contains at least one of the `Entry` types (`Int` or
261/// `Pointer`).
262pub struct XArray<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize> {
263 root: Node<T, SHIFT, SIZE>,
264}
265
266impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize> Default for XArray<T, SHIFT, SIZE> {
267 fn default() -> Self {
268 Self::new()
269 }
270}
271
272impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize> XArray<T, SHIFT, SIZE> {
273 const fn validate() {
274 const_assert!(SHIFT > 0, "SHIFT must be > 0");
275 const_assert!(SIZE == (1 << SHIFT), "SIZE != 1 << SHIFT");
276 const_assert!(
277 T::FOREIGN_ALIGN >= 4,
278 "ForeignOwnable pointers must be 4-byte aligned"
279 );
280 }
281
282 /// Creates a new empty [`XArray`].
283 pub const fn new() -> Self {
284 Self::validate();
285 // INVARIANT:
286 // - `Self::validate` checks `T::FOREIGN_ALIGN >= 4`, `SHIFT > 0` and `SIZE == 1 << SHIFT`
287 // at compile time.
288 // - `Node::new` fills every slot with `Slot::EMPTY`, which satisfies the empty-slot case
289 // of the `Slot` invariants.
290 // - Every slot is empty, and an empty slot is valid at any level.
291 XArray { root: Node::new() }
292 }
293
294 /// Returns the number of levels in the tree.
295 const fn levels() -> usize {
296 (usize::BITS as usize).div_ceil(SHIFT)
297 }
298
299 /// Returns `true` if the tree contains no entries.
300 ///
301 /// Scanning the root node suffices: by the type invariants, every node slot in it leads to at
302 /// least one entry.
303 pub fn is_empty(&self) -> bool {
304 self.root.is_empty()
305 }
306
307 /// Erases the entry at `index`.
308 ///
309 /// Returns the previous entry, or [`None`] if the slot was empty. Empty intermediate nodes are
310 /// freed during traversal.
311 pub fn erase(&mut self, index: usize) -> Option<Entry<T>> {
312 self.root.erase(index, Self::levels() - 1)
313 }
314
315 /// Stores an entry at `index`.
316 ///
317 /// Returns the previous entry, or [`None`] if the slot was empty.
318 ///
319 /// # Errors
320 ///
321 /// Returns a [`StoreError`] carrying the entry back to the caller, with error [`ENOMEM`] if
322 /// a new intermediate node cannot be allocated. A failed stored leaves the tree unchanged. For
323 /// C callers, [`EINVAL`] in case of tree corruption detection.
324 pub fn store(
325 &mut self,
326 index: usize,
327 entry: Entry<T>,
328 flags: Flags,
329 ) -> Result<Option<Entry<T>>, StoreError<T>> {
330 self.root.store(index, entry, Self::levels() - 1, flags)
331 }
332
333 /// Loads the entry at `index`.
334 ///
335 /// Returns [`None`] if the slot is empty. The returned [`BorrowedEntry`] is a value that
336 /// borrows from the array where pointer entries carry `T::Borrowed<'_>` (e.g., `&T` for
337 /// `KBox<T>`), and integer entries carry a copy of the [`Value`].
338 pub fn load(&self, index: usize) -> Option<BorrowedEntry<'_, T>> {
339 self.root.load(index, Self::levels() - 1)
340 }
341
342 /// Loads the entry at `index` for mutation.
343 ///
344 /// Returns [`None`] if the slot is empty. The returned [`BorrowedEntryMut`] is a value that
345 /// borrows from the array where pointer entries carry `T::BorrowedMut<'_>` (e.g., `&mut T` for
346 /// `KBox<T>`), and integer entries carry a copy of the [`Value`].
347 pub fn load_mut(&mut self, index: usize) -> Option<BorrowedEntryMut<'_, T>> {
348 self.root.load_mut(index, Self::levels() - 1)
349 }
350}
351
352/// The internal storage unit: a single `usize` encoding an [`Entry`] or an internal node pointer.
353///
354/// # Invariants
355///
356/// The encoded value `self.0` is one of:
357/// - `0`: the slot is empty.
358/// - An odd value `(v << 1) | 1`: an integer value `v` where `v <= usize::MAX >> 1`.
359/// - An even, non-zero value with bits `1:0 == 0b00`: a valid, non-null pointer previously returned
360/// by [`ForeignOwnable::into_foreign()`].
361/// - An even, non-zero value with bits `1:0 == 0b10` and value > `NODE_THRESHOLD`: a valid pointer
362/// to a live `Node<T, SHIFT, SIZE>` allocation, created by [`Slot::mk_node()`] from
363/// [`KBox::into_raw()`] tagged with `| 2`. The slot owns the [`KBox<Node>`] allocation.
364//
365// All entries with bits `1:0 == 0b10` are internal to the XArray implementation. The encoded value
366// distinguishes sub-types:
367//
368// - Offset 0..=62, encoded 2..=250: sibling entries.
369// The encoded value contains the offset of the canonical slot within the same node (multi-index
370// entries, CONFIG_XARRAY_MULTI).
371//
372// - Logical 256, encoded 1026: retry (XA_RETRY_ENTRY).
373// Tombstone signaling concurrent tree modification; RCU lock-free readers must restart.
374//
375// - Logical 257, encoded 1030: zero (XA_ZERO_ENTRY).
376// Placeholder marking a slot as occupied but logically empty (xa_reserve, XA_FLAGS_TRACK_FREE).
377//
378// - Encoded value > `NODE_THRESHOLD` (4096): node pointers (heap addresses tagged with | 2). Always
379// above this threshold.
380//
381// Note: C error entries (xa_is_err()) also encode as internal entries with values far above this
382// threshold. They are never stored in tree slots, only returned by the XArray state machine API. C
383// callers bypass this assumption; the FFI layer must reject error entries before they reach Rust,
384// where kind() would misclassify them as Node, causing as_node() to dereference an invalid
385// pointer.
386//
387// This implementation only creates node pointers via `mk_node()`. The other sub-types are reserved
388// for future RCU and multi-index support. See include/linux/xarray.h.
389#[repr(transparent)]
390struct Slot<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize>(usize, PhantomData<T>);
391
392impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize> Default for Slot<T, SHIFT, SIZE> {
393 fn default() -> Self {
394 Self::EMPTY
395 }
396}
397
398#[derive(Copy, Clone)]
399enum SlotType {
400 Empty,
401 Pointer,
402 Internal,
403 Node, // Internal with value > NODE_THRESHOLD.
404 Int,
405}
406
407impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize> Slot<T, SHIFT, SIZE> {
408 // INVARIANT: `0` is the encoding for an empty slot.
409 const EMPTY: Self = Slot(0, PhantomData);
410
411 /// Encodes an [`Entry<T>`] into a [`Slot`] for tree storage.
412 fn encode(entry: Entry<T>) -> Self {
413 const_assert!(
414 T::FOREIGN_ALIGN >= 4,
415 "ForeignOwnable pointers must be 4-byte aligned"
416 );
417
418 match entry {
419 Entry::Int(v) => {
420 // INVARIANT: `*v <= usize::MAX >> 1` is guaranteed by `Value` (`Bounded`), so the
421 // shift cannot overflow and the encoded value is odd.
422 Slot((*v << 1) | 1, PhantomData)
423 }
424 Entry::Pointer(p) => {
425 let bits = p.into_foreign() as usize;
426 debug_assert!(bits != 0, "ForeignOwnable returned null");
427 debug_assert!(bits & 3 == 0, "ForeignOwnable pointer not 4-byte aligned");
428 // INVARIANT: `into_foreign()` guarantees a non-null pointer aligned to
429 // `T::FOREIGN_ALIGN`, and `const_assert!(T::FOREIGN_ALIGN >= 4)` above ensures
430 // bits `1:0 == 0b00`.
431 Slot(bits, PhantomData)
432 }
433 }
434 }
435
436 /// Decodes a [`Slot`] into an owned [`Entry<T>`], consuming the slot.
437 ///
438 /// Returns [`None`] for empty slots.
439 fn decode(self) -> Option<Entry<T>> {
440 let slot_type = self.kind();
441 let bits = mem::ManuallyDrop::new(self).0;
442
443 match slot_type {
444 SlotType::Empty => None,
445 // Undo the `(v << 1) | 1` encoding from `Slot::encode`.
446 SlotType::Int => Some(Entry::Int(Value::from_expr(bits >> 1))),
447 SlotType::Node | SlotType::Internal => {
448 debug_assert!(false, "attempt to decode internal/node entry");
449 None
450 }
451 SlotType::Pointer => {
452 // SAFETY:
453 // - By the type invariant, a slot classified `Pointer` holds a pointer returned by
454 // a previous call to `T::into_foreign()`.
455 // - `decode` takes the slot by value, so the caller has already removed it from
456 // the tree, and `ManuallyDrop` suppresses `Slot::drop`. This is therefore the
457 // only `from_foreign` call for this pointer.
458 Some(Entry::Pointer(unsafe {
459 T::from_foreign(bits as *mut c_void)
460 }))
461 }
462 }
463 }
464
465 /// Borrows the entry in this slot without consuming it.
466 ///
467 /// Returns [`None`] for empty slots. Pointer entries are borrowed via
468 /// [`ForeignOwnable::borrow()`].
469 fn borrow(&self) -> Option<BorrowedEntry<'_, T>> {
470 let slot_type = self.kind();
471 let bits = self.0;
472
473 match slot_type {
474 SlotType::Empty => None,
475 // Undo the `(v << 1) | 1` encoding from `Slot::encode`.
476 SlotType::Int => Some(BorrowedEntry::Int(Value::from_expr(bits >> 1))),
477 SlotType::Node | SlotType::Internal => {
478 debug_assert!(false, "attempt to borrow internal/node entry");
479 None
480 }
481 SlotType::Pointer => {
482 // SAFETY:
483 // - By the type invariant, a slot classified `Pointer` holds a pointer returned by
484 // a previous call to `T::into_foreign()`.
485 // - Every path that reaches `from_foreign` for this slot needs ownership of it
486 // (`decode`) or a unique borrow (`Slot::drop`), and reaching either from the
487 // array requires `&mut self` on the `XArray`. Neither can coexist with this
488 // shared borrow, so any `from_foreign` on this pointer happens after the borrow
489 // ends.
490 Some(BorrowedEntry::Pointer(unsafe {
491 T::borrow(bits as *mut c_void)
492 }))
493 }
494 }
495 }
496
497 /// Mutably borrows the entry in this slot without consuming it.
498 ///
499 /// Returns [`None`] for empty slots. Pointer entries are borrowed via
500 /// [`ForeignOwnable::borrow_mut()`]; integer entries are returned by value.
501 fn borrow_mut(&mut self) -> Option<BorrowedEntryMut<'_, T>> {
502 let slot_type = self.kind();
503 let bits = self.0;
504
505 match slot_type {
506 SlotType::Empty => None,
507 // Undo the `(v << 1) | 1` encoding from `Slot::encode`.
508 SlotType::Int => Some(BorrowedEntryMut::Int(Value::from_expr(bits >> 1))),
509 SlotType::Node | SlotType::Internal => {
510 debug_assert!(false, "attempt to borrow internal/node entry");
511 None
512 }
513 SlotType::Pointer => {
514 // SAFETY:
515 // - By the type invariant, a slot classified `Pointer` holds a pointer returned by
516 // a previous call to `T::into_foreign()`.
517 // - The returned value borrows `self` mutably, so no other `borrow()` or
518 // `borrow_mut()` on this slot can overlap it, and every path that reaches
519 // `from_foreign` for this slot (`decode`, `Slot::drop`) needs the slot by value
520 // or by unique borrow, so any `from_foreign` on this pointer happens after the
521 // borrow ends.
522 Some(BorrowedEntryMut::Pointer(unsafe {
523 T::borrow_mut(bits as *mut c_void)
524 }))
525 }
526 }
527 }
528
529 // The boundary between internal entries and node pointers.
530 const NODE_THRESHOLD: usize = 4096;
531
532 #[inline]
533 fn kind(&self) -> SlotType {
534 let slot = self.0;
535 if slot == 0 {
536 return SlotType::Empty;
537 }
538 match slot & 3 {
539 2 if slot > Self::NODE_THRESHOLD => SlotType::Node,
540 2 => SlotType::Internal,
541 1 | 3 => SlotType::Int,
542 _ => SlotType::Pointer,
543 }
544 }
545
546 #[inline]
547 fn is_empty(&self) -> bool {
548 matches!(self.kind(), SlotType::Empty)
549 }
550
551 #[inline]
552 fn is_node(&self) -> bool {
553 matches!(self.kind(), SlotType::Node)
554 }
555
556 /// Returns a shared reference to the child node pointed to by this entry, or [`None`] if this
557 /// is not a node slot.
558 fn as_node(&self) -> Option<&Node<T, SHIFT, SIZE>> {
559 if !self.is_node() {
560 return None;
561 }
562 let ptr = (self.0 & !3) as *const Node<T, SHIFT, SIZE>;
563 // SAFETY:
564 // - By the type invariant, a slot classified `Node` holds `KBox::into_raw()` of a valid,
565 // live `KBox<Node<T, SHIFT, SIZE>>` allocation owned by this slot. `& !3` reverses the
566 // `| 2` tag.
567 // - The returned reference borrows `self`, so the slot cannot be modified and the
568 // allocation cannot be freed while it is live.
569 Some(unsafe { &*ptr })
570 }
571
572 /// Returns a mutable reference to the child node pointed to by this entry, or [`None`] if this
573 /// is not a node slot.
574 fn as_node_mut(&mut self) -> Option<&mut Node<T, SHIFT, SIZE>> {
575 if !self.is_node() {
576 return None;
577 }
578 let ptr = (self.0 & !3) as *mut Node<T, SHIFT, SIZE>;
579 // SAFETY:
580 // - By the type invariant, a slot classified `Node` holds `KBox::into_raw()` of a valid,
581 // live `KBox<Node<T, SHIFT, SIZE>>` allocation owned by this slot. `& !3` reverses the
582 // `| 2` tag.
583 // - The returned reference borrows `self` mutably, so no other reference to the allocation
584 // can exist and the slot cannot be modified while it is live.
585 Some(unsafe { &mut *ptr })
586 }
587
588 /// Creates a node slot from a heap-allocated [`Node`].
589 fn mk_node(node: KBox<Node<T, SHIFT, SIZE>>) -> Self {
590 let ptr = KBox::into_raw(node) as usize;
591 debug_assert!(ptr & 3 == 0, "Node pointer not aligned");
592 // INVARIANT: `ptr` owns a live `KBox<Node>` allocation from `into_raw()`, so it is at least
593 // 4-byte aligned (checked above) and `| 2` gives bits `1:0 == 0b10`. Kernel heap addresses
594 // are far above `NODE_THRESHOLD`, so the result classifies as node.
595 Slot(ptr | 2, PhantomData)
596 }
597}
598
599impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize> Drop for Slot<T, SHIFT, SIZE> {
600 fn drop(&mut self) {
601 match self.kind() {
602 SlotType::Pointer => {
603 // SAFETY:
604 // - By the type invariant, a slot classified `Pointer` holds a pointer returned by
605 // a previous call to `T::into_foreign()`.
606 // - Every other `from_foreign` path (`decode`) consumes the slot through
607 // `ManuallyDrop`, which suppresses this destructor, so this is the only
608 // `from_foreign` call for this pointer.
609 drop(unsafe { T::from_foreign(self.0 as *mut c_void) });
610 }
611 SlotType::Node => {
612 let ptr = (self.0 & !3) as *mut Node<T, SHIFT, SIZE>;
613 // SAFETY:
614 // - By the type invariant, a slot classified `Node` holds a pointer produced by
615 // `KBox::into_raw()` in `Slot::mk_node()`, tagged with `| 2`; `& !3` above
616 // reverses the tag.
617 // - The slot is being dropped and passes that ownership to the reconstructed box.
618 // `decode()`, the only other consumer of a slot by value, never accepts node
619 // slots, so this is the only `KBox::from_raw()` for this pointer.
620 //
621 // Dropping the box drops the child's slots in turn, freeing the subtree. The
622 // recursion is bounded by the tree depth.
623 drop(unsafe { KBox::from_raw(ptr) });
624 }
625 SlotType::Internal => {
626 debug_assert!(false, "internal entry must not reach Slot::drop");
627 }
628 _ => {}
629 }
630 }
631}
632
633/// A single node in the radix tree. Each node contains `SIZE` slots, where each slot may be empty,
634/// contain a user entry (integer or pointer), or point to a child node at the next tree level.
635///
636/// # Invariants
637///
638/// - Interior nodes (level > 0): each slot is either `Empty` or a `Node` pointer created by
639/// [`Slot::mk_node()`] from a valid [`KBox<Node<T, SHIFT, SIZE>>`] allocation.
640/// - Leaf nodes (level == 0): each slot is either `Empty`, `Int`, or `Pointer`. No `Node` or
641/// `Internal` slots may appear at level 0.
642struct Node<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize> {
643 slots: [Slot<T, SHIFT, SIZE>; SIZE],
644}
645
646impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize> Node<T, SHIFT, SIZE> {
647 // Bitmask for extracting the slot offset. Equivalent to XA_CHUNK_MASK.
648 const MASK: usize = SIZE - 1;
649
650 const fn new() -> Self {
651 // INVARIANT: every slot is `Slot::EMPTY`, so the node satisfies the type invariants at any
652 // level.
653 Self {
654 slots: [const { Slot::EMPTY }; SIZE],
655 }
656 }
657
658 /// Extracts the slot index for `index` at the given tree `level`.
659 ///
660 /// Equivalent to `get_offset()` (see `lib/xarray.c`).
661 #[inline]
662 fn slot_index(index: usize, level: usize) -> usize {
663 (index >> (level * SHIFT)) & Self::MASK
664 }
665
666 /// Returns `true` if every slot in this node is empty.
667 fn is_empty(&self) -> bool {
668 self.slots.iter().all(|slot| slot.is_empty())
669 }
670
671 /// Erases the entry at `index`.
672 ///
673 /// Returns the previous entry, or [`None`] if the slot was empty. Frees empty intermediate
674 /// nodes on the way back up.
675 fn erase(&mut self, index: usize, level: usize) -> Option<Entry<T>> {
676 let slot_index = Self::slot_index(index, level);
677 let slot = &mut self.slots[slot_index];
678 if level == 0 {
679 debug_assert!(!slot.is_node(), "Found node pointer at leaf level");
680 // INVARIANT: `mem::take` leaves `Slot::EMPTY` behind, which is permitted at leaf level.
681 let old = mem::take(slot);
682 return old.decode();
683 }
684
685 if let Some(child) = slot.as_node_mut() {
686 let old_value = child.erase(index, level - 1);
687 if child.is_empty() {
688 // INVARIANT: `mem::take` leaves `Slot::EMPTY` behind, which is permitted at
689 // interior level. Dropping the taken slot frees the child node.
690 drop(mem::take(slot));
691 }
692 old_value
693 } else {
694 // Values at intermediate levels indicate tree corruption.
695 debug_assert!(slot.is_empty(), "Non-null non-node entry");
696 None
697 }
698 }
699
700 /// Builds an unlinked subtree that holds `entry` at `index`, from `level` down to leaf.
701 ///
702 /// A failed node allocation at any level returns the [`StoreError`] carrying `entry`, and the
703 /// nodes built so far are dropped automatically on the way out. The caller links the subtree
704 /// into the main tree only after the whole build has succeeded.
705 fn mk_subtree(
706 index: usize,
707 entry: Entry<T>,
708 level: usize,
709 flags: Flags,
710 ) -> Result<KBox<Self>, StoreError<T>> {
711 let mut node = match KBox::new(Self::new(), flags) {
712 Ok(node) => node,
713 Err(error) => {
714 return Err(StoreError {
715 error: error.into(),
716 entry,
717 })
718 }
719 };
720 let slot_index = Self::slot_index(index, level);
721 if level == 0 {
722 // INVARIANT: `Slot::encode` returns an `Int` or `Pointer` slot, both of which are
723 // permitted at leaf level.
724 node.slots[slot_index] = Slot::encode(entry);
725 } else {
726 let child_node = Self::mk_subtree(index, entry, level - 1, flags)?;
727 // INVARIANT: `Slot::mk_node` returns a node slot holding a valid `KBox<Node>`, which
728 // is permitted at interior level. The child subtree holds `entry` at its leaf level.
729 node.slots[slot_index] = Slot::mk_node(child_node);
730 }
731 Ok(node)
732 }
733
734 /// Stores `entry` at `index`, allocating intermediate nodes as needed.
735 ///
736 /// Returns the previous entry, or [`None`] if the slot was empty.
737 fn store(
738 &mut self,
739 index: usize,
740 entry: Entry<T>,
741 level: usize,
742 flags: Flags,
743 ) -> Result<Option<Entry<T>>, StoreError<T>> {
744 let slot_index = Self::slot_index(index, level);
745 let slot = &mut self.slots[slot_index];
746 if level == 0 {
747 debug_assert!(!slot.is_node(), "Found node pointer at leaf level");
748 // INVARIANT: `Slot::encode` returns an `Int` or `Pointer` slot, both of which are
749 // permitted at leaf level.
750 let old = mem::replace(slot, Slot::encode(entry));
751 return Ok(old.decode());
752 }
753
754 if slot.is_empty() {
755 // Link the subtree only after every allocation has succeeded. A failed allocation drops
756 // the partial subtree and leaves the main tree untouched.
757 let child_node = Self::mk_subtree(index, entry, level - 1, flags)?;
758 // INVARIANT: `Slot::mk_node` returns a node slot holding a valid `KBox<Node>`, which
759 // is permitted at interior level. The subtree holds `entry` at its leaf level.
760 *slot = Slot::mk_node(child_node);
761 return Ok(None);
762 }
763
764 let Some(child_node) = slot.as_node_mut() else {
765 // Unreachable unless the tree is corrupt. Rust type safety prevents this; C callers
766 // bypass that guarantee, so the FFI layer must ensure tree integrity before reaching
767 // this path.
768 debug_assert!(false, "Non-null non-node entry");
769 return Err(StoreError {
770 error: EINVAL,
771 entry,
772 });
773 };
774 // Any code after this call would block tail-call elimination.
775 child_node.store(index, entry, level - 1, flags)
776 }
777
778 /// Loads the entry at `index`.
779 ///
780 /// Returns a borrowed view of the entry, or [`None`] if the slot is empty.
781 fn load(&self, index: usize, level: usize) -> Option<BorrowedEntry<'_, T>> {
782 let slot_index = Self::slot_index(index, level);
783 let slot = &self.slots[slot_index];
784 if level == 0 {
785 debug_assert!(!slot.is_node(), "Found node pointer at leaf level");
786 return slot.borrow();
787 }
788
789 // Values at intermediate levels indicate tree corruption: trap when debug assertions are
790 // enabled, load as absent otherwise. Same shape as `load_mut()`, where the borrow checker
791 // constraints it.
792 debug_assert!(slot.is_node() || slot.is_empty(), "Non-null non-node entry");
793 slot.as_node()?.load(index, level - 1)
794 }
795
796 /// Loads the entry at `index` for mutation.
797 ///
798 /// Returns [`None`] if the slot is empty.
799 fn load_mut(&mut self, index: usize, level: usize) -> Option<BorrowedEntryMut<'_, T>> {
800 let slot_index = Self::slot_index(index, level);
801 let slot = &mut self.slots[slot_index];
802 if level == 0 {
803 debug_assert!(!slot.is_node(), "Found node pointer at leaf level");
804 return slot.borrow_mut();
805 }
806
807 // Values at intermediate levels indicate tree corruption: trap when debug assertions are
808 // enabled, load as absent otherwise.
809 debug_assert!(slot.is_node() || slot.is_empty(), "Non-null non-node entry");
810 slot.as_node_mut()?.load_mut(index, level - 1)
811 }
812}
813
814#[macros::kunit_tests(rust_rxarray)]
815mod tests {
816 use super::*;
817 use kernel::alloc::flags;
818
819 // Dispatches a test across all SHIFT/SIZE configurations. Default arm passes <T, SHIFT, SIZE>
820 // with T = KBox<u64>; `ptr` arm passes <SHIFT, SIZE> only for pointer tests that must construct
821 // KBox<u64> values because ForeignOwnable has no constructor, so T must be concrete.
822 macro_rules! for_each_xarray {
823 ($fn:ident) => {
824 $fn::<KBox<u64>, 4, 16>();
825 $fn::<KBox<u64>, 6, 64>();
826 };
827 (ptr, $fn:ident) => {
828 $fn::<4, 16>();
829 $fn::<6, 64>();
830 };
831 }
832
833 // `XArray` carries no explicit `Send`/`Sync` impl: the `PhantomData<T>` in `Slot` makes the
834 // auto-derived bounds follow `T`. These assertions fail to compile if that ever stops holding.
835 const fn assert_send<T: Send>() {}
836 const fn assert_sync<T: Sync>() {}
837
838 fn assert_auto_traits_impl<
839 T: ForeignOwnable + Send + Sync,
840 const SHIFT: usize,
841 const SIZE: usize,
842 >() {
843 assert_send::<XArray<T, SHIFT, SIZE>>();
844 assert_sync::<XArray<T, SHIFT, SIZE>>();
845 }
846
847 #[test]
848 fn assert_auto_traits() {
849 for_each_xarray!(assert_auto_traits_impl);
850 }
851
852 fn new_is_empty_impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize>() {
853 let xa = XArray::<T, SHIFT, SIZE>::new();
854 assert!(xa.is_empty());
855 assert!(xa.load(0).is_none());
856 assert!(xa.load(usize::MAX).is_none());
857 }
858
859 #[test]
860 fn new_is_empty() {
861 for_each_xarray!(new_is_empty_impl);
862 }
863
864 fn store_load_value_impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize>() {
865 let mut xa = XArray::<T, SHIFT, SIZE>::new();
866 let old = xa.store(0, Entry::int::<137>(), flags::GFP_KERNEL).unwrap();
867 assert!(old.is_none());
868 assert!(!xa.is_empty());
869
870 match xa.load(0) {
871 Some(BorrowedEntry::Int(v)) => assert_eq!(v, 137),
872 _ => panic!("expected Int"),
873 };
874 }
875
876 #[test]
877 fn store_load_value() {
878 for_each_xarray!(store_load_value_impl);
879 }
880
881 fn overwrite_value_impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize>() {
882 let mut xa = XArray::<T, SHIFT, SIZE>::new();
883 xa.store(137, Entry::int::<1001>(), flags::GFP_KERNEL)
884 .unwrap();
885 let old = xa
886 .store(137, Entry::int::<2002>(), flags::GFP_KERNEL)
887 .unwrap();
888
889 match old {
890 Some(Entry::Int(v)) => assert_eq!(v, 1001),
891 _ => panic!("expected old Int"),
892 }
893 match xa.load(137) {
894 Some(BorrowedEntry::Int(v)) => assert_eq!(v, 2002),
895 _ => panic!("expected Int"),
896 };
897 }
898
899 #[test]
900 fn overwrite_value() {
901 for_each_xarray!(overwrite_value_impl);
902 }
903
904 fn erase_value_impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize>() {
905 let mut xa = XArray::<T, SHIFT, SIZE>::new();
906 xa.store(137, Entry::int::<1001>(), flags::GFP_KERNEL)
907 .unwrap();
908 xa.store(138, Entry::int::<1002>(), flags::GFP_KERNEL)
909 .unwrap();
910 xa.store(139, Entry::int::<1003>(), flags::GFP_KERNEL)
911 .unwrap();
912
913 let old = xa.erase(138);
914 match old {
915 Some(Entry::Int(v)) => assert_eq!(v, 1002),
916 _ => panic!("expected erased Int"),
917 }
918 assert!(xa.load(138).is_none());
919
920 match xa.load(137) {
921 Some(BorrowedEntry::Int(v)) => assert_eq!(v, 1001),
922 _ => panic!("expected Int at neighbor"),
923 }
924 match xa.load(139) {
925 Some(BorrowedEntry::Int(v)) => assert_eq!(v, 1003),
926 _ => panic!("expected Int at neighbor"),
927 };
928 }
929
930 #[test]
931 fn erase_value() {
932 for_each_xarray!(erase_value_impl);
933 }
934
935 // Two paths: (1) empty tree with no nodes allocated, (2) intermediate nodes exist but the
936 // target leaf slot was never stored.
937 fn erase_nonexistent_impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize>() {
938 let mut xa = XArray::<T, SHIFT, SIZE>::new();
939 assert!(xa.erase(999).is_none());
940
941 // Intermediate nodes exist for index 0; index 1 shares the same leaf node but its slot was
942 // never populated.
943 xa.store(0, Entry::int::<1>(), flags::GFP_KERNEL).unwrap();
944 assert!(xa.erase(1).is_none());
945 match xa.load(0) {
946 Some(BorrowedEntry::Int(v)) => assert_eq!(v, 1),
947 _ => panic!("expected Int after erasing neighbor"),
948 };
949 }
950
951 #[test]
952 fn erase_nonexistent() {
953 for_each_xarray!(erase_nonexistent_impl);
954 }
955
956 // After erase frees intermediate nodes, re-store at the same index must re-allocate them.
957 fn erase_and_restore_impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize>() {
958 let mut xa = XArray::<T, SHIFT, SIZE>::new();
959 xa.store(137, Entry::int::<1001>(), flags::GFP_KERNEL)
960 .unwrap();
961
962 let erased = xa.erase(137);
963 match erased {
964 Some(Entry::Int(v)) => assert_eq!(v, 1001),
965 _ => panic!("expected erased Int"),
966 }
967 assert!(xa.load(137).is_none());
968
969 let old = xa
970 .store(137, Entry::int::<2002>(), flags::GFP_KERNEL)
971 .unwrap();
972 assert!(old.is_none());
973 match xa.load(137) {
974 Some(BorrowedEntry::Int(v)) => assert_eq!(v, 2002),
975 _ => panic!("expected Int"),
976 };
977 }
978
979 #[test]
980 fn erase_and_restore() {
981 for_each_xarray!(erase_and_restore_impl);
982 }
983
984 // Stores at node boundaries to exercise tree structure:
985 // - SIZE-1: last slot in the first leaf node.
986 // - SIZE: first index requiring a second leaf node.
987 // - SIZE*SIZE-1: last index in the first level-1 subtree.
988 // - SIZE*SIZE: first index requiring a third tree level.
989 fn store_at_boundaries_impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize>() {
990 let mut xa = XArray::<T, SHIFT, SIZE>::new();
991 xa.store(SIZE - 1, Entry::int::<0xA>(), flags::GFP_KERNEL)
992 .unwrap();
993 xa.store(SIZE, Entry::int::<0xB>(), flags::GFP_KERNEL)
994 .unwrap();
995 xa.store(SIZE * SIZE - 1, Entry::int::<0xC>(), flags::GFP_KERNEL)
996 .unwrap();
997 xa.store(SIZE * SIZE, Entry::int::<0xD>(), flags::GFP_KERNEL)
998 .unwrap();
999
1000 match xa.load(SIZE - 1) {
1001 Some(BorrowedEntry::Int(v)) => assert_eq!(v, 0xA),
1002 _ => panic!("expected Int at SIZE-1"),
1003 }
1004 match xa.load(SIZE) {
1005 Some(BorrowedEntry::Int(v)) => assert_eq!(v, 0xB),
1006 _ => panic!("expected Int at SIZE"),
1007 }
1008 match xa.load(SIZE * SIZE - 1) {
1009 Some(BorrowedEntry::Int(v)) => assert_eq!(v, 0xC),
1010 _ => panic!("expected Int at SIZE*SIZE-1"),
1011 }
1012 match xa.load(SIZE * SIZE) {
1013 Some(BorrowedEntry::Int(v)) => assert_eq!(v, 0xD),
1014 _ => panic!("expected Int at SIZE*SIZE"),
1015 }
1016 assert!(xa.load(0).is_none());
1017 }
1018
1019 #[test]
1020 fn store_at_boundaries() {
1021 for_each_xarray!(store_at_boundaries_impl);
1022 }
1023
1024 // For XArray6 this allocates 10 intermediate nodes; for XArray4, 15. Erasing verifies cascading
1025 // cleanup frees all intermediate nodes back to the root.
1026 fn store_at_max_index_impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize>() {
1027 let mut xa = XArray::<T, SHIFT, SIZE>::new();
1028 xa.store(usize::MAX, Entry::int::<0xFF>(), flags::GFP_KERNEL)
1029 .unwrap();
1030 match xa.load(usize::MAX) {
1031 Some(BorrowedEntry::Int(v)) => assert_eq!(v, 0xFF),
1032 _ => panic!("expected Int at usize::MAX"),
1033 }
1034 assert!(xa.load(0).is_none());
1035
1036 match xa.erase(usize::MAX) {
1037 Some(Entry::Int(v)) => assert_eq!(v, 0xFF),
1038 _ => panic!("expected erased Int at usize::MAX"),
1039 }
1040 assert!(xa.load(usize::MAX).is_none());
1041 assert!(xa.is_empty());
1042 }
1043
1044 #[test]
1045 fn store_at_max_index() {
1046 for_each_xarray!(store_at_max_index_impl);
1047 }
1048
1049 // SIZE*3 entries spanning multiple leaf nodes. Erases even indices and verifies odd indices
1050 // remain intact. Erase return values are not checked here; that path is covered by erase_value.
1051 fn bulk_operations_impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize>() {
1052 let mut xa = XArray::<T, SHIFT, SIZE>::new();
1053 let count = SIZE * 3;
1054
1055 for i in 0..count {
1056 xa.store(i, Entry::try_int(i * 10).unwrap(), flags::GFP_KERNEL)
1057 .unwrap();
1058 }
1059
1060 for i in 0..count {
1061 if i % 2 == 0 {
1062 xa.erase(i);
1063 }
1064 }
1065
1066 for i in 0..count {
1067 match xa.load(i) {
1068 Some(BorrowedEntry::Int(v)) => {
1069 assert_eq!(i % 2, 1);
1070 assert_eq!(v, i * 10);
1071 }
1072 Some(BorrowedEntry::Pointer(_)) => {
1073 panic!("unexpected Pointer in value-only tree")
1074 }
1075 None => assert_eq!(i % 2, 0),
1076 }
1077 }
1078 }
1079
1080 #[test]
1081 fn bulk_operations() {
1082 for_each_xarray!(bulk_operations_impl);
1083 }
1084
1085 // Stores entries in different subtrees (indices 0 and SIZE diverge at level 1), then erases
1086 // both. The second erase cascades cleanup through intermediate nodes that no longer have any
1087 // children.
1088 fn erase_all_restores_empty_impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize>() {
1089 let mut xa = XArray::<T, SHIFT, SIZE>::new();
1090 xa.store(0, Entry::int::<1>(), flags::GFP_KERNEL).unwrap();
1091 xa.store(SIZE, Entry::int::<2>(), flags::GFP_KERNEL)
1092 .unwrap();
1093 assert!(!xa.is_empty());
1094
1095 xa.erase(0);
1096 assert!(!xa.is_empty());
1097 xa.erase(SIZE);
1098 assert!(xa.is_empty());
1099 }
1100
1101 #[test]
1102 fn erase_all_restores_empty() {
1103 for_each_xarray!(erase_all_restores_empty_impl);
1104 }
1105
1106 // Entry::int::<0>() encodes as (0 << 1) | 1 = 1; must not be confused with the empty slot
1107 // encoding (0).
1108 fn value_zero_impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize>() {
1109 let mut xa = XArray::<T, SHIFT, SIZE>::new();
1110 xa.store(0, Entry::int::<0>(), flags::GFP_KERNEL).unwrap();
1111 assert!(!xa.is_empty());
1112 match xa.load(0) {
1113 Some(BorrowedEntry::Int(v)) => assert_eq!(v, 0),
1114 _ => panic!("expected Int"),
1115 }
1116
1117 match xa.erase(0) {
1118 Some(Entry::Int(v)) => assert_eq!(v, 0),
1119 _ => panic!("expected erased Int"),
1120 }
1121 assert!(xa.load(0).is_none());
1122 }
1123
1124 #[test]
1125 fn value_zero() {
1126 for_each_xarray!(value_zero_impl);
1127 }
1128
1129 // Pointer-specific tests (ForeignOwnable path with KBox<u64>).
1130
1131 fn store_load_pointer_impl<const SHIFT: usize, const SIZE: usize>() {
1132 let mut xa = XArray::<KBox<u64>, SHIFT, SIZE>::new();
1133 let boxed = KBox::new(42u64, flags::GFP_KERNEL).unwrap();
1134 let old = xa
1135 .store(0, Entry::Pointer(boxed), flags::GFP_KERNEL)
1136 .unwrap();
1137 assert!(old.is_none());
1138
1139 match xa.load(0) {
1140 Some(BorrowedEntry::Pointer(val)) => assert_eq!(*val, 42u64),
1141 _ => panic!("expected Pointer"),
1142 }
1143 }
1144
1145 #[test]
1146 fn store_load_pointer() {
1147 for_each_xarray!(ptr, store_load_pointer_impl);
1148 }
1149
1150 // Erase returns the owned KBox, verifying that Slot::decode transfers ownership via
1151 // ManuallyDrop without double-free or leak.
1152 fn erase_returns_pointer_impl<const SHIFT: usize, const SIZE: usize>() {
1153 let mut xa = XArray::<KBox<u64>, SHIFT, SIZE>::new();
1154 let boxed = KBox::new(99u64, flags::GFP_KERNEL).unwrap();
1155 xa.store(5, Entry::Pointer(boxed), flags::GFP_KERNEL)
1156 .unwrap();
1157
1158 match xa.erase(5) {
1159 Some(Entry::Pointer(owned)) => assert_eq!(*owned, 99u64),
1160 _ => panic!("expected owned Pointer"),
1161 }
1162 assert!(xa.load(5).is_none());
1163 }
1164
1165 #[test]
1166 fn erase_returns_pointer() {
1167 for_each_xarray!(ptr, erase_returns_pointer_impl);
1168 }
1169
1170 fn overwrite_pointer_with_value_impl<const SHIFT: usize, const SIZE: usize>() {
1171 let mut xa = XArray::<KBox<u64>, SHIFT, SIZE>::new();
1172 let boxed = KBox::new(42u64, flags::GFP_KERNEL).unwrap();
1173 xa.store(0, Entry::Pointer(boxed), flags::GFP_KERNEL)
1174 .unwrap();
1175
1176 let old = xa.store(0, Entry::int::<137>(), flags::GFP_KERNEL).unwrap();
1177 match old {
1178 Some(Entry::Pointer(p)) => assert_eq!(*p, 42u64),
1179 _ => panic!("expected old Pointer"),
1180 }
1181 match xa.load(0) {
1182 Some(BorrowedEntry::Int(v)) => assert_eq!(v, 137),
1183 _ => panic!("expected Int"),
1184 }
1185 }
1186
1187 #[test]
1188 fn overwrite_pointer_with_value() {
1189 for_each_xarray!(ptr, overwrite_pointer_with_value_impl);
1190 }
1191
1192 fn overwrite_value_with_pointer_impl<const SHIFT: usize, const SIZE: usize>() {
1193 let mut xa = XArray::<KBox<u64>, SHIFT, SIZE>::new();
1194 xa.store(0, Entry::int::<137>(), flags::GFP_KERNEL).unwrap();
1195
1196 let boxed = KBox::new(42u64, flags::GFP_KERNEL).unwrap();
1197 let old = xa
1198 .store(0, Entry::Pointer(boxed), flags::GFP_KERNEL)
1199 .unwrap();
1200 match old {
1201 Some(Entry::Int(v)) => assert_eq!(v, 137),
1202 _ => panic!("expected old Int"),
1203 }
1204 match xa.load(0) {
1205 Some(BorrowedEntry::Pointer(val)) => assert_eq!(*val, 42u64),
1206 _ => panic!("expected Pointer"),
1207 }
1208 }
1209
1210 #[test]
1211 fn overwrite_value_with_pointer() {
1212 for_each_xarray!(ptr, overwrite_value_with_pointer_impl);
1213 }
1214
1215 fn mixed_values_and_pointers_impl<const SHIFT: usize, const SIZE: usize>() {
1216 let mut xa = XArray::<KBox<u64>, SHIFT, SIZE>::new();
1217 let boxed = KBox::new(42u64, flags::GFP_KERNEL).unwrap();
1218 xa.store(0, Entry::int::<100>(), flags::GFP_KERNEL).unwrap();
1219 xa.store(1, Entry::Pointer(boxed), flags::GFP_KERNEL)
1220 .unwrap();
1221
1222 match xa.load(0) {
1223 Some(BorrowedEntry::Int(v)) => assert_eq!(v, 100),
1224 _ => panic!("expected Int"),
1225 }
1226 match xa.load(1) {
1227 Some(BorrowedEntry::Pointer(val)) => assert_eq!(*val, 42u64),
1228 _ => panic!("expected Pointer"),
1229 }
1230 }
1231
1232 #[test]
1233 fn mixed_values_and_pointers() {
1234 for_each_xarray!(ptr, mixed_values_and_pointers_impl);
1235 }
1236
1237 // Drops a tree with mixed Int (even indices) and Pointer (odd indices) entries. Correctness
1238 // depends on KASAN/kmemleak detecting leaks or double-frees.
1239 fn drop_frees_pointers_impl<const SHIFT: usize, const SIZE: usize>() {
1240 let mut xa = XArray::<KBox<u64>, SHIFT, SIZE>::new();
1241 let count = SIZE * 2;
1242 for i in 0..count {
1243 if i % 2 == 0 {
1244 xa.store(i, Entry::try_int(i * 10).unwrap(), flags::GFP_KERNEL)
1245 .unwrap();
1246 } else {
1247 let b = KBox::new(i as u64, flags::GFP_KERNEL).unwrap();
1248 xa.store(i, Entry::Pointer(b), flags::GFP_KERNEL).unwrap();
1249 }
1250 }
1251 }
1252
1253 #[test]
1254 fn drop_frees_pointers() {
1255 for_each_xarray!(ptr, drop_frees_pointers_impl);
1256 }
1257
1258 // usize::MAX >> 1 is the maximum valid integer entry. Exercises both compile-time validation
1259 // (Entry::int) and runtime validation (Entry::try_int).
1260 fn value_encoding_boundary_impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize>() {
1261 let mut xa = XArray::<T, SHIFT, SIZE>::new();
1262 let max = usize::MAX >> 1;
1263
1264 // Runtime: try_int accepts max, rejects max+1.
1265 assert!(Entry::<T>::try_int(max).is_some());
1266 assert!(Entry::<T>::try_int(max + 1).is_none());
1267 assert!(Entry::<T>::try_int(usize::MAX).is_none());
1268
1269 // Compile-time: `Entry::int` validates via `const_assert!` in `Bounded::new`.
1270 xa.store(0, Entry::int::<{ usize::MAX >> 1 }>(), flags::GFP_KERNEL)
1271 .unwrap();
1272 match xa.load(0) {
1273 Some(BorrowedEntry::Int(v)) => assert_eq!(v, max),
1274 _ => panic!("expected max value"),
1275 };
1276 }
1277
1278 #[test]
1279 fn value_encoding_boundary() {
1280 for_each_xarray!(value_encoding_boundary_impl);
1281 }
1282
1283 fn overwrite_pointer_with_pointer_impl<const SHIFT: usize, const SIZE: usize>() {
1284 let mut xa = XArray::<KBox<u64>, SHIFT, SIZE>::new();
1285 let first = KBox::new(42u64, flags::GFP_KERNEL).unwrap();
1286 xa.store(0, Entry::Pointer(first), flags::GFP_KERNEL)
1287 .unwrap();
1288
1289 let second = KBox::new(99u64, flags::GFP_KERNEL).unwrap();
1290 let old = xa
1291 .store(0, Entry::Pointer(second), flags::GFP_KERNEL)
1292 .unwrap();
1293 match old {
1294 Some(Entry::Pointer(p)) => assert_eq!(*p, 42u64),
1295 _ => panic!("expected old Pointer"),
1296 }
1297 match xa.load(0) {
1298 Some(BorrowedEntry::Pointer(val)) => assert_eq!(*val, 99u64),
1299 _ => panic!("expected new Pointer"),
1300 }
1301 }
1302
1303 #[test]
1304 fn overwrite_pointer_with_pointer() {
1305 for_each_xarray!(ptr, overwrite_pointer_with_pointer_impl);
1306 }
1307
1308 fn erase_at_boundaries_impl<T: ForeignOwnable, const SHIFT: usize, const SIZE: usize>() {
1309 let mut xa = XArray::<T, SHIFT, SIZE>::new();
1310 xa.store(SIZE - 1, Entry::int::<0xA>(), flags::GFP_KERNEL)
1311 .unwrap();
1312 xa.store(SIZE, Entry::int::<0xB>(), flags::GFP_KERNEL)
1313 .unwrap();
1314 xa.store(SIZE * SIZE - 1, Entry::int::<0xC>(), flags::GFP_KERNEL)
1315 .unwrap();
1316 xa.store(SIZE * SIZE, Entry::int::<0xD>(), flags::GFP_KERNEL)
1317 .unwrap();
1318
1319 match xa.erase(SIZE * SIZE) {
1320 Some(Entry::Int(v)) => assert_eq!(v, 0xD),
1321 _ => panic!("expected erased Int at SIZE*SIZE"),
1322 }
1323 match xa.erase(SIZE * SIZE - 1) {
1324 Some(Entry::Int(v)) => assert_eq!(v, 0xC),
1325 _ => panic!("expected erased Int at SIZE*SIZE-1"),
1326 }
1327 match xa.erase(SIZE) {
1328 Some(Entry::Int(v)) => assert_eq!(v, 0xB),
1329 _ => panic!("expected erased Int at SIZE"),
1330 }
1331 match xa.erase(SIZE - 1) {
1332 Some(Entry::Int(v)) => assert_eq!(v, 0xA),
1333 _ => panic!("expected erased Int at SIZE-1"),
1334 }
1335 assert!(xa.is_empty());
1336 }
1337
1338 #[test]
1339 fn erase_at_boundaries() {
1340 for_each_xarray!(erase_at_boundaries_impl);
1341 }
1342
1343 // Erasing the sole pointer must return the owned KBox and free all intermediate nodes.
1344 fn erase_last_pointer_cascading_impl<const SHIFT: usize, const SIZE: usize>() {
1345 let mut xa = XArray::<KBox<u64>, SHIFT, SIZE>::new();
1346 let boxed = KBox::new(777u64, flags::GFP_KERNEL).unwrap();
1347 xa.store(0, Entry::Pointer(boxed), flags::GFP_KERNEL)
1348 .unwrap();
1349
1350 match xa.erase(0) {
1351 Some(Entry::Pointer(p)) => assert_eq!(*p, 777u64),
1352 _ => panic!("expected owned Pointer"),
1353 }
1354 assert!(xa.is_empty());
1355 }
1356
1357 #[test]
1358 fn erase_last_pointer_cascading() {
1359 for_each_xarray!(ptr, erase_last_pointer_cascading_impl);
1360 }
1361
1362 fn load_mut_entries_impl<const SHIFT: usize, const SIZE: usize>() {
1363 let mut xa = XArray::<KBox<u64>, SHIFT, SIZE>::new();
1364 assert!(xa.load_mut(0).is_none());
1365
1366 let boxed = KBox::new(137u64, flags::GFP_KERNEL).unwrap();
1367 xa.store(0, Entry::Pointer(boxed), flags::GFP_KERNEL)
1368 .unwrap();
1369 xa.store(1, Entry::int::<137>(), flags::GFP_KERNEL).unwrap();
1370
1371 match xa.load_mut(0) {
1372 Some(BorrowedEntryMut::Pointer(val)) => *val = 131u64,
1373 _ => panic!("expected Pointer"),
1374 }
1375 match xa.load(0) {
1376 Some(BorrowedEntry::Pointer(val)) => assert_eq!(*val, 131u64),
1377 _ => panic!("expected Pointer"),
1378 }
1379 match xa.load_mut(1) {
1380 Some(BorrowedEntryMut::Int(val)) => assert_eq!(val, 137),
1381 _ => panic!("expected Int"),
1382 }
1383 }
1384
1385 #[test]
1386 fn load_mut_entries() {
1387 for_each_xarray!(ptr, load_mut_entries_impl);
1388 }
1389
1390 fn store_error_impl<const SHIFT: usize, const SIZE: usize>() {
1391 let err = StoreError {
1392 error: ENOMEM,
1393 entry: Entry::<KBox<u64>>::int::<137>(),
1394 };
1395 match &err.entry {
1396 Entry::Int(value) => assert_eq!(*value, 137),
1397 _ => panic!("expected Int"),
1398 }
1399 let e: Error = err.into();
1400 assert_eq!(e.to_errno(), ENOMEM.to_errno());
1401 }
1402
1403 #[test]
1404 fn store_error() {
1405 for_each_xarray!(ptr, store_error_impl);
1406 }
1407}