[PATCH v9 2/2] rust: xarray: Add an abstraction for XArray

Tamir Duberstein posted 2 patches 3 days, 4 hours ago
There is a newer version of this series
[PATCH v9 2/2] rust: xarray: Add an abstraction for XArray
Posted by Tamir Duberstein 3 days, 4 hours ago
`XArray` is an efficient sparse array of pointers. Add a Rust
abstraction for this type.

This implementation bounds the element type on `ForeignOwnable` and
requires explicit locking for all operations. Future work may leverage
RCU to enable lockless operation.

Signed-off-by: Tamir Duberstein <tamird@gmail.com>
---
 rust/bindings/bindings_helper.h |   6 +
 rust/helpers/helpers.c          |   1 +
 rust/helpers/xarray.c           |  28 +++++
 rust/kernel/alloc.rs            |   5 +
 rust/kernel/lib.rs              |   1 +
 rust/kernel/xarray.rs           | 259 ++++++++++++++++++++++++++++++++++++++++
 6 files changed, 300 insertions(+)

diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index a80783fcbe042a28124620ce4710ed5bdc2d0790..131ed24629c7411419c99ebd01727fd17ee4f802 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -21,6 +21,7 @@
 #include <linux/slab.h>
 #include <linux/wait.h>
 #include <linux/workqueue.h>
+#include <linux/xarray.h>
 
 /* `bindgen` gets confused at certain things. */
 const size_t RUST_CONST_HELPER_ARCH_SLAB_MINALIGN = ARCH_SLAB_MINALIGN;
@@ -33,3 +34,8 @@ const gfp_t RUST_CONST_HELPER___GFP_ZERO = __GFP_ZERO;
 const gfp_t RUST_CONST_HELPER___GFP_HIGHMEM = ___GFP_HIGHMEM;
 const gfp_t RUST_CONST_HELPER___GFP_NOWARN = ___GFP_NOWARN;
 const blk_features_t RUST_CONST_HELPER_BLK_FEAT_ROTATIONAL = BLK_FEAT_ROTATIONAL;
+
+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;
diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c
index 20a0c69d5cc7b8775f505f94d06d06379a4583b0..22c3c9fb6298b0a3b59b1290976e927ef0bc9b8e 100644
--- a/rust/helpers/helpers.c
+++ b/rust/helpers/helpers.c
@@ -25,3 +25,4 @@
 #include "vmalloc.c"
 #include "wait.c"
 #include "workqueue.c"
