All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/9] rust: workqueue: add bindings for the workqueue
@ 2023-07-11  9:32 Alice Ryhl
  2023-07-11  9:32 ` [PATCH v3 1/9] rust: add offset_of! macro Alice Ryhl
                   ` (9 more replies)
  0 siblings, 10 replies; 31+ messages in thread
From: Alice Ryhl @ 2023-07-11  9:32 UTC (permalink / raw)
  To: rust-for-linux, Tejun Heo, Miguel Ojeda
  Cc: Lai Jiangshan, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron, Benno Lossin, Alice Ryhl,
	linux-kernel, patches

This patchset contains Rust bindings for the kernel workqueue.

One of the primary goals behind the design used in this patch is that we
must support embedding the `work_struct` as a field in user-provided
types, because this allows you to submit things to the workqueue without
having to allocate, making the submission infallible. If we didn't have
to support this, then the patch would be much simpler. One of the main
things that make it complicated is that we must ensure that the function
pointer in the `work_struct` is compatible with the struct it is
contained within.

The original version of the workqueue bindings was written by Wedson,
but I have rewritten much of it so that it uses the pin-init
infrastructure and can be used with containers other than `Arc`.

Changes v2 -> v3:

 * Moved dependency patches so they are first.
 * Various documentation and comment improvements.
 * Changed implementation of `Arc::from_raw`.
 * Use __INIT_WORK_WITH_KEY instead of __INIT_WORK and use `LockClassKey`
   where appropriate.
 * Removed PhantomPinned from Work. This depends on [1] for correctness.

More detailed changelogs can be found on the individual patches.

v1: https://lore.kernel.org/all/20230517203119.3160435-1-aliceryhl@google.com/
v2: https://lore.kernel.org/all/20230601134946.3887870-1-aliceryhl@google.com/

[1]: https://lore.kernel.org/all/20230630150216.109789-1-benno.lossin@proton.me/

Alice Ryhl (5):
  rust: workqueue: add low-level workqueue bindings
  rust: workqueue: add helper for defining work_struct fields
  rust: workqueue: implement `WorkItemPointer` for pointer types
  rust: workqueue: add `try_spawn` helper method
  rust: workqueue: add examples

Wedson Almeida Filho (4):
  rust: add offset_of! macro
  rust: sync: add `Arc::{from_raw, into_raw}`
  workqueue: introduce `__INIT_WORK_WITH_KEY`
  rust: workqueue: define built-in queues

 include/linux/workqueue.h       |  17 +-
 rust/bindings/bindings_helper.h |   1 +
 rust/helpers.c                  |   8 +
 rust/kernel/lib.rs              |  39 ++
 rust/kernel/sync/arc.rs         |  49 ++-
 rust/kernel/workqueue.rs        | 659 ++++++++++++++++++++++++++++++++
 scripts/Makefile.build          |   2 +-
 7 files changed, 767 insertions(+), 8 deletions(-)
 create mode 100644 rust/kernel/workqueue.rs


base-commit: d2e3115d717197cb2bc020dd1f06b06538474ac3
-- 
2.41.0.255.g8b1d071c50-goog


^ permalink raw reply	[flat|nested] 31+ messages in thread

* [PATCH v3 1/9] rust: add offset_of! macro
  2023-07-11  9:32 [PATCH v3 0/9] rust: workqueue: add bindings for the workqueue Alice Ryhl
@ 2023-07-11  9:32 ` Alice Ryhl
  2023-08-21 18:43   ` Andreas Hindborg (Samsung)
  2023-07-11  9:32 ` [PATCH v3 2/9] rust: sync: add `Arc::{from_raw, into_raw}` Alice Ryhl
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 31+ messages in thread
From: Alice Ryhl @ 2023-07-11  9:32 UTC (permalink / raw)
  To: rust-for-linux, Tejun Heo, Miguel Ojeda
  Cc: Lai Jiangshan, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron, Benno Lossin, Alice Ryhl,
	linux-kernel, patches, Wedson Almeida Filho,
	Martin Rodriguez Reboredo

From: Wedson Almeida Filho <walmeida@microsoft.com>

This macro is used to compute the offset of a field in a struct.

This commit enables an unstable feature that is necessary for using
the macro in a constant. However, this is not a problem as the macro
will become available from the Rust standard library soon [1]. The
unstable feature can be disabled again once that happens.

The macro in this patch does not support sub-fields. That is, you cannot
write `offset_of!(MyStruct, field.sub_field)` to get the offset of
`sub_field` with `field`'s type being a struct with a field called
`sub_field`. This is because `field` might be a `Box<SubStruct>`, which
means that you would be trying to compute the offset to something in an
entirely different allocation. There's no easy way to fix the current
macro to support subfields, but the version being added to the standard
library should support it, so the limitation is temporary and not a big
deal.

Link: https://github.com/rust-lang/rust/issues/106655 [1]
Signed-off-by: Wedson Almeida Filho <walmeida@microsoft.com>
Co-developed-by: Alice Ryhl <aliceryhl@google.com>
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
Reviewed-by: Martin Rodriguez Reboredo <yakoyoku@gmail.com>
Reviewed-by: Gary Guo <gary@garyguo.net>
Reviewed-by: Benno Lossin <benno.lossin@proton.me>
---
v2 -> v3:
 * Add comment as suggested in https://lore.kernel.org/rust-for-linux/875y862lr7.fsf@metaspace.dk/
 * Added Reviewed-by from Gary and Benno.

 rust/kernel/lib.rs     | 37 +++++++++++++++++++++++++++++++++++++
 scripts/Makefile.build |  2 +-
 2 files changed, 38 insertions(+), 1 deletion(-)

diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 85b261209977..788914fd935f 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -14,6 +14,7 @@
 #![no_std]
 #![feature(allocator_api)]
 #![feature(coerce_unsized)]
+#![feature(const_refs_to_cell)]
 #![feature(dispatch_from_dyn)]
 #![feature(new_uninit)]
 #![feature(receiver_trait)]
@@ -97,3 +98,39 @@ fn panic(info: &core::panic::PanicInfo<'_>) -> ! {
     // instead of `!`. See <https://github.com/rust-lang/rust-bindgen/issues/2094>.
     loop {}
 }
+
+/// Calculates the offset of a field from the beginning of the struct it belongs to.
+///
+/// # Examples
+///
+/// ```
+/// #[repr(C)]
+/// struct Test {
+///     a: u64,
+///     b: u32,
+/// }
+///
+/// assert_eq!(kernel::offset_of!(Test, b), 8);
+/// ```
+#[macro_export]
+macro_rules! offset_of {
+    ($type:path, $field:ident) => {{
+        // Statically ensure that the type has a field of the given name. This ensures that no
+        // deref coercion is happening.
+        let $type { $field: _, .. };
+        let tmp = ::core::mem::MaybeUninit::<$type>::uninit();
+        let outer = tmp.as_ptr();
+        // To avoid warnings when nesting `unsafe` blocks.
+        #[allow(unused_unsafe)]
+        // SAFETY: The pointer is valid and aligned, just not initialised; `addr_of` ensures that
+        // we don't actually read from `outer` (which would be UB) nor create an intermediate
+        // reference.
+        let inner = unsafe { ::core::ptr::addr_of!((*outer).$field) } as *const u8;
+        // To avoid warnings when nesting `unsafe` blocks.
+        #[allow(unused_unsafe)]
+        // SAFETY: The two pointers are within the same allocation block.
+        unsafe {
+            inner.offset_from(outer as *const u8) as usize
+        }
+    }};
+}
diff --git a/scripts/Makefile.build b/scripts/Makefile.build
index 78175231c969..819510694769 100644
--- a/scripts/Makefile.build
+++ b/scripts/Makefile.build
@@ -277,7 +277,7 @@ $(obj)/%.lst: $(src)/%.c FORCE
 # Compile Rust sources (.rs)
 # ---------------------------------------------------------------------------
 
-rust_allowed_features := new_uninit
+rust_allowed_features := const_refs_to_cell,new_uninit
 
 rust_common_cmd = \
 	RUST_MODFILE=$(modfile) $(RUSTC_OR_CLIPPY) $(rust_flags) \
-- 
2.41.0.255.g8b1d071c50-goog


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v3 2/9] rust: sync: add `Arc::{from_raw, into_raw}`
  2023-07-11  9:32 [PATCH v3 0/9] rust: workqueue: add bindings for the workqueue Alice Ryhl
  2023-07-11  9:32 ` [PATCH v3 1/9] rust: add offset_of! macro Alice Ryhl
@ 2023-07-11  9:32 ` Alice Ryhl
  2023-07-12 20:33   ` Martin Rodriguez Reboredo
                     ` (2 more replies)
  2023-07-11  9:32 ` [PATCH 3/9] workqueue: introduce `__INIT_WORK_WITH_KEY` Alice Ryhl
                   ` (7 subsequent siblings)
  9 siblings, 3 replies; 31+ messages in thread
From: Alice Ryhl @ 2023-07-11  9:32 UTC (permalink / raw)
  To: rust-for-linux, Tejun Heo, Miguel Ojeda
  Cc: Lai Jiangshan, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron, Benno Lossin, Alice Ryhl,
	linux-kernel, patches, Wedson Almeida Filho

From: Wedson Almeida Filho <walmeida@microsoft.com>

These methods can be used to turn an `Arc` into a raw pointer and back,
in a way that preserves the metadata for fat pointers.

This is done using the unstable ptr_metadata feature [1]. However, it
could also be done using the unstable pointer_byte_offsets feature [2],
which is likely to have a shorter path to stabilization than
ptr_metadata.

Link: https://github.com/rust-lang/rust/issues/81513 [1]
Link: https://github.com/rust-lang/rust/issues/96283 [2]
Signed-off-by: Wedson Almeida Filho <walmeida@microsoft.com>
Co-developed-by: Alice Ryhl <aliceryhl@google.com>
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
Reviewed-by: Gary Guo <gary@garyguo.net>
---
v2 -> v3:
 * Use `transmute_copy` to convert metadata.
 * Use `add` instead of `wrapping_add`.
 * Dropped Reviewed-by from Martin and Benno due to changes.

 rust/kernel/lib.rs      |  1 +
 rust/kernel/sync/arc.rs | 49 +++++++++++++++++++++++++++++++++++++++--
 2 files changed, 48 insertions(+), 2 deletions(-)

diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 788914fd935f..6963d11092c4 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -17,6 +17,7 @@
 #![feature(const_refs_to_cell)]
 #![feature(dispatch_from_dyn)]
 #![feature(new_uninit)]
+#![feature(ptr_metadata)]
 #![feature(receiver_trait)]
 #![feature(unsize)]
 
diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs
index a89843cacaad..4046b534e53b 100644
--- a/rust/kernel/sync/arc.rs
+++ b/rust/kernel/sync/arc.rs
@@ -24,13 +24,13 @@
 };
 use alloc::boxed::Box;
 use core::{
-    alloc::AllocError,
+    alloc::{AllocError, Layout},
     fmt,
     marker::{PhantomData, Unsize},
     mem::{ManuallyDrop, MaybeUninit},
     ops::{Deref, DerefMut},
     pin::Pin,
-    ptr::NonNull,
+    ptr::{NonNull, Pointee},
 };
 use macros::pin_data;
 
@@ -212,6 +212,51 @@ unsafe fn from_inner(inner: NonNull<ArcInner<T>>) -> Self {
         }
     }
 
+    /// Convert the [`Arc`] into a raw pointer.
+    ///
+    /// The raw pointer has ownership of the refcount that this Arc object owned.
+    pub fn into_raw(self) -> *const T {
+        let ptr = self.ptr.as_ptr();
+        core::mem::forget(self);
+        // SAFETY: The pointer is valid.
+        unsafe { core::ptr::addr_of!((*ptr).data) }
+    }
+
+    /// Recreates an [`Arc`] instance previously deconstructed via [`Arc::into_raw`].
+    ///
+    /// This code relies on the `repr(C)` layout of structs as described in
+    /// <https://doc.rust-lang.org/reference/type-layout.html#reprc-structs>.
+    ///
+    /// # Safety
+    ///
+    /// `ptr` must have been returned by a previous call to [`Arc::into_raw`]. Additionally, it
+    /// can only be called once for each previous call to [`Arc::into_raw`].
+    pub unsafe fn from_raw(ptr: *const T) -> Self {
+        let refcount_layout = Layout::new::<bindings::refcount_t>();
+        // SAFETY: The caller guarantees that the pointer is valid.
+        let val_layout = Layout::for_value(unsafe { &*ptr });
+        // SAFETY: We're computing the layout of a real struct that existed when compiling this
+        // binary, so its layout is not so large that it can trigger arithmetic overflow.
+        let val_offset = unsafe { refcount_layout.extend(val_layout).unwrap_unchecked().1 };
+
+        let metadata: <T as Pointee>::Metadata = core::ptr::metadata(ptr);
+        // SAFETY: The metadata of `T` and `ArcInner<T>` is the same because `ArcInner` is a struct
+        // with `T` as its last field.
+        //
+        // This is documented at:
+        // <https://doc.rust-lang.org/std/ptr/trait.Pointee.html>.
+        let metadata: <ArcInner<T> as Pointee>::Metadata =
+            unsafe { core::mem::transmute_copy(&metadata) };
+        // SAFETY: The pointer is in-bounds of an allocation both before and after offsetting the
+        // pointer, since it originates from a previous call to `Arc::into_raw` and is still valid.
+        let ptr = unsafe { (ptr as *mut u8).sub(val_offset) as *mut () };
+        let ptr = core::ptr::from_raw_parts_mut(ptr, metadata);
+
+        // SAFETY: By the safety requirements we know that `ptr` came from `Arc::into_raw`, so the
+        // reference count held then will be owned by the new `Arc` object.
+        unsafe { Self::from_inner(NonNull::new_unchecked(ptr)) }
+    }
+
     /// Returns an [`ArcBorrow`] from the given [`Arc`].
     ///
     /// This is useful when the argument of a function call is an [`ArcBorrow`] (e.g., in a method
-- 
2.41.0.255.g8b1d071c50-goog


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH 3/9] workqueue: introduce `__INIT_WORK_WITH_KEY`
  2023-07-11  9:32 [PATCH v3 0/9] rust: workqueue: add bindings for the workqueue Alice Ryhl
  2023-07-11  9:32 ` [PATCH v3 1/9] rust: add offset_of! macro Alice Ryhl
  2023-07-11  9:32 ` [PATCH v3 2/9] rust: sync: add `Arc::{from_raw, into_raw}` Alice Ryhl
@ 2023-07-11  9:32 ` Alice Ryhl
  2023-07-11 10:49   ` Alice Ryhl
                     ` (2 more replies)
  2023-07-11  9:32 ` [PATCH v3 4/9] rust: workqueue: add low-level workqueue bindings Alice Ryhl
                   ` (6 subsequent siblings)
  9 siblings, 3 replies; 31+ messages in thread
From: Alice Ryhl @ 2023-07-11  9:32 UTC (permalink / raw)
  To: rust-for-linux, Tejun Heo, Miguel Ojeda
  Cc: Lai Jiangshan, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron, Benno Lossin, Alice Ryhl,
	linux-kernel, patches, Wedson Almeida Filho

From: Wedson Almeida Filho <walmeida@microsoft.com>

A Rust helper (introduced in a later patch) needs to call
`__INIT_WORK` with a passed key, rather than define one in place.

In order to do that, this moves the initialization code from
the `__INIT_WORK` macro into a new `__INIT_WORK_WITH_KEY` macro
which takes the key as an extra parameter.

Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
Signed-off-by: Wedson Almeida Filho <walmeida@microsoft.com>
Co-developed-by: Miguel Ojeda <ojeda@kernel.org>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
Acked-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
---
Taken from [1]. Wedson's email updated at Wedson's request. Tejun's
Acked-by taken from [2].

[1]: https://lore.kernel.org/rust-for-linux/20220802015052.10452-7-ojeda@kernel.org/
[2]: https://lore.kernel.org/rust-for-linux/Yvq3IfK4+C94AeE2@slm.duckdns.org/

 include/linux/workqueue.h | 31 +++++++++++++++++++------------
 1 file changed, 19 insertions(+), 12 deletions(-)

diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index 3992c994787f..c91a84a4723d 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -221,24 +221,31 @@ static inline unsigned int work_static(struct work_struct *work) { return 0; }
  * to generate better code.
  */
 #ifdef CONFIG_LOCKDEP
+#define __INIT_WORK_WITH_KEY(_work, _func, _onstack, _key)		\
+	do {								\
+		__init_work((_work), _onstack);				\
+		(_work)->data = (atomic_long_t) WORK_DATA_INIT();	\
+		lockdep_init_map(&(_work)->lockdep_map, "(work_completion)"#_work, _key, 0); \
+		INIT_LIST_HEAD(&(_work)->entry);			\
+		(_work)->func = (_func);				\
+	} while (0)
+
 #define __INIT_WORK(_work, _func, _onstack)				\
 	do {								\
 		static struct lock_class_key __key;			\
-									\
-		__init_work((_work), _onstack);				\
-		(_work)->data = (atomic_long_t) WORK_DATA_INIT();	\
-		lockdep_init_map(&(_work)->lockdep_map, "(work_completion)"#_work, &__key, 0); \
-		INIT_LIST_HEAD(&(_work)->entry);			\
-		(_work)->func = (_func);				\
+		__INIT_WORK_WITH_KEY(_work, _func, _onstack, &__key);	\
 	} while (0)
 #else
+#define __INIT_WORK_WITH_KEY(_work, _func, _onstack, _key)		\
+	do {								\
+		__init_work((_work), _onstack);				\
+		(_work)->data = (atomic_long_t) WORK_DATA_INIT();	\
+		INIT_LIST_HEAD(&(_work)->entry);			\
+		(_work)->func = (_func);				\
+	} while (0)
+
 #define __INIT_WORK(_work, _func, _onstack)				\
-	do {								\
-		__init_work((_work), _onstack);				\
-		(_work)->data = (atomic_long_t) WORK_DATA_INIT();	\
-		INIT_LIST_HEAD(&(_work)->entry);			\
-		(_work)->func = (_func);				\
-	} while (0)
+	__INIT_WORK_WITH_KEY(_work, _func, _onstack, NULL)
 #endif
 
 #define INIT_WORK(_work, _func)						\
-- 
2.41.0.255.g8b1d071c50-goog


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v3 4/9] rust: workqueue: add low-level workqueue bindings
  2023-07-11  9:32 [PATCH v3 0/9] rust: workqueue: add bindings for the workqueue Alice Ryhl
                   ` (2 preceding siblings ...)
  2023-07-11  9:32 ` [PATCH 3/9] workqueue: introduce `__INIT_WORK_WITH_KEY` Alice Ryhl
@ 2023-07-11  9:32 ` Alice Ryhl
  2023-07-11 22:23   ` Boqun Feng
  2023-07-11  9:32 ` [PATCH v3 5/9] rust: workqueue: define built-in queues Alice Ryhl
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 31+ messages in thread
From: Alice Ryhl @ 2023-07-11  9:32 UTC (permalink / raw)
  To: rust-for-linux, Tejun Heo, Miguel Ojeda
  Cc: Lai Jiangshan, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron, Benno Lossin, Alice Ryhl,
	linux-kernel, patches, Martin Rodriguez Reboredo,
	Andreas Hindborg

