| From 1b56e765bf8990f1f60e124926c11fc4ac63d752 Mon Sep 17 00:00:00 2001 |
| From: Danilo Krummrich <dakr@kernel.org> |
| Date: Thu, 12 Jun 2025 14:17:13 +0200 |
| Subject: rust: completion: implement initial abstraction |
| |
| From: Danilo Krummrich <dakr@kernel.org> |
| |
| commit 1b56e765bf8990f1f60e124926c11fc4ac63d752 upstream. |
| |
| Implement a minimal abstraction for the completion synchronization |
| primitive. |
| |
| This initial abstraction only adds complete_all() and |
| wait_for_completion(), since that is what is required for the subsequent |
| Devres patch. |
| |
| Cc: Ingo Molnar <mingo@redhat.com> |
| Cc: Peter Zijlstra <peterz@infradead.org> |
| Cc: Juri Lelli <juri.lelli@redhat.com> |
| Cc: Vincent Guittot <vincent.guittot@linaro.org> |
| Cc: Dietmar Eggemann <dietmar.eggemann@arm.com> |
| Cc: Steven Rostedt <rostedt@goodmis.org> |
| Cc: Ben Segall <bsegall@google.com> |
| Cc: Mel Gorman <mgorman@suse.de> |
| Cc: Valentin Schneider <vschneid@redhat.com> |
| Reviewed-by: Alice Ryhl <aliceryhl@google.com> |
| Reviewed-by: Boqun Feng <boqun.feng@gmail.com> |
| Reviewed-by: Benno Lossin <lossin@kernel.org> |
| Acked-by: Miguel Ojeda <ojeda@kernel.org> |
| Link: https://lore.kernel.org/r/20250612121817.1621-2-dakr@kernel.org |
| Signed-off-by: Danilo Krummrich <dakr@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| rust/bindings/bindings_helper.h | 1 |
| rust/helpers/completion.c | 8 ++ |
| rust/helpers/helpers.c | 1 |
| rust/kernel/sync.rs | 2 |
| rust/kernel/sync/completion.rs | 112 ++++++++++++++++++++++++++++++++++++++++ |
| 5 files changed, 124 insertions(+) |
| create mode 100644 rust/helpers/completion.c |
| create mode 100644 rust/kernel/sync/completion.rs |
| |
| --- a/rust/bindings/bindings_helper.h |
| +++ b/rust/bindings/bindings_helper.h |
| @@ -10,6 +10,7 @@ |
| #include <linux/blk-mq.h> |
| #include <linux/blk_types.h> |
| #include <linux/blkdev.h> |
| +#include <linux/completion.h> |
| #include <linux/cpumask.h> |
| #include <linux/cred.h> |
| #include <linux/device/faux.h> |
| --- /dev/null |
| +++ b/rust/helpers/completion.c |
| @@ -0,0 +1,8 @@ |
| +// SPDX-License-Identifier: GPL-2.0 |
| + |
| +#include <linux/completion.h> |
| + |
| +void rust_helper_init_completion(struct completion *x) |
| +{ |
| + init_completion(x); |
| +} |
| --- a/rust/helpers/helpers.c |
| +++ b/rust/helpers/helpers.c |
| @@ -11,6 +11,7 @@ |
| #include "bug.c" |
| #include "build_assert.c" |
| #include "build_bug.c" |
| +#include "completion.c" |
| #include "cpumask.c" |
| #include "cred.c" |
| #include "device.c" |
| --- a/rust/kernel/sync.rs |
| +++ b/rust/kernel/sync.rs |
| @@ -10,6 +10,7 @@ use crate::types::Opaque; |
| use pin_init; |
| |
| mod arc; |
| +pub mod completion; |
| mod condvar; |
| pub mod lock; |
| mod locked_by; |
| @@ -17,6 +18,7 @@ pub mod poll; |
| pub mod rcu; |
| |
| pub use arc::{Arc, ArcBorrow, UniqueArc}; |
| +pub use completion::Completion; |
| pub use condvar::{new_condvar, CondVar, CondVarTimeoutResult}; |
| pub use lock::global::{global_lock, GlobalGuard, GlobalLock, GlobalLockBackend, GlobalLockedBy}; |
| pub use lock::mutex::{new_mutex, Mutex, MutexGuard}; |
| --- /dev/null |
| +++ b/rust/kernel/sync/completion.rs |
| @@ -0,0 +1,112 @@ |
| +// SPDX-License-Identifier: GPL-2.0 |
| + |
| +//! Completion support. |
| +//! |
| +//! Reference: <https://docs.kernel.org/scheduler/completion.html> |
| +//! |
| +//! C header: [`include/linux/completion.h`](srctree/include/linux/completion.h) |
| + |
| +use crate::{bindings, prelude::*, types::Opaque}; |
| + |
| +/// Synchronization primitive to signal when a certain task has been completed. |
| +/// |
| +/// The [`Completion`] synchronization primitive signals when a certain task has been completed by |
| +/// waking up other tasks that have been queued up to wait for the [`Completion`] to be completed. |
| +/// |
| +/// # Examples |
| +/// |
| +/// ``` |
| +/// use kernel::sync::{Arc, Completion}; |
| +/// use kernel::workqueue::{self, impl_has_work, new_work, Work, WorkItem}; |
| +/// |
| +/// #[pin_data] |
| +/// struct MyTask { |
| +/// #[pin] |
| +/// work: Work<MyTask>, |
| +/// #[pin] |
| +/// done: Completion, |
| +/// } |
| +/// |
| +/// impl_has_work! { |
| +/// impl HasWork<Self> for MyTask { self.work } |
| +/// } |
| +/// |
| +/// impl MyTask { |
| +/// fn new() -> Result<Arc<Self>> { |
| +/// let this = Arc::pin_init(pin_init!(MyTask { |
| +/// work <- new_work!("MyTask::work"), |
| +/// done <- Completion::new(), |
| +/// }), GFP_KERNEL)?; |
| +/// |
| +/// let _ = workqueue::system().enqueue(this.clone()); |
| +/// |
| +/// Ok(this) |
| +/// } |
| +/// |
| +/// fn wait_for_completion(&self) { |
| +/// self.done.wait_for_completion(); |
| +/// |
| +/// pr_info!("Completion: task complete\n"); |
| +/// } |
| +/// } |
| +/// |
| +/// impl WorkItem for MyTask { |
| +/// type Pointer = Arc<MyTask>; |
| +/// |
| +/// fn run(this: Arc<MyTask>) { |
| +/// // process this task |
| +/// this.done.complete_all(); |
| +/// } |
| +/// } |
| +/// |
| +/// let task = MyTask::new()?; |
| +/// task.wait_for_completion(); |
| +/// # Ok::<(), Error>(()) |
| +/// ``` |
| +#[pin_data] |
| +pub struct Completion { |
| + #[pin] |
| + inner: Opaque<bindings::completion>, |
| +} |
| + |
| +// SAFETY: `Completion` is safe to be send to any task. |
| +unsafe impl Send for Completion {} |
| + |
| +// SAFETY: `Completion` is safe to be accessed concurrently. |
| +unsafe impl Sync for Completion {} |
| + |
| +impl Completion { |
| + /// Create an initializer for a new [`Completion`]. |
| + pub fn new() -> impl PinInit<Self> { |
| + pin_init!(Self { |
| + inner <- Opaque::ffi_init(|slot: *mut bindings::completion| { |
| + // SAFETY: `slot` is a valid pointer to an uninitialized `struct completion`. |
| + unsafe { bindings::init_completion(slot) }; |
| + }), |
| + }) |
| + } |
| + |
| + fn as_raw(&self) -> *mut bindings::completion { |
| + self.inner.get() |
| + } |
| + |
| + /// Signal all tasks waiting on this completion. |
| + /// |
| + /// This method wakes up all tasks waiting on this completion; after this operation the |
| + /// completion is permanently done, i.e. signals all current and future waiters. |
| + pub fn complete_all(&self) { |
| + // SAFETY: `self.as_raw()` is a pointer to a valid `struct completion`. |
| + unsafe { bindings::complete_all(self.as_raw()) }; |
| + } |
| + |
| + /// Wait for completion of a task. |
| + /// |
| + /// This method waits for the completion of a task; it is not interruptible and there is no |
| + /// timeout. |
| + /// |
| + /// See also [`Completion::complete_all`]. |
| + pub fn wait_for_completion(&self) { |
| + // SAFETY: `self.as_raw()` is a pointer to a valid `struct completion`. |
| + unsafe { bindings::wait_for_completion(self.as_raw()) }; |
| + } |
| +} |