+#include "xarray.c"
diff --git a/rust/helpers/xarray.c b/rust/helpers/xarray.c
new file mode 100644
index 0000000000000000000000000000000000000000..60b299f11451d2c4a75e50e25dec4dac13f143f4
--- /dev/null
+++ b/rust/helpers/xarray.c
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/xarray.h>
+
+int rust_helper_xa_err(void *entry)
+{
+	return xa_err(entry);
+}
+
+void rust_helper_xa_init_flags(struct xarray *xa, gfp_t flags)
+{
+	return xa_init_flags(xa, flags);
+}
+
+int rust_helper_xa_trylock(struct xarray *xa)
+{
+	return xa_trylock(xa);
+}
+
+void rust_helper_xa_lock(struct xarray *xa)
+{
+	return xa_lock(xa);
+}
+
+void rust_helper_xa_unlock(struct xarray *xa)
+{
+	return xa_unlock(xa);
+}
diff --git a/rust/kernel/alloc.rs b/rust/kernel/alloc.rs
index f2f7f3a53d298cf899e062346202ba3285ce3676..be9f164ece2e0fe71143e0201247d2b70c193c51 100644
--- a/rust/kernel/alloc.rs
+++ b/rust/kernel/alloc.rs
@@ -39,6 +39,11 @@
 pub struct Flags(u32);
 
 impl Flags {
+    /// Get a flags value with all bits unset.
+    pub fn empty() -> Self {
+        Self(0)
+    }
+
     /// Get the raw representation of this flag.
     pub(crate) fn as_raw(self) -> u32 {
         self.0
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index bf8d7f841f9425d19a24f3910929839cfe705c7f..6f301ad7f6fbc57b09dcd6a6e90bd87f29df948f 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -60,6 +60,7 @@
 pub mod types;
 pub mod uaccess;
 pub mod workqueue;
+pub mod xarray;
 
 #[doc(hidden)]
 pub use bindings;
diff --git a/rust/kernel/xarray.rs b/rust/kernel/xarray.rs
new file mode 100644
index 0000000000000000000000000000000000000000..57dbdb0a82623e3de779e26525e7dd27ce4db712
--- /dev/null
+++ b/rust/kernel/xarray.rs
@@ -0,0 +1,259 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! XArray abstraction.
+//!
+//! C header: [`include/linux/xarray.h`](srctree/include/linux/xarray.h)
+
+use core::pin::Pin;
+
+use crate::{
+    alloc, bindings, build_assert, build_error,
+    error::{Error, Result},
+    init::PinInit,
+    pin_init,
+    types::{ForeignOwnable, Opaque},
+};
+use core::{iter, marker::PhantomData, mem};
+use macros::{pin_data, pinned_drop};
+
+/// An array which efficiently maps sparse integer indices to owned objects.
+///
+/// This is similar to a [`crate::alloc::kvec::Vec<Option<T>>`], but more efficient when there are
+/// holes in the index space, and can be efficiently grown.
+///
+/// # Invariants
+///
+/// `self.xa` is always an initialized and valid [`bindings::xarray`] whose entries are either
+/// `XA_ZERO_ENTRY` or came from `T::into_foreign`.
+///
+/// # Examples
+///
+/// ```rust
+/// use kernel::alloc::KBox;
+/// use kernel::xarray::{AllocKind, XArray};
+///
+/// let xa = KBox::pin_init(XArray::new(AllocKind::Alloc1), GFP_KERNEL)?;
+///
+/// let dead = KBox::new(0xdead, GFP_KERNEL)?;
+/// let beef = KBox::new(0xbeef, GFP_KERNEL)?;
+///
+/// let mut guard = xa.lock();
+///
+/// assert_eq!(guard.get(0), None);
+///
+/// assert_eq!(guard.store(0, dead, GFP_KERNEL).unwrap().as_deref(), None);
+/// assert_eq!(guard.get(0).copied(), Some(0xdead));
+///
+/// *guard.get_mut(0).unwrap() = 0xffff;
+/// assert_eq!(guard.get(0).copied(), Some(0xffff));
+///
+/// assert_eq!(guard.store(0, beef, GFP_KERNEL).unwrap().as_deref().copied(), Some(0xffff));
+/// assert_eq!(guard.get(0).copied(), Some(0xbeef));
+///
+/// guard.remove(0);
+/// assert_eq!(guard.get(0), None);
+///
+/// # Ok::<(), Error>(())
+/// ```
+#[pin_data(PinnedDrop)]
+pub struct XArray<T: ForeignOwnable> {
+    #[pin]
+    xa: Opaque<bindings::xarray>,
+    _p: PhantomData<T>,
+}
+
+#[pinned_drop]
+impl<T: ForeignOwnable> PinnedDrop for XArray<T> {
+    fn drop(self: Pin<&mut Self>) {
+        self.iter().for_each(|ptr| {
+            let ptr = ptr.as_ptr();
+            // SAFETY: `ptr` came from `T::into_foreign`.
+            //
+            // INVARIANT: we own the only reference to the array which is being dropped so the
+            // broken invariant is not observable on function exit.
+            drop(unsafe { T::from_foreign(ptr) })
+        });
+
+        // SAFETY: `self.xa` is always valid by the type invariant.
+        unsafe { bindings::xa_destroy(self.xa.get()) };
+    }
+}
+
+/// Flags passed to [`XArray::new`] to configure the array's allocation tracking behavior.
+pub enum AllocKind {
+    /// Consider the first element to be at index 0.
+    Alloc,
+    /// Consider the first element to be at index 1.
+    Alloc1,
+}
+
+impl<T: ForeignOwnable> XArray<T> {
+    /// Creates a new [`XArray`].
+    pub fn new(kind: AllocKind) -> impl PinInit<Self> {
+        let flags = match kind {
+            AllocKind::Alloc => bindings::XA_FLAGS_ALLOC,
+            AllocKind::Alloc1 => bindings::XA_FLAGS_ALLOC1,
+        };
+        pin_init!(Self {
+            // SAFETY: `xa` is valid while the closure is called.
+            xa <- Opaque::ffi_init(|xa| unsafe {
+                bindings::xa_init_flags(xa, flags)
+            }),
+            _p: PhantomData,
+        })
+    }
+
+    fn iter(&self) -> impl Iterator<Item = core::ptr::NonNull<T::PointedTo>> + '_ {
+        // TODO: Remove when https://lore.kernel.org/all/20240913213041.395655-5-gary@garyguo.net/ is applied.
+        const MIN: core::ffi::c_ulong = core::ffi::c_ulong::MIN;
+        const MAX: core::ffi::c_ulong = core::ffi::c_ulong::MAX;
+
+        let mut index = MIN;
+
+        // SAFETY: `self.xa` is always valid by the type invariant.
+        iter::once(unsafe {
+            bindings::xa_find(self.xa.get(), &mut index, MAX, bindings::XA_PRESENT)
+        })
+        .chain(iter::from_fn(move || {
+            // SAFETY: `self.xa` is always valid by the type invariant.
+            Some(unsafe {
+                bindings::xa_find_after(self.xa.get(), &mut index, MAX, bindings::XA_PRESENT)
+            })
+        }))
+        .map_while(|ptr| core::ptr::NonNull::new(ptr.cast()))
+    }
+
+    /// Attempts to lock the [`XArray`] for exclusive access.
+    pub fn try_lock(&self) -> Option<Guard<'_, T>> {
+        // SAFETY: `self.xa` is always valid by the type invariant.
+        (unsafe { bindings::xa_trylock(self.xa.get()) } != 0).then(|| Guard { xa: self })
+    }
+
+    /// Locks the [`XArray`] for exclusive access.
+    pub fn lock(&self) -> Guard<'_, T> {
+        // SAFETY: `self.xa` is always valid by the type invariant.
+        unsafe { bindings::xa_lock(self.xa.get()) };
+
+        Guard { xa: self }
+    }
+}
+
+/// A lock guard.
+///
+/// The lock is unlocked when the guard goes out of scope.
+#[must_use = "the lock unlocks immediately when the guard is unused"]
+pub struct Guard<'a, T: ForeignOwnable> {
+    xa: &'a XArray<T>,
+}
+
+impl<T: ForeignOwnable> Drop for Guard<'_, T> {
+    fn drop(&mut self) {
+        // SAFETY: `self.xa.xa` is always valid by the type invariant.
+        //
+        // SAFETY: The caller holds the lock, so it is safe to unlock it.
+        unsafe { bindings::xa_unlock(self.xa.xa.get()) };
+    }
+}
+
+// TODO: Remove when https://lore.kernel.org/all/20240913213041.395655-5-gary@garyguo.net/ is applied.
+fn to_index(i: usize) -> core::ffi::c_ulong {
+    i.try_into()
+        .unwrap_or_else(|_| build_error!("cannot convert usize to c_ulong"))
+}
+
+impl<'a, T: ForeignOwnable> Guard<'a, T> {
+    fn load<F, U>(&mut self, index: usize, f: F) -> Option<U>
+    where
+        F: FnOnce(core::ptr::NonNull<T::PointedTo>) -> U,
+    {
+        // SAFETY: `self.xa.xa` is always valid by the type invariant.
+        let ptr = unsafe { bindings::xa_load(self.xa.xa.get(), to_index(index)) };
+        let ptr = core::ptr::NonNull::new(ptr.cast())?;
+        Some(f(ptr))
+    }
+
+    /// Loads an entry from the array.
+    ///
+    /// Returns the entry at the given index.
+    pub fn get(&mut self, index: usize) -> Option<T::Borrowed<'_>> {
+        self.load(index, |ptr| {
+            // SAFETY: `ptr` came from `T::into_foreign`.
+            unsafe { T::borrow(ptr.as_ptr()) }
+        })
+    }
+
+    /// Loads an entry from the array.
+    ///
+    /// Returns the entry at the given index.
+    pub fn get_mut(&mut self, index: usize) -> Option<T::BorrowedMut<'_>> {
+        self.load(index, |ptr| {
+            // SAFETY: `ptr` came from `T::into_foreign`.
+            unsafe { T::borrow_mut(ptr.as_ptr()) }
+        })
+    }
+
+    /// Erases an entry from the array.
+    ///
+    /// Returns the entry which was previously at the given index.
+    pub fn remove(&mut self, index: usize) -> Option<T> {
+        // SAFETY: `self.xa.xa` is always valid by the type invariant.
+        //
+        // SAFETY: The caller holds the lock.
+        let ptr = unsafe { bindings::__xa_erase(self.xa.xa.get(), to_index(index)) }.cast();
+        // SAFETY: `ptr` is either NULL or came from `T::into_foreign`.
+        unsafe { T::try_from_foreign(ptr) }
+    }
+
+    /// Stores an entry in the array.
+    ///
+    /// On success, returns the entry which was previously at the given index.
+    ///
+    /// On failure, returns the entry which was attempted to be stored.
+    pub fn store(
+        &mut self,
+        index: usize,
+        value: T,
+        gfp: alloc::Flags,
+    ) -> Result<Option<T>, (T, Error)> {
+        build_assert!(
+            mem::align_of::<T::PointedTo>() >= 4,
+            "pointers stored in XArray must be 4-byte aligned"
+        );
+        let new = value.into_foreign();
+
+        let old = {
+            let new = new.cast();
+            // SAFETY: `self.xa.xa` is always valid by the type invariant.
+            //
+            // SAFETY: The caller holds the lock.
+            //
+            // INVARIANT: `new` came from `T::into_foreign`.
+            unsafe { bindings::__xa_store(self.xa.xa.get(), to_index(index), new, gfp.as_raw()) }
+        };
+
+        // SAFETY: `__xa_store` returns the old entry at this index on success or `xa_err` if an
+        // error happened.
+        match unsafe { bindings::xa_err(old) } {
+            0 => {
+                let old = old.cast();
+                // SAFETY: `ptr` is either NULL or came from `T::into_foreign`.
+                Ok(unsafe { T::try_from_foreign(old) })
+            }
+            errno => {
+                // SAFETY: `new` came from `T::into_foreign` and `__xa_store` does not take
+                // ownership of the value on error.
+                let value = unsafe { T::from_foreign(new) };
+                Err((value, Error::from_errno(errno)))
+            }
+        }
+    }
+}
+
+// SAFETY: It is safe to send `XArray<T>` to another thread when the underlying `T` is `Send`
+// because XArray is thread-safe and all mutation operations are synchronized.
+unsafe impl<T: ForeignOwnable + Send> Send for XArray<T> {}
+
+// SAFETY: It is safe to send `&XArray<T>` to another thread when the underlying `T` is `Sync`
+// because it effectively means sharing `&T` (which is safe because `T` is `Sync`). Additionally,
+// `T` is `Send` because XArray is thread-safe and all mutation operations are internally locked.
+unsafe impl<T: ForeignOwnable + Send + Sync> Sync for XArray<T> {}