Define basic low-level bindings to a kernel workqueue. The API defined
here can only be used unsafely. Later commits will provide safe
wrappers.

Co-developed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
Reviewed-by: Martin Rodriguez Reboredo <yakoyoku@gmail.com>
Reviewed-by: Andreas Hindborg (Samsung) <nmi@metaspace.dk>
Reviewed-by: Benno Lossin <benno.lossin@proton.me>
---
v2 -> v3:
 * Update documentation to say "guarantees section".
 * Add Reviewed-by from Martin, Andreas, Benno.

 rust/bindings/bindings_helper.h |   1 +
 rust/kernel/lib.rs              |   1 +
 rust/kernel/workqueue.rs        | 108 ++++++++++++++++++++++++++++++++
 3 files changed, 110 insertions(+)
 create mode 100644 rust/kernel/workqueue.rs

diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 3e601ce2548d..4e1c0938c8cb 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -11,6 +11,7 @@
 #include <linux/refcount.h>
 #include <linux/wait.h>
 #include <linux/sched.h>
+#include <linux/workqueue.h>
 
 /* `bindgen` gets confused at certain things. */
 const gfp_t BINDINGS_GFP_KERNEL = GFP_KERNEL;
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 6963d11092c4..6d63f4f6bb8a 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -45,6 +45,7 @@
 pub mod sync;
 pub mod task;
 pub mod types;
+pub mod workqueue;
 
 #[doc(hidden)]
 pub use bindings;
diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs
new file mode 100644
index 000000000000..060d26dfcc7d
--- /dev/null
+++ b/rust/kernel/workqueue.rs
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Work queues.
+//!
+//! C header: [`include/linux/workqueue.h`](../../../../include/linux/workqueue.h)
+
+use crate::{bindings, types::Opaque};
+
+/// A kernel work queue.
+///
+/// Wraps the kernel's C `struct workqueue_struct`.
+///
+/// It allows work items to be queued to run on thread pools managed by the kernel. Several are
+/// always available, for example, `system`, `system_highpri`, `system_long`, etc.
+#[repr(transparent)]
+pub struct Queue(Opaque<bindings::workqueue_struct>);
+
+// SAFETY: Kernel workqueues are usable from any thread.
+unsafe impl Send for Queue {}
+unsafe impl Sync for Queue {}
+
+impl Queue {
+    /// Use the provided `struct workqueue_struct` with Rust.
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that the provided raw pointer is not dangling, that it points at a
+    /// valid workqueue, and that it remains valid until the end of 'a.
+    pub unsafe fn from_raw<'a>(ptr: *const bindings::workqueue_struct) -> &'a Queue {
+        // SAFETY: The `Queue` type is `#[repr(transparent)]`, so the pointer cast is valid. The
+        // caller promises that the pointer is not dangling.
+        unsafe { &*(ptr as *const Queue) }
+    }
+
+    /// Enqueues a work item.
+    ///
+    /// This may fail if the work item is already enqueued in a workqueue.
+    ///
+    /// The work item will be submitted using `WORK_CPU_UNBOUND`.
+    pub fn enqueue<W, const ID: u64>(&self, w: W) -> W::EnqueueOutput
+    where
+        W: RawWorkItem<ID> + Send + 'static,
+    {
+        let queue_ptr = self.0.get();
+
+        // SAFETY: We only return `false` if the `work_struct` is already in a workqueue. The other
+        // `__enqueue` requirements are not relevant since `W` is `Send` and static.
+        //
+        // The call to `bindings::queue_work_on` will dereference the provided raw pointer, which
+        // is ok because `__enqueue` guarantees that the pointer is valid for the duration of this
+        // closure.
+        //
+        // Furthermore, if the C workqueue code accesses the pointer after this call to
+        // `__enqueue`, then the work item was successfully enqueued, and `bindings::queue_work_on`
+        // will have returned true. In this case, `__enqueue` promises that the raw pointer will
+        // stay valid until we call the function pointer in the `work_struct`, so the access is ok.
+        unsafe {
+            w.__enqueue(move |work_ptr| {
+                bindings::queue_work_on(bindings::WORK_CPU_UNBOUND as _, queue_ptr, work_ptr)
+            })
+        }
+    }
+}
+
+/// A raw work item.
+///
+/// This is the low-level trait that is designed for being as general as possible.
+///
+/// The `ID` parameter to this trait exists so that a single type can provide multiple
+/// implementations of this trait. For example, if a struct has multiple `work_struct` fields, then
+/// you will implement this trait once for each field, using a different id for each field. The
+/// actual value of the id is not important as long as you use different ids for different fields
+/// of the same struct. (Fields of different structs need not use different ids.)
+///
+/// Note that the id is used only to select the right method to call during compilation. It wont be
+/// part of the final executable.
+///
+/// # Safety
+///
+/// Implementers must ensure that any pointers passed to a `queue_work_on` closure by `__enqueue`
+/// remain valid for the duration specified in the guarantees section of the documentation for
+/// `__enqueue`.
+pub unsafe trait RawWorkItem<const ID: u64> {
+    /// The return type of [`Queue::enqueue`].
+    type EnqueueOutput;
+
+    /// Enqueues this work item on a queue using the provided `queue_work_on` method.
+    ///
+    /// # Guarantees
+    ///
+    /// If this method calls the provided closure, then the raw pointer is guaranteed to point at a
+    /// valid `work_struct` for the duration of the call to the closure. If the closure returns
+    /// true, then it is further guaranteed that the pointer remains valid until someone calls the
+    /// function pointer stored in the `work_struct`.
+    ///
+    /// # Safety
+    ///
+    /// The provided closure may only return `false` if the `work_struct` is already in a workqueue.
+    ///
+    /// If the work item type is annotated with any lifetimes, then you must not call the function
+    /// pointer after any such lifetime expires. (Never calling the function pointer is okay.)
+    ///
+    /// If the work item type is not [`Send`], then the function pointer must be called on the same
+    /// thread as the call to `__enqueue`.
+    unsafe fn __enqueue<F>(self, queue_work_on: F) -> Self::EnqueueOutput
+    where
+        F: FnOnce(*mut bindings::work_struct) -> bool;
+}
-- 
2.41.0.255.g8b1d071c50-goog


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v3 5/9] rust: workqueue: define built-in queues
  2023-07-11  9:32 [PATCH v3 0/9] rust: workqueue: add bindings for the workqueue Alice Ryhl
                   ` (3 preceding siblings ...)
  2023-07-11  9:32 ` [PATCH v3 4/9] rust: workqueue: add low-level workqueue bindings Alice Ryhl
@ 2023-07-11  9:32 ` Alice Ryhl
  2023-07-11  9:33 ` [PATCH v3 6/9] rust: workqueue: add helper for defining work_struct fields Alice Ryhl
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 31+ messages in thread
From: Alice Ryhl @ 2023-07-11  9:32 UTC (permalink / raw)
  To: rust-for-linux, Tejun Heo, Miguel Ojeda
  Cc: Lai Jiangshan, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron, Benno Lossin, Alice Ryhl,
	linux-kernel, patches, Wedson Almeida Filho,
	Martin Rodriguez Reboredo, Andreas Hindborg

From: Wedson Almeida Filho <walmeida@microsoft.com>

We provide these methods because it lets us access these queues from
Rust without using unsafe code.

These methods return `&'static Queue`. References annotated with the
'static lifetime are used when the referent will stay alive forever.
That is ok for these queues because they are global variables and cannot
be destroyed.

Signed-off-by: Wedson Almeida Filho <walmeida@microsoft.com>
Co-developed-by: Alice Ryhl <aliceryhl@google.com>
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
Reviewed-by: Martin Rodriguez Reboredo <yakoyoku@gmail.com>
Reviewed-by: Gary Guo <gary@garyguo.net>
Reviewed-by: Andreas Hindborg (Samsung) <nmi@metaspace.dk>
Reviewed-by: Benno Lossin <benno.lossin@proton.me>
---
v2 -> v3:
 * Explain what a freezable workqueue is.
 * Add Reviewed-by from Gary, Andreas, Benno.

 rust/kernel/workqueue.rs | 71 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 71 insertions(+)

diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs
index 060d26dfcc7d..cad039dfc5a9 100644
--- a/rust/kernel/workqueue.rs
+++ b/rust/kernel/workqueue.rs
@@ -106,3 +106,74 @@ unsafe fn __enqueue<F>(self, queue_work_on: F) -> Self::EnqueueOutput
     where
         F: FnOnce(*mut bindings::work_struct) -> bool;
 }
+
+/// Returns the system work queue (`system_wq`).
+///
+/// It is the one used by `schedule[_delayed]_work[_on]()`. Multi-CPU multi-threaded. There are
+/// users which expect relatively short queue flush time.
+///
+/// Callers shouldn't queue work items which can run for too long.
+pub fn system() -> &'static Queue {
+    // SAFETY: `system_wq` is a C global, always available.
+    unsafe { Queue::from_raw(bindings::system_wq) }
+}
+
+/// Returns the system high-priority work queue (`system_highpri_wq`).
+///
+/// It is similar to the one returned by [`system`] but for work items which require higher
+/// scheduling priority.
+pub fn system_highpri() -> &'static Queue {
+    // SAFETY: `system_highpri_wq` is a C global, always available.
+    unsafe { Queue::from_raw(bindings::system_highpri_wq) }
+}
+
+/// Returns the system work queue for potentially long-running work items (`system_long_wq`).
+///
+/// It is similar to the one returned by [`system`] but may host long running work items. Queue
+/// flushing might take relatively long.
+pub fn system_long() -> &'static Queue {
+    // SAFETY: `system_long_wq` is a C global, always available.
+    unsafe { Queue::from_raw(bindings::system_long_wq) }
+}
+
+/// Returns the system unbound work queue (`system_unbound_wq`).
+///
+/// Workers are not bound to any specific CPU, not concurrency managed, and all queued work items
+/// are executed immediately as long as `max_active` limit is not reached and resources are
+/// available.
+pub fn system_unbound() -> &'static Queue {
+    // SAFETY: `system_unbound_wq` is a C global, always available.
+    unsafe { Queue::from_raw(bindings::system_unbound_wq) }
+}
+
+/// Returns the system freezable work queue (`system_freezable_wq`).
+///
+/// It is equivalent to the one returned by [`system`] except that it's freezable.
+///
+/// A freezable workqueue participates in the freeze phase of the system suspend operations. Work
+/// items on the workqueue are drained and no new work item starts execution until thawed.
+pub fn system_freezable() -> &'static Queue {
+    // SAFETY: `system_freezable_wq` is a C global, always available.
+    unsafe { Queue::from_raw(bindings::system_freezable_wq) }
+}
+
+/// Returns the system power-efficient work queue (`system_power_efficient_wq`).
+///
+/// It is inclined towards saving power and is converted to "unbound" variants if the
+/// `workqueue.power_efficient` kernel parameter is specified; otherwise, it is similar to the one
+/// returned by [`system`].
+pub fn system_power_efficient() -> &'static Queue {
+    // SAFETY: `system_power_efficient_wq` is a C global, always available.
+    unsafe { Queue::from_raw(bindings::system_power_efficient_wq) }
+}
+
+/// Returns the system freezable power-efficient work queue (`system_freezable_power_efficient_wq`).
+///
+/// It is similar to the one returned by [`system_power_efficient`] except that is freezable.
+///
+/// A freezable workqueue participates in the freeze phase of the system suspend operations. Work
+/// items on the workqueue are drained and no new work item starts execution until thawed.
+pub fn system_freezable_power_efficient() -> &'static Queue {
+    // SAFETY: `system_freezable_power_efficient_wq` is a C global, always available.
+    unsafe { Queue::from_raw(bindings::system_freezable_power_efficient_wq) }
+}
-- 
2.41.0.255.g8b1d071c50-goog


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v3 6/9] rust: workqueue: add helper for defining work_struct fields
  2023-07-11  9:32 [PATCH v3 0/9] rust: workqueue: add bindings for the workqueue Alice Ryhl
                   ` (4 preceding siblings ...)
  2023-07-11  9:32 ` [PATCH v3 5/9] rust: workqueue: define built-in queues Alice Ryhl
@ 2023-07-11  9:33 ` Alice Ryhl
  2023-07-12 20:43   ` Martin Rodriguez Reboredo
                     ` (2 more replies)
  2023-07-11  9:33 ` [PATCH v3 7/9] rust: workqueue: implement `WorkItemPointer` for pointer types Alice Ryhl
                   ` (3 subsequent siblings)
  9 siblings, 3 replies; 31+ messages in thread
From: Alice Ryhl @ 2023-07-11  9:33 UTC (permalink / raw)
  To: rust-for-linux, Tejun Heo, Miguel Ojeda
  Cc: Lai Jiangshan, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron, Benno Lossin, Alice Ryhl,
	linux-kernel, patches

The main challenge with defining `work_struct` fields is making sure
that the function pointer stored in the `work_struct` is appropriate for
the work item type it is embedded in. It needs to know the offset of the
`work_struct` field being used (even if there are several!) so that it
can do a `container_of`, and it needs to know the type of the work item
so that it can call into the right user-provided code. All of this needs
to happen in a way that provides a safe API to the user, so that users
of the workqueue cannot mix up the function pointers.

There are three important pieces that are relevant when doing this:

 * The pointer type.
 * The work item struct. This is what the pointer points at.
 * The `work_struct` field. This is a field of the work item struct.

This patch introduces a separate trait for each piece. The pointer type
is given a `WorkItemPointer` trait, which pointer types need to
implement to be usable with the workqueue. This trait will be
implemented for `Arc` and `Box` in a later patch in this patchset.
Implementing this trait is unsafe because this is where the
`container_of` operation happens, but user-code will not need to
implement it themselves.

The work item struct should then implement the `WorkItem` trait. This
trait is where user-code specifies what they want to happen when a work
item is executed. It also specifies what the correct pointer type is.

Finally, to make the work item struct know the offset of its
`work_struct` field, we use a trait called `HasWork<T, ID>`. If a type
implements this trait, then the type declares that, at the given offset,
there is a field of type `Work<T, ID>`. The trait is marked unsafe
because the OFFSET constant must be correct, but we provide an
`impl_has_work!` macro that can safely implement `HasWork<T>` on a type.
The macro expands to something that only compiles if the specified field
really has the type `Work<T>`. It is used like this:

```
struct MyWorkItem {
    work_field: Work<MyWorkItem, 1>,
}

