* [PATCH v19 0/3] rust: xarray: Add a minimal abstraction for XArray
@ 2025-04-23 13:54 Tamir Duberstein
2025-04-23 13:54 ` [PATCH v19 1/3] rust: types: add `ForeignOwnable::PointedTo` Tamir Duberstein
` (3 more replies)
0 siblings, 4 replies; 12+ messages in thread
From: Tamir Duberstein @ 2025-04-23 13:54 UTC (permalink / raw)
To: Danilo Krummrich, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Matthew Wilcox, Bjorn Helgaas, Greg Kroah-Hartman,
Rafael J. Wysocki, Tamir Duberstein, FUJITA Tomonori,
Rob Herring (Arm)
Cc: Maíra Canal, Asahi Lina, rust-for-linux, linux-fsdevel,
linux-kernel, linux-pci
This is a reimagining relative to earlier versions[0] by Asahi Lina and
Maíra Canal.
It is needed to support rust-binder, though this version only provides
enough machinery to support rnull.
Link: https://lore.kernel.org/rust-for-linux/20240309235927.168915-2-mcanal@igalia.com/ [0]
---
Changes in v19:
- Rebase on v6.15-rc2.
- Link to v18: https://lore.kernel.org/r/20250221-rust-xarray-bindings-v18-0-cbabe5ddfc32@gmail.com
Changes in v18:
- Add INVARIANT comment in `XArray::new`. (Danilo Krummrich)
- Replace destructuring with field access in
`impl<T> From<StoreError<T>> for Error`. (Danilo Krummrich)
- Use enumerations in SAFETY comments (3x). (Danilo Krummrich)
- Link to v17: https://lore.kernel.org/r/20250218-rust-xarray-bindings-v17-0-f3a99196e538@gmail.com
Changes in v17:
- Drop patch "rust: remove redundant `as _` casts". (Danilo Krummrich)
- Drop trailers for shared commit from configfs series[0]. (Danilo
Krummrich)
- Avoid shadowing expressions with .cast() calls. (Danilo Krummrich)
- Link to v16: https://lore.kernel.org/r/20250207-rust-xarray-bindings-v16-0-256b0cf936bd@gmail.com
Changes in v16:
- Extract prequel patch for `as _` casts. (Danilo Krummrich)
- Improve doc and safety comments. (Boqun Feng)
- Pull trailers for shared commit from configfs series[0]. (Andreas Hindborg, Alice Ryhl, Fiona Behrens)
- Link to configfs series: https://lore.kernel.org/rust-for-linux/20250131-configfs-v1-1-87947611401c@kernel.org/
- Link to v15: https://lore.kernel.org/r/20250206-rust-xarray-bindings-v15-0-a22b5dcacab3@gmail.com
Changes in v15:
- Rebase on v6.14-rc1.
- Add MAINTAINERS entry.
- Link to v14: https://lore.kernel.org/r/20241217-rust-xarray-bindings-v14-0-9fef3cefcb41@gmail.com
Changes in v14:
- Remove TODO made stale by Gary Guo's FFI type series.
- Link: https://lore.kernel.org/all/20240913213041.395655-5-gary@garyguo.net/
- Link to v13: https://lore.kernel.org/r/20241213-rust-xarray-bindings-v13-0-8655164e624f@gmail.com
Changes in v13:
- Replace `bool::then` with `if`. (Miguel Ojeda)
- Replace `match` with `let` + `if`. (Miguel Ojeda)
- Link to v12: https://lore.kernel.org/r/20241212-rust-xarray-bindings-v12-0-59ab9b1f4d2e@gmail.com
Changes in v12:
- Import `core::ptr::NonNull`. (Alice Ryhl)
- Introduce `StoreError` to allow `?` to be used with `Guard::store`.
(Alice Ryhl)
- Replace `{crate,core}::ffi::c_ulong` and clarify TODO with respect to
`usize`. (Alice Ryhl)
- Drop `T: Sync` bound on `impl Sync for XArray<T>`. (Alice Ryhl)
- Reword `Send` and `Sync` safety comments to match the style used in
`lock.rs`. (Alice Ryhl and Andreas
Hindborg)
- Link to v11: https://lore.kernel.org/r/20241203-rust-xarray-bindings-v11-0-58a95d137ec2@gmail.com
Changes in v11:
- Consolidate imports. (Alice Ryhl)
- Use literal `0` rather than `MIN`. (Alice Ryhl)
- Use bulleted list in SAFETY comment. (Alice Ryhl)
- Document (un)locking behavior of `Guard::store`. (Alice Ryhl)
- Document Normal API behavior WRT `XA_ZERO_ENTRY`. (Alice Ryhl)
- Rewrite `unsafe impl Sync` SAFETY comment. (Andreas Hindborg)
- Link to v10: https://lore.kernel.org/r/20241120-rust-xarray-bindings-v10-0-a25b2b0bf582@gmail.com
Changes in v10:
- Guard::get takes &self instead of &mut self. (Andreas Hindborg)
- Guard is !Send. (Boqun Feng)
- Add Inspired-by tags. (Maíra Canal and Asahi Lina)
- Rebase on linux-next, use NotThreadSafe. (Alice Ryhl)
- Link to v9: https://lore.kernel.org/r/20241118-rust-xarray-bindings-v9-0-3219cdb53685@gmail.com
---
Tamir Duberstein (3):
rust: types: add `ForeignOwnable::PointedTo`
rust: xarray: Add an abstraction for XArray
MAINTAINERS: add entry for Rust XArray API
MAINTAINERS | 11 ++
rust/bindings/bindings_helper.h | 6 +
rust/helpers/helpers.c | 1 +
rust/helpers/xarray.c | 28 ++++
rust/kernel/alloc/kbox.rs | 38 +++---
rust/kernel/lib.rs | 1 +
rust/kernel/miscdevice.rs | 10 +-
rust/kernel/pci.rs | 2 +-
rust/kernel/platform.rs | 2 +-
rust/kernel/sync/arc.rs | 21 +--
rust/kernel/types.rs | 46 ++++---
rust/kernel/xarray.rs | 275 ++++++++++++++++++++++++++++++++++++++++
12 files changed, 392 insertions(+), 49 deletions(-)
---
base-commit: 9d7a0577c9db35c4cc52db90bc415ea248446472
change-id: 20241020-rust-xarray-bindings-bef514142968
Best regards,
--
Tamir Duberstein <tamird@gmail.com>
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v19 1/3] rust: types: add `ForeignOwnable::PointedTo`
2025-04-23 13:54 [PATCH v19 0/3] rust: xarray: Add a minimal abstraction for XArray Tamir Duberstein
@ 2025-04-23 13:54 ` Tamir Duberstein
2025-04-30 18:31 ` Gary Guo
2025-04-23 13:54 ` [PATCH v19 2/3] rust: xarray: Add an abstraction for XArray Tamir Duberstein
` (2 subsequent siblings)
3 siblings, 1 reply; 12+ messages in thread
From: Tamir Duberstein @ 2025-04-23 13:54 UTC (permalink / raw)
To: Danilo Krummrich, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Matthew Wilcox, Bjorn Helgaas, Greg Kroah-Hartman,
Rafael J. Wysocki, Tamir Duberstein, FUJITA Tomonori,
Rob Herring (Arm)
Cc: Maíra Canal, Asahi Lina, rust-for-linux, linux-fsdevel,
linux-kernel, linux-pci
Allow implementors to specify the foreign pointer type; this exposes
information about the pointed-to type such as its alignment.
This requires the trait to be `unsafe` since it is now possible for
implementors to break soundness by returning a misaligned pointer.
Encoding the pointer type in the trait (and avoiding pointer casts)
allows the compiler to check that implementors return the correct
pointer type. This is preferable to directly encoding the alignment in
the trait using a constant as the compiler would be unable to check it.
Acked-by: Danilo Krummrich <dakr@kernel.org>
Signed-off-by: Tamir Duberstein <tamird@gmail.com>
---
rust/kernel/alloc/kbox.rs | 38 ++++++++++++++++++++------------------
rust/kernel/miscdevice.rs | 10 +++++-----
rust/kernel/pci.rs | 2 +-
rust/kernel/platform.rs | 2 +-
rust/kernel/sync/arc.rs | 21 ++++++++++++---------
rust/kernel/types.rs | 46 +++++++++++++++++++++++++++++++---------------
6 files changed, 70 insertions(+), 49 deletions(-)
diff --git a/rust/kernel/alloc/kbox.rs b/rust/kernel/alloc/kbox.rs
index b77d32f3a58b..6aa88b01e84d 100644
--- a/rust/kernel/alloc/kbox.rs
+++ b/rust/kernel/alloc/kbox.rs
@@ -360,68 +360,70 @@ fn try_init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E>
}
}
-impl<T: 'static, A> ForeignOwnable for Box<T, A>
+// SAFETY: The `into_foreign` function returns a pointer that is well-aligned.
+unsafe impl<T: 'static, A> ForeignOwnable for Box<T, A>
where
A: Allocator,
{
+ type PointedTo = T;
type Borrowed<'a> = &'a T;
type BorrowedMut<'a> = &'a mut T;
- fn into_foreign(self) -> *mut crate::ffi::c_void {
- Box::into_raw(self).cast()
+ fn into_foreign(self) -> *mut Self::PointedTo {
+ Box::into_raw(self)
}
- unsafe fn from_foreign(ptr: *mut crate::ffi::c_void) -> Self {
+ unsafe fn from_foreign(ptr: *mut Self::PointedTo) -> Self {
// SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous
// call to `Self::into_foreign`.
- unsafe { Box::from_raw(ptr.cast()) }
+ unsafe { Box::from_raw(ptr) }
}
- unsafe fn borrow<'a>(ptr: *mut crate::ffi::c_void) -> &'a T {
+ unsafe fn borrow<'a>(ptr: *mut Self::PointedTo) -> &'a T {
// SAFETY: The safety requirements of this method ensure that the object remains alive and
// immutable for the duration of 'a.
- unsafe { &*ptr.cast() }
+ unsafe { &*ptr }
}
- unsafe fn borrow_mut<'a>(ptr: *mut crate::ffi::c_void) -> &'a mut T {
- let ptr = ptr.cast();
+ unsafe fn borrow_mut<'a>(ptr: *mut Self::PointedTo) -> &'a mut T {
// SAFETY: The safety requirements of this method ensure that the pointer is valid and that
// nothing else will access the value for the duration of 'a.
unsafe { &mut *ptr }
}
}
-impl<T: 'static, A> ForeignOwnable for Pin<Box<T, A>>
+// SAFETY: The `into_foreign` function returns a pointer that is well-aligned.
+unsafe impl<T: 'static, A> ForeignOwnable for Pin<Box<T, A>>
where
A: Allocator,
{
+ type PointedTo = T;
type Borrowed<'a> = Pin<&'a T>;
type BorrowedMut<'a> = Pin<&'a mut T>;
- fn into_foreign(self) -> *mut crate::ffi::c_void {
+ fn into_foreign(self) -> *mut Self::PointedTo {
// SAFETY: We are still treating the box as pinned.
- Box::into_raw(unsafe { Pin::into_inner_unchecked(self) }).cast()
+ Box::into_raw(unsafe { Pin::into_inner_unchecked(self) })
}
- unsafe fn from_foreign(ptr: *mut crate::ffi::c_void) -> Self {
+ unsafe fn from_foreign(ptr: *mut Self::PointedTo) -> Self {
// SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous
// call to `Self::into_foreign`.
- unsafe { Pin::new_unchecked(Box::from_raw(ptr.cast())) }
+ unsafe { Pin::new_unchecked(Box::from_raw(ptr)) }
}
- unsafe fn borrow<'a>(ptr: *mut crate::ffi::c_void) -> Pin<&'a T> {
+ unsafe fn borrow<'a>(ptr: *mut Self::PointedTo) -> Pin<&'a T> {
// SAFETY: The safety requirements for this function ensure that the object is still alive,
// so it is safe to dereference the raw pointer.
// The safety requirements of `from_foreign` also ensure that the object remains alive for
// the lifetime of the returned value.
- let r = unsafe { &*ptr.cast() };
+ let r = unsafe { &*ptr };
// SAFETY: This pointer originates from a `Pin<Box<T>>`.
unsafe { Pin::new_unchecked(r) }
}
- unsafe fn borrow_mut<'a>(ptr: *mut crate::ffi::c_void) -> Pin<&'a mut T> {
- let ptr = ptr.cast();
+ unsafe fn borrow_mut<'a>(ptr: *mut Self::PointedTo) -> Pin<&'a mut T> {
// SAFETY: The safety requirements for this function ensure that the object is still alive,
// so it is safe to dereference the raw pointer.
// The safety requirements of `from_foreign` also ensure that the object remains alive for
diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs
index fa9ecc42602a..b4c5f74de23d 100644
--- a/rust/kernel/miscdevice.rs
+++ b/rust/kernel/miscdevice.rs
@@ -200,7 +200,7 @@ impl<T: MiscDevice> MiscdeviceVTable<T> {
// type.
//
// SAFETY: The open call of a file can access the private data.
- unsafe { (*raw_file).private_data = ptr.into_foreign() };
+ unsafe { (*raw_file).private_data = ptr.into_foreign().cast() };
0
}
@@ -211,7 +211,7 @@ impl<T: MiscDevice> MiscdeviceVTable<T> {
/// must be associated with a `MiscDeviceRegistration<T>`.
unsafe extern "C" fn release(_inode: *mut bindings::inode, file: *mut bindings::file) -> c_int {
// SAFETY: The release call of a file owns the private data.
- let private = unsafe { (*file).private_data };
+ let private = unsafe { (*file).private_data }.cast();
// SAFETY: The release call of a file owns the private data.
let ptr = unsafe { <T::Ptr as ForeignOwnable>::from_foreign(private) };
@@ -228,7 +228,7 @@ impl<T: MiscDevice> MiscdeviceVTable<T> {
/// `file` must be a valid file that is associated with a `MiscDeviceRegistration<T>`.
unsafe extern "C" fn ioctl(file: *mut bindings::file, cmd: c_uint, arg: c_ulong) -> c_long {
// SAFETY: The ioctl call of a file can access the private data.
- let private = unsafe { (*file).private_data };
+ let private = unsafe { (*file).private_data }.cast();
// SAFETY: Ioctl calls can borrow the private data of the file.
let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) };
@@ -253,7 +253,7 @@ impl<T: MiscDevice> MiscdeviceVTable<T> {
arg: c_ulong,
) -> c_long {
// SAFETY: The compat ioctl call of a file can access the private data.
- let private = unsafe { (*file).private_data };
+ let private = unsafe { (*file).private_data }.cast();
// SAFETY: Ioctl calls can borrow the private data of the file.
let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) };
@@ -274,7 +274,7 @@ impl<T: MiscDevice> MiscdeviceVTable<T> {
/// - `seq_file` must be a valid `struct seq_file` that we can write to.
unsafe extern "C" fn show_fdinfo(seq_file: *mut bindings::seq_file, file: *mut bindings::file) {
// SAFETY: The release call of a file owns the private data.
- let private = unsafe { (*file).private_data };
+ let private = unsafe { (*file).private_data }.cast();
// SAFETY: Ioctl calls can borrow the private data of the file.
let device = unsafe { <T::Ptr as ForeignOwnable>::borrow(private) };
// SAFETY:
diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs
index c97d6d470b28..3aeb1250c27f 100644
--- a/rust/kernel/pci.rs
+++ b/rust/kernel/pci.rs
@@ -89,7 +89,7 @@ extern "C" fn probe_callback(
extern "C" fn remove_callback(pdev: *mut bindings::pci_dev) {
// SAFETY: The PCI bus only ever calls the remove callback with a valid pointer to a
// `struct pci_dev`.
- let ptr = unsafe { bindings::pci_get_drvdata(pdev) };
+ let ptr = unsafe { bindings::pci_get_drvdata(pdev) }.cast();
// SAFETY: `remove_callback` is only ever called after a successful call to
// `probe_callback`, hence it's guaranteed that `ptr` points to a valid and initialized
diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs
index 4917cb34e2fe..fd4a494f30e8 100644
--- a/rust/kernel/platform.rs
+++ b/rust/kernel/platform.rs
@@ -80,7 +80,7 @@ extern "C" fn probe_callback(pdev: *mut bindings::platform_device) -> kernel::ff
extern "C" fn remove_callback(pdev: *mut bindings::platform_device) {
// SAFETY: `pdev` is a valid pointer to a `struct platform_device`.
- let ptr = unsafe { bindings::platform_get_drvdata(pdev) };
+ let ptr = unsafe { bindings::platform_get_drvdata(pdev) }.cast();
// SAFETY: `remove_callback` is only ever called after a successful call to
// `probe_callback`, hence it's guaranteed that `ptr` points to a valid and initialized
diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs
index 8484c814609a..a42c164e577a 100644
--- a/rust/kernel/sync/arc.rs
+++ b/rust/kernel/sync/arc.rs
@@ -140,9 +140,10 @@ pub struct Arc<T: ?Sized> {
_p: PhantomData<ArcInner<T>>,
}
+#[doc(hidden)]
#[pin_data]
#[repr(C)]
-struct ArcInner<T: ?Sized> {
+pub struct ArcInner<T: ?Sized> {
refcount: Opaque<bindings::refcount_t>,
data: T,
}
@@ -371,18 +372,20 @@ pub fn into_unique_or_drop(self) -> Option<Pin<UniqueArc<T>>> {
}
}
-impl<T: 'static> ForeignOwnable for Arc<T> {
+// SAFETY: The `into_foreign` function returns a pointer that is well-aligned.
+unsafe impl<T: 'static> ForeignOwnable for Arc<T> {
+ type PointedTo = ArcInner<T>;
type Borrowed<'a> = ArcBorrow<'a, T>;
type BorrowedMut<'a> = Self::Borrowed<'a>;
- fn into_foreign(self) -> *mut crate::ffi::c_void {
- ManuallyDrop::new(self).ptr.as_ptr().cast()
+ fn into_foreign(self) -> *mut Self::PointedTo {
+ ManuallyDrop::new(self).ptr.as_ptr()
}
- unsafe fn from_foreign(ptr: *mut crate::ffi::c_void) -> Self {
+ unsafe fn from_foreign(ptr: *mut Self::PointedTo) -> Self {
// SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous
// call to `Self::into_foreign`.
- let inner = unsafe { NonNull::new_unchecked(ptr.cast::<ArcInner<T>>()) };
+ let inner = unsafe { NonNull::new_unchecked(ptr) };
// SAFETY: By the safety requirement of this function, we know that `ptr` came from
// a previous call to `Arc::into_foreign`, which guarantees that `ptr` is valid and
@@ -390,17 +393,17 @@ unsafe fn from_foreign(ptr: *mut crate::ffi::c_void) -> Self {
unsafe { Self::from_inner(inner) }
}
- unsafe fn borrow<'a>(ptr: *mut crate::ffi::c_void) -> ArcBorrow<'a, T> {
+ unsafe fn borrow<'a>(ptr: *mut Self::PointedTo) -> ArcBorrow<'a, T> {
// SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous
// call to `Self::into_foreign`.
- let inner = unsafe { NonNull::new_unchecked(ptr.cast::<ArcInner<T>>()) };
+ let inner = unsafe { NonNull::new_unchecked(ptr) };
// SAFETY: The safety requirements of `from_foreign` ensure that the object remains alive
// for the lifetime of the returned value.
unsafe { ArcBorrow::new(inner) }
}
- unsafe fn borrow_mut<'a>(ptr: *mut crate::ffi::c_void) -> ArcBorrow<'a, T> {
+ unsafe fn borrow_mut<'a>(ptr: *mut Self::PointedTo) -> ArcBorrow<'a, T> {
// SAFETY: The safety requirements for `borrow_mut` are a superset of the safety
// requirements for `borrow`.
unsafe { Self::borrow(ptr) }
diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
index 9d0471afc964..86562e738eac 100644
--- a/rust/kernel/types.rs
+++ b/rust/kernel/types.rs
@@ -18,7 +18,19 @@
///
/// This trait is meant to be used in cases when Rust objects are stored in C objects and
/// eventually "freed" back to Rust.
-pub trait ForeignOwnable: Sized {
+///
+/// # Safety
+///
+/// Implementers must ensure that [`into_foreign`] returns a pointer which meets the alignment
+/// requirements of [`PointedTo`].
+///
+/// [`into_foreign`]: Self::into_foreign
+/// [`PointedTo`]: Self::PointedTo
+pub unsafe trait ForeignOwnable: Sized {
+ /// Type used when the value is foreign-owned. In practical terms only defines the alignment of
+ /// the pointer.
+ type PointedTo;
+
/// Type used to immutably borrow a value that is currently foreign-owned.
type Borrowed<'a>;
@@ -27,16 +39,18 @@ pub trait ForeignOwnable: Sized {
/// Converts a Rust-owned object to a foreign-owned one.
///
- /// The foreign representation is a pointer to void. There are no guarantees for this pointer.
- /// For example, it might be invalid, dangling or pointing to uninitialized memory. Using it in
- /// any way except for [`from_foreign`], [`try_from_foreign`], [`borrow`], or [`borrow_mut`] can
- /// result in undefined behavior.
+ /// # Guarantees
+ ///
+ /// The return value is guaranteed to be well-aligned, but there are no other guarantees for
+ /// this pointer. For example, it might be null, dangling, or point to uninitialized memory.
+ /// Using it in any way except for [`ForeignOwnable::from_foreign`], [`ForeignOwnable::borrow`],
+ /// [`ForeignOwnable::try_from_foreign`] can result in undefined behavior.
///
/// [`from_foreign`]: Self::from_foreign
/// [`try_from_foreign`]: Self::try_from_foreign
/// [`borrow`]: Self::borrow
/// [`borrow_mut`]: Self::borrow_mut
- fn into_foreign(self) -> *mut crate::ffi::c_void;
+ fn into_foreign(self) -> *mut Self::PointedTo;
/// Converts a foreign-owned object back to a Rust-owned one.
///
@@ -46,7 +60,7 @@ pub trait ForeignOwnable: Sized {
/// must not be passed to `from_foreign` more than once.
///
/// [`into_foreign`]: Self::into_foreign
- unsafe fn from_foreign(ptr: *mut crate::ffi::c_void) -> Self;
+ unsafe fn from_foreign(ptr: *mut Self::PointedTo) -> Self;
/// Tries to convert a foreign-owned object back to a Rust-owned one.
///
@@ -58,7 +72,7 @@ pub trait ForeignOwnable: Sized {
/// `ptr` must either be null or satisfy the safety requirements for [`from_foreign`].
///
/// [`from_foreign`]: Self::from_foreign
- unsafe fn try_from_foreign(ptr: *mut crate::ffi::c_void) -> Option<Self> {
+ unsafe fn try_from_foreign(ptr: *mut Self::PointedTo) -> Option<Self> {
if ptr.is_null() {
None
} else {
@@ -81,7 +95,7 @@ unsafe fn try_from_foreign(ptr: *mut crate::ffi::c_void) -> Option<Self> {
///
/// [`into_foreign`]: Self::into_foreign
/// [`from_foreign`]: Self::from_foreign
- unsafe fn borrow<'a>(ptr: *mut crate::ffi::c_void) -> Self::Borrowed<'a>;
+ unsafe fn borrow<'a>(ptr: *mut Self::PointedTo) -> Self::Borrowed<'a>;
/// Borrows a foreign-owned object mutably.
///
@@ -109,21 +123,23 @@ unsafe fn try_from_foreign(ptr: *mut crate::ffi::c_void) -> Option<Self> {
/// [`from_foreign`]: Self::from_foreign
/// [`borrow`]: Self::borrow
/// [`Arc`]: crate::sync::Arc
- unsafe fn borrow_mut<'a>(ptr: *mut crate::ffi::c_void) -> Self::BorrowedMut<'a>;
+ unsafe fn borrow_mut<'a>(ptr: *mut Self::PointedTo) -> Self::BorrowedMut<'a>;
}
-impl ForeignOwnable for () {
+// SAFETY: The `into_foreign` function returns a pointer that is dangling, but well-aligned.
+unsafe impl ForeignOwnable for () {
+ type PointedTo = ();
type Borrowed<'a> = ();
type BorrowedMut<'a> = ();
- fn into_foreign(self) -> *mut crate::ffi::c_void {
+ fn into_foreign(self) -> *mut Self::PointedTo {
core::ptr::NonNull::dangling().as_ptr()
}
- unsafe fn from_foreign(_: *mut crate::ffi::c_void) -> Self {}
+ unsafe fn from_foreign(_: *mut Self::PointedTo) -> Self {}
- unsafe fn borrow<'a>(_: *mut crate::ffi::c_void) -> Self::Borrowed<'a> {}
- unsafe fn borrow_mut<'a>(_: *mut crate::ffi::c_void) -> Self::BorrowedMut<'a> {}
+ unsafe fn borrow<'a>(_: *mut Self::PointedTo) -> Self::Borrowed<'a> {}
+ unsafe fn borrow_mut<'a>(_: *mut Self::PointedTo) -> Self::BorrowedMut<'a> {}
}
/// Runs a cleanup function/closure when dropped.
--
2.49.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v19 2/3] rust: xarray: Add an abstraction for XArray
2025-04-23 13:54 [PATCH v19 0/3] rust: xarray: Add a minimal abstraction for XArray Tamir Duberstein
2025-04-23 13:54 ` [PATCH v19 1/3] rust: types: add `ForeignOwnable::PointedTo` Tamir Duberstein
@ 2025-04-23 13:54 ` Tamir Duberstein
2025-04-23 13:54 ` [PATCH v19 3/3] MAINTAINERS: add entry for Rust XArray API Tamir Duberstein
2025-04-26 19:48 ` [PATCH v19 0/3] rust: xarray: Add a minimal abstraction for XArray Andreas Hindborg
3 siblings, 0 replies; 12+ messages in thread
From: Tamir Duberstein @ 2025-04-23 13:54 UTC (permalink / raw)
To: Danilo Krummrich, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Matthew Wilcox, Bjorn Helgaas, Greg Kroah-Hartman,
Rafael J. Wysocki, Tamir Duberstein, FUJITA Tomonori,
Rob Herring (Arm)
Cc: Maíra Canal, Asahi Lina, rust-for-linux, linux-fsdevel,
linux-kernel, linux-pci
`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.
Inspired-by: Maíra Canal <mcanal@igalia.com>
Inspired-by: Asahi Lina <lina@asahilina.net>
Reviewed-by: Andreas Hindborg <a.hindborg@kernel.org>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
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/lib.rs | 1 +
rust/kernel/xarray.rs | 275 ++++++++++++++++++++++++++++++++++++++++
5 files changed, 311 insertions(+)
diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index ab37e1d35c70..e0bcd130b494 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -37,6 +37,7 @@
#include <linux/tracepoint.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
+#include <linux/xarray.h>
#include <trace/events/rust_sample.h>
#if defined(CONFIG_DRM_PANIC_SCREEN_QR_CODE)
@@ -55,3 +56,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 1e7c84df7252..80785b1e7a63 100644
--- a/rust/helpers/helpers.c
+++ b/rust/helpers/helpers.c
@@ -38,3 +38,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 000000000000..60b299f11451
--- /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/lib.rs b/rust/kernel/lib.rs
index de07aadd1ff5..715fab6b1345 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -88,6 +88,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 000000000000..75719e7bb491
--- /dev/null
+++ b/rust/kernel/xarray.rs
@@ -0,0 +1,275 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! XArray abstraction.
+//!
+//! C header: [`include/linux/xarray.h`](srctree/include/linux/xarray.h)
+
+use crate::{
+ alloc, bindings, build_assert,
+ error::{Error, Result},
+ types::{ForeignOwnable, NotThreadSafe, Opaque},
+};
+use core::{iter, marker::PhantomData, mem, pin::Pin, ptr::NonNull};
+use pin_init::{pin_data, pin_init, pinned_drop, PinInit};
+
+/// 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)?.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)?.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 initializer for this type.
+ 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.
+ //
+ // INVARIANT: `xa` is initialized here to an empty, valid [`bindings::xarray`].
+ xa <- Opaque::ffi_init(|xa| unsafe {
+ bindings::xa_init_flags(xa, flags)
+ }),
+ _p: PhantomData,
+ })
+ }
+
+ fn iter(&self) -> impl Iterator<Item = NonNull<T::PointedTo>> + '_ {
+ let mut index = 0;
+
+ // SAFETY: `self.xa` is always valid by the type invariant.
+ iter::once(unsafe {
+ bindings::xa_find(self.xa.get(), &mut index, usize::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, usize::MAX, bindings::XA_PRESENT)
+ })
+ }))
+ .map_while(|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.
+ if (unsafe { bindings::xa_trylock(self.xa.get()) } != 0) {
+ Some(Guard {
+ xa: self,
+ _not_send: NotThreadSafe,
+ })
+ } else {
+ None
+ }
+ }
+
+ /// 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,
+ _not_send: NotThreadSafe,
+ }
+ }
+}
+
+/// 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>,
+ _not_send: NotThreadSafe,
+}
+
+impl<T: ForeignOwnable> Drop for Guard<'_, T> {
+ fn drop(&mut self) {
+ // SAFETY:
+ // - `self.xa.xa` is always valid by the type invariant.
+ // - The caller holds the lock, so it is safe to unlock it.
+ unsafe { bindings::xa_unlock(self.xa.xa.get()) };
+ }
+}
+
+/// The error returned by [`store`](Guard::store).
+///
+/// Contains the underlying error and the value that was not stored.
+pub struct StoreError<T> {
+ /// The error that occurred.
+ pub error: Error,
+ /// The value that was not stored.
+ pub value: T,
+}
+
+impl<T> From<StoreError<T>> for Error {
+ fn from(value: StoreError<T>) -> Self {
+ value.error
+ }
+}
+
+impl<'a, T: ForeignOwnable> Guard<'a, T> {
+ fn load<F, U>(&self, index: usize, f: F) -> Option<U>
+ where
+ F: FnOnce(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(), index) };
+ let ptr = NonNull::new(ptr.cast())?;
+ Some(f(ptr))
+ }
+
+ /// Provides a reference to the element at the given index.
+ pub fn get(&self, index: usize) -> Option<T::Borrowed<'_>> {
+ self.load(index, |ptr| {
+ // SAFETY: `ptr` came from `T::into_foreign`.
+ unsafe { T::borrow(ptr.as_ptr()) }
+ })
+ }
+
+ /// Provides a mutable reference to the element 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()) }
+ })
+ }
+
+ /// Removes and returns the element at the given index.
+ pub fn remove(&mut self, index: usize) -> Option<T> {
+ // SAFETY:
+ // - `self.xa.xa` is always valid by the type invariant.
+ // - The caller holds the lock.
+ let ptr = unsafe { bindings::__xa_erase(self.xa.xa.get(), index) }.cast();
+ // SAFETY:
+ // - `ptr` is either NULL or came from `T::into_foreign`.
+ // - `&mut self` guarantees that the lifetimes of [`T::Borrowed`] and [`T::BorrowedMut`]
+ // borrowed from `self` have ended.
+ unsafe { T::try_from_foreign(ptr) }
+ }
+
+ /// Stores an element at the given index.
+ ///
+ /// May drop the lock if needed to allocate memory, and then reacquire it afterwards.
+ ///
+ /// On success, returns the element which was previously at the given index.
+ ///
+ /// On failure, returns the element which was attempted to be stored.
+ pub fn store(
+ &mut self,
+ index: usize,
+ value: T,
+ gfp: alloc::Flags,
+ ) -> Result<Option<T>, StoreError<T>> {
+ 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.
+ // - The caller holds the lock.
+ //
+ // INVARIANT: `new` came from `T::into_foreign`.
+ unsafe { bindings::__xa_store(self.xa.xa.get(), index, new, gfp.as_raw()) }
+ };
+
+ // SAFETY: `__xa_store` returns the old entry at this index on success or `xa_err` if an
+ // error happened.
+ let errno = unsafe { bindings::xa_err(old) };
+ if errno != 0 {
+ // 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(StoreError {
+ value,
+ error: Error::from_errno(errno),
+ })
+ } else {
+ let old = old.cast();
+ // SAFETY: `ptr` is either NULL or came from `T::into_foreign`.
+ //
+ // NB: `XA_ZERO_ENTRY` is never returned by functions belonging to the Normal XArray
+ // API; such entries present as `NULL`.
+ Ok(unsafe { T::try_from_foreign(old) })
+ }
+ }
+}
+
+// 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> {}
+
+// SAFETY: `XArray<T>` serialises the interior mutability it provides so it is `Sync` iff `T` is
+// `Send`.
+unsafe impl<T: ForeignOwnable + Send> Sync for XArray<T> {}
--
2.49.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v19 3/3] MAINTAINERS: add entry for Rust XArray API
2025-04-23 13:54 [PATCH v19 0/3] rust: xarray: Add a minimal abstraction for XArray Tamir Duberstein
2025-04-23 13:54 ` [PATCH v19 1/3] rust: types: add `ForeignOwnable::PointedTo` Tamir Duberstein
2025-04-23 13:54 ` [PATCH v19 2/3] rust: xarray: Add an abstraction for XArray Tamir Duberstein
@ 2025-04-23 13:54 ` Tamir Duberstein
2025-04-26 19:48 ` [PATCH v19 0/3] rust: xarray: Add a minimal abstraction for XArray Andreas Hindborg
3 siblings, 0 replies; 12+ messages in thread
From: Tamir Duberstein @ 2025-04-23 13:54 UTC (permalink / raw)
To: Danilo Krummrich, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Matthew Wilcox, Bjorn Helgaas, Greg Kroah-Hartman,
Rafael J. Wysocki, Tamir Duberstein, FUJITA Tomonori,
Rob Herring (Arm)
Cc: Maíra Canal, Asahi Lina, rust-for-linux, linux-fsdevel,
linux-kernel, linux-pci
Add an entry for the Rust xarray abstractions.
Acked-by: Andreas Hindborg <a.hindborg@kernel.org>
Signed-off-by: Tamir Duberstein <tamird@gmail.com>
---
MAINTAINERS | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index fa1e04e87d1d..925d64be9dd6 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -26310,6 +26310,17 @@ F: lib/test_xarray.c
F: lib/xarray.c
F: tools/testing/radix-tree
+XARRAY API [RUST]
+M: Tamir Duberstein <tamird@gmail.com>
+M: Andreas Hindborg <a.hindborg@kernel.org>
+L: rust-for-linux@vger.kernel.org
+S: Supported
+W: https://rust-for-linux.com
+B: https://github.com/Rust-for-Linux/linux/issues
+C: https://rust-for-linux.zulipchat.com
+T: git https://github.com/Rust-for-Linux/linux.git rust-next
+F: rust/kernel/xarray.rs
+
XBOX DVD IR REMOTE
M: Benjamin Valentin <benpicco@googlemail.com>
S: Maintained
--
2.49.0
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v19 0/3] rust: xarray: Add a minimal abstraction for XArray
2025-04-23 13:54 [PATCH v19 0/3] rust: xarray: Add a minimal abstraction for XArray Tamir Duberstein
` (2 preceding siblings ...)
2025-04-23 13:54 ` [PATCH v19 3/3] MAINTAINERS: add entry for Rust XArray API Tamir Duberstein
@ 2025-04-26 19:48 ` Andreas Hindborg
2025-04-27 14:39 ` Danilo Krummrich
3 siblings, 1 reply; 12+ messages in thread
From: Andreas Hindborg @ 2025-04-26 19:48 UTC (permalink / raw)
To: Danilo Krummrich, Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Alice Ryhl, Trevor Gross,
Matthew Wilcox, Bjorn Helgaas, Greg Kroah-Hartman,
Rafael J. Wysocki, FUJITA Tomonori, Rob Herring (Arm),
Tamir Duberstein
Cc: Maíra Canal, Asahi Lina, rust-for-linux, linux-fsdevel,
linux-kernel, linux-pci
On Wed, 23 Apr 2025 09:54:36 -0400, Tamir Duberstein wrote:
> This is a reimagining relative to earlier versions[0] by Asahi Lina and
> Maíra Canal.
>
> It is needed to support rust-binder, though this version only provides
> enough machinery to support rnull.
>
>
> [...]
Applied, thanks!
[1/3] rust: types: add `ForeignOwnable::PointedTo`
commit: a68f46e837473de56e2c101bc0df19078a0cfeaf
[2/3] rust: xarray: Add an abstraction for XArray
commit: dea08321b98ed6b4e06680886f60160d30254a6d
[3/3] MAINTAINERS: add entry for Rust XArray API
commit: 1061e78014e80982814083ec8375c455848abdb4
Best regards,
--
Andreas Hindborg <a.hindborg@kernel.org>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v19 0/3] rust: xarray: Add a minimal abstraction for XArray
2025-04-26 19:48 ` [PATCH v19 0/3] rust: xarray: Add a minimal abstraction for XArray Andreas Hindborg
@ 2025-04-27 14:39 ` Danilo Krummrich
2025-04-27 15:57 ` Andreas Hindborg
0 siblings, 1 reply; 12+ messages in thread
From: Danilo Krummrich @ 2025-04-27 14:39 UTC (permalink / raw)
To: Andreas Hindborg
Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Alice Ryhl, Trevor Gross,
Matthew Wilcox, Bjorn Helgaas, Greg Kroah-Hartman,
Rafael J. Wysocki, FUJITA Tomonori, Rob Herring (Arm),
Tamir Duberstein, Maíra Canal, Asahi Lina, rust-for-linux,
linux-fsdevel, linux-kernel, linux-pci
On Sat, Apr 26, 2025 at 09:48:53PM +0200, Andreas Hindborg wrote:
>
> On Wed, 23 Apr 2025 09:54:36 -0400, Tamir Duberstein wrote:
> > This is a reimagining relative to earlier versions[0] by Asahi Lina and
> > Maíra Canal.
> >
> > It is needed to support rust-binder, though this version only provides
> > enough machinery to support rnull.
> >
> >
> > [...]
>
> Applied, thanks!
>
> [1/3] rust: types: add `ForeignOwnable::PointedTo`
> commit: a68f46e837473de56e2c101bc0df19078a0cfeaf
> [2/3] rust: xarray: Add an abstraction for XArray
> commit: dea08321b98ed6b4e06680886f60160d30254a6d
> [3/3] MAINTAINERS: add entry for Rust XArray API
> commit: 1061e78014e80982814083ec8375c455848abdb4
I assume this went into xarray-next? If so, you probably want to adjust the
MAINTAINERS entry accordingly.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v19 0/3] rust: xarray: Add a minimal abstraction for XArray
2025-04-27 14:39 ` Danilo Krummrich
@ 2025-04-27 15:57 ` Andreas Hindborg
2025-04-28 7:14 ` Andreas Hindborg
0 siblings, 1 reply; 12+ messages in thread
From: Andreas Hindborg @ 2025-04-27 15:57 UTC (permalink / raw)
To: Danilo Krummrich
Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Alice Ryhl, Trevor Gross,
Matthew Wilcox, Bjorn Helgaas, Greg Kroah-Hartman,
Rafael J. Wysocki, FUJITA Tomonori, Rob Herring (Arm),
Tamir Duberstein, Maíra Canal, Asahi Lina, rust-for-linux,
linux-fsdevel, linux-kernel, linux-pci
"Danilo Krummrich" <dakr@kernel.org> writes:
> On Sat, Apr 26, 2025 at 09:48:53PM +0200, Andreas Hindborg wrote:
>>
>> On Wed, 23 Apr 2025 09:54:36 -0400, Tamir Duberstein wrote:
>> > This is a reimagining relative to earlier versions[0] by Asahi Lina and
>> > Maíra Canal.
>> >
>> > It is needed to support rust-binder, though this version only provides
>> > enough machinery to support rnull.
>> >
>> >
>> > [...]
>>
>> Applied, thanks!
>>
>> [1/3] rust: types: add `ForeignOwnable::PointedTo`
>> commit: a68f46e837473de56e2c101bc0df19078a0cfeaf
>> [2/3] rust: xarray: Add an abstraction for XArray
>> commit: dea08321b98ed6b4e06680886f60160d30254a6d
>> [3/3] MAINTAINERS: add entry for Rust XArray API
>> commit: 1061e78014e80982814083ec8375c455848abdb4
>
> I assume this went into xarray-next? If so, you probably want to adjust the
> MAINTAINERS entry accordingly.
Yes, thanks for catching that. I'm very much in the learning phase
still.
Best regards,
Andreas Hindborg
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v19 0/3] rust: xarray: Add a minimal abstraction for XArray
2025-04-27 15:57 ` Andreas Hindborg
@ 2025-04-28 7:14 ` Andreas Hindborg
0 siblings, 0 replies; 12+ messages in thread
From: Andreas Hindborg @ 2025-04-28 7:14 UTC (permalink / raw)
To: Danilo Krummrich
Cc: Miguel Ojeda, Alex Gaynor, Boqun Feng, Gary Guo,
Björn Roy Baron, Benno Lossin, Alice Ryhl, Trevor Gross,
Matthew Wilcox, Bjorn Helgaas, Greg Kroah-Hartman,
Rafael J. Wysocki, FUJITA Tomonori, Rob Herring (Arm),
Tamir Duberstein, Maíra Canal, Asahi Lina, rust-for-linux,
linux-fsdevel, linux-kernel, linux-pci
Andreas Hindborg <a.hindborg@kernel.org> writes:
> "Danilo Krummrich" <dakr@kernel.org> writes:
>
>> On Sat, Apr 26, 2025 at 09:48:53PM +0200, Andreas Hindborg wrote:
>>>
>>> On Wed, 23 Apr 2025 09:54:36 -0400, Tamir Duberstein wrote:
>>> > This is a reimagining relative to earlier versions[0] by Asahi Lina and
>>> > Maíra Canal.
>>> >
>>> > It is needed to support rust-binder, though this version only provides
>>> > enough machinery to support rnull.
>>> >
>>> >
>>> > [...]
>>>
>>> Applied, thanks!
>>>
>>> [1/3] rust: types: add `ForeignOwnable::PointedTo`
>>> commit: a68f46e837473de56e2c101bc0df19078a0cfeaf
>>> [2/3] rust: xarray: Add an abstraction for XArray
>>> commit: dea08321b98ed6b4e06680886f60160d30254a6d
>>> [3/3] MAINTAINERS: add entry for Rust XArray API
>>> commit: 1061e78014e80982814083ec8375c455848abdb4
>>
>> I assume this went into xarray-next? If so, you probably want to adjust the
>> MAINTAINERS entry accordingly.
>
> Yes, thanks for catching that. I'm very much in the learning phase
> still.
>
I changed the branch to `xarray-rust` on my side.
Best regards,
Andreas Hindborg
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v19 1/3] rust: types: add `ForeignOwnable::PointedTo`
2025-04-23 13:54 ` [PATCH v19 1/3] rust: types: add `ForeignOwnable::PointedTo` Tamir Duberstein
@ 2025-04-30 18:31 ` Gary Guo
2025-04-30 18:57 ` Tamir Duberstein
0 siblings, 1 reply; 12+ messages in thread
From: Gary Guo @ 2025-04-30 18:31 UTC (permalink / raw)
To: Tamir Duberstein
Cc: Danilo Krummrich, Miguel Ojeda, Alex Gaynor, Boqun Feng,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Matthew Wilcox, Bjorn Helgaas, Greg Kroah-Hartman,
Rafael J. Wysocki, FUJITA Tomonori, Rob Herring (Arm),
Maíra Canal, Asahi Lina, rust-for-linux, linux-fsdevel,
linux-kernel, linux-pci
On Wed, 23 Apr 2025 09:54:37 -0400
Tamir Duberstein <tamird@gmail.com> wrote:
> Allow implementors to specify the foreign pointer type; this exposes
> information about the pointed-to type such as its alignment.
>
> This requires the trait to be `unsafe` since it is now possible for
> implementors to break soundness by returning a misaligned pointer.
>
> Encoding the pointer type in the trait (and avoiding pointer casts)
> allows the compiler to check that implementors return the correct
> pointer type. This is preferable to directly encoding the alignment in
> the trait using a constant as the compiler would be unable to check it.
>
> Acked-by: Danilo Krummrich <dakr@kernel.org>
> Signed-off-by: Tamir Duberstein <tamird@gmail.com>
> ---
> rust/kernel/alloc/kbox.rs | 38 ++++++++++++++++++++------------------
> rust/kernel/miscdevice.rs | 10 +++++-----
> rust/kernel/pci.rs | 2 +-
> rust/kernel/platform.rs | 2 +-
> rust/kernel/sync/arc.rs | 21 ++++++++++++---------
> rust/kernel/types.rs | 46 +++++++++++++++++++++++++++++++---------------
> 6 files changed, 70 insertions(+), 49 deletions(-)
>
> diff --git a/rust/kernel/alloc/kbox.rs b/rust/kernel/alloc/kbox.rs
> index b77d32f3a58b..6aa88b01e84d 100644
> --- a/rust/kernel/alloc/kbox.rs
> +++ b/rust/kernel/alloc/kbox.rs
> @@ -360,68 +360,70 @@ fn try_init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E>
> }
> }
>
> -impl<T: 'static, A> ForeignOwnable for Box<T, A>
> +// SAFETY: The `into_foreign` function returns a pointer that is well-aligned.
> +unsafe impl<T: 'static, A> ForeignOwnable for Box<T, A>
> where
> A: Allocator,
> {
> + type PointedTo = T;
I don't think this is the correct solution for this. The returned
pointer is supposed to opaque, and exposing this type may encourage
this is to be wrongly used.
IIUC, the only reason for this to be exposed is for XArray to be able
to check alignment. However `align_of::<PointedTo>()` is not the
minimum guaranteed alignment.
For example, if the type is allocated via kernel allocator then it can
always guarantee to be at least usize-aligned. ZST can be arbitrarily
aligned so ForeignOwnable` implementation could return a
validly-aligned pointer for XArray. Actually, I think all current
ForeignOwnable implementation can be modified to always give 4-byte
aligned pointers.
Having a const associated item indicating the minimum guaranteed
alignment for *that specific container* is the correct way IMO, not to
reason about the pointee type!
Best,
Gary
> type Borrowed<'a> = &'a T;
> type BorrowedMut<'a> = &'a mut T;
>
> - fn into_foreign(self) -> *mut crate::ffi::c_void {
> - Box::into_raw(self).cast()
> + fn into_foreign(self) -> *mut Self::PointedTo {
> + Box::into_raw(self)
> }
>
> - unsafe fn from_foreign(ptr: *mut crate::ffi::c_void) -> Self {
> + unsafe fn from_foreign(ptr: *mut Self::PointedTo) -> Self {
> // SAFETY: The safety requirements of this function ensure that `ptr` comes from a previous
> // call to `Self::into_foreign`.
> - unsafe { Box::from_raw(ptr.cast()) }
> + unsafe { Box::from_raw(ptr) }
> }
>
> - unsafe fn borrow<'a>(ptr: *mut crate::ffi::c_void) -> &'a T {
> + unsafe fn borrow<'a>(ptr: *mut Self::PointedTo) -> &'a T {
> // SAFETY: The safety requirements of this method ensure that the object remains alive and
> // immutable for the duration of 'a.
> - unsafe { &*ptr.cast() }
> + unsafe { &*ptr }
> }
>
> - unsafe fn borrow_mut<'a>(ptr: *mut crate::ffi::c_void) -> &'a mut T {
> - let ptr = ptr.cast();
> + unsafe fn borrow_mut<'a>(ptr: *mut Self::PointedTo) -> &'a mut T {
> // SAFETY: The safety requirements of this method ensure that the pointer is valid and that
> // nothing else will access the value for the duration of 'a.
> unsafe { &mut *ptr }
> }
> }
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v19 1/3] rust: types: add `ForeignOwnable::PointedTo`
2025-04-30 18:31 ` Gary Guo
@ 2025-04-30 18:57 ` Tamir Duberstein
2025-05-01 7:17 ` Alice Ryhl
0 siblings, 1 reply; 12+ messages in thread
From: Tamir Duberstein @ 2025-04-30 18:57 UTC (permalink / raw)
To: Gary Guo
Cc: Danilo Krummrich, Miguel Ojeda, Alex Gaynor, Boqun Feng,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Matthew Wilcox, Bjorn Helgaas, Greg Kroah-Hartman,
Rafael J. Wysocki, FUJITA Tomonori, Rob Herring (Arm),
Maíra Canal, Asahi Lina, rust-for-linux, linux-fsdevel,
linux-kernel, linux-pci
On Wed, Apr 30, 2025 at 11:31 AM Gary Guo <gary@garyguo.net> wrote:
>
> On Wed, 23 Apr 2025 09:54:37 -0400
> Tamir Duberstein <tamird@gmail.com> wrote:
>
> > Allow implementors to specify the foreign pointer type; this exposes
> > information about the pointed-to type such as its alignment.
> >
> > This requires the trait to be `unsafe` since it is now possible for
> > implementors to break soundness by returning a misaligned pointer.
> >
> > Encoding the pointer type in the trait (and avoiding pointer casts)
> > allows the compiler to check that implementors return the correct
> > pointer type. This is preferable to directly encoding the alignment in
> > the trait using a constant as the compiler would be unable to check it.
> >
> > Acked-by: Danilo Krummrich <dakr@kernel.org>
> > Signed-off-by: Tamir Duberstein <tamird@gmail.com>
> > ---
> > rust/kernel/alloc/kbox.rs | 38 ++++++++++++++++++++------------------
> > rust/kernel/miscdevice.rs | 10 +++++-----
> > rust/kernel/pci.rs | 2 +-
> > rust/kernel/platform.rs | 2 +-
> > rust/kernel/sync/arc.rs | 21 ++++++++++++---------
> > rust/kernel/types.rs | 46 +++++++++++++++++++++++++++++++---------------
> > 6 files changed, 70 insertions(+), 49 deletions(-)
> >
> > diff --git a/rust/kernel/alloc/kbox.rs b/rust/kernel/alloc/kbox.rs
> > index b77d32f3a58b..6aa88b01e84d 100644
> > --- a/rust/kernel/alloc/kbox.rs
> > +++ b/rust/kernel/alloc/kbox.rs
> > @@ -360,68 +360,70 @@ fn try_init<E>(init: impl Init<T, E>, flags: Flags) -> Result<Self, E>
> > }
> > }
> >
> > -impl<T: 'static, A> ForeignOwnable for Box<T, A>
> > +// SAFETY: The `into_foreign` function returns a pointer that is well-aligned.
> > +unsafe impl<T: 'static, A> ForeignOwnable for Box<T, A>
> > where
> > A: Allocator,
> > {
> > + type PointedTo = T;
>
> I don't think this is the correct solution for this. The returned
> pointer is supposed to opaque, and exposing this type may encourage
> this is to be wrongly used.
Can you give an example?
> IIUC, the only reason for this to be exposed is for XArray to be able
> to check alignment. However `align_of::<PointedTo>()` is not the
> minimum guaranteed alignment.
>
> For example, if the type is allocated via kernel allocator then it can
> always guarantee to be at least usize-aligned. ZST can be arbitrarily
> aligned so ForeignOwnable` implementation could return a
> validly-aligned pointer for XArray. Actually, I think all current
> ForeignOwnable implementation can be modified to always give 4-byte
> aligned pointers.
Is your concern that this is *too restrictive*? It might be that the
minimum alignment is greater than `align_of::<PointedTo>()`, but not
less.
> Having a const associated item indicating the minimum guaranteed
> alignment for *that specific container* is the correct way IMO, not to
> reason about the pointee type!
How do you determine the value? You're at quite some distance from the
allocator implementation.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v19 1/3] rust: types: add `ForeignOwnable::PointedTo`
2025-04-30 18:57 ` Tamir Duberstein
@ 2025-05-01 7:17 ` Alice Ryhl
2025-05-01 8:07 ` Andreas Hindborg
0 siblings, 1 reply; 12+ messages in thread
From: Alice Ryhl @ 2025-05-01 7:17 UTC (permalink / raw)
To: Tamir Duberstein
Cc: Gary Guo, Danilo Krummrich, Miguel Ojeda, Alex Gaynor, Boqun Feng,
Björn Roy Baron, Benno Lossin, Andreas Hindborg,
Trevor Gross, Matthew Wilcox, Bjorn Helgaas, Greg Kroah-Hartman,
Rafael J. Wysocki, FUJITA Tomonori, Rob Herring (Arm),
Maíra Canal, Asahi Lina, rust-for-linux, linux-fsdevel,
linux-kernel, linux-pci
On Wed, Apr 30, 2025 at 8:57 PM Tamir Duberstein <tamird@gmail.com> wrote:
>
> On Wed, Apr 30, 2025 at 11:31 AM Gary Guo <gary@garyguo.net> wrote:
> >
> > On Wed, 23 Apr 2025 09:54:37 -0400
> > Tamir Duberstein <tamird@gmail.com> wrote:
> > > -impl<T: 'static, A> ForeignOwnable for Box<T, A>
> > > +// SAFETY: The `into_foreign` function returns a pointer that is well-aligned.
> > > +unsafe impl<T: 'static, A> ForeignOwnable for Box<T, A>
> > > where
> > > A: Allocator,
> > > {
> > > + type PointedTo = T;
> >
> > I don't think this is the correct solution for this. The returned
> > pointer is supposed to opaque, and exposing this type may encourage
> > this is to be wrongly used.
>
> Can you give an example?
This came up when we discussed this patch in the meeting yesterday:
https://lore.kernel.org/all/20250227-configfs-v5-1-c40e8dc3b9cd@kernel.org/
This is incorrect use of the trait. The pointer is supposed to be
opaque, and you can't dereference it. See my reply to that patch as
well:
https://lore.kernel.org/all/CAH5fLggDwPBzMO2Z48oMjDm4qgoNM0NQs_63TxmVEGy+gtMpOA@mail.gmail.com/
Alice
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v19 1/3] rust: types: add `ForeignOwnable::PointedTo`
2025-05-01 7:17 ` Alice Ryhl
@ 2025-05-01 8:07 ` Andreas Hindborg
0 siblings, 0 replies; 12+ messages in thread
From: Andreas Hindborg @ 2025-05-01 8:07 UTC (permalink / raw)
To: Alice Ryhl
Cc: Tamir Duberstein, Gary Guo, Danilo Krummrich, Miguel Ojeda,
Alex Gaynor, Boqun Feng, Björn Roy Baron, Benno Lossin,
Trevor Gross, Matthew Wilcox, Bjorn Helgaas, Greg Kroah-Hartman,
Rafael J. Wysocki, FUJITA Tomonori, Rob Herring (Arm),
Maíra Canal, Asahi Lina, rust-for-linux, linux-fsdevel,
linux-kernel, linux-pci
"Alice Ryhl" <aliceryhl@google.com> writes:
> On Wed, Apr 30, 2025 at 8:57 PM Tamir Duberstein <tamird@gmail.com> wrote:
>>
>> On Wed, Apr 30, 2025 at 11:31 AM Gary Guo <gary@garyguo.net> wrote:
>> >
>> > On Wed, 23 Apr 2025 09:54:37 -0400
>> > Tamir Duberstein <tamird@gmail.com> wrote:
>> > > -impl<T: 'static, A> ForeignOwnable for Box<T, A>
>> > > +// SAFETY: The `into_foreign` function returns a pointer that is well-aligned.
>> > > +unsafe impl<T: 'static, A> ForeignOwnable for Box<T, A>
>> > > where
>> > > A: Allocator,
>> > > {
>> > > + type PointedTo = T;
>> >
>> > I don't think this is the correct solution for this. The returned
>> > pointer is supposed to opaque, and exposing this type may encourage
>> > this is to be wrongly used.
>>
>> Can you give an example?
>
> This came up when we discussed this patch in the meeting yesterday:
> https://lore.kernel.org/all/20250227-configfs-v5-1-c40e8dc3b9cd@kernel.org/
>
> This is incorrect use of the trait. The pointer is supposed to be
> opaque, and you can't dereference it. See my reply to that patch as
> well:
> https://lore.kernel.org/all/CAH5fLggDwPBzMO2Z48oMjDm4qgoNM0NQs_63TxmVEGy+gtMpOA@mail.gmail.com/
For reference, the outcome of the discussion yesterday:
- The use of `ForeignOwnable` in the configfs series is not correct. The pointer
must be opaque. I will drop the use of `ForeignOwnable` and adapt
`Arc` methods `into_raw`/`from_raw` instead. I had a plan to make the
code generic over the pointer type with a bound on `ForeignOwnable`.
A new trait is required for that now.
- There may be a use case for a trait that allows passing ownership of
an object to C, similar to `ForeignOwnable` but with a non-opaque
pointer. Trait methods would be `into_raw`, `from_raw`, `borrow`.
- The solution for alignment adopted in this (xarray) series is not
ideal. However, given the timeline we will proceed merging the series
as is, and then change the solution to the one outlined by Gary in
the next cycle.
@Gary you mentioned an implementation of the solution you outlined is
already posted to the list. I can't seem to find it, can you point to
it?
Best regards,
Andreas Hindborg
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2025-05-01 8:08 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-04-23 13:54 [PATCH v19 0/3] rust: xarray: Add a minimal abstraction for XArray Tamir Duberstein
2025-04-23 13:54 ` [PATCH v19 1/3] rust: types: add `ForeignOwnable::PointedTo` Tamir Duberstein
2025-04-30 18:31 ` Gary Guo
2025-04-30 18:57 ` Tamir Duberstein
2025-05-01 7:17 ` Alice Ryhl
2025-05-01 8:07 ` Andreas Hindborg
2025-04-23 13:54 ` [PATCH v19 2/3] rust: xarray: Add an abstraction for XArray Tamir Duberstein
2025-04-23 13:54 ` [PATCH v19 3/3] MAINTAINERS: add entry for Rust XArray API Tamir Duberstein
2025-04-26 19:48 ` [PATCH v19 0/3] rust: xarray: Add a minimal abstraction for XArray Andreas Hindborg
2025-04-27 14:39 ` Danilo Krummrich
2025-04-27 15:57 ` Andreas Hindborg
2025-04-28 7:14 ` Andreas Hindborg
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).