-- 
2.47.0
Re: [PATCH v9 2/2] rust: xarray: Add an abstraction for XArray
Posted by Boqun Feng 2 days, 22 hours ago
On Mon, Nov 18, 2024 at 11:33:36AM -0500, Tamir Duberstein wrote:
[...]
> +
> +/// A lock guard.
> +///
> +/// The lock is unlocked when the guard goes out of scope.
> +#[must_use = "the lock unlocks immediately when the guard is unused"]
> +pub struct Guard<'a, T: ForeignOwnable> {
> +    xa: &'a XArray<T>,
> +}

`Guard` would be `Send` if `XArray<T>` is `Sync`, however, it's
incorrect since `Guard` represents an xa_lock() held, and that's a
spin_lock, so cannot be dropped on another thread/context. `Guard`
should probably be marked as `!Send`. Or am I missing something subtle
here?

Regards,
Boqun

> +
> +impl<T: ForeignOwnable> Drop for Guard<'_, T> {
> +    fn drop(&mut self) {
> +        // SAFETY: `self.xa.xa` is always valid by the type invariant.
> +        //
> +        // SAFETY: The caller holds the lock, so it is safe to unlock it.
> +        unsafe { bindings::xa_unlock(self.xa.xa.get()) };
> +    }
> +}
> +
[...]
> +// SAFETY: It is safe to send `XArray<T>` to another thread when the underlying `T` is `Send`
> +// because XArray is thread-safe and all mutation operations are synchronized.
> +unsafe impl<T: ForeignOwnable + Send> Send for XArray<T> {}
> +
> +// SAFETY: It is safe to send `&XArray<T>` to another thread when the underlying `T` is `Sync`
> +// because it effectively means sharing `&T` (which is safe because `T` is `Sync`). Additionally,
> +// `T` is `Send` because XArray is thread-safe and all mutation operations are internally locked.
> +unsafe impl<T: ForeignOwnable + Send + Sync> Sync for XArray<T> {}
> 
> -- 
> 2.47.0
> 
>
Re: [PATCH v9 2/2] rust: xarray: Add an abstraction for XArray
Posted by Tamir Duberstein 2 days, 4 hours ago
On Mon, Nov 18, 2024 at 5:18 PM Boqun Feng <boqun.feng@gmail.com> wrote:
>
> On Mon, Nov 18, 2024 at 11:33:36AM -0500, Tamir Duberstein wrote:
> [...]
> > +
> > +/// A lock guard.
> > +///
> > +/// The lock is unlocked when the guard goes out of scope.
> > +#[must_use = "the lock unlocks immediately when the guard is unused"]
> > +pub struct Guard<'a, T: ForeignOwnable> {
> > +    xa: &'a XArray<T>,
> > +}
>
> `Guard` would be `Send` if `XArray<T>` is `Sync`, however, it's
> incorrect since `Guard` represents an xa_lock() held, and that's a
> spin_lock, so cannot be dropped on another thread/context. `Guard`
> should probably be marked as `!Send`. Or am I missing something subtle
> here?