impl_has_work! {
    impl HasWork<MyWorkItem, 1> for MyWorkItem { self.work_field }
}
```

Note that since the `Work` type is annotated with an id, you can have
several `work_struct` fields by using a different id for each one.

Co-developed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
---
v2 -> v3:
 * Use __INIT_WORK_WITH_KEY instead of __INIT_WORK.
 * Expand documentation for WorkItemPointer.
 * Expand documentation for HasWork.
 * Removed PhantomPinned from Work. This depends on [1] for correctness.
 * Dropped Reviewed-by annotations due to changes.

[1]: https://lore.kernel.org/all/20230630150216.109789-1-benno.lossin@proton.me/

 rust/helpers.c           |   8 ++
 rust/kernel/workqueue.rs | 240 ++++++++++++++++++++++++++++++++++++++-
 2 files changed, 247 insertions(+), 1 deletion(-)

diff --git a/rust/helpers.c b/rust/helpers.c
index bb594da56137..f7a04a266f46 100644
--- a/rust/helpers.c
+++ b/rust/helpers.c
@@ -27,6 +27,7 @@
 #include <linux/spinlock.h>
 #include <linux/sched/signal.h>
 #include <linux/wait.h>
+#include <linux/workqueue.h>
 
 __noreturn void rust_helper_BUG(void)
 {
@@ -135,6 +136,13 @@ void rust_helper_put_task_struct(struct task_struct *t)
 }
 EXPORT_SYMBOL_GPL(rust_helper_put_task_struct);
 
+void rust_helper___INIT_WORK_WITH_KEY(struct work_struct *work, work_func_t func,
+				      bool on_stack, struct lock_class_key *key)
+{
+	__INIT_WORK_WITH_KEY(work, func, on_stack, key);
+}
+EXPORT_SYMBOL_GPL(rust_helper___INIT_WORK_WITH_KEY);
+
 /*
  * We use `bindgen`'s `--size_t-is-usize` option to bind the C `size_t` type
  * as the Rust `usize` type, so we can use it in contexts where Rust
diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs
index cad039dfc5a9..a7c972bda0ed 100644
--- a/rust/kernel/workqueue.rs
+++ b/rust/kernel/workqueue.rs
@@ -2,9 +2,34 @@
 
 //! Work queues.
 //!
+//! This file has two components: The raw work item API, and the safe work item API.
+//!
+//! One pattern that is used in both APIs is the `ID` const generic, which exists to allow a single
+//! type to define multiple `work_struct` fields. This is done by choosing an id for each field,
+//! and using that id to specify which field you wish to use. (The actual value doesn't matter, as
+//! long as you use different values for different fields of the same struct.) Since these IDs are
+//! generic, they are used only at compile-time, so they shouldn't exist in the final binary.
+//!
+//! # The raw API
+//!
+//! The raw API consists of the `RawWorkItem` trait, where the work item needs to provide an
+//! arbitrary function that knows how to enqueue the work item. It should usually not be used
+//! directly, but if you want to, you can use it without using the pieces from the safe API.
+//!
+//! # The safe API
+//!
+//! The safe API is used via the `Work` struct and `WorkItem` traits. Furthermore, it also includes
+//! a trait called `WorkItemPointer`, which is usually not used directly by the user.
+//!
+//!  * The `Work` struct is the Rust wrapper for the C `work_struct` type.
+//!  * The `WorkItem` trait is implemented for structs that can be enqueued to a workqueue.
+//!  * The `WorkItemPointer` trait is implemented for the pointer type that points at a something
+//!    that implements `WorkItem`.
+//!
 //! C header: [`include/linux/workqueue.h`](../../../../include/linux/workqueue.h)
 
-use crate::{bindings, types::Opaque};
+use crate::{bindings, prelude::*, sync::LockClassKey, types::Opaque};
+use core::marker::PhantomData;
 
 /// A kernel work queue.
 ///
@@ -107,6 +132,219 @@ unsafe fn __enqueue<F>(self, queue_work_on: F) -> Self::EnqueueOutput
         F: FnOnce(*mut bindings::work_struct) -> bool;
 }
 
+/// Defines the method that should be called directly when a work item is executed.
+///
+/// This trait is implemented by `Pin<Box<T>>` and `Arc<T>`, and is mainly intended to be
+/// implemented for smart pointer types. For your own structs, you would implement [`WorkItem`]
+/// instead. The `run` method on this trait will usually just perform the appropriate
+/// `container_of` translation and then call into the `run` method from the [`WorkItem`] trait.
+///
+/// This trait is used when the `work_struct` field is defined using the [`Work`] helper.
+///
+/// # Safety
+///
+/// Implementers must ensure that [`__enqueue`] uses a `work_struct` initialized with the [`run`]
+/// method of this trait as the function pointer.
+///
+/// [`__enqueue`]: RawWorkItem::__enqueue
+/// [`run`]: WorkItemPointer::run
+pub unsafe trait WorkItemPointer<const ID: u64>: RawWorkItem<ID> {
+    /// Run this work item.
+    ///
+    /// # Safety
+    ///
+    /// The provided `work_struct` pointer must originate from a previous call to `__enqueue` where
+    /// the `queue_work_on` closure returned true, and the pointer must still be valid.
+    unsafe extern "C" fn run(ptr: *mut bindings::work_struct);
+}
+
+/// Defines the method that should be called when this work item is executed.
+///
+/// This trait is used when the `work_struct` field is defined using the [`Work`] helper.
+pub trait WorkItem<const ID: u64 = 0> {
+    /// The pointer type that this struct is wrapped in. This will typically be `Arc<Self>` or
+    /// `Pin<Box<Self>>`.
+    type Pointer: WorkItemPointer<ID>;
+
+    /// The method that should be called when this work item is executed.
+    fn run(this: Self::Pointer);
+}
+
+/// Links for a work item.
+///
+/// This struct contains a function pointer to the `run` function from the [`WorkItemPointer`]
+/// trait, and defines the linked list pointers necessary to enqueue a work item in a workqueue.
+///
+/// Wraps the kernel's C `struct work_struct`.
+///
+/// This is a helper type used to associate a `work_struct` with the [`WorkItem`] that uses it.
+#[repr(transparent)]
+pub struct Work<T: ?Sized, const ID: u64 = 0> {
+    work: Opaque<bindings::work_struct>,
+    _inner: PhantomData<T>,
+}
+
+// SAFETY: Kernel work items are usable from any thread.
+//
+// We do not need to constrain `T` since the work item does not actually contain a `T`.
+unsafe impl<T: ?Sized, const ID: u64> Send for Work<T, ID> {}
+// SAFETY: Kernel work items are usable from any thread.
+//
+// We do not need to constrain `T` since the work item does not actually contain a `T`.
+unsafe impl<T: ?Sized, const ID: u64> Sync for Work<T, ID> {}
+
+impl<T: ?Sized, const ID: u64> Work<T, ID> {
+    /// Creates a new instance of [`Work`].
+    #[inline]
+    #[allow(clippy::new_ret_no_self)]
+    pub fn new(key: &'static LockClassKey) -> impl PinInit<Self>
+    where
+        T: WorkItem<ID>,
+    {
+        // SAFETY: The `WorkItemPointer` implementation promises that `run` can be used as the work
+        // item function.
+        unsafe {
+            kernel::init::pin_init_from_closure(move |slot| {
+                let slot = Self::raw_get(slot);
+                bindings::__INIT_WORK_WITH_KEY(slot, Some(T::Pointer::run), false, key.as_ptr());
+                Ok(())
+            })
+        }
+    }
+
+    /// Get a pointer to the inner `work_struct`.
+    ///
+    /// # Safety
+    ///
+    /// The provided pointer must not be dangling and must be properly aligned. (But the memory
+    /// need not be initialized.)
+    #[inline]
+    pub unsafe fn raw_get(ptr: *const Self) -> *mut bindings::work_struct {
+        // SAFETY: The caller promises that the pointer is aligned and not dangling.
+        //
+        // A pointer cast would also be ok due to `#[repr(transparent)]`. We use `addr_of!` so that
+        // the compiler does not complain that the `work` field is unused.
+        unsafe { Opaque::raw_get(core::ptr::addr_of!((*ptr).work)) }
+    }
+}
+
+/// Declares that a type has a [`Work<T, ID>`] field.
+///
+/// The intended way of using this trait is via the [`impl_has_work!`] macro. You can use the macro
+/// like this:
+///
+/// ```no_run
+/// use kernel::prelude::*;
+/// use kernel::workqueue::Work;
+///
+/// struct MyWorkItem {
+///     work_field: Work<MyWorkItem, 1>,
+/// }
+///
+/// impl_has_work! {
+///     impl HasWork<MyWorkItem, 1> for MyWorkItem { self.work_field }
+/// }
+/// ```
+///
+/// Note that since the `Work` type is annotated with an id, you can have several `work_struct`
+/// fields by using a different id for each one.
+///
+/// # Safety
+///
+/// The [`OFFSET`] constant must be the offset of a field in Self of type [`Work<T, ID>`]. The methods on
+/// this trait must have exactly the behavior that the definitions given below have.
+///
+/// [`Work<T, ID>`]: Work
+/// [`impl_has_work!`]: crate::impl_has_work
+/// [`OFFSET`]: HasWork::OFFSET
+pub unsafe trait HasWork<T, const ID: u64 = 0> {
+    /// The offset of the [`Work<T, ID>`] field.
+    ///
+    /// [`Work<T, ID>`]: Work
+    const OFFSET: usize;
+
+    /// Returns the offset of the [`Work<T, ID>`] field.
+    ///
+    /// This method exists because the [`OFFSET`] constant cannot be accessed if the type is not Sized.
+    ///
+    /// [`Work<T, ID>`]: Work
+    /// [`OFFSET`]: HasWork::OFFSET
+    #[inline]
+    fn get_work_offset(&self) -> usize {
+        Self::OFFSET
+    }
+
+    /// Returns a pointer to the [`Work<T, ID>`] field.
+    ///
+    /// # Safety
+    ///
+    /// The provided pointer must point at a valid struct of type `Self`.
+    ///
+    /// [`Work<T, ID>`]: Work
+    #[inline]
+    unsafe fn raw_get_work(ptr: *mut Self) -> *mut Work<T, ID> {
+        // SAFETY: The caller promises that the pointer is valid.
+        unsafe { (ptr as *mut u8).add(Self::OFFSET) as *mut Work<T, ID> }
+    }
+
+    /// Returns a pointer to the struct containing the [`Work<T, ID>`] field.
+    ///
+    /// # Safety
+    ///
+    /// The pointer must point at a [`Work<T, ID>`] field in a struct of type `Self`.
+    ///
+    /// [`Work<T, ID>`]: Work
+    #[inline]
+    unsafe fn work_container_of(ptr: *mut Work<T, ID>) -> *mut Self
+    where
+        Self: Sized,
+    {
+        // SAFETY: The caller promises that the pointer points at a field of the right type in the
+        // right kind of struct.
+        unsafe { (ptr as *mut u8).sub(Self::OFFSET) as *mut Self }
+    }
+}
+
+/// Used to safely implement the [`HasWork<T, ID>`] trait.
+///
+/// # Examples
+///
+/// ```
+/// use kernel::sync::Arc;
+///
+/// struct MyStruct {
+///     work_field: Work<MyStruct, 17>,
+/// }
+///
+/// impl_has_work! {
+///     impl HasWork<MyStruct, 17> for MyStruct { self.work_field }
+/// }
+/// ```
+///
+/// [`HasWork<T, ID>`]: HasWork
+#[macro_export]
+macro_rules! impl_has_work {
+    ($(impl$(<$($implarg:ident),*>)?
+       HasWork<$work_type:ty $(, $id:tt)?>
+       for $self:ident $(<$($selfarg:ident),*>)?
+       { self.$field:ident }
+    )*) => {$(
+        // SAFETY: The implementation of `raw_get_work` only compiles if the field has the right
+        // type.
+        unsafe impl$(<$($implarg),*>)? $crate::workqueue::HasWork<$work_type $(, $id)?> for $self $(<$($selfarg),*>)? {
+            const OFFSET: usize = $crate::offset_of!(Self, $field) as usize;
+
+            #[inline]
+            unsafe fn raw_get_work(ptr: *mut Self) -> *mut $crate::workqueue::Work<$work_type $(, $id)?> {
+                // SAFETY: The caller promises that the pointer is not dangling.
+                unsafe {
+                    ::core::ptr::addr_of_mut!((*ptr).$field)
+                }
+            }
+        }
+    )*};
+}
+
 /// Returns the system work queue (`system_wq`).
 ///
 /// It is the one used by `schedule[_delayed]_work[_on]()`. Multi-CPU multi-threaded. There are
-- 
2.41.0.255.g8b1d071c50-goog


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v3 7/9] rust: workqueue: implement `WorkItemPointer` for pointer types
  2023-07-11  9:32 [PATCH v3 0/9] rust: workqueue: add bindings for the workqueue Alice Ryhl
                   ` (5 preceding siblings ...)
  2023-07-11  9:33 ` [PATCH v3 6/9] rust: workqueue: add helper for defining work_struct fields Alice Ryhl
@ 2023-07-11  9:33 ` Alice Ryhl
  2023-07-11  9:33 ` [PATCH v3 8/9] rust: workqueue: add `try_spawn` helper method Alice Ryhl
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 31+ messages in thread
From: Alice Ryhl @ 2023-07-11  9:33 UTC (permalink / raw)
  To: rust-for-linux, Tejun Heo, Miguel Ojeda
  Cc: Lai Jiangshan, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron, Benno Lossin, Alice Ryhl,
	linux-kernel, patches, Martin Rodriguez Reboredo,
	Andreas Hindborg

This implements the `WorkItemPointer` trait for the pointer types that
you are likely to use the workqueue with. The `Arc` type is for
reference counted objects, and the `Pin<Box<T>>` type is for objects
where the caller has exclusive ownership of the object.

Co-developed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
Reviewed-by: Martin Rodriguez Reboredo <yakoyoku@gmail.com>
Reviewed-by: Andreas Hindborg (Samsung) <nmi@metaspace.dk>
Reviewed-by: Benno Lossin <benno.lossin@proton.me>
---
v2 -> v3:
 * Use `cast_mut` to cast pointer in `impl RawWorkItem for Arc`
 * Add Reviewed-by from Martin, Andreas, Benno.

 rust/kernel/workqueue.rs | 97 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 96 insertions(+), 1 deletion(-)

diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs
index a7c972bda0ed..e760040762bd 100644
--- a/rust/kernel/workqueue.rs
+++ b/rust/kernel/workqueue.rs
@@ -28,8 +28,10 @@
 //!
 //! C header: [`include/linux/workqueue.h`](../../../../include/linux/workqueue.h)
 
-use crate::{bindings, prelude::*, sync::LockClassKey, types::Opaque};
+use crate::{bindings, prelude::*, sync::Arc, sync::LockClassKey, types::Opaque};
+use alloc::boxed::Box;
 use core::marker::PhantomData;
+use core::pin::Pin;
 
 /// A kernel work queue.
 ///
@@ -345,6 +347,99 @@ unsafe fn raw_get_work(ptr: *mut Self) -> *mut $crate::workqueue::Work<$work_typ
     )*};
 }
 
+unsafe impl<T, const ID: u64> WorkItemPointer<ID> for Arc<T>
+where
+    T: WorkItem<ID, Pointer = Self>,
+    T: HasWork<T, ID>,
+{
+    unsafe extern "C" fn run(ptr: *mut bindings::work_struct) {
+        // SAFETY: The `__enqueue` method always uses a `work_struct` stored in a `Work<T, ID>`.
+        let ptr = ptr as *mut Work<T, ID>;
+        // SAFETY: This computes the pointer that `__enqueue` got from `Arc::into_raw`.
+        let ptr = unsafe { T::work_container_of(ptr) };
+        // SAFETY: This pointer comes from `Arc::into_raw` and we've been given back ownership.
+        let arc = unsafe { Arc::from_raw(ptr) };
+
+        T::run(arc)
+    }
+}
+
+unsafe impl<T, const ID: u64> RawWorkItem<ID> for Arc<T>
+where
+    T: WorkItem<ID, Pointer = Self>,
+    T: HasWork<T, ID>,
+{
+    type EnqueueOutput = Result<(), Self>;
+
+    unsafe fn __enqueue<F>(self, queue_work_on: F) -> Self::EnqueueOutput
+    where
+        F: FnOnce(*mut bindings::work_struct) -> bool,
+    {
+        // Casting between const and mut is not a problem as long as the pointer is a raw pointer.
+        let ptr = Arc::into_raw(self).cast_mut();
+
+        // SAFETY: Pointers into an `Arc` point at a valid value.
+        let work_ptr = unsafe { T::raw_get_work(ptr) };
+        // SAFETY: `raw_get_work` returns a pointer to a valid value.
+        let work_ptr = unsafe { Work::raw_get(work_ptr) };
+
+        if queue_work_on(work_ptr) {
+            Ok(())
+        } else {
+            // SAFETY: The work queue has not taken ownership of the pointer.
+            Err(unsafe { Arc::from_raw(ptr) })
+        }
+    }
+}
+
+unsafe impl<T, const ID: u64> WorkItemPointer<ID> for Pin<Box<T>>
+where
+    T: WorkItem<ID, Pointer = Self>,
+    T: HasWork<T, ID>,
+{
+    unsafe extern "C" fn run(ptr: *mut bindings::work_struct) {
+        // SAFETY: The `__enqueue` method always uses a `work_struct` stored in a `Work<T, ID>`.
+        let ptr = ptr as *mut Work<T, ID>;
+        // SAFETY: This computes the pointer that `__enqueue` got from `Arc::into_raw`.
+        let ptr = unsafe { T::work_container_of(ptr) };
+        // SAFETY: This pointer comes from `Arc::into_raw` and we've been given back ownership.
+        let boxed = unsafe { Box::from_raw(ptr) };
+        // SAFETY: The box was already pinned when it was enqueued.
+        let pinned = unsafe { Pin::new_unchecked(boxed) };
+
+        T::run(pinned)
+    }
+}
+
+unsafe impl<T, const ID: u64> RawWorkItem<ID> for Pin<Box<T>>
+where
+    T: WorkItem<ID, Pointer = Self>,
+    T: HasWork<T, ID>,
+{
+    type EnqueueOutput = ();
+
+    unsafe fn __enqueue<F>(self, queue_work_on: F) -> Self::EnqueueOutput
+    where
+        F: FnOnce(*mut bindings::work_struct) -> bool,
+    {
+        // SAFETY: We're not going to move `self` or any of its fields, so its okay to temporarily
+        // remove the `Pin` wrapper.
+        let boxed = unsafe { Pin::into_inner_unchecked(self) };
+        let ptr = Box::into_raw(boxed);
+
+        // SAFETY: Pointers into a `Box` point at a valid value.
+        let work_ptr = unsafe { T::raw_get_work(ptr) };
+        // SAFETY: `raw_get_work` returns a pointer to a valid value.
+        let work_ptr = unsafe { Work::raw_get(work_ptr) };
+
+        if !queue_work_on(work_ptr) {
+            // SAFETY: This method requires exclusive ownership of the box, so it cannot be in a
+            // workqueue.
+            unsafe { ::core::hint::unreachable_unchecked() }
+        }
+    }
+}
+
 /// Returns the system work queue (`system_wq`).
 ///
 /// It is the one used by `schedule[_delayed]_work[_on]()`. Multi-CPU multi-threaded. There are
