The C code defines 2 new workqueues: system_percpu_wq and system_dfl_wq,
respectively the futures replacement for system_wq and system_unbound_wq.
This change introduce system_percpu(), that use the new system_percpu_wq.
system_wq will be replaced in a future release cycle and should
not be used.
Suggested-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Marco Crivellari <marco.crivellari@suse.com>
---
rust/kernel/workqueue.rs | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs
index 300cc2bfe012..05f213444b91 100644
--- a/rust/kernel/workqueue.rs
+++ b/rust/kernel/workqueue.rs
@@ -940,11 +940,26 @@ unsafe impl<T, const ID: u64> RawDelayedWorkItem<ID> for Pin<KBox<T>>
/// users which expect relatively short queue flush time.
///
/// Callers shouldn't queue work items which can run for too long.
+///
+/// Note: `system_wq` will be removed in a future release cycle. Use [`system_percpu_wq`] instead.
pub fn system() -> &'static Queue {
// SAFETY: `system_wq` is a C global, always available.
unsafe { Queue::from_raw(bindings::system_wq) }
}
+/// Returns the system work queue (`system_percpu_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.
+///
+/// Note: `system_percpu_wq` will replace ['system_wq`] in a future relase cycle.
+pub fn system_percpu() -> &'static Queue {
+ // SAFETY: `system_percpu_wq` is a C global, always available.
+ unsafe { Queue::from_raw(bindings::system_percpu_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
--
2.51.0
On Wed, Oct 8, 2025 at 5:16 PM Marco Crivellari
<marco.crivellari@suse.com> wrote:
>
> +/// Note: `system_percpu_wq` will replace ['system_wq`] in a future relase cycle.
Please check your patch with `make ... rustdoc` (which would complain
here about an unescaped backtick) and others like `make ... CLIPPY=1`:
https://rust-for-linux.com/contributing#submit-checklist-addendum
Also, in general, please use intra-doc links wherever possible.
Thanks!
Cheers,
Miguel
On Wed, Oct 08, 2025 at 05:15:54PM +0200, Marco Crivellari wrote:
> The C code defines 2 new workqueues: system_percpu_wq and system_dfl_wq,
> respectively the futures replacement for system_wq and system_unbound_wq.
>
> This change introduce system_percpu(), that use the new system_percpu_wq.
>
> system_wq will be replaced in a future release cycle and should
> not be used.
>
> Suggested-by: Tejun Heo <tj@kernel.org>
> Signed-off-by: Marco Crivellari <marco.crivellari@suse.com>
If we were to expose the system_percpu_wq to Rust, then we should also
add queue_work_on() API to Rust, otherwise it's kinda pointless IMO.
PS. We can use the CpuId abstraction:
http://rust.docs.kernel.org/kernel/cpu/struct.CpuId.html
and have an API like:
ipml Queue {
pub fn queue_on(&self, cpu: CpuId, w: W) -> W::EqueueOutput
}
or maybe a different new type `PerCpuQueue`?
Regards,
Boqun
> ---
> rust/kernel/workqueue.rs | 15 +++++++++++++++
> 1 file changed, 15 insertions(+)
>
> diff --git a/rust/kernel/workqueue.rs b/rust/kernel/workqueue.rs
> index 300cc2bfe012..05f213444b91 100644
> --- a/rust/kernel/workqueue.rs
> +++ b/rust/kernel/workqueue.rs
> @@ -940,11 +940,26 @@ unsafe impl<T, const ID: u64> RawDelayedWorkItem<ID> for Pin<KBox<T>>
> /// users which expect relatively short queue flush time.
> ///
> /// Callers shouldn't queue work items which can run for too long.
> +///
> +/// Note: `system_wq` will be removed in a future release cycle. Use [`system_percpu_wq`] instead.
> pub fn system() -> &'static Queue {
> // SAFETY: `system_wq` is a C global, always available.
> unsafe { Queue::from_raw(bindings::system_wq) }
> }
>
> +/// Returns the system work queue (`system_percpu_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.
> +///
> +/// Note: `system_percpu_wq` will replace ['system_wq`] in a future relase cycle.
> +pub fn system_percpu() -> &'static Queue {
> + // SAFETY: `system_percpu_wq` is a C global, always available.
> + unsafe { Queue::from_raw(bindings::system_percpu_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
> --
> 2.51.0
>
On Wed, Oct 08, 2025 at 08:56:04AM -0700, Boqun Feng wrote:
> On Wed, Oct 08, 2025 at 05:15:54PM +0200, Marco Crivellari wrote:
> > The C code defines 2 new workqueues: system_percpu_wq and system_dfl_wq,
> > respectively the futures replacement for system_wq and system_unbound_wq.
> >
> > This change introduce system_percpu(), that use the new system_percpu_wq.
> >
> > system_wq will be replaced in a future release cycle and should
> > not be used.
> >
> > Suggested-by: Tejun Heo <tj@kernel.org>
> > Signed-off-by: Marco Crivellari <marco.crivellari@suse.com>
>
> If we were to expose the system_percpu_wq to Rust, then we should also
> add queue_work_on() API to Rust, otherwise it's kinda pointless IMO.
>
> PS. We can use the CpuId abstraction:
>
> http://rust.docs.kernel.org/kernel/cpu/struct.CpuId.html
>
> and have an API like:
>
> ipml Queue {
> pub fn queue_on(&self, cpu: CpuId, w: W) -> W::EqueueOutput
> }
>
> or maybe a different new type `PerCpuQueue`?
>
> Regards,
> Boqun
How is it ... can we cleanly separate queues into those where you must
specify the cpuid, and those where you shouldn't?
Alice
On Thu, Oct 9, 2025 at 1:17 PM Alice Ryhl <aliceryhl@google.com> wrote:
> [...]
> > If we were to expose the system_percpu_wq to Rust, then we should also
> > add queue_work_on() API to Rust, otherwise it's kinda pointless IMO.
> >
> > PS. We can use the CpuId abstraction:
> >
> > http://rust.docs.kernel.org/kernel/cpu/struct.CpuId.html
> >
> > and have an API like:
> >
> > ipml Queue {
> > pub fn queue_on(&self, cpu: CpuId, w: W) -> W::EqueueOutput
> > }
> >
> > or maybe a different new type `PerCpuQueue`?
> >
> > Regards,
> > Boqun
>
> How is it ... can we cleanly separate queues into those where you must
> specify the cpuid, and those where you shouldn't?
Hi,
Sorry to come back to you so late. I still had many other subsystems patches,
now there are way less, many of them are accepted.
Can I have some guidance about this? I am new to Rust.
What's the best way in order to expose the workqueues?
If I understand correctly, the Idea is extends the functionalities of:
https://rust.docs.kernel.org/kernel/workqueue/struct.Queue.html
adding the "queue_on" function.
Creating a new type like "PerCpuQueue" I guess it means... wraps always
the workqueue_struct structure and defines what's appropriate, like the
new per-cpu workqueue.
Many thanks in advance!
--
Marco Crivellari
L3 Support Engineer
On Fri, Jan 09, 2026 at 05:32:23PM +0100, Marco Crivellari wrote:
> On Thu, Oct 9, 2025 at 1:17 PM Alice Ryhl <aliceryhl@google.com> wrote:
> > [...]
> > > If we were to expose the system_percpu_wq to Rust, then we should also
> > > add queue_work_on() API to Rust, otherwise it's kinda pointless IMO.
> > >
> > > PS. We can use the CpuId abstraction:
> > >
> > > http://rust.docs.kernel.org/kernel/cpu/struct.CpuId.html
> > >
> > > and have an API like:
> > >
> > > ipml Queue {
> > > pub fn queue_on(&self, cpu: CpuId, w: W) -> W::EqueueOutput
> > > }
> > >
> > > or maybe a different new type `PerCpuQueue`?
> > >
> > > Regards,
> > > Boqun
> >
> > How is it ... can we cleanly separate queues into those where you must
> > specify the cpuid, and those where you shouldn't?
>
> Hi,
>
> Sorry to come back to you so late. I still had many other subsystems patches,
> now there are way less, many of them are accepted.
>
> Can I have some guidance about this? I am new to Rust.
> What's the best way in order to expose the workqueues?
>
> If I understand correctly, the Idea is extends the functionalities of:
>
> https://rust.docs.kernel.org/kernel/workqueue/struct.Queue.html
>
> adding the "queue_on" function.
>
> Creating a new type like "PerCpuQueue" I guess it means... wraps always
> the workqueue_struct structure and defines what's appropriate, like the
> new per-cpu workqueue.
>
> Many thanks in advance!
Yes, we can provide a new `struct PerCpuQueue` with same contents as
`Queue`, where the `enqueue` and `enqueue_delayed` methods take a cpu id
parameter.
Then, all of the functions for obtaining queues at the bottom of the
file are updated to return &PerCpuQueue instead of &Queue when a cpu id
sone option here is tohould be provided to spawn on that queue.
This way, you write:
workqueue::system().enqueue(my_work_item)
or you write:
workqueue::system_percpu().enqueue(my_work_item, cpu_id)
This way you must supply cpu id with system_percpu_wq() but not with
system().
--
Another approach is to add a new `enqueue_cpu` to the existing `Queue`
struct. In that case, all of these four combinations become legal:
workqueue::system().enqueue(my_work_item)
workqueue::system().enqueue_cpu(my_work_item, cpu_id)
workqueue::system_percpu().enqueue(my_work_item)
workqueue::system_percpu().enqueue_cpu(my_work_item, cpu_id)
which approach is best depends on whether you want all four combinations
to be legal or not.
Alice
On Mon, Jan 12, 2026 at 10:05 AM Alice Ryhl <aliceryhl@google.com> wrote: > [...] > Yes, we can provide a new `struct PerCpuQueue` with same contents as > `Queue`, where the `enqueue` and `enqueue_delayed` methods take a cpu id > parameter. > > Then, all of the functions for obtaining queues at the bottom of the > file are updated to return &PerCpuQueue instead of &Queue when a cpu id > sone option here is tohould be provided to spawn on that queue. > > This way, you write: > > workqueue::system().enqueue(my_work_item) > > or you write: > > workqueue::system_percpu().enqueue(my_work_item, cpu_id) > > This way you must supply cpu id with system_percpu_wq() but not with > system(). > > -- > > Another approach is to add a new `enqueue_cpu` to the existing `Queue` > struct. In that case, all of these four combinations become legal: > > workqueue::system().enqueue(my_work_item) > workqueue::system().enqueue_cpu(my_work_item, cpu_id) > workqueue::system_percpu().enqueue(my_work_item) > workqueue::system_percpu().enqueue_cpu(my_work_item, cpu_id) > > which approach is best depends on whether you want all four combinations > to be legal or not. > > Alice Thank you Alice. Personally I'm more oriented to the 1st version you mentioned. Seems a cleaner interface for the user. Should I start with a new v1 about this, or better increment the actual version? Thank you! -- Marco Crivellari L3 Support Engineer
On Mon, Jan 12, 2026 at 5:10 PM Marco Crivellari <marco.crivellari@suse.com> wrote: > > On Mon, Jan 12, 2026 at 10:05 AM Alice Ryhl <aliceryhl@google.com> wrote: > > [...] > > Yes, we can provide a new `struct PerCpuQueue` with same contents as > > `Queue`, where the `enqueue` and `enqueue_delayed` methods take a cpu id > > parameter. > > > > Then, all of the functions for obtaining queues at the bottom of the > > file are updated to return &PerCpuQueue instead of &Queue when a cpu id > > sone option here is tohould be provided to spawn on that queue. > > > > This way, you write: > > > > workqueue::system().enqueue(my_work_item) > > > > or you write: > > > > workqueue::system_percpu().enqueue(my_work_item, cpu_id) > > > > This way you must supply cpu id with system_percpu_wq() but not with > > system(). > > > > -- > > > > Another approach is to add a new `enqueue_cpu` to the existing `Queue` > > struct. In that case, all of these four combinations become legal: > > > > workqueue::system().enqueue(my_work_item) > > workqueue::system().enqueue_cpu(my_work_item, cpu_id) > > workqueue::system_percpu().enqueue(my_work_item) > > workqueue::system_percpu().enqueue_cpu(my_work_item, cpu_id) > > > > which approach is best depends on whether you want all four combinations > > to be legal or not. > > > > Alice > > Thank you Alice. > > Personally I'm more oriented to the 1st version you mentioned. Seems a > cleaner interface for the user. It's fine with me, thanks! Tejun, any concerns? > Should I start with a new v1 about this, or better increment the actual version? As long as you keep the history in the cover letter, either is fine. Alice
On Mon, Jan 12, 2026 at 5:23 PM Alice Ryhl <aliceryhl@google.com> wrote:
> [...]
> > > Another approach is to add a new `enqueue_cpu` to the existing `Queue`
> > > struct. In that case, all of these four combinations become legal:
> > >
> > > workqueue::system().enqueue(my_work_item)
> > > workqueue::system().enqueue_cpu(my_work_item, cpu_id)
> > > workqueue::system_percpu().enqueue(my_work_item)
> > > workqueue::system_percpu().enqueue_cpu(my_work_item, cpu_id)
> > >
> > > which approach is best depends on whether you want all four combinations
> > > to be legal or not.
Hi Alice,
I was starting yesterday evening when I realized the 2nd approach
would be a better
fit for the work we should do now. I also think in this series we
should already convert
the system() users to system_percpu() (same goes for system_unbound()
=> system_dfl()).
Using the 2nd approach would just make the migration smooth because we can just
rename all the users of those functions.
I think it's better to migrate / convert to the new functions because
they are using the new
introduced workqueues. Sooner or later in the C code we are going to
have warnings
for users who are stuck on the older workqueues, so it's better to
also migrate the Rust code
on the newer version.
In short: I would like to introduce only enqueue_cpu() so that it's
just easier to do a 1:1 conversion
without changing the behavior and in the meantime introduce these renames:
system_unbound() => system_dfl()
system() => system_percpu()
What do you think?
Thanks!
--
Marco Crivellari
L3 Support Engineer
On Tue, Feb 03, 2026 at 09:41:07AM +0100, Marco Crivellari wrote: > On Mon, Jan 12, 2026 at 5:23 PM Alice Ryhl <aliceryhl@google.com> wrote: > > [...] > > > > Another approach is to add a new `enqueue_cpu` to the existing `Queue` > > > > struct. In that case, all of these four combinations become legal: > > > > > > > > workqueue::system().enqueue(my_work_item) > > > > workqueue::system().enqueue_cpu(my_work_item, cpu_id) > > > > workqueue::system_percpu().enqueue(my_work_item) > > > > workqueue::system_percpu().enqueue_cpu(my_work_item, cpu_id) > > > > > > > > which approach is best depends on whether you want all four combinations > > > > to be legal or not. > > Hi Alice, > > I was starting yesterday evening when I realized the 2nd approach > would be a better > fit for the work we should do now. I also think in this series we > should already convert > the system() users to system_percpu() (same goes for system_unbound() > => system_dfl()). > > Using the 2nd approach would just make the migration smooth because we can just > rename all the users of those functions. > > I think it's better to migrate / convert to the new functions because > they are using the new > introduced workqueues. Sooner or later in the C code we are going to > have warnings > for users who are stuck on the older workqueues, so it's better to > also migrate the Rust code > on the newer version. > > In short: I would like to introduce only enqueue_cpu() so that it's > just easier to do a 1:1 conversion > without changing the behavior and in the meantime introduce these renames: > > system_unbound() => system_dfl() > system() => system_percpu() > > > What do you think? I'm ok with the simpler approach. Alice
On Mon, Jan 12, 2026 at 5:23 PM Alice Ryhl <aliceryhl@google.com> wrote: > [...] > > > Should I start with a new v1 about this, or better increment the actual version? > > As long as you keep the history in the cover letter, either is fine. Many thanks, I will do as you suggested! -- Marco Crivellari L3 Support Engineer
© 2016 - 2026 Red Hat, Inc.