I didn't know about this requirement, thanks for calling it out. I
have added `_not_send: PhantomData<*mut ()>` in v10.
Re: [PATCH v9 2/2] rust: xarray: Add an abstraction for XArray
Posted by Alice Ryhl 2 days, 4 hours ago
On Tue, Nov 19, 2024 at 5:24 PM Tamir Duberstein <tamird@gmail.com> wrote:
>
> On Mon, Nov 18, 2024 at 5:18 PM Boqun Feng <boqun.feng@gmail.com> wrote:
> >
> > On Mon, Nov 18, 2024 at 11:33:36AM -0500, Tamir Duberstein wrote:
> > [...]
> > > +
> > > +/// A lock guard.
> > > +///
> > > +/// The lock is unlocked when the guard goes out of scope.
> > > +#[must_use = "the lock unlocks immediately when the guard is unused"]
> > > +pub struct Guard<'a, T: ForeignOwnable> {
> > > +    xa: &'a XArray<T>,
> > > +}
> >
> > `Guard` would be `Send` if `XArray<T>` is `Sync`, however, it's
> > incorrect since `Guard` represents an xa_lock() held, and that's a
> > spin_lock, so cannot be dropped on another thread/context. `Guard`
> > should probably be marked as `!Send`. Or am I missing something subtle
> > here?
>
> I didn't know about this requirement, thanks for calling it out. I
> have added `_not_send: PhantomData<*mut ()>` in v10.