-- 
2.41.0.255.g8b1d071c50-goog


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v3 8/9] rust: workqueue: add `try_spawn` helper method
  2023-07-11  9:32 [PATCH v3 0/9] rust: workqueue: add bindings for the workqueue Alice Ryhl
                   ` (6 preceding siblings ...)
  2023-07-11  9:33 ` [PATCH v3 7/9] rust: workqueue: implement `WorkItemPointer` for pointer types Alice Ryhl
@ 2023-07-11  9:33 ` Alice Ryhl
  2023-07-11  9:33 ` [PATCH v3 9/9] rust: workqueue: add examples Alice Ryhl
  2023-07-11 22:17 ` [PATCH v3 0/9] rust: workqueue: add bindings for the workqueue Tejun Heo
  9 siblings, 0 replies; 31+ messages in thread
From: Alice Ryhl @ 2023-07-11  9:33 UTC (permalink / raw)
  To: rust-for-linux, Tejun Heo, Miguel Ojeda
  Cc: Lai Jiangshan, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron, Benno Lossin, Alice Ryhl,
	linux-kernel, patches, Martin Rodriguez Reboredo,
	Andreas Hindborg

This adds a convenience method that lets you spawn a closure for
execution on a workqueue. This will be the most convenient way to use
workqueues, but it is fallible because it needs to allocate memory.

Co-developed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Alice Ryhl <aliceryhl@google.com>
Reviewed-by: Martin Rodriguez Reboredo <yakoyoku@gmail.com>
Reviewed-by: Andreas Hindborg (Samsung) <nmi@metaspace.dk>
Reviewed-by: Benno Lossin <benno.lossin@proton.me>
---
v2 -> v3:
 * Use a LockClassKey when constructing `ClosureWork`.
 * Add Reviewed-by from Martin, Andreas, Benno.

 rust/kernel/workqueue.rs | 43 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs
index e760040762bd..3a3a8b52bfd9 100644
--- a/rust/kernel/workqueue.rs
+++ b/rust/kernel/workqueue.rs
@@ -29,6 +29,7 @@
 //! C header: [`include/linux/workqueue.h`](../../../../include/linux/workqueue.h)
 
 use crate::{bindings, prelude::*, sync::Arc, sync::LockClassKey, types::Opaque};
+use alloc::alloc::AllocError;
 use alloc::boxed::Box;
 use core::marker::PhantomData;
 use core::pin::Pin;
@@ -87,6 +88,44 @@ pub fn enqueue<W, const ID: u64>(&self, w: W) -> W::EnqueueOutput
             })
         }
     }
+
+    /// Tries to spawn the given function or closure as a work item.
+    ///
+    /// This method can fail because it allocates memory to store the work item.
+    pub fn try_spawn<T: 'static + Send + FnOnce()>(&self, func: T) -> Result<(), AllocError> {
+        let init = pin_init!(ClosureWork {
+            work <- Work::new(kernel::static_lock_class!()),
+            func: Some(func),
+        });
+
+        self.enqueue(Box::pin_init(init).map_err(|_| AllocError)?);
+        Ok(())
+    }
+}
+
+/// A helper type used in `try_spawn`.
+#[pin_data]
+struct ClosureWork<T> {
+    #[pin]
+    work: Work<ClosureWork<T>>,
+    func: Option<T>,
+}
+
+impl<T> ClosureWork<T> {
+    fn project(self: Pin<&mut Self>) -> &mut Option<T> {
+        // SAFETY: The `func` field is not structurally pinned.
+        unsafe { &mut self.get_unchecked_mut().func }
+    }
+}
+
+impl<T: FnOnce()> WorkItem for ClosureWork<T> {
+    type Pointer = Pin<Box<Self>>;
+
+    fn run(mut this: Pin<Box<Self>>) {
+        if let Some(func) = this.as_mut().project().take() {
+            (func)()
+        }
+    }
 }
 
 /// A raw work item.
@@ -347,6 +386,10 @@ unsafe fn raw_get_work(ptr: *mut Self) -> *mut $crate::workqueue::Work<$work_typ
     )*};
 }
 
+impl_has_work! {
+    impl<T> HasWork<Self> for ClosureWork<T> { self.work }
+}
+
 unsafe impl<T, const ID: u64> WorkItemPointer<ID> for Arc<T>
 where
     T: WorkItem<ID, Pointer = Self>,
-- 
2.41.0.255.g8b1d071c50-goog


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* [PATCH v3 9/9] rust: workqueue: add examples
  2023-07-11  9:32 [PATCH v3 0/9] rust: workqueue: add bindings for the workqueue Alice Ryhl
                   ` (7 preceding siblings ...)
  2023-07-11  9:33 ` [PATCH v3 8/9] rust: workqueue: add `try_spawn` helper method Alice Ryhl
@ 2023-07-11  9:33 ` Alice Ryhl
  2023-07-14 22:40   ` Boqun Feng
  2023-07-11 22:17 ` [PATCH v3 0/9] rust: workqueue: add bindings for the workqueue Tejun Heo
  9 siblings, 1 reply; 31+ messages in thread
From: Alice Ryhl @ 2023-07-11  9:33 UTC (permalink / raw)
  To: rust-for-linux, Tejun Heo, Miguel Ojeda
  Cc: Lai Jiangshan, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron, Benno Lossin, Alice Ryhl,
	linux-kernel, patches, Martin Rodriguez Reboredo,
	Andreas Hindborg

This adds two examples of how to use the workqueue. The first example
shows how to use it when you only have one `work_struct` field, and the
second example shows how to use it when you have multiple `work_struct`
fields.

Signed-off-by: Alice Ryhl <aliceryhl@google.com>
Reviewed-by: Martin Rodriguez Reboredo <yakoyoku@gmail.com>
Reviewed-by: Gary Guo <gary@garyguo.net>
Reviewed-by: Andreas Hindborg (Samsung) <nmi@metaspace.dk>
Reviewed-by: Benno Lossin <benno.lossin@proton.me>
---
v2 -> v3:
 * Use LockClassKey in constructors in examples.
 * Add Reviewed-by from Martin, Gary, Andreas, Benno.

 rust/kernel/workqueue.rs | 104 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 104 insertions(+)

diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs
index 3a3a8b52bfd9..482d3eeae7d8 100644
--- a/rust/kernel/workqueue.rs
+++ b/rust/kernel/workqueue.rs
@@ -26,6 +26,110 @@
 //!  * The `WorkItemPointer` trait is implemented for the pointer type that points at a something
 //!    that implements `WorkItem`.
 //!
+//! ## Example
+//!
+//! This example defines a struct that holds an integer and can be scheduled on the workqueue. When
+//! the struct is executed, it will print the integer. Since there is only one `work_struct` field,
+//! we do not need to specify ids for the fields.
+//!
+//! ```
+//! use kernel::prelude::*;
+//! use kernel::sync::Arc;
+//! use kernel::workqueue::{self, Work, WorkItem};
+//!
+//! #[pin_data]
+//! struct MyStruct {
+//!     value: i32,
+//!     #[pin]
+//!     work: Work<MyStruct>,
+//! }
+//!
+//! impl_has_work! {
+//!     impl HasWork<Self> for MyStruct { self.work }
+//! }
+//!
+//! impl MyStruct {
+//!     fn new(value: i32) -> Result<Arc<Self>> {
+//!         Arc::pin_init(pin_init!(MyStruct {
+//!             value,
+//!             work <- Work::new(kernel::static_lock_class!()),
+//!         }))
+//!     }
+//! }
+//!
+//! impl WorkItem for MyStruct {
+//!     type Pointer = Arc<MyStruct>;
+//!
+//!     fn run(this: Arc<MyStruct>) {
+//!         pr_info!("The value is: {}", this.value);
+//!     }
+//! }
+//!
+//! /// This method will enqueue the struct for execution on the system workqueue, where its value
+//! /// will be printed.
+//! fn print_later(val: Arc<MyStruct>) {
+//!     let _ = workqueue::system().enqueue(val);
+//! }
+//! ```
+//!
+//! The following example shows how multiple `work_struct` fields can be used:
+//!
+//! ```
+//! use kernel::prelude::*;
+//! use kernel::sync::Arc;
+//! use kernel::workqueue::{self, Work, WorkItem};
+//!
+//! #[pin_data]
+//! struct MyStruct {
+//!     value_1: i32,
+//!     value_2: i32,
+//!     #[pin]
+//!     work_1: Work<MyStruct, 1>,
+//!     #[pin]
+//!     work_2: Work<MyStruct, 2>,
+//! }
+//!
+//! impl_has_work! {
+//!     impl HasWork<Self, 1> for MyStruct { self.work_1 }
+//!     impl HasWork<Self, 2> for MyStruct { self.work_2 }
+//! }
+//!
+//! impl MyStruct {
+//!     fn new(value_1: i32, value_2: i32) -> Result<Arc<Self>> {
+//!         Arc::pin_init(pin_init!(MyStruct {
+//!             value_1,
+//!             value_2,
+//!             work_1 <- Work::new(kernel::static_lock_class!()),
+//!             work_2 <- Work::new(kernel::static_lock_class!()),
+//!         }))
+//!     }
+//! }
+//!
+//! impl WorkItem<1> for MyStruct {
+//!     type Pointer = Arc<MyStruct>;
+//!
+//!     fn run(this: Arc<MyStruct>) {
+//!         pr_info!("The value is: {}", this.value_1);
+//!     }
+//! }
+//!
+//! impl WorkItem<2> for MyStruct {
+//!     type Pointer = Arc<MyStruct>;
+//!
+//!     fn run(this: Arc<MyStruct>) {
+//!         pr_info!("The second value is: {}", this.value_2);
+//!     }
+//! }
+//!
+//! fn print_1_later(val: Arc<MyStruct>) {
+//!     let _ = workqueue::system().enqueue::<Arc<MyStruct>, 1>(val);
+//! }
+//!
+//! fn print_2_later(val: Arc<MyStruct>) {
+//!     let _ = workqueue::system().enqueue::<Arc<MyStruct>, 2>(val);
+//! }
+//! ```
+//!
 //! C header: [`include/linux/workqueue.h`](../../../../include/linux/workqueue.h)
 
 use crate::{bindings, prelude::*, sync::Arc, sync::LockClassKey, types::Opaque};
-- 
2.41.0.255.g8b1d071c50-goog


^ permalink raw reply related	[flat|nested] 31+ messages in thread

* Re: [PATCH 3/9] workqueue: introduce `__INIT_WORK_WITH_KEY`
  2023-07-11  9:32 ` [PATCH 3/9] workqueue: introduce `__INIT_WORK_WITH_KEY` Alice Ryhl
@ 2023-07-11 10:49   ` Alice Ryhl
  2023-07-12  6:33   ` Boqun Feng
  2023-07-12 20:34   ` Martin Rodriguez Reboredo
  2 siblings, 0 replies; 31+ messages in thread
From: Alice Ryhl @ 2023-07-11 10:49 UTC (permalink / raw)
  To: rust-for-linux
  Cc: Lai Jiangshan, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron, Benno Lossin, linux-kernel,
	patches, Wedson Almeida Filho, Alice Ryhl, Tejun Heo,
	Miguel Ojeda

On 7/11/23 11:32, Alice Ryhl wrote:
> From: Wedson Almeida Filho <walmeida@microsoft.com>
> 
> A Rust helper (introduced in a later patch) needs to call
> `__INIT_WORK` with a passed key, rather than define one in place.
> 
> In order to do that, this moves the initialization code from
> the `__INIT_WORK` macro into a new `__INIT_WORK_WITH_KEY` macro
> which takes the key as an extra parameter.
> 
> Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
> Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
> Signed-off-by: Wedson Almeida Filho <walmeida@microsoft.com>
> Co-developed-by: Miguel Ojeda <ojeda@kernel.org>
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
> Acked-by: Tejun Heo <tj@kernel.org>
> Signed-off-by: Alice Ryhl <aliceryhl@google.com>
> ---

Oops, I messed up the subject of this one. It was supposed to say
[PATCH v3 3/9].

Sorry about that.

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v3 0/9] rust: workqueue: add bindings for the workqueue
  2023-07-11  9:32 [PATCH v3 0/9] rust: workqueue: add bindings for the workqueue Alice Ryhl
                   ` (8 preceding siblings ...)
  2023-07-11  9:33 ` [PATCH v3 9/9] rust: workqueue: add examples Alice Ryhl
@ 2023-07-11 22:17 ` Tejun Heo
  2023-07-11 23:44   ` Miguel Ojeda
  9 siblings, 1 reply; 31+ messages in thread
From: Tejun Heo @ 2023-07-11 22:17 UTC (permalink / raw)
  To: Alice Ryhl
  Cc: rust-for-linux, Miguel Ojeda, Lai Jiangshan,
	Wedson Almeida Filho, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, linux-kernel, patches

Hello,

On Tue, Jul 11, 2023 at 09:32:54AM +0000, Alice Ryhl wrote:
> This patchset contains Rust bindings for the kernel workqueue.
> 
> One of the primary goals behind the design used in this patch is that we
> must support embedding the `work_struct` as a field in user-provided
> types, because this allows you to submit things to the workqueue without
> having to allocate, making the submission infallible. If we didn't have
> to support this, then the patch would be much simpler. One of the main
> things that make it complicated is that we must ensure that the function
> pointer in the `work_struct` is compatible with the struct it is
> contained within.
> 
> The original version of the workqueue bindings was written by Wedson,
> but I have rewritten much of it so that it uses the pin-init
> infrastructure and can be used with containers other than `Arc`.

I don't understand a lot but the part that I understand (Alice helped me a
lot, thanks) and the example usages look fine to me. While the interface
leaves some workqueue features uncovered (e.g. flushing, creating custom
workqueues, queueing on a specific CPU), there's nothing blocking adding
them later and this looks like a good place to start. So, from workqueue
POV:

 Acked-by: Tejun Heo <tj@kernel.org>

