From: Alice Ryhl <aliceryhl@google.com>
To: Danilo Krummrich <dakr@kernel.org>
Cc: tj@kernel.org, jiangshanlai@gmail.com, ojeda@kernel.org,
boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com,
lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu,
daniel.almeida@collabora.com, tamird@kernel.org,
acourbot@nvidia.com, work@onurozkan.dev, jhubbard@nvidia.com,
rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org,
driver-core@lists.linux.dev
Subject: Re: [PATCH v2 5/6] rust: workqueue: add ScopedQueue for lifetime bound items
Date: Wed, 2 Sep 2026 14:40:51 +0000 [thread overview]
Message-ID: <apg1c4GdVrhYDK1P@google.com> (raw)
In-Reply-To: <20260807165252.3849875-6-dakr@kernel.org>
On Fri, Aug 07, 2026 at 06:52:48PM +0200, Danilo Krummrich wrote:
> From: Onur Özkan <work@onurozkan.dev>
>
> Add a workqueue wrapper for work items that are not 'static.
>
> Tyr reset work is queued from a handle that owns a Controller<'bound>
> where the work item holds references tied to the lifetime of the bound
> device and its mapped IO state. The existing API only accepts 'static
> work items which cannot express that relationship.
>
> Introduce ScopedQueue for this case. It owns the underlying workqueue
> and ties enqueued work to the queue lifetime so borrowed state cannot
> outlive the queue that may still run it.
>
> Construction is unsafe because the queue must not be leaked.
>
> `compile_fail` doc-tests are ignored for now as KUnit doesn't support
> that. Enabling those tests as regular code block would raise this error:
>
> ERROR:root:error[E0597]: `data` does not live long enough
> --> rust/doctests_kernel_generated.rs:22029:44
> |
> 22027 | let data = ();
> | ---- binding `data` declared here
> 22028 | // SAFETY: Queue is not leaked.
> 22029 | queue = unsafe { new_queue(&data)? };
> | ^^^^^ borrowed value does not live long enough
> 22030 | }
> | - `data` dropped here while still borrowed
> ...
> 22034 | }
> | - borrow might be used here, when `queue` is dropped and runs the `Drop` code for type `ScopedQueue`
> |
> = note: values in a scope are dropped in the opposite order they are defined
The '^^^^^' on the warning doesn't quite point at the right location.
>
> which is exactly the constraint ScopedQueue is meant to enforce.
>
> Suggested-by: Danilo Krummrich <dakr@kernel.org>
> Signed-off-by: Onur Özkan <work@onurozkan.dev>
> [ Move from scoped_queue.rs to scoped.rs, which can be shared with
> ScopedWork; add missing inline annotations. - Danilo ]
> Signed-off-by: Danilo Krummrich <dakr@kernel.org>
> ---
> rust/kernel/workqueue/mod.rs | 3 +
> rust/kernel/workqueue/scoped.rs | 190 ++++++++++++++++++++++++++++++++
> 2 files changed, 193 insertions(+)
> create mode 100644 rust/kernel/workqueue/scoped.rs
>
> diff --git a/rust/kernel/workqueue/mod.rs b/rust/kernel/workqueue/mod.rs
> index 8eb2d037be83..551fa1401b85 100644
> --- a/rust/kernel/workqueue/mod.rs
> +++ b/rust/kernel/workqueue/mod.rs
> @@ -212,6 +212,9 @@
> mod builder;
> pub use self::builder::Builder;
>
> +mod scoped;
> +pub use self::scoped::ScopedQueue;
> +
> /// Creates a [`Work`] initialiser with the given name and a newly-created lock class.
> #[macro_export]
> macro_rules! new_work {
> diff --git a/rust/kernel/workqueue/scoped.rs b/rust/kernel/workqueue/scoped.rs
> new file mode 100644
> index 000000000000..18a4b6f6cf18
> --- /dev/null
> +++ b/rust/kernel/workqueue/scoped.rs
> @@ -0,0 +1,190 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +//! Lifetime-scoped workqueues.
> +//!
> +//! Provides [`ScopedQueue`] for work items that may borrow data with some
> +//! non-`'static` lifetime.
> +//!
> +//! Unlike [`Queue`] which only accepts `'static` work items, [`ScopedQueue`]
> +//! owns its underlying queue and relies on that queue being dropped to drain
> +//! pending and running work before borrowed data can go out of scope.
> +//!
> +//! TODO: Remove `ignore` once KUnit supports `compile_fail` on doc-tests.
> +//! ```compile_fail,ignore
> +//! use kernel::prelude::*;
> +//! use kernel::workqueue::ScopedQueue;
> +//!
> +//! /// # Safety
> +//! ///
> +//! /// Returned queue must not be leaked.
> +//! unsafe fn new_queue<'bound>(_: &'bound ()) -> Result<ScopedQueue<'bound>> {
> +//! // SAFETY: Caller guarantees that the returned queue is not leaked.
> +//! unsafe { ScopedQueue::new(c"scoped_queue") }
> +//! }
> +//!
> +//! fn queue_outlives_borrowed_data() -> Result {
> +//! let queue;
> +//!
> +//! {
> +//! let data = ();
> +//! // SAFETY: Queue is not leaked.
> +//! queue = unsafe { new_queue(&data)? };
> +//! }
> +//! // Here the `compile_fail` is fulfilled as `queue` would be dropped
> +//! // after `data`.
> +//! Ok(())
> +//! }
> +//! ```
> +//!
> +//! TODO: Remove `ignore` once KUnit supports `compile_fail` on doc-tests.
> +//! ```compile_fail,ignore
> +//! use kernel::prelude::*;
> +//! use kernel::sync::Arc;
> +//! use kernel::workqueue::{
> +//! impl_has_work,
> +//! new_work,
> +//! ScopedQueue,
> +//! Work,
> +//! WorkItem,
> +//! };
> +//!
> +//! #[pin_data]
> +//! struct BorrowedWork<'bound> {
> +//! data: &'bound (),
> +//! #[pin]
> +//! work: Work<BorrowedWork<'bound>>,
> +//! }
> +//!
> +//! impl_has_work! {
> +//! impl{'bound} HasWork<BorrowedWork<'bound>> for BorrowedWork<'bound> { self.work }
> +//! }
> +//!
> +//! impl<'bound> WorkItem for BorrowedWork<'bound> {
> +//! type Pointer = Arc<Self>;
> +//!
> +//! fn run(_this: Arc<Self>) {}
> +//! }
> +//!
> +//! impl<'bound> BorrowedWork<'bound> {
> +//! fn new(data: &'bound ()) -> Result<Arc<Self>> {
> +//! Arc::pin_init(
> +//! pin_init!(Self {
> +//! data,
> +//! work <- new_work!("BorrowedWork::work"),
> +//! }),
> +//! GFP_KERNEL,
> +//! )
> +//! }
> +//! }
> +//!
> +//! struct Handle<'bound> {
> +//! work: Arc<BorrowedWork<'bound>>,
> +//! wq: ScopedQueue<'bound>,
> +//! }
> +//!
> +//! impl<'bound> Handle<'bound> {
> +//! /// # Safety
> +//! ///
> +//! /// Returned handle must not be leaked.
> +//! unsafe fn new(data: &'bound ()) -> Result<Self> {
> +//! Ok(Self {
> +//! work: BorrowedWork::new(data)?,
> +//! // SAFETY: Caller guarantees that the returned handle is not leaked.
> +//! wq: unsafe { ScopedQueue::new(c"handle_wq")? },
> +//! })
> +//! }
> +//! }
> +//!
> +//! fn handle_outlives_borrowed_data() -> Result {
> +//! let handle;
> +//!
> +//! {
> +//! let data = ();
> +//! // SAFETY: Handle is not leaked.
> +//! handle = unsafe { Handle::new(&data)? };
> +//!
> +//! let _ = handle.wq.enqueue(handle.work.clone());
> +//! }
> +//! // Here the `compile_fail` is fulfilled as `handle` would be dropped
> +//! // after `data`.
> +//! Ok(())
> +//! }
> +//! ```
> +
> +use super::{
> + OwnedQueue,
> + Queue,
> + RawWorkItem, //
> +};
> +
> +use crate::{
> + bindings,
> + ffi,
> + prelude::*, //
> +};
> +
> +use core::marker::PhantomData;
> +
> +/// An owned workqueue that can enqueue work items borrowing from `'scope`.
> +///
> +/// A `ScopedQueue` must not outlive data borrowed by its work items.
> +pub struct ScopedQueue<'scope> {
> + inner: OwnedQueue,
> + _scope: PhantomData<&'scope mut &'scope ()>,
> +}
A Queue is the same as a ScopedQueue<'static>, so we don't necessarily
need a new type if we add a lifetime to Queue and add two constructors:
fn new() -> Queue<'static>;
unsafe fn new_scoped() -> Queue<'a>;
Alice
next prev parent reply other threads:[~2026-09-02 14:40 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-07 16:52 [PATCH v2 0/6] workqueue: OwnedQueue, ScopedQueue and ScopedWork Danilo Krummrich
2026-08-07 16:52 ` [PATCH v2 1/6] rust: workqueue: replace deprecated system_wq with system_{percpu,dfl}_wq Danilo Krummrich
2026-08-27 17:12 ` Daniel Almeida
2026-08-07 16:52 ` [PATCH v2 2/6] rust: workqueue: restrict delayed work to global wqs Danilo Krummrich
2026-08-27 17:13 ` Daniel Almeida
2026-08-07 16:52 ` [PATCH v2 3/6] rust: workqueue: create workqueue subdirectory Danilo Krummrich
2026-08-27 17:16 ` Daniel Almeida
2026-08-07 16:52 ` [PATCH v2 4/6] rust: workqueue: add creation of workqueues Danilo Krummrich
2026-08-07 22:39 ` Danilo Krummrich
2026-08-27 19:25 ` Daniel Almeida
2026-08-27 19:25 ` Daniel Almeida
2026-08-07 16:52 ` [PATCH v2 5/6] rust: workqueue: add ScopedQueue for lifetime bound items Danilo Krummrich
2026-08-27 21:39 ` Daniel Almeida
2026-09-12 7:58 ` Onur Özkan
2026-09-02 14:40 ` Alice Ryhl [this message]
2026-09-12 7:54 ` Onur Özkan
2026-08-07 16:52 ` [PATCH v2 6/6] rust: workqueue: add ScopedWork for non-'static work items Danilo Krummrich
2026-08-07 18:35 ` Danilo Krummrich
2026-08-27 23:07 ` Daniel Almeida
2026-09-02 14:49 ` Alice Ryhl
2026-09-02 14:52 ` Gary Guo
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=apg1c4GdVrhYDK1P@google.com \
--to=aliceryhl@google.com \
--cc=a.hindborg@kernel.org \
--cc=acourbot@nvidia.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun@kernel.org \
--cc=dakr@kernel.org \
--cc=daniel.almeida@collabora.com \
--cc=driver-core@lists.linux.dev \
--cc=gary@garyguo.net \
--cc=jhubbard@nvidia.com \
--cc=jiangshanlai@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=tamird@kernel.org \
--cc=tj@kernel.org \
--cc=tmgross@umich.edu \
--cc=work@onurozkan.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.