You can use _nts: NotThreadSafe. The type in question has landed in
6.13 and is available in Linus's tree since yesterday.

Alice
Re: [PATCH v9 2/2] rust: xarray: Add an abstraction for XArray
Posted by Tamir Duberstein 2 days, 4 hours ago
On Tue, Nov 19, 2024 at 11:28 AM Alice Ryhl <aliceryhl@google.com> wrote:
>
> On Tue, Nov 19, 2024 at 5:24 PM Tamir Duberstein <tamird@gmail.com> wrote:
> >
> > On Mon, Nov 18, 2024 at 5:18 PM Boqun Feng <boqun.feng@gmail.com> wrote:
> > >
> > > On Mon, Nov 18, 2024 at 11:33:36AM -0500, Tamir Duberstein wrote:
> > > [...]
> > > > +
> > > > +/// A lock guard.
> > > > +///
> > > > +/// The lock is unlocked when the guard goes out of scope.
> > > > +#[must_use = "the lock unlocks immediately when the guard is unused"]
> > > > +pub struct Guard<'a, T: ForeignOwnable> {
> > > > +    xa: &'a XArray<T>,
> > > > +}
> > >
> > > `Guard` would be `Send` if `XArray<T>` is `Sync`, however, it's
> > > incorrect since `Guard` represents an xa_lock() held, and that's a
> > > spin_lock, so cannot be dropped on another thread/context. `Guard`
> > > should probably be marked as `!Send`. Or am I missing something subtle
> > > here?
> >
> > I didn't know about this requirement, thanks for calling it out. I
> > have added `_not_send: PhantomData<*mut ()>` in v10.
>
> You can use _nts: NotThreadSafe. The type in question has landed in
> 6.13 and is available in Linus's tree since yesterday.