Please feel free to route the patches through the rust tree. If you want
them to go through the workqueue tree, please let me know.

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v3 4/9] rust: workqueue: add low-level workqueue bindings
  2023-07-11  9:32 ` [PATCH v3 4/9] rust: workqueue: add low-level workqueue bindings Alice Ryhl
@ 2023-07-11 22:23   ` Boqun Feng
  2023-07-17 13:53     ` Alice Ryhl
  0 siblings, 1 reply; 31+ messages in thread
From: Boqun Feng @ 2023-07-11 22:23 UTC (permalink / raw)
  To: Alice Ryhl
  Cc: rust-for-linux, Tejun Heo, Miguel Ojeda, Lai Jiangshan,
	Wedson Almeida Filho, Alex Gaynor, Gary Guo,
	Björn Roy Baron, Benno Lossin, linux-kernel, patches,
	Martin Rodriguez Reboredo, Andreas Hindborg

On Tue, Jul 11, 2023 at 09:32:58AM +0000, Alice Ryhl wrote:
> Define basic low-level bindings to a kernel workqueue. The API defined
> here can only be used unsafely. Later commits will provide safe
> wrappers.
> 
> Co-developed-by: Gary Guo <gary@garyguo.net>
> Signed-off-by: Gary Guo <gary@garyguo.net>
> Signed-off-by: Alice Ryhl <aliceryhl@google.com>
> Reviewed-by: Martin Rodriguez Reboredo <yakoyoku@gmail.com>
> Reviewed-by: Andreas Hindborg (Samsung) <nmi@metaspace.dk>
> Reviewed-by: Benno Lossin <benno.lossin@proton.me>
> ---
> v2 -> v3:
>  * Update documentation to say "guarantees section".
>  * Add Reviewed-by from Martin, Andreas, Benno.
> 
>  rust/bindings/bindings_helper.h |   1 +
>  rust/kernel/lib.rs              |   1 +
>  rust/kernel/workqueue.rs        | 108 ++++++++++++++++++++++++++++++++
>  3 files changed, 110 insertions(+)
>  create mode 100644 rust/kernel/workqueue.rs
> 
> diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
> index 3e601ce2548d..4e1c0938c8cb 100644
> --- a/rust/bindings/bindings_helper.h
> +++ b/rust/bindings/bindings_helper.h
> @@ -11,6 +11,7 @@
>  #include <linux/refcount.h>
>  #include <linux/wait.h>
>  #include <linux/sched.h>
> +#include <linux/workqueue.h>
>  
>  /* `bindgen` gets confused at certain things. */
>  const gfp_t BINDINGS_GFP_KERNEL = GFP_KERNEL;
> diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
> index 6963d11092c4..6d63f4f6bb8a 100644
> --- a/rust/kernel/lib.rs
> +++ b/rust/kernel/lib.rs
> @@ -45,6 +45,7 @@
>  pub mod sync;
>  pub mod task;
>  pub mod types;
> +pub mod workqueue;
>  
>  #[doc(hidden)]
>  pub use bindings;
> diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs
> new file mode 100644
> index 000000000000..060d26dfcc7d
> --- /dev/null
> +++ b/rust/kernel/workqueue.rs
> @@ -0,0 +1,108 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +//! Work queues.
> +//!
> +//! C header: [`include/linux/workqueue.h`](../../../../include/linux/workqueue.h)
> +
> +use crate::{bindings, types::Opaque};
> +
> +/// A kernel work queue.
> +///
> +/// Wraps the kernel's C `struct workqueue_struct`.
> +///
> +/// It allows work items to be queued to run on thread pools managed by the kernel. Several are
> +/// always available, for example, `system`, `system_highpri`, `system_long`, etc.
> +#[repr(transparent)]
> +pub struct Queue(Opaque<bindings::workqueue_struct>);
> +
> +// SAFETY: Kernel workqueues are usable from any thread.
> +unsafe impl Send for Queue {}
> +unsafe impl Sync for Queue {}

I don't think "usable from any thread" is the accurate wording here, it
sounds to me that there are types that cannot be used for a particular
type of threads ;-)

Maybe

	// SAFETY: Accesses to workqueues used by [`Queue`] are
	// thread-safe.

?

Rest of this patch looks good to me.

Reviewed-by: Boqun Feng <boqun.feng@gmail.com>

Regards,
Boqun

> +
> +impl Queue {
> +    /// Use the provided `struct workqueue_struct` with Rust.
> +    ///
> +    /// # Safety
> +    ///
> +    /// The caller must ensure that the provided raw pointer is not dangling, that it points at a
> +    /// valid workqueue, and that it remains valid until the end of 'a.
> +    pub unsafe fn from_raw<'a>(ptr: *const bindings::workqueue_struct) -> &'a Queue {
> +        // SAFETY: The `Queue` type is `#[repr(transparent)]`, so the pointer cast is valid. The
> +        // caller promises that the pointer is not dangling.
> +        unsafe { &*(ptr as *const Queue) }
> +    }
> +
> +    /// Enqueues a work item.
> +    ///
> +    /// This may fail if the work item is already enqueued in a workqueue.
> +    ///
> +    /// The work item will be submitted using `WORK_CPU_UNBOUND`.
> +    pub fn enqueue<W, const ID: u64>(&self, w: W) -> W::EnqueueOutput
> +    where
> +        W: RawWorkItem<ID> + Send + 'static,
> +    {
> +        let queue_ptr = self.0.get();
> +
> +        // SAFETY: We only return `false` if the `work_struct` is already in a workqueue. The other
> +        // `__enqueue` requirements are not relevant since `W` is `Send` and static.
> +        //
> +        // The call to `bindings::queue_work_on` will dereference the provided raw pointer, which
> +        // is ok because `__enqueue` guarantees that the pointer is valid for the duration of this
> +        // closure.
> +        //
> +        // Furthermore, if the C workqueue code accesses the pointer after this call to
> +        // `__enqueue`, then the work item was successfully enqueued, and `bindings::queue_work_on`
> +        // will have returned true. In this case, `__enqueue` promises that the raw pointer will
> +        // stay valid until we call the function pointer in the `work_struct`, so the access is ok.
> +        unsafe {
> +            w.__enqueue(move |work_ptr| {
> +                bindings::queue_work_on(bindings::WORK_CPU_UNBOUND as _, queue_ptr, work_ptr)
> +            })
> +        }
> +    }
> +}
> +
> +/// A raw work item.
> +///
> +/// This is the low-level trait that is designed for being as general as possible.
> +///
> +/// The `ID` parameter to this trait exists so that a single type can provide multiple
> +/// implementations of this trait. For example, if a struct has multiple `work_struct` fields, then
> +/// you will implement this trait once for each field, using a different id for each field. The
> +/// actual value of the id is not important as long as you use different ids for different fields
> +/// of the same struct. (Fields of different structs need not use different ids.)
> +///
> +/// Note that the id is used only to select the right method to call during compilation. It wont be
> +/// part of the final executable.
> +///
> +/// # Safety
> +///
> +/// Implementers must ensure that any pointers passed to a `queue_work_on` closure by `__enqueue`
> +/// remain valid for the duration specified in the guarantees section of the documentation for
> +/// `__enqueue`.
> +pub unsafe trait RawWorkItem<const ID: u64> {
> +    /// The return type of [`Queue::enqueue`].
> +    type EnqueueOutput;
> +
> +    /// Enqueues this work item on a queue using the provided `queue_work_on` method.
> +    ///
> +    /// # Guarantees
> +    ///
> +    /// If this method calls the provided closure, then the raw pointer is guaranteed to point at a
> +    /// valid `work_struct` for the duration of the call to the closure. If the closure returns
> +    /// true, then it is further guaranteed that the pointer remains valid until someone calls the
> +    /// function pointer stored in the `work_struct`.
> +    ///
> +    /// # Safety
> +    ///
> +    /// The provided closure may only return `false` if the `work_struct` is already in a workqueue.
> +    ///
> +    /// If the work item type is annotated with any lifetimes, then you must not call the function
> +    /// pointer after any such lifetime expires. (Never calling the function pointer is okay.)
> +    ///
> +    /// If the work item type is not [`Send`], then the function pointer must be called on the same
> +    /// thread as the call to `__enqueue`.
> +    unsafe fn __enqueue<F>(self, queue_work_on: F) -> Self::EnqueueOutput
> +    where
> +        F: FnOnce(*mut bindings::work_struct) -> bool;
> +}
> -- 
> 2.41.0.255.g8b1d071c50-goog
> 

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v3 0/9] rust: workqueue: add bindings for the workqueue
  2023-07-11 22:17 ` [PATCH v3 0/9] rust: workqueue: add bindings for the workqueue Tejun Heo
@ 2023-07-11 23:44   ` Miguel Ojeda
  2023-07-12  0:27     ` Tejun Heo
  0 siblings, 1 reply; 31+ messages in thread
From: Miguel Ojeda @ 2023-07-11 23:44 UTC (permalink / raw)
  To: Tejun Heo
  Cc: Alice Ryhl, rust-for-linux, Miguel Ojeda, Lai Jiangshan,
	Wedson Almeida Filho, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, linux-kernel, patches

On Wed, Jul 12, 2023 at 12:17 AM Tejun Heo <tj@kernel.org> wrote:
>
> I don't understand a lot but the part that I understand (Alice helped me a
> lot, thanks) and the example usages look fine to me. While the interface
> leaves some workqueue features uncovered (e.g. flushing, creating custom
> workqueues, queueing on a specific CPU), there's nothing blocking adding
> them later and this looks like a good place to start. So, from workqueue
> POV:
>
>  Acked-by: Tejun Heo <tj@kernel.org>

Thanks a lot Tejun!

> Please feel free to route the patches through the rust tree. If you want
> them to go through the workqueue tree, please let me know.

As you prefer -- if you are willing to take them and/or maintain or
co-maintain patches to it, and it is not a lot of work for you, then
it would be great to get you involved, of course. Otherwise, we can
apply them to the Rust tree too.

Cheers,
Miguel

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v3 0/9] rust: workqueue: add bindings for the workqueue
  2023-07-11 23:44   ` Miguel Ojeda
@ 2023-07-12  0:27     ` Tejun Heo
  2023-07-12 16:36       ` Miguel Ojeda
  0 siblings, 1 reply; 31+ messages in thread
From: Tejun Heo @ 2023-07-12  0:27 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Alice Ryhl, rust-for-linux, Miguel Ojeda, Lai Jiangshan,
	Wedson Almeida Filho, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, linux-kernel, patches

Hello, Miguel.

On Wed, Jul 12, 2023 at 01:44:47AM +0200, Miguel Ojeda wrote:
> > Please feel free to route the patches through the rust tree. If you want
> > them to go through the workqueue tree, please let me know.
> 
> As you prefer -- if you are willing to take them and/or maintain or
> co-maintain patches to it, and it is not a lot of work for you, then
> it would be great to get you involved, of course. Otherwise, we can
> apply them to the Rust tree too.

It's not a lot of overhead for me but I'm also not sure whether I can be
actually useful. Once folks are happy with it, I can create a separate
branch for this series in the wq tree so that others can easily pull from
it. Let's see how that goes and if my involvement turns out to be pointless
we can route future changes through the rust tree.

Thanks.

-- 
tejun

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 3/9] workqueue: introduce `__INIT_WORK_WITH_KEY`
  2023-07-11  9:32 ` [PATCH 3/9] workqueue: introduce `__INIT_WORK_WITH_KEY` Alice Ryhl
  2023-07-11 10:49   ` Alice Ryhl
@ 2023-07-12  6:33   ` Boqun Feng
  2023-07-12 20:34   ` Martin Rodriguez Reboredo
  2 siblings, 0 replies; 31+ messages in thread
From: Boqun Feng @ 2023-07-12  6:33 UTC (permalink / raw)
  To: Alice Ryhl
  Cc: rust-for-linux, Tejun Heo, Miguel Ojeda, Lai Jiangshan,
	Wedson Almeida Filho, Alex Gaynor, Gary Guo,
	Björn Roy Baron, Benno Lossin, linux-kernel, patches,
	Wedson Almeida Filho

On Tue, Jul 11, 2023 at 09:32:57AM +0000, Alice Ryhl wrote:
> From: Wedson Almeida Filho <walmeida@microsoft.com>
> 
> A Rust helper (introduced in a later patch) needs to call
> `__INIT_WORK` with a passed key, rather than define one in place.
> 
> In order to do that, this moves the initialization code from
> the `__INIT_WORK` macro into a new `__INIT_WORK_WITH_KEY` macro
> which takes the key as an extra parameter.
> 
> Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
> Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
> Signed-off-by: Wedson Almeida Filho <walmeida@microsoft.com>
> Co-developed-by: Miguel Ojeda <ojeda@kernel.org>
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
> Acked-by: Tejun Heo <tj@kernel.org>
> Signed-off-by: Alice Ryhl <aliceryhl@google.com>
> ---
> Taken from [1]. Wedson's email updated at Wedson's request. Tejun's
> Acked-by taken from [2].
> 
> [1]: https://lore.kernel.org/rust-for-linux/20220802015052.10452-7-ojeda@kernel.org/
> [2]: https://lore.kernel.org/rust-for-linux/Yvq3IfK4+C94AeE2@slm.duckdns.org/
> 
>  include/linux/workqueue.h | 31 +++++++++++++++++++------------
>  1 file changed, 19 insertions(+), 12 deletions(-)
> 
> diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
> index 3992c994787f..c91a84a4723d 100644
> --- a/include/linux/workqueue.h
> +++ b/include/linux/workqueue.h
> @@ -221,24 +221,31 @@ static inline unsigned int work_static(struct work_struct *work) { return 0; }
>   * to generate better code.
>   */
>  #ifdef CONFIG_LOCKDEP
> +#define __INIT_WORK_WITH_KEY(_work, _func, _onstack, _key)		\
> +	do {								\
> +		__init_work((_work), _onstack);				\
> +		(_work)->data = (atomic_long_t) WORK_DATA_INIT();	\
> +		lockdep_init_map(&(_work)->lockdep_map, "(work_completion)"#_work, _key, 0); \

The lock class name is generated as static string via C macro
"(work_completion)"#_work, and since Rust side helper will wrap it as
a function, so all work items in Rust will have the same lock class name
i.e. "(work_completion)work". ;-) 

Those names are for lockdep report readers to locate which lock class
cause the problem, so it make senses to have different names for
different work item types. Maybe change the C side function as what I
suggested[1], and use `core::any::typename::<Self>()` as the name? (Self
is `Work` since it's called in `Work::new`).

[1]: https://lore.kernel.org/rust-for-linux/ZHoZuIz97JN1VSBf@boqun-archlinux/

Regards,
Boqun

> +		INIT_LIST_HEAD(&(_work)->entry);			\
> +		(_work)->func = (_func);				\
> +	} while (0)
> +
>  #define __INIT_WORK(_work, _func, _onstack)				\
>  	do {								\
>  		static struct lock_class_key __key;			\
> -									\
> -		__init_work((_work), _onstack);				\
> -		(_work)->data = (atomic_long_t) WORK_DATA_INIT();	\
> -		lockdep_init_map(&(_work)->lockdep_map, "(work_completion)"#_work, &__key, 0); \
> -		INIT_LIST_HEAD(&(_work)->entry);			\
> -		(_work)->func = (_func);				\
> +		__INIT_WORK_WITH_KEY(_work, _func, _onstack, &__key);	\
>  	} while (0)
>  #else
> +#define __INIT_WORK_WITH_KEY(_work, _func, _onstack, _key)		\
> +	do {								\
> +		__init_work((_work), _onstack);				\
> +		(_work)->data = (atomic_long_t) WORK_DATA_INIT();	\
> +		INIT_LIST_HEAD(&(_work)->entry);			\
> +		(_work)->func = (_func);				\
> +	} while (0)
> +
>  #define __INIT_WORK(_work, _func, _onstack)				\
> -	do {								\
> -		__init_work((_work), _onstack);				\
> -		(_work)->data = (atomic_long_t) WORK_DATA_INIT();	\
> -		INIT_LIST_HEAD(&(_work)->entry);			\
> -		(_work)->func = (_func);				\
> -	} while (0)
> +	__INIT_WORK_WITH_KEY(_work, _func, _onstack, NULL)
>  #endif
>  
>  #define INIT_WORK(_work, _func)						\
> -- 
> 2.41.0.255.g8b1d071c50-goog
> 

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v3 0/9] rust: workqueue: add bindings for the workqueue
  2023-07-12  0:27     ` Tejun Heo
@ 2023-07-12 16:36       ` Miguel Ojeda
  0 siblings, 0 replies; 31+ messages in thread
From: Miguel Ojeda @ 2023-07-12 16:36 UTC (permalink / raw)
  To: Tejun Heo
  Cc: Alice Ryhl, rust-for-linux, Miguel Ojeda, Lai Jiangshan,
	Wedson Almeida Filho, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, linux-kernel, patches

On Wed, Jul 12, 2023 at 2:28 AM Tejun Heo <tj@kernel.org> wrote:
>
> It's not a lot of overhead for me but I'm also not sure whether I can be
> actually useful. Once folks are happy with it, I can create a separate
> branch for this series in the wq tree so that others can easily pull from
> it. Let's see how that goes and if my involvement turns out to be pointless
> we can route future changes through the rust tree.

Sounds good, thanks! (and the branch would indeed be very good, in
case we/someone need it in the Rust tree this cycle too).

Cheers,
Miguel

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v3 2/9] rust: sync: add `Arc::{from_raw, into_raw}`
  2023-07-11  9:32 ` [PATCH v3 2/9] rust: sync: add `Arc::{from_raw, into_raw}` Alice Ryhl
@ 2023-07-12 20:33   ` Martin Rodriguez Reboredo
  2023-07-15  9:42   ` Benno Lossin
  2023-08-22 11:46   ` Andreas Hindborg (Samsung)
  2 siblings, 0 replies; 31+ messages in thread
From: Martin Rodriguez Reboredo @ 2023-07-12 20:33 UTC (permalink / raw)
  To: Alice Ryhl, rust-for-linux, Tejun Heo, Miguel Ojeda
  Cc: Lai Jiangshan, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron, Benno Lossin, linux-kernel,
	patches, Wedson Almeida Filho

On 7/11/23 06:32, Alice Ryhl wrote:
> From: Wedson Almeida Filho <walmeida@microsoft.com>
> 
> These methods can be used to turn an `Arc` into a raw pointer and back,
> in a way that preserves the metadata for fat pointers.
> 
> This is done using the unstable ptr_metadata feature [1]. However, it
> could also be done using the unstable pointer_byte_offsets feature [2],
> which is likely to have a shorter path to stabilization than
> ptr_metadata.
> 
> Link: https://github.com/rust-lang/rust/issues/81513 [1]
> Link: https://github.com/rust-lang/rust/issues/96283 [2]
> Signed-off-by: Wedson Almeida Filho <walmeida@microsoft.com>
> Co-developed-by: Alice Ryhl <aliceryhl@google.com>
> Signed-off-by: Alice Ryhl <aliceryhl@google.com>
> Reviewed-by: Gary Guo <gary@garyguo.net>
> ---
> [...]

Reviewed-by: Martin Rodriguez Reboredo <yakoyoku@gmail.com>

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH 3/9] workqueue: introduce `__INIT_WORK_WITH_KEY`
  2023-07-11  9:32 ` [PATCH 3/9] workqueue: introduce `__INIT_WORK_WITH_KEY` Alice Ryhl
  2023-07-11 10:49   ` Alice Ryhl
  2023-07-12  6:33   ` Boqun Feng
@ 2023-07-12 20:34   ` Martin Rodriguez Reboredo
  2 siblings, 0 replies; 31+ messages in thread
From: Martin Rodriguez Reboredo @ 2023-07-12 20:34 UTC (permalink / raw)
  To: Alice Ryhl, rust-for-linux, Tejun Heo, Miguel Ojeda
  Cc: Lai Jiangshan, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron, Benno Lossin, linux-kernel,
	patches, Wedson Almeida Filho

On 7/11/23 06:32, Alice Ryhl wrote:
> From: Wedson Almeida Filho <walmeida@microsoft.com>
> 
> A Rust helper (introduced in a later patch) needs to call
> `__INIT_WORK` with a passed key, rather than define one in place.
> 
> In order to do that, this moves the initialization code from
> the `__INIT_WORK` macro into a new `__INIT_WORK_WITH_KEY` macro
> which takes the key as an extra parameter.
> 
> Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
> Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
> Signed-off-by: Wedson Almeida Filho <walmeida@microsoft.com>
> Co-developed-by: Miguel Ojeda <ojeda@kernel.org>
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
> Acked-by: Tejun Heo <tj@kernel.org>
> Signed-off-by: Alice Ryhl <aliceryhl@google.com>
> ---
> [...]

Reviewed-by: Martin Rodriguez Reboredo <yakoyoku@gmail.com>

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v3 6/9] rust: workqueue: add helper for defining work_struct fields
  2023-07-11  9:33 ` [PATCH v3 6/9] rust: workqueue: add helper for defining work_struct fields Alice Ryhl
@ 2023-07-12 20:43   ` Martin Rodriguez Reboredo
  2023-07-15  9:43   ` Benno Lossin
  2023-08-22 19:59   ` Andreas Hindborg (Samsung)
  2 siblings, 0 replies; 31+ messages in thread
From: Martin Rodriguez Reboredo @ 2023-07-12 20:43 UTC (permalink / raw)
  To: Alice Ryhl, rust-for-linux, Tejun Heo, Miguel Ojeda
  Cc: Lai Jiangshan, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron, Benno Lossin, linux-kernel,
	patches

On 7/11/23 06:33, Alice Ryhl wrote:
> The main challenge with defining `work_struct` fields is making sure
> that the function pointer stored in the `work_struct` is appropriate for
> the work item type it is embedded in. It needs to know the offset of the
> `work_struct` field being used (even if there are several!) so that it
> can do a `container_of`, and it needs to know the type of the work item
> so that it can call into the right user-provided code. All of this needs
> to happen in a way that provides a safe API to the user, so that users
> of the workqueue cannot mix up the function pointers.
> 
> There are three important pieces that are relevant when doing this:
> 
>   * The pointer type.
>   * The work item struct. This is what the pointer points at.
>   * The `work_struct` field. This is a field of the work item struct.
> 
> This patch introduces a separate trait for each piece. The pointer type
> is given a `WorkItemPointer` trait, which pointer types need to
> implement to be usable with the workqueue. This trait will be
> implemented for `Arc` and `Box` in a later patch in this patchset.
> Implementing this trait is unsafe because this is where the
> `container_of` operation happens, but user-code will not need to
> implement it themselves.
> 
> The work item struct should then implement the `WorkItem` trait. This
> trait is where user-code specifies what they want to happen when a work
> item is executed. It also specifies what the correct pointer type is.
> 
> Finally, to make the work item struct know the offset of its
> `work_struct` field, we use a trait called `HasWork<T, ID>`. If a type
> implements this trait, then the type declares that, at the given offset,
> there is a field of type `Work<T, ID>`. The trait is marked unsafe
> because the OFFSET constant must be correct, but we provide an
> `impl_has_work!` macro that can safely implement `HasWork<T>` on a type.
> The macro expands to something that only compiles if the specified field
> really has the type `Work<T>`. It is used like this:
> 
> ```
> struct MyWorkItem {
>      work_field: Work<MyWorkItem, 1>,
> }
> 
> impl_has_work! {
>      impl HasWork<MyWorkItem, 1> for MyWorkItem { self.work_field }
> }
> ```
> 
> Note that since the `Work` type is annotated with an id, you can have
> several `work_struct` fields by using a different id for each one.
> 
> Co-developed-by: Gary Guo <gary@garyguo.net>
> Signed-off-by: Gary Guo <gary@garyguo.net>
> Signed-off-by: Alice Ryhl <aliceryhl@google.com>
> ---
> [...]

Reviewed-by: Martin Rodriguez Reboredo <yakoyoku@gmail.com>

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v3 9/9] rust: workqueue: add examples
  2023-07-11  9:33 ` [PATCH v3 9/9] rust: workqueue: add examples Alice Ryhl
@ 2023-07-14 22:40   ` Boqun Feng
  0 siblings, 0 replies; 31+ messages in thread
From: Boqun Feng @ 2023-07-14 22:40 UTC (permalink / raw)
  To: Alice Ryhl
  Cc: rust-for-linux, Tejun Heo, Miguel Ojeda, Lai Jiangshan,
	Wedson Almeida Filho, Alex Gaynor, Gary Guo,
	Björn Roy Baron, Benno Lossin, linux-kernel, patches,
	Martin Rodriguez Reboredo, Andreas Hindborg

On Tue, Jul 11, 2023 at 09:33:03AM +0000, Alice Ryhl wrote:
> This adds two examples of how to use the workqueue. The first example
> shows how to use it when you only have one `work_struct` field, and the
> second example shows how to use it when you have multiple `work_struct`
> fields.
> 

These examples are nice, but look like we need the following based on
the whole patchset to make them compile as doc/kunit tests[1]:

diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs
index d99f55a021dd..1ccc511dbe87 100644
--- a/rust/kernel/workqueue.rs
+++ b/rust/kernel/workqueue.rs
@@ -34,6 +34,7 @@
 //!
 //! ```
 //! use kernel::prelude::*;
+//! use kernel::impl_has_work;
 //! use kernel::sync::Arc;
 //! use kernel::workqueue::{self, Work, WorkItem};
 //!
@@ -76,6 +77,7 @@
 //!
 //! ```
 //! use kernel::prelude::*;
+//! use kernel::impl_has_work;
 //! use kernel::sync::Arc;
 //! use kernel::workqueue::{self, Work, WorkItem};
 //!