TIL, thanks - though it looks like the field name is still `_not_send`.

How do I set the base-commit/deps such that both
https://github.com/torvalds/linux/commit/e7572e5deaf3bc36818f19ba35ac8e0c454c8bac
and https://github.com/Rust-for-Linux/linux/commit/d072acda4862f095ec9056979b654cc06a22cc68
are present, given that the former is in 6.13 and the latter in
rust-next?
Re: [PATCH v9 2/2] rust: xarray: Add an abstraction for XArray
Posted by Alice Ryhl 2 days, 4 hours ago
On Tue, Nov 19, 2024 at 5:40 PM Tamir Duberstein <tamird@gmail.com> wrote:
>
> On Tue, Nov 19, 2024 at 11:28 AM Alice Ryhl <aliceryhl@google.com> wrote:
> >
> > On Tue, Nov 19, 2024 at 5:24 PM Tamir Duberstein <tamird@gmail.com> wrote:
> > >
> > > On Mon, Nov 18, 2024 at 5:18 PM Boqun Feng <boqun.feng@gmail.com> wrote:
> > > >
> > > > On Mon, Nov 18, 2024 at 11:33:36AM -0500, Tamir Duberstein wrote:
> > > > [...]
> > > > > +
> > > > > +/// A lock guard.
> > > > > +///
> > > > > +/// The lock is unlocked when the guard goes out of scope.
> > > > > +#[must_use = "the lock unlocks immediately when the guard is unused"]
> > > > > +pub struct Guard<'a, T: ForeignOwnable> {
> > > > > +    xa: &'a XArray<T>,
> > > > > +}
> > > >
> > > > `Guard` would be `Send` if `XArray<T>` is `Sync`, however, it's
> > > > incorrect since `Guard` represents an xa_lock() held, and that's a
> > > > spin_lock, so cannot be dropped on another thread/context. `Guard`
> > > > should probably be marked as `!Send`. Or am I missing something subtle
> > > > here?
> > >
> > > I didn't know about this requirement, thanks for calling it out. I
> > > have added `_not_send: PhantomData<*mut ()>` in v10.
> >
> > You can use _nts: NotThreadSafe. The type in question has landed in
> > 6.13 and is available in Linus's tree since yesterday.
>
> TIL, thanks - though it looks like the field name is still `_not_send`.
>
> How do I set the base-commit/deps such that both
> https://github.com/torvalds/linux/commit/e7572e5deaf3bc36818f19ba35ac8e0c454c8bac
> and https://github.com/Rust-for-Linux/linux/commit/d072acda4862f095ec9056979b654cc06a22cc68
> are present, given that the former is in 6.13 and the latter in
> rust-next?

Either you merge them yourself or you wait for rust-next to get merged
into Linus's branch.

Alice
Re: [PATCH v9 2/2] rust: xarray: Add an abstraction for XArray
Posted by Tamir Duberstein 2 days, 4 hours ago
On Tue, Nov 19, 2024 at 11:43 AM Alice Ryhl <aliceryhl@google.com> wrote:
>
> On Tue, Nov 19, 2024 at 5:40 PM Tamir Duberstein <tamird@gmail.com> wrote:
> >
> > On Tue, Nov 19, 2024 at 11:28 AM Alice Ryhl <aliceryhl@google.com> wrote:
> > >
> > > On Tue, Nov 19, 2024 at 5:24 PM Tamir Duberstein <tamird@gmail.com> wrote:
> > > >
> > > > On Mon, Nov 18, 2024 at 5:18 PM Boqun Feng <boqun.feng@gmail.com> wrote:
> > > > >
> > > > > On Mon, Nov 18, 2024 at 11:33:36AM -0500, Tamir Duberstein wrote:
> > > > > [...]
> > > > > > +
> > > > > > +/// A lock guard.
> > > > > > +///
> > > > > > +/// The lock is unlocked when the guard goes out of scope.
> > > > > > +#[must_use = "the lock unlocks immediately when the guard is unused"]
> > > > > > +pub struct Guard<'a, T: ForeignOwnable> {
> > > > > > +    xa: &'a XArray<T>,
> > > > > > +}
> > > > >
> > > > > `Guard` would be `Send` if `XArray<T>` is `Sync`, however, it's
> > > > > incorrect since `Guard` represents an xa_lock() held, and that's a
> > > > > spin_lock, so cannot be dropped on another thread/context. `Guard`
> > > > > should probably be marked as `!Send`. Or am I missing something subtle
> > > > > here?
> > > >
> > > > I didn't know about this requirement, thanks for calling it out. I
> > > > have added `_not_send: PhantomData<*mut ()>` in v10.
> > >
> > > You can use _nts: NotThreadSafe. The type in question has landed in
> > > 6.13 and is available in Linus's tree since yesterday.
> >
> > TIL, thanks - though it looks like the field name is still `_not_send`.
> >
> > How do I set the base-commit/deps such that both
> > https://github.com/torvalds/linux/commit/e7572e5deaf3bc36818f19ba35ac8e0c454c8bac
> > and https://github.com/Rust-for-Linux/linux/commit/d072acda4862f095ec9056979b654cc06a22cc68
> > are present, given that the former is in 6.13 and the latter in
> > rust-next?
>
> Either you merge them yourself or you wait for rust-next to get merged
> into Linus's branch.

Sure, I can merge them locally - but how do I properly send a patch
that relies on both to the list?
Re: [PATCH v9 2/2] rust: xarray: Add an abstraction for XArray
Posted by Miguel Ojeda 2 days, 4 hours ago
On Tue, Nov 19, 2024 at 5:51 PM Tamir Duberstein <tamird@gmail.com> wrote:
>
> Sure, I can merge them locally - but how do I properly send a patch
> that relies on both to the list?

You can mention in the cover letter your prerequisites.

Cheers,
Miguel
Re: [PATCH v9 2/2] rust: xarray: Add an abstraction for XArray
Posted by Tamir Duberstein 2 days, 2 hours ago
Looks like there are merge conflicts between v6.13 and rust-next.
What's the usual process for resolution?
Re: [PATCH v9 2/2] rust: xarray: Add an abstraction for XArray
Posted by Miguel Ojeda 2 days, 2 hours ago
On Tue, Nov 19, 2024 at 7:22 PM Tamir Duberstein <tamird@gmail.com> wrote:
>
> Looks like there are merge conflicts between v6.13 and rust-next.
> What's the usual process for resolution?

You can take a look, for instance, at how it was done in linux-next.

(Nit: mainline is not yet v6.13)

Cheers,
Miguel
Re: [PATCH v9 2/2] rust: xarray: Add an abstraction for XArray
Posted by Tamir Duberstein 2 days, 2 hours ago
On Tue, Nov 19, 2024 at 1:40 PM Miguel Ojeda
<miguel.ojeda.sandonis@gmail.com> wrote:
>
> On Tue, Nov 19, 2024 at 7:22 PM Tamir Duberstein <tamird@gmail.com> wrote:
> >
> > Looks like there are merge conflicts between v6.13 and rust-next.
> > What's the usual process for resolution?
>
> You can take a look, for instance, at how it was done in linux-next.
>
> (Nit: mainline is not yet v6.13)

I guess I can just set base-commit to linux-next.