@@ -380,6 +382,7 @@ pub unsafe fn raw_get(ptr: *const Self) -> *mut bindings::work_struct {
 ///
 /// ```no_run
 /// use kernel::prelude::*;
+/// use kernel::impl_has_work;
 /// use kernel::workqueue::Work;
 ///
 /// struct MyWorkItem {
@@ -456,6 +459,8 @@ unsafe fn work_container_of(ptr: *mut Work<T, ID>) -> *mut Self
 ///
 /// ```
 /// use kernel::sync::Arc;
+/// use kernel::impl_has_work;
+/// use kernel::workqueue::{self, Work, WorkItem};
 ///
 /// struct MyStruct {
 ///     work_field: Work<MyStruct, 17>,

[1]: https://lore.kernel.org/rust-for-linux/20230614180837.630180-1-ojeda@kernel.org/

Regards,
Boqun

> Signed-off-by: Alice Ryhl <aliceryhl@google.com>
> Reviewed-by: Martin Rodriguez Reboredo <yakoyoku@gmail.com>
> Reviewed-by: Gary Guo <gary@garyguo.net>
> Reviewed-by: Andreas Hindborg (Samsung) <nmi@metaspace.dk>
> Reviewed-by: Benno Lossin <benno.lossin@proton.me>
> ---
> v2 -> v3:
>  * Use LockClassKey in constructors in examples.
>  * Add Reviewed-by from Martin, Gary, Andreas, Benno.
> 
>  rust/kernel/workqueue.rs | 104 +++++++++++++++++++++++++++++++++++++++
>  1 file changed, 104 insertions(+)
> 
> diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs
> index 3a3a8b52bfd9..482d3eeae7d8 100644
> --- a/rust/kernel/workqueue.rs
> +++ b/rust/kernel/workqueue.rs
> @@ -26,6 +26,110 @@
>  //!  * The `WorkItemPointer` trait is implemented for the pointer type that points at a something
>  //!    that implements `WorkItem`.
>  //!
> +//! ## Example
> +//!
> +//! This example defines a struct that holds an integer and can be scheduled on the workqueue. When
> +//! the struct is executed, it will print the integer. Since there is only one `work_struct` field,
> +//! we do not need to specify ids for the fields.
> +//!
> +//! ```
> +//! use kernel::prelude::*;
> +//! use kernel::sync::Arc;
> +//! use kernel::workqueue::{self, Work, WorkItem};
> +//!
> +//! #[pin_data]
> +//! struct MyStruct {
> +//!     value: i32,
> +//!     #[pin]
> +//!     work: Work<MyStruct>,
> +//! }
> +//!
> +//! impl_has_work! {
> +//!     impl HasWork<Self> for MyStruct { self.work }
> +//! }
> +//!
> +//! impl MyStruct {
> +//!     fn new(value: i32) -> Result<Arc<Self>> {
> +//!         Arc::pin_init(pin_init!(MyStruct {
> +//!             value,
> +//!             work <- Work::new(kernel::static_lock_class!()),
> +//!         }))
> +//!     }
> +//! }
> +//!
> +//! impl WorkItem for MyStruct {
> +//!     type Pointer = Arc<MyStruct>;
> +//!
> +//!     fn run(this: Arc<MyStruct>) {
> +//!         pr_info!("The value is: {}", this.value);
> +//!     }
> +//! }
> +//!
> +//! /// This method will enqueue the struct for execution on the system workqueue, where its value
> +//! /// will be printed.
> +//! fn print_later(val: Arc<MyStruct>) {
> +//!     let _ = workqueue::system().enqueue(val);
> +//! }
> +//! ```
> +//!
> +//! The following example shows how multiple `work_struct` fields can be used:
> +//!
> +//! ```
> +//! use kernel::prelude::*;
> +//! use kernel::sync::Arc;
> +//! use kernel::workqueue::{self, Work, WorkItem};
> +//!
> +//! #[pin_data]
> +//! struct MyStruct {
> +//!     value_1: i32,
> +//!     value_2: i32,
> +//!     #[pin]
> +//!     work_1: Work<MyStruct, 1>,
> +//!     #[pin]
> +//!     work_2: Work<MyStruct, 2>,
> +//! }
> +//!
> +//! impl_has_work! {
> +//!     impl HasWork<Self, 1> for MyStruct { self.work_1 }
> +//!     impl HasWork<Self, 2> for MyStruct { self.work_2 }
> +//! }
> +//!
> +//! impl MyStruct {
> +//!     fn new(value_1: i32, value_2: i32) -> Result<Arc<Self>> {
> +//!         Arc::pin_init(pin_init!(MyStruct {
> +//!             value_1,
> +//!             value_2,
> +//!             work_1 <- Work::new(kernel::static_lock_class!()),
> +//!             work_2 <- Work::new(kernel::static_lock_class!()),
> +//!         }))
> +//!     }
> +//! }
> +//!
> +//! impl WorkItem<1> for MyStruct {
> +//!     type Pointer = Arc<MyStruct>;
> +//!
> +//!     fn run(this: Arc<MyStruct>) {
> +//!         pr_info!("The value is: {}", this.value_1);
> +//!     }
> +//! }
> +//!
> +//! impl WorkItem<2> for MyStruct {
> +//!     type Pointer = Arc<MyStruct>;
> +//!
> +//!     fn run(this: Arc<MyStruct>) {
> +//!         pr_info!("The second value is: {}", this.value_2);
> +//!     }
> +//! }
> +//!
> +//! fn print_1_later(val: Arc<MyStruct>) {
> +//!     let _ = workqueue::system().enqueue::<Arc<MyStruct>, 1>(val);
> +//! }
> +//!
> +//! fn print_2_later(val: Arc<MyStruct>) {
> +//!     let _ = workqueue::system().enqueue::<Arc<MyStruct>, 2>(val);
> +//! }
> +//! ```
> +//!
>  //! C header: [`include/linux/workqueue.h`](../../../../include/linux/workqueue.h)
>  
>  use crate::{bindings, prelude::*, sync::Arc, sync::LockClassKey, types::Opaque};
> -- 
> 2.41.0.255.g8b1d071c50-goog
> 

^ permalink raw reply related	[flat|nested] 31+ messages in thread

* Re: [PATCH v3 2/9] rust: sync: add `Arc::{from_raw, into_raw}`
  2023-07-11  9:32 ` [PATCH v3 2/9] rust: sync: add `Arc::{from_raw, into_raw}` Alice Ryhl
  2023-07-12 20:33   ` Martin Rodriguez Reboredo
@ 2023-07-15  9:42   ` Benno Lossin
  2023-07-17 13:47     ` Alice Ryhl
  2023-08-22 11:46   ` Andreas Hindborg (Samsung)
  2 siblings, 1 reply; 31+ messages in thread
From: Benno Lossin @ 2023-07-15  9:42 UTC (permalink / raw)
  To: Alice Ryhl
  Cc: rust-for-linux, Tejun Heo, Miguel Ojeda, Lai Jiangshan,
	Wedson Almeida Filho, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, linux-kernel, patches,
	Wedson Almeida Filho

> From: Wedson Almeida Filho <walmeida@microsoft.com>
> 
> These methods can be used to turn an `Arc` into a raw pointer and back,
> in a way that preserves the metadata for fat pointers.
> 
> This is done using the unstable ptr_metadata feature [1]. However, it
> could also be done using the unstable pointer_byte_offsets feature [2],
> which is likely to have a shorter path to stabilization than
> ptr_metadata.
> 
> Link: https://github.com/rust-lang/rust/issues/81513 [1]
> Link: https://github.com/rust-lang/rust/issues/96283 [2]
> Signed-off-by: Wedson Almeida Filho <walmeida@microsoft.com>
> Co-developed-by: Alice Ryhl <aliceryhl@google.com>
> Signed-off-by: Alice Ryhl <aliceryhl@google.com>
> Reviewed-by: Gary Guo <gary@garyguo.net>

LGTM, two small documentation nits below, with them fixed you can add:

Reviewed-by: Benno Lossin <benno.lossin@proton.me>

> ---
> v2 -> v3:
>  * Use `transmute_copy` to convert metadata.
>  * Use `add` instead of `wrapping_add`.
>  * Dropped Reviewed-by from Martin and Benno due to changes.
> 
>  rust/kernel/lib.rs      |  1 +
>  rust/kernel/sync/arc.rs | 49 +++++++++++++++++++++++++++++++++++++++--
>  2 files changed, 48 insertions(+), 2 deletions(-)
> 
> diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
> index 788914fd935f..6963d11092c4 100644
> --- a/rust/kernel/lib.rs
> +++ b/rust/kernel/lib.rs
> @@ -17,6 +17,7 @@
>  #![feature(const_refs_to_cell)]
>  #![feature(dispatch_from_dyn)]
>  #![feature(new_uninit)]
> +#![feature(ptr_metadata)]
>  #![feature(receiver_trait)]
>  #![feature(unsize)]
> 
> diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs
> index a89843cacaad..4046b534e53b 100644
> --- a/rust/kernel/sync/arc.rs
> +++ b/rust/kernel/sync/arc.rs
> @@ -24,13 +24,13 @@
>  };
>  use alloc::boxed::Box;
>  use core::{
> -    alloc::AllocError,
> +    alloc::{AllocError, Layout},
>      fmt,
>      marker::{PhantomData, Unsize},
>      mem::{ManuallyDrop, MaybeUninit},
>      ops::{Deref, DerefMut},
>      pin::Pin,
> -    ptr::NonNull,
> +    ptr::{NonNull, Pointee},
>  };
>  use macros::pin_data;
> 
> @@ -212,6 +212,51 @@ unsafe fn from_inner(inner: NonNull<ArcInner<T>>) -> Self {
>          }
>      }
> 
> +    /// Convert the [`Arc`] into a raw pointer.
> +    ///
> +    /// The raw pointer has ownership of the refcount that this Arc object owned.
> +    pub fn into_raw(self) -> *const T {
> +        let ptr = self.ptr.as_ptr();
> +        core::mem::forget(self);
> +        // SAFETY: The pointer is valid.
> +        unsafe { core::ptr::addr_of!((*ptr).data) }
> +    }
> +
> +    /// Recreates an [`Arc`] instance previously deconstructed via [`Arc::into_raw`].
> +    ///
> +    /// This code relies on the `repr(C)` layout of structs as described in
> +    /// <https://doc.rust-lang.org/reference/type-layout.html#reprc-structs>.

Why is this in the documentation? I feel like it should be a normal code
comment at the very start of the function.

> +    ///
> +    /// # Safety
> +    ///
> +    /// `ptr` must have been returned by a previous call to [`Arc::into_raw`]. Additionally, it
> +    /// can only be called once for each previous call to [`Arc::into_raw`].

"it can only" -> "it must only"

--
Cheers,
Benno

> +    pub unsafe fn from_raw(ptr: *const T) -> Self {
> +        let refcount_layout = Layout::new::<bindings::refcount_t>();
> +        // SAFETY: The caller guarantees that the pointer is valid.
> +        let val_layout = Layout::for_value(unsafe { &*ptr });
> +        // SAFETY: We're computing the layout of a real struct that existed when compiling this
> +        // binary, so its layout is not so large that it can trigger arithmetic overflow.
> +        let val_offset = unsafe { refcount_layout.extend(val_layout).unwrap_unchecked().1 };
> +
> +        let metadata: <T as Pointee>::Metadata = core::ptr::metadata(ptr);
> +        // SAFETY: The metadata of `T` and `ArcInner<T>` is the same because `ArcInner` is a struct
> +        // with `T` as its last field.
> +        //
> +        // This is documented at:
> +        // <https://doc.rust-lang.org/std/ptr/trait.Pointee.html>.
> +        let metadata: <ArcInner<T> as Pointee>::Metadata =
> +            unsafe { core::mem::transmute_copy(&metadata) };
> +        // SAFETY: The pointer is in-bounds of an allocation both before and after offsetting the
> +        // pointer, since it originates from a previous call to `Arc::into_raw` and is still valid.
> +        let ptr = unsafe { (ptr as *mut u8).sub(val_offset) as *mut () };
> +        let ptr = core::ptr::from_raw_parts_mut(ptr, metadata);
> +
> +        // SAFETY: By the safety requirements we know that `ptr` came from `Arc::into_raw`, so the
> +        // reference count held then will be owned by the new `Arc` object.
> +        unsafe { Self::from_inner(NonNull::new_unchecked(ptr)) }
> +    }
> +
>      /// Returns an [`ArcBorrow`] from the given [`Arc`].
>      ///
>      /// This is useful when the argument of a function call is an [`ArcBorrow`] (e.g., in a method
> --
> 2.41.0.255.g8b1d071c50-goog
> 


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v3 6/9] rust: workqueue: add helper for defining work_struct fields
  2023-07-11  9:33 ` [PATCH v3 6/9] rust: workqueue: add helper for defining work_struct fields Alice Ryhl
  2023-07-12 20:43   ` Martin Rodriguez Reboredo
@ 2023-07-15  9:43   ` Benno Lossin
  2023-07-17 14:49     ` Alice Ryhl
  2023-08-22 18:24     ` Andreas Hindborg (Samsung)
  2023-08-22 19:59   ` Andreas Hindborg (Samsung)
  2 siblings, 2 replies; 31+ messages in thread
From: Benno Lossin @ 2023-07-15  9:43 UTC (permalink / raw)
  To: Alice Ryhl
  Cc: rust-for-linux, Tejun Heo, Miguel Ojeda, Lai Jiangshan,
	Wedson Almeida Filho, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, linux-kernel, patches

> The main challenge with defining `work_struct` fields is making sure
> that the function pointer stored in the `work_struct` is appropriate for
> the work item type it is embedded in. It needs to know the offset of the
> `work_struct` field being used (even if there are several!) so that it
> can do a `container_of`, and it needs to know the type of the work item
> so that it can call into the right user-provided code. All of this needs
> to happen in a way that provides a safe API to the user, so that users
> of the workqueue cannot mix up the function pointers.
> 
> There are three important pieces that are relevant when doing this:
> 
>  * The pointer type.
>  * The work item struct. This is what the pointer points at.
>  * The `work_struct` field. This is a field of the work item struct.
> 
> This patch introduces a separate trait for each piece. The pointer type
> is given a `WorkItemPointer` trait, which pointer types need to
> implement to be usable with the workqueue. This trait will be
> implemented for `Arc` and `Box` in a later patch in this patchset.
> Implementing this trait is unsafe because this is where the
> `container_of` operation happens, but user-code will not need to
> implement it themselves.
> 
> The work item struct should then implement the `WorkItem` trait. This
> trait is where user-code specifies what they want to happen when a work
> item is executed. It also specifies what the correct pointer type is.
> 
> Finally, to make the work item struct know the offset of its
> `work_struct` field, we use a trait called `HasWork<T, ID>`. If a type
> implements this trait, then the type declares that, at the given offset,
> there is a field of type `Work<T, ID>`. The trait is marked unsafe
> because the OFFSET constant must be correct, but we provide an
> `impl_has_work!` macro that can safely implement `HasWork<T>` on a type.
> The macro expands to something that only compiles if the specified field
> really has the type `Work<T>`. It is used like this:
> 
> ```
> struct MyWorkItem {
>     work_field: Work<MyWorkItem, 1>,
> }
> 
> impl_has_work! {
>     impl HasWork<MyWorkItem, 1> for MyWorkItem { self.work_field }
> }
> ```
> 
> Note that since the `Work` type is annotated with an id, you can have
> several `work_struct` fields by using a different id for each one.
> 
> Co-developed-by: Gary Guo <gary@garyguo.net>
> Signed-off-by: Gary Guo <gary@garyguo.net>
> Signed-off-by: Alice Ryhl <aliceryhl@google.com>
> ---
> v2 -> v3:
>  * Use __INIT_WORK_WITH_KEY instead of __INIT_WORK.
>  * Expand documentation for WorkItemPointer.
>  * Expand documentation for HasWork.
>  * Removed PhantomPinned from Work. This depends on [1] for correctness.
>  * Dropped Reviewed-by annotations due to changes.
> 
> [1]: https://lore.kernel.org/all/20230630150216.109789-1-benno.lossin@proton.me/
> 
>  rust/helpers.c           |   8 ++
>  rust/kernel/workqueue.rs | 240 ++++++++++++++++++++++++++++++++++++++-
>  2 files changed, 247 insertions(+), 1 deletion(-)
> 
> diff --git a/rust/helpers.c b/rust/helpers.c
> index bb594da56137..f7a04a266f46 100644
> --- a/rust/helpers.c
> +++ b/rust/helpers.c
> @@ -27,6 +27,7 @@
>  #include <linux/spinlock.h>
>  #include <linux/sched/signal.h>
>  #include <linux/wait.h>
> +#include <linux/workqueue.h>
> 
>  __noreturn void rust_helper_BUG(void)
>  {
> @@ -135,6 +136,13 @@ void rust_helper_put_task_struct(struct task_struct *t)
>  }
>  EXPORT_SYMBOL_GPL(rust_helper_put_task_struct);
> 
> +void rust_helper___INIT_WORK_WITH_KEY(struct work_struct *work, work_func_t func,
> +				      bool on_stack, struct lock_class_key *key)
> +{
> +	__INIT_WORK_WITH_KEY(work, func, on_stack, key);
> +}
> +EXPORT_SYMBOL_GPL(rust_helper___INIT_WORK_WITH_KEY);
> +
>  /*
>   * We use `bindgen`'s `--size_t-is-usize` option to bind the C `size_t` type
>   * as the Rust `usize` type, so we can use it in contexts where Rust
> diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs
> index cad039dfc5a9..a7c972bda0ed 100644
> --- a/rust/kernel/workqueue.rs
> +++ b/rust/kernel/workqueue.rs
> @@ -2,9 +2,34 @@
> 
>  //! Work queues.
>  //!
> +//! This file has two components: The raw work item API, and the safe work item API.
> +//!
> +//! One pattern that is used in both APIs is the `ID` const generic, which exists to allow a single
> +//! type to define multiple `work_struct` fields. This is done by choosing an id for each field,
> +//! and using that id to specify which field you wish to use. (The actual value doesn't matter, as
> +//! long as you use different values for different fields of the same struct.) Since these IDs are
> +//! generic, they are used only at compile-time, so they shouldn't exist in the final binary.
> +//!
> +//! # The raw API
> +//!
> +//! The raw API consists of the `RawWorkItem` trait, where the work item needs to provide an
> +//! arbitrary function that knows how to enqueue the work item. It should usually not be used
> +//! directly, but if you want to, you can use it without using the pieces from the safe API.

"but if you want to" -> "but if you really have to"

And I would swap the raw API section with the safe API section, this will
help guide people to the safe API.

> +//!
> +//! # The safe API
> +//!
> +//! The safe API is used via the `Work` struct and `WorkItem` traits. Furthermore, it also includes
> +//! a trait called `WorkItemPointer`, which is usually not used directly by the user.
> +//!
> +//!  * The `Work` struct is the Rust wrapper for the C `work_struct` type.
> +//!  * The `WorkItem` trait is implemented for structs that can be enqueued to a workqueue.
> +//!  * The `WorkItemPointer` trait is implemented for the pointer type that points at a something
> +//!    that implements `WorkItem`.
> +//!
>  //! C header: [`include/linux/workqueue.h`](../../../../include/linux/workqueue.h)
> 
> -use crate::{bindings, types::Opaque};
> +use crate::{bindings, prelude::*, sync::LockClassKey, types::Opaque};
> +use core::marker::PhantomData;
> 
>  /// A kernel work queue.
>  ///
> @@ -107,6 +132,219 @@ unsafe fn __enqueue<F>(self, queue_work_on: F) -> Self::EnqueueOutput
>          F: FnOnce(*mut bindings::work_struct) -> bool;
>  }
> 
> +/// Defines the method that should be called directly when a work item is executed.
> +///
> +/// This trait is implemented by `Pin<Box<T>>` and `Arc<T>`, and is mainly intended to be
> +/// implemented for smart pointer types. For your own structs, you would implement [`WorkItem`]
> +/// instead. The `run` method on this trait will usually just perform the appropriate
> +/// `container_of` translation and then call into the `run` method from the [`WorkItem`] trait.
> +///
> +/// This trait is used when the `work_struct` field is defined using the [`Work`] helper.
> +///
> +/// # Safety
> +///
> +/// Implementers must ensure that [`__enqueue`] uses a `work_struct` initialized with the [`run`]
> +/// method of this trait as the function pointer.
> +///
> +/// [`__enqueue`]: RawWorkItem::__enqueue
> +/// [`run`]: WorkItemPointer::run
> +pub unsafe trait WorkItemPointer<const ID: u64>: RawWorkItem<ID> {
> +    /// Run this work item.
> +    ///
> +    /// # Safety
> +    ///
> +    /// The provided `work_struct` pointer must originate from a previous call to `__enqueue` where
> +    /// the `queue_work_on` closure returned true, and the pointer must still be valid.
> +    unsafe extern "C" fn run(ptr: *mut bindings::work_struct);
> +}
> +
> +/// Defines the method that should be called when this work item is executed.
> +///
> +/// This trait is used when the `work_struct` field is defined using the [`Work`] helper.
> +pub trait WorkItem<const ID: u64 = 0> {
> +    /// The pointer type that this struct is wrapped in. This will typically be `Arc<Self>` or
> +    /// `Pin<Box<Self>>`.
> +    type Pointer: WorkItemPointer<ID>;
> +
> +    /// The method that should be called when this work item is executed.
> +    fn run(this: Self::Pointer);
> +}
> +
> +/// Links for a work item.
> +///
> +/// This struct contains a function pointer to the `run` function from the [`WorkItemPointer`]
> +/// trait, and defines the linked list pointers necessary to enqueue a work item in a workqueue.
> +///
> +/// Wraps the kernel's C `struct work_struct`.
> +///
> +/// This is a helper type used to associate a `work_struct` with the [`WorkItem`] that uses it.
> +#[repr(transparent)]
> +pub struct Work<T: ?Sized, const ID: u64 = 0> {
> +    work: Opaque<bindings::work_struct>,
> +    _inner: PhantomData<T>,

Should this really be `PhantomData<T>`? Are you dropping `T`s in the 
destructor of `Work<T>`? I do not think so `PhantomData<fn() -> Box<T>>`
should do the trick.

> +}
> +
> +// SAFETY: Kernel work items are usable from any thread.
> +//
> +// We do not need to constrain `T` since the work item does not actually contain a `T`.
> +unsafe impl<T: ?Sized, const ID: u64> Send for Work<T, ID> {}
> +// SAFETY: Kernel work items are usable from any thread.
> +//
> +// We do not need to constrain `T` since the work item does not actually contain a `T`.
> +unsafe impl<T: ?Sized, const ID: u64> Sync for Work<T, ID> {}
> +
> +impl<T: ?Sized, const ID: u64> Work<T, ID> {
> +    /// Creates a new instance of [`Work`].
> +    #[inline]
> +    #[allow(clippy::new_ret_no_self)]
> +    pub fn new(key: &'static LockClassKey) -> impl PinInit<Self>
> +    where
> +        T: WorkItem<ID>,
> +    {
> +        // SAFETY: The `WorkItemPointer` implementation promises that `run` can be used as the work
> +        // item function.
> +        unsafe {
> +            kernel::init::pin_init_from_closure(move |slot| {
> +                let slot = Self::raw_get(slot);
> +                bindings::__INIT_WORK_WITH_KEY(slot, Some(T::Pointer::run), false, key.as_ptr());
> +                Ok(())
> +            })
> +        }

Please do this instead:
```
        pin_init!(Self {
            // SAFETY: The `WorkItemPointer` implementation promises that `run` can be used as the
            // work item function.
            work <- Opaque::ffi_init(|slot| unsafe {
                bindings::__INIT_WORK_WITH_KEY(slot, Some(T::Pointer::run), false, key.as_ptr())
            }),
            _inner: PhantomData,
        })
```

> +    }
> +
> +    /// Get a pointer to the inner `work_struct`.
> +    ///
> +    /// # Safety
> +    ///
> +    /// The provided pointer must not be dangling and must be properly aligned. (But the memory
> +    /// need not be initialized.)
> +    #[inline]
> +    pub unsafe fn raw_get(ptr: *const Self) -> *mut bindings::work_struct {
> +        // SAFETY: The caller promises that the pointer is aligned and not dangling.
> +        //
> +        // A pointer cast would also be ok due to `#[repr(transparent)]`. We use `addr_of!` so that
> +        // the compiler does not complain that the `work` field is unused.
> +        unsafe { Opaque::raw_get(core::ptr::addr_of!((*ptr).work)) }
> +    }
> +}
> +
> +/// Declares that a type has a [`Work<T, ID>`] field.
> +///
> +/// The intended way of using this trait is via the [`impl_has_work!`] macro. You can use the macro
> +/// like this:
> +///
> +/// ```no_run
> +/// use kernel::prelude::*;
> +/// use kernel::workqueue::Work;
> +///
> +/// struct MyWorkItem {
> +///     work_field: Work<MyWorkItem, 1>,
> +/// }
> +///
> +/// impl_has_work! {
> +///     impl HasWork<MyWorkItem, 1> for MyWorkItem { self.work_field }
> +/// }
> +/// ```
> +///
> +/// Note that since the `Work` type is annotated with an id, you can have several `work_struct`
> +/// fields by using a different id for each one.
> +///
> +/// # Safety
> +///
> +/// The [`OFFSET`] constant must be the offset of a field in Self of type [`Work<T, ID>`]. The methods on
> +/// this trait must have exactly the behavior that the definitions given below have.
> +///
> +/// [`Work<T, ID>`]: Work
> +/// [`impl_has_work!`]: crate::impl_has_work
> +/// [`OFFSET`]: HasWork::OFFSET
> +pub unsafe trait HasWork<T, const ID: u64 = 0> {

Is there a reason that `T` is `Sized` here?

--
Cheers,
Benno

> +    /// The offset of the [`Work<T, ID>`] field.
> +    ///
> +    /// [`Work<T, ID>`]: Work
> +    const OFFSET: usize;
> +
> +    /// Returns the offset of the [`Work<T, ID>`] field.
> +    ///
> +    /// This method exists because the [`OFFSET`] constant cannot be accessed if the type is not Sized.
> +    ///
> +    /// [`Work<T, ID>`]: Work
> +    /// [`OFFSET`]: HasWork::OFFSET
> +    #[inline]
> +    fn get_work_offset(&self) -> usize {
> +        Self::OFFSET
> +    }
> +
> +    /// Returns a pointer to the [`Work<T, ID>`] field.
> +    ///
> +    /// # Safety
> +    ///
> +    /// The provided pointer must point at a valid struct of type `Self`.
> +    ///
> +    /// [`Work<T, ID>`]: Work
> +    #[inline]
> +    unsafe fn raw_get_work(ptr: *mut Self) -> *mut Work<T, ID> {
> +        // SAFETY: The caller promises that the pointer is valid.
> +        unsafe { (ptr as *mut u8).add(Self::OFFSET) as *mut Work<T, ID> }
> +    }
> +
> +    /// Returns a pointer to the struct containing the [`Work<T, ID>`] field.
> +    ///
> +    /// # Safety
> +    ///
> +    /// The pointer must point at a [`Work<T, ID>`] field in a struct of type `Self`.
> +    ///
> +    /// [`Work<T, ID>`]: Work
> +    #[inline]
> +    unsafe fn work_container_of(ptr: *mut Work<T, ID>) -> *mut Self
> +    where
> +        Self: Sized,
> +    {
> +        // SAFETY: The caller promises that the pointer points at a field of the right type in the
> +        // right kind of struct.
> +        unsafe { (ptr as *mut u8).sub(Self::OFFSET) as *mut Self }
> +    }
> +}
> +
> +/// Used to safely implement the [`HasWork<T, ID>`] trait.
> +///
> +/// # Examples
> +///
> +/// ```
> +/// use kernel::sync::Arc;
> +///
> +/// struct MyStruct {
> +///     work_field: Work<MyStruct, 17>,
> +/// }
> +///
> +/// impl_has_work! {
> +///     impl HasWork<MyStruct, 17> for MyStruct { self.work_field }
> +/// }
> +/// ```
> +///
> +/// [`HasWork<T, ID>`]: HasWork
> +#[macro_export]
> +macro_rules! impl_has_work {
> +    ($(impl$(<$($implarg:ident),*>)?
> +       HasWork<$work_type:ty $(, $id:tt)?>
> +       for $self:ident $(<$($selfarg:ident),*>)?
> +       { self.$field:ident }
> +    )*) => {$(
> +        // SAFETY: The implementation of `raw_get_work` only compiles if the field has the right
> +        // type.
> +        unsafe impl$(<$($implarg),*>)? $crate::workqueue::HasWork<$work_type $(, $id)?> for $self $(<$($selfarg),*>)? {
> +            const OFFSET: usize = $crate::offset_of!(Self, $field) as usize;
> +
> +            #[inline]
> +            unsafe fn raw_get_work(ptr: *mut Self) -> *mut $crate::workqueue::Work<$work_type $(, $id)?> {
> +                // SAFETY: The caller promises that the pointer is not dangling.
> +                unsafe {
> +                    ::core::ptr::addr_of_mut!((*ptr).$field)
> +                }
> +            }
> +        }
> +    )*};
> +}
> +
>  /// Returns the system work queue (`system_wq`).
>  ///
>  /// It is the one used by `schedule[_delayed]_work[_on]()`. Multi-CPU multi-threaded. There are
> --
> 2.41.0.255.g8b1d071c50-goog
> 


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v3 2/9] rust: sync: add `Arc::{from_raw, into_raw}`
  2023-07-15  9:42   ` Benno Lossin
@ 2023-07-17 13:47     ` Alice Ryhl
  0 siblings, 0 replies; 31+ messages in thread
From: Alice Ryhl @ 2023-07-17 13:47 UTC (permalink / raw)
  To: benno.lossin
  Cc: alex.gaynor, aliceryhl, bjorn3_gh, boqun.feng, gary,
	jiangshanlai, linux-kernel, ojeda, patches, rust-for-linux, tj,
	walmeida, wedsonaf

Benno Lossin <benno.lossin@proton.me> writes:
>> +    /// This code relies on the `repr(C)` layout of structs as described in
>> +    /// <https://doc.rust-lang.org/reference/type-layout.html#reprc-structs>.
> 
> Why is this in the documentation? I feel like it should be a normal code
> comment at the very start of the function.

In fact, I think we can drop this comment entirely. The motivation
behind using `Layout::extend` for computing `val_offset` is that its
correctness does not rely on how the repr(C) layout algorithm works.

(As opposed to how the previous implementation's correctness *does*
depend on knowing the repr(C) layout algorithm:
    Layout::new::<ArcInner<()>>().align_to(align).unwrap().pad_to_align().size()
)

>> +    ///
>> +    /// # Safety
>> +    ///
>> +    /// `ptr` must have been returned by a previous call to [`Arc::into_raw`]. Additionally, it
>> +    /// can only be called once for each previous call to [`Arc::into_raw`].
> 
> "it can only" -> "it must only"

Sounds good. I'll change it to use "must" in the next version.

Alice


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v3 4/9] rust: workqueue: add low-level workqueue bindings
  2023-07-11 22:23   ` Boqun Feng
@ 2023-07-17 13:53     ` Alice Ryhl
  0 siblings, 0 replies; 31+ messages in thread
From: Alice Ryhl @ 2023-07-17 13:53 UTC (permalink / raw)
  To: boqun.feng
  Cc: alex.gaynor, aliceryhl, benno.lossin, bjorn3_gh, gary,
	jiangshanlai, linux-kernel, nmi, ojeda, patches, rust-for-linux,
	tj, wedsonaf, yakoyoku

Boqun Feng <boqun.feng@gmail.com> writes:
>> +// SAFETY: Kernel workqueues are usable from any thread.
>> +unsafe impl Send for Queue {}
>> +unsafe impl Sync for Queue {}
> 
> I don't think "usable from any thread" is the accurate wording here, it
> sounds to me that there are types that cannot be used for a particular
> type of threads ;-)
> 
> Maybe
> 
> 	// SAFETY: Accesses to workqueues used by [`Queue`] are
> 	// thread-safe.
> 
> ?

Sure, I'll make that change in the next version.

Alice


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v3 6/9] rust: workqueue: add helper for defining work_struct fields
  2023-07-15  9:43   ` Benno Lossin
@ 2023-07-17 14:49     ` Alice Ryhl
  2023-08-22 18:24     ` Andreas Hindborg (Samsung)
  1 sibling, 0 replies; 31+ messages in thread
From: Alice Ryhl @ 2023-07-17 14:49 UTC (permalink / raw)
  To: benno.lossin
  Cc: alex.gaynor, aliceryhl, bjorn3_gh, boqun.feng, gary,
	jiangshanlai, linux-kernel, ojeda, patches, rust-for-linux, tj,
	wedsonaf

Benno Lossin <benno.lossin@proton.me> writes:
>> +/// Links for a work item.
>> +///
>> +/// This struct contains a function pointer to the `run` function from the [`WorkItemPointer`]
>> +/// trait, and defines the linked list pointers necessary to enqueue a work item in a workqueue.
>> +///
>> +/// Wraps the kernel's C `struct work_struct`.
>> +///
>> +/// This is a helper type used to associate a `work_struct` with the [`WorkItem`] that uses it.
>> +#[repr(transparent)]
>> +pub struct Work<T: ?Sized, const ID: u64 = 0> {
>> +    work: Opaque<bindings::work_struct>,
>> +    _inner: PhantomData<T>,
>
> Should this really be `PhantomData<T>`? Are you dropping `T`s in the 
> destructor of `Work<T>`? I do not think so `PhantomData<fn() -> Box<T>>`
> should do the trick.

Hmm. The `work_struct` effectively has a field of type `fn(T::Pointer)`,
so arguably, that's the type that should be used for the `PhantomData`.
This makes `Work` contravariant instead.

That said, the type `T` is going to be the struct itself, so, for
example, a `MyStruct<'a>` might have a `&'a i32` and a
`Work<MyStruct<'a>>` field, so it ends up being invariant.

By that argument, perhaps we should just make `Work` invariant instead?
We can do that with `PhantomData<*mut T>`.

>> +pub unsafe trait HasWork<T, const ID: u64 = 0> {
> 
> Is there a reason that `T` is `Sized` here?

Hmm, that's an oversight. In v1 of this patchset, the Sized requirement
was correct since T was the pointer type, but now it isn't anymore.

Alice

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v3 1/9] rust: add offset_of! macro
  2023-07-11  9:32 ` [PATCH v3 1/9] rust: add offset_of! macro Alice Ryhl
@ 2023-08-21 18:43   ` Andreas Hindborg (Samsung)
  0 siblings, 0 replies; 31+ messages in thread
From: Andreas Hindborg (Samsung) @ 2023-08-21 18:43 UTC (permalink / raw)
  To: Alice Ryhl
  Cc: rust-for-linux, Tejun Heo, Miguel Ojeda, Lai Jiangshan,
	Wedson Almeida Filho, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, linux-kernel, patches,
	Wedson Almeida Filho, Martin Rodriguez Reboredo


Hi Alice,

Alice Ryhl <aliceryhl@google.com> writes:

> From: Wedson Almeida Filho <walmeida@microsoft.com>
>
> This macro is used to compute the offset of a field in a struct.
>
> This commit enables an unstable feature that is necessary for using
> the macro in a constant. However, this is not a problem as the macro
> will become available from the Rust standard library soon [1]. The
> unstable feature can be disabled again once that happens.
>
> The macro in this patch does not support sub-fields. That is, you cannot
> write `offset_of!(MyStruct, field.sub_field)` to get the offset of
> `sub_field` with `field`'s type being a struct with a field called
> `sub_field`. This is because `field` might be a `Box<SubStruct>`, which
> means that you would be trying to compute the offset to something in an
> entirely different allocation. There's no easy way to fix the current
> macro to support subfields, but the version being added to the standard
> library should support it, so the limitation is temporary and not a big
> deal.

I think `#![feature(offset_of)]` is available in 1.71.0, can we use that directly?

BR Andreas

^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v3 2/9] rust: sync: add `Arc::{from_raw, into_raw}`
  2023-07-11  9:32 ` [PATCH v3 2/9] rust: sync: add `Arc::{from_raw, into_raw}` Alice Ryhl
  2023-07-12 20:33   ` Martin Rodriguez Reboredo
  2023-07-15  9:42   ` Benno Lossin
@ 2023-08-22 11:46   ` Andreas Hindborg (Samsung)
  2 siblings, 0 replies; 31+ messages in thread
From: Andreas Hindborg (Samsung) @ 2023-08-22 11:46 UTC (permalink / raw)
  To: Alice Ryhl
  Cc: rust-for-linux, Tejun Heo, Miguel Ojeda, Lai Jiangshan,
	Wedson Almeida Filho, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, linux-kernel, patches,
	Wedson Almeida Filho


Alice Ryhl <aliceryhl@google.com> writes:

> From: Wedson Almeida Filho <walmeida@microsoft.com>
>
> These methods can be used to turn an `Arc` into a raw pointer and back,
> in a way that preserves the metadata for fat pointers.
>
> This is done using the unstable ptr_metadata feature [1]. However, it
> could also be done using the unstable pointer_byte_offsets feature [2],
> which is likely to have a shorter path to stabilization than
> ptr_metadata.
>
> Link: https://github.com/rust-lang/rust/issues/81513 [1]
> Link: https://github.com/rust-lang/rust/issues/96283 [2]
> Signed-off-by: Wedson Almeida Filho <walmeida@microsoft.com>
> Co-developed-by: Alice Ryhl <aliceryhl@google.com>
> Signed-off-by: Alice Ryhl <aliceryhl@google.com>
> Reviewed-by: Gary Guo <gary@garyguo.net>
> ---

Reviewed-by: Andreas Hindborg <a.hindborg@samsung.com>


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v3 6/9] rust: workqueue: add helper for defining work_struct fields
  2023-07-15  9:43   ` Benno Lossin
  2023-07-17 14:49     ` Alice Ryhl
@ 2023-08-22 18:24     ` Andreas Hindborg (Samsung)
  2023-08-23  9:06       ` Andreas Hindborg (Samsung)
  1 sibling, 1 reply; 31+ messages in thread
From: Andreas Hindborg (Samsung) @ 2023-08-22 18:24 UTC (permalink / raw)
  To: Benno Lossin
  Cc: Alice Ryhl, rust-for-linux, Tejun Heo, Miguel Ojeda,
	Lai Jiangshan, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron, linux-kernel, patches


Hi Benno,

Benno Lossin <benno.lossin@proton.me> writes:

...

>> +/// Links for a work item.
>> +///
>> +/// This struct contains a function pointer to the `run` function from the [`WorkItemPointer`]
>> +/// trait, and defines the linked list pointers necessary to enqueue a work item in a workqueue.
>> +///
>> +/// Wraps the kernel's C `struct work_struct`.
>> +///
>> +/// This is a helper type used to associate a `work_struct` with the [`WorkItem`] that uses it.
>> +#[repr(transparent)]
>> +pub struct Work<T: ?Sized, const ID: u64 = 0> {
>> +    work: Opaque<bindings::work_struct>,
>> +    _inner: PhantomData<T>,
>
> Should this really be `PhantomData<T>`? Are you dropping `T`s in the 
> destructor of `Work<T>`? I do not think so `PhantomData<fn() -> Box<T>>`
> should do the trick.
>

Could you elaborate what is the issue in having `PhantomData<T>`?

BR Andreas


^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v3 6/9] rust: workqueue: add helper for defining work_struct fields
  2023-07-11  9:33 ` [PATCH v3 6/9] rust: workqueue: add helper for defining work_struct fields Alice Ryhl
  2023-07-12 20:43   ` Martin Rodriguez Reboredo
  2023-07-15  9:43   ` Benno Lossin
@ 2023-08-22 19:59   ` Andreas Hindborg (Samsung)
  2 siblings, 0 replies; 31+ messages in thread
From: Andreas Hindborg (Samsung) @ 2023-08-22 19:59 UTC (permalink / raw)
  To: Alice Ryhl
  Cc: rust-for-linux, Tejun Heo, Miguel Ojeda, Lai Jiangshan,
	Wedson Almeida Filho, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, linux-kernel, patches


Alice Ryhl <aliceryhl@google.com> writes:

> The main challenge with defining `work_struct` fields is making sure
> that the function pointer stored in the `work_struct` is appropriate for
> the work item type it is embedded in. It needs to know the offset of the
> `work_struct` field being used (even if there are several!) so that it
> can do a `container_of`, and it needs to know the type of the work item
> so that it can call into the right user-provided code. All of this needs
> to happen in a way that provides a safe API to the user, so that users
> of the workqueue cannot mix up the function pointers.
>
> There are three important pieces that are relevant when doing this:
>
>  * The pointer type.
>  * The work item struct. This is what the pointer points at.
>  * The `work_struct` field. This is a field of the work item struct.
>
> This patch introduces a separate trait for each piece. The pointer type
> is given a `WorkItemPointer` trait, which pointer types need to
> implement to be usable with the workqueue. This trait will be
> implemented for `Arc` and `Box` in a later patch in this patchset.
> Implementing this trait is unsafe because this is where the
> `container_of` operation happens, but user-code will not need to
> implement it themselves.
>
> The work item struct should then implement the `WorkItem` trait. This
> trait is where user-code specifies what they want to happen when a work
> item is executed. It also specifies what the correct pointer type is.
>
> Finally, to make the work item struct know the offset of its
> `work_struct` field, we use a trait called `HasWork<T, ID>`. If a type
> implements this trait, then the type declares that, at the given offset,
> there is a field of type `Work<T, ID>`. The trait is marked unsafe
> because the OFFSET constant must be correct, but we provide an
> `impl_has_work!` macro that can safely implement `HasWork<T>` on a type.
> The macro expands to something that only compiles if the specified field
> really has the type `Work<T>`. It is used like this:
>
> ```
> struct MyWorkItem {
>     work_field: Work<MyWorkItem, 1>,
> }
>
> impl_has_work! {
>     impl HasWork<MyWorkItem, 1> for MyWorkItem { self.work_field }
> }
> ```
>
> Note that since the `Work` type is annotated with an id, you can have
> several `work_struct` fields by using a different id for each one.
>
> Co-developed-by: Gary Guo <gary@garyguo.net>
> Signed-off-by: Gary Guo <gary@garyguo.net>
> Signed-off-by: Alice Ryhl <aliceryhl@google.com>
> ---

Reviewed-by: Andreas Hindborg <a.hindborg@samsung.com>



^ permalink raw reply	[flat|nested] 31+ messages in thread

* Re: [PATCH v3 6/9] rust: workqueue: add helper for defining work_struct fields
  2023-08-22 18:24     ` Andreas Hindborg (Samsung)
@ 2023-08-23  9:06       ` Andreas Hindborg (Samsung)
  0 siblings, 0 replies; 31+ messages in thread
From: Andreas Hindborg (Samsung) @ 2023-08-23  9:06 UTC (permalink / raw)
  To: Benno Lossin
  Cc: Alice Ryhl, rust-for-linux, Tejun Heo, Miguel Ojeda,
	Lai Jiangshan, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron, linux-kernel, patches


"Andreas Hindborg (Samsung)" <nmi@metaspace.dk> writes:

> Hi Benno,
>
> Benno Lossin <benno.lossin@proton.me> writes:
>
> ...
>
>>> +/// Links for a work item.
>>> +///
>>> +/// This struct contains a function pointer to the `run` function from the [`WorkItemPointer`]
>>> +/// trait, and defines the linked list pointers necessary to enqueue a work item in a workqueue.
>>> +///
>>> +/// Wraps the kernel's C `struct work_struct`.
>>> +///
>>> +/// This is a helper type used to associate a `work_struct` with the [`WorkItem`] that uses it.
>>> +#[repr(transparent)]
>>> +pub struct Work<T: ?Sized, const ID: u64 = 0> {
>>> +    work: Opaque<bindings::work_struct>,
>>> +    _inner: PhantomData<T>,
>>
>> Should this really be `PhantomData<T>`? Are you dropping `T`s in the 
>> destructor of `Work<T>`? I do not think so `PhantomData<fn() -> Box<T>>`
>> should do the trick.
>>
>
> Could you elaborate what is the issue in having `PhantomData<T>`?

I played around with this and as far as I can tell, using
`PhantomData<fn() -> Box<T>>` does not disable dropck for T. Thus,
`PhantomData<T>` has the same effect as `PhantomData<fn() -> Box<T>`,
which is covariance over T and dropck:

```rust
use std::marker::PhantomData;

struct A<T> {
    _marker: PhantomData<fn() -> Box<T>>,
}

//#[cfg(disable)]
impl<T> Drop for A<T> {
    fn drop(&mut self) {
        todo!()
    }
}

struct B {}

fn main() {
    let (_a, b);
    b = B {};
    _a = foo(&b);
}

fn foo<'a>(_b: &'a B) -> A<&'a B> {
    let a: A<&'a B> = A {
        _marker: PhantomData,
    };
    a
}
```

This is a little surprising to me since nomicon [1] explicitly marks
`PhantomData<T>` as "covariant (with drop check)" but only "covariant"
for `PhantomData<fn() -> T>`.

Not sure why you wanted the box?

Best regards,
Andreas


[1] https://doc.rust-lang.org/nomicon/phantom-data.html#table-of-phantomdata-patterns

^ permalink raw reply	[flat|nested] 31+ messages in thread

end of thread, other threads:[~2023-08-23  9:14 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-07-11  9:32 [PATCH v3 0/9] rust: workqueue: add bindings for the workqueue Alice Ryhl
2023-07-11  9:32 ` [PATCH v3 1/9] rust: add offset_of! macro Alice Ryhl
2023-08-21 18:43   ` Andreas Hindborg (Samsung)
2023-07-11  9:32 ` [PATCH v3 2/9] rust: sync: add `Arc::{from_raw, into_raw}` Alice Ryhl
2023-07-12 20:33   ` Martin Rodriguez Reboredo
2023-07-15  9:42   ` Benno Lossin
2023-07-17 13:47     ` Alice Ryhl
2023-08-22 11:46   ` Andreas Hindborg (Samsung)
2023-07-11  9:32 ` [PATCH 3/9] workqueue: introduce `__INIT_WORK_WITH_KEY` Alice Ryhl
2023-07-11 10:49   ` Alice Ryhl
2023-07-12  6:33   ` Boqun Feng
2023-07-12 20:34   ` Martin Rodriguez Reboredo
2023-07-11  9:32 ` [PATCH v3 4/9] rust: workqueue: add low-level workqueue bindings Alice Ryhl
2023-07-11 22:23   ` Boqun Feng
2023-07-17 13:53     ` Alice Ryhl
2023-07-11  9:32 ` [PATCH v3 5/9] rust: workqueue: define built-in queues Alice Ryhl
2023-07-11  9:33 ` [PATCH v3 6/9] rust: workqueue: add helper for defining work_struct fields Alice Ryhl
2023-07-12 20:43   ` Martin Rodriguez Reboredo
2023-07-15  9:43   ` Benno Lossin
2023-07-17 14:49     ` Alice Ryhl
2023-08-22 18:24     ` Andreas Hindborg (Samsung)
2023-08-23  9:06       ` Andreas Hindborg (Samsung)
2023-08-22 19:59   ` Andreas Hindborg (Samsung)
2023-07-11  9:33 ` [PATCH v3 7/9] rust: workqueue: implement `WorkItemPointer` for pointer types Alice Ryhl
2023-07-11  9:33 ` [PATCH v3 8/9] rust: workqueue: add `try_spawn` helper method Alice Ryhl
2023-07-11  9:33 ` [PATCH v3 9/9] rust: workqueue: add examples Alice Ryhl
2023-07-14 22:40   ` Boqun Feng
2023-07-11 22:17 ` [PATCH v3 0/9] rust: workqueue: add bindings for the workqueue Tejun Heo
2023-07-11 23:44   ` Miguel Ojeda
2023-07-12  0:27     ` Tejun Heo
2023-07-12 16:36       ` Miguel Ojeda

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.