* [PATCH] checkpatch: Check WQ_PERCPU or WQ_UNBOUND presence in alloc_workqueue() users
@ 2026-06-03 14:09 Marco Crivellari
2026-06-04 5:08 ` Joe Perches
0 siblings, 1 reply; 5+ messages in thread
From: Marco Crivellari @ 2026-06-03 14:09 UTC (permalink / raw)
To: linux-kernel
Cc: Andy Whitcroft, Joe Perches, Dwaipayan Ray, Lukas Bulwahn,
Tejun Heo, Frederic Weisbecker, Marco Crivellari, Michal Hocko,
Breno Leitao
The workqueue API introduced a new flag, WQ_PERCPU, that has to be used when
WQ_UNBOUND is not present. One of these flags must be present, but not
both of them.
To limit usage mistakes, emit an ERROR if one of the below condition is met:
- alloc_workqueue() is called without WQ_PERCPU nor WQ_UNBOUND
- alloc_workqueue() is called with both WQ_PERCPU and WQ_UNBOUND
Signed-off-by: Marco Crivellari <marco.crivellari@suse.com>
---
scripts/checkpatch.pl | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 0492d6afc9a1..2706aba6dac0 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -7804,6 +7804,22 @@ sub process {
ERROR("UNINITIALIZED_PTR_WITH_FREE",
"pointer '$1' with __free attribute should be initialized\n" . $herecurr);
}
+
+# check alloc_workqueue() flags parameter (2nd argument) for WQ_PERCPU, WQ_UNBOUND presence
+ if ($line =~ /\balloc_workqueue\s*\(/ &&
+ $stat =~ /\balloc_workqueue\s*\(\s*[^,]+\s*,\s*([^,]+)/s) {
+ my $flags = $1;
+ my $has_percpu = $flags =~ /\bWQ_PERCPU\b/;
+ my $has_unbound = $flags =~ /\bWQ_UNBOUND\b/;
+
+ if ($has_percpu && $has_unbound) {
+ ERROR("ALLOC_WORKQUEUE_FLAGS",
+ "alloc_workqueue() second parameter should not contain both WQ_PERCPU and WQ_UNBOUND\n" . $herecurr);
+ } elsif (!$has_percpu && !$has_unbound) {
+ ERROR("ALLOC_WORKQUEUE_FLAGS",
+ "alloc_workqueue() second parameter should specify either WQ_PERCPU or WQ_UNBOUND\n" . $herecurr);
+ }
+ }
}
# If we have no input at all, then there is nothing to report on
--
2.54.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] checkpatch: Check WQ_PERCPU or WQ_UNBOUND presence in alloc_workqueue() users
2026-06-03 14:09 [PATCH] checkpatch: Check WQ_PERCPU or WQ_UNBOUND presence in alloc_workqueue() users Marco Crivellari
@ 2026-06-04 5:08 ` Joe Perches
2026-06-04 9:31 ` Marco Crivellari
0 siblings, 1 reply; 5+ messages in thread
From: Joe Perches @ 2026-06-04 5:08 UTC (permalink / raw)
To: Marco Crivellari, linux-kernel
Cc: Andy Whitcroft, Dwaipayan Ray, Lukas Bulwahn, Tejun Heo,
Frederic Weisbecker, Michal Hocko, Breno Leitao
On Wed, 2026-06-03 at 16:09 +0200, Marco Crivellari wrote:
> The workqueue API introduced a new flag, WQ_PERCPU, that has to be used when
> WQ_UNBOUND is not present. One of these flags must be present, but not
> both of them.
>
> To limit usage mistakes, emit an ERROR if one of the below condition is met:
> - alloc_workqueue() is called without WQ_PERCPU nor WQ_UNBOUND
> - alloc_workqueue() is called with both WQ_PERCPU and WQ_UNBOUND
[]
> diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
[]
> @@ -7804,6 +7804,22 @@ sub process {
> ERROR("UNINITIALIZED_PTR_WITH_FREE",
> "pointer '$1' with __free attribute should be initialized\n" . $herecurr);
> }
> +
> +# check alloc_workqueue() flags parameter (2nd argument) for WQ_PERCPU, WQ_UNBOUND presence
> + if ($line =~ /\balloc_workqueue\s*\(/ &&
> + $stat =~ /\balloc_workqueue\s*\(\s*[^,]+\s*,\s*([^,]+)/s) {
> + my $flags = $1;
> + my $has_percpu = $flags =~ /\bWQ_PERCPU\b/;
> + my $has_unbound = $flags =~ /\bWQ_UNBOUND\b/;
> +
> + if ($has_percpu && $has_unbound) {
> + ERROR("ALLOC_WORKQUEUE_FLAGS",
> + "alloc_workqueue() second parameter should not contain both WQ_PERCPU and WQ_UNBOUND\n" . $herecurr);
> + } elsif (!$has_percpu && !$has_unbound) {
> + ERROR("ALLOC_WORKQUEUE_FLAGS",
> + "alloc_workqueue() second parameter should specify either WQ_PERCPU or WQ_UNBOUND\n" . $herecurr);
> + }
> + }
> }
OK but a couple comments:
Add devm_alloc_workqueue as well?
Avoid using $line here as $stat isn't populated on multi-line uses
of alloc_workqueue. Just test $stat
Using the patch below gives a few matches treewide with a few
false positives as the flags are stored in a variable in
drivers/nvme/host/... and fs/btrfs/...
-----------------
block/blk-zoned.c
-----------------
ERROR: alloc_workqueue() must specify either WQ_PERCPU or WQ_UNBOUND
#1926: FILE: block/blk-zoned.c:1926:
+ disk->zone_wplugs_wq =
+ alloc_workqueue("%s_zwplugs", WQ_MEM_RECLAIM | WQ_HIGHPRI,
+ pool_size, disk->disk_name);
-----------------------------------------
drivers/gpu/drm/bridge/analogix/anx7625.c
-----------------------------------------
ERROR: alloc_workqueue() must specify either WQ_PERCPU or WQ_UNBOUND
#2851: FILE: drivers/gpu/drm/bridge/analogix/anx7625.c:2851:
+ platform->workqueue = alloc_workqueue("anx7625_work",
+ WQ_FREEZABLE | WQ_MEM_RECLAIM, 1);
-------------------------------------
drivers/gpu/drm/nouveau/nouveau_drm.c
-------------------------------------
ERROR: alloc_workqueue() must specify either WQ_PERCPU or WQ_UNBOUND
#635: FILE: drivers/gpu/drm/nouveau/nouveau_drm.c:635:
+ drm->sched_wq = alloc_workqueue("nouveau_sched_wq_shared", 0,
+ WQ_MAX_ACTIVE);
---------------------------------------
drivers/gpu/drm/nouveau/nouveau_sched.c
---------------------------------------
ERROR: alloc_workqueue() must specify either WQ_PERCPU or WQ_UNBOUND
#417: FILE: drivers/gpu/drm/nouveau/nouveau_sched.c:417:
+ wq = alloc_workqueue("nouveau_sched_wq_%d", 0, WQ_MAX_ACTIVE,
+ current->pid);
------------------------------------------
drivers/media/pci/ddbridge/ddbridge-core.c
------------------------------------------
ERROR: alloc_workqueue() must specify either WQ_PERCPU or WQ_UNBOUND
#3433: FILE: drivers/media/pci/ddbridge/ddbridge-core.c:3433:
+ ddb_wq = alloc_workqueue("ddbridge", 0, 0);
-------------------------------------
drivers/net/wireless/ath/ath6kl/usb.c
-------------------------------------
ERROR: alloc_workqueue() must specify either WQ_PERCPU or WQ_UNBOUND
#639: FILE: drivers/net/wireless/ath/ath6kl/usb.c:639:
+ ar_usb->wq = alloc_workqueue("ath6kl_wq", 0, 0);
------------------------
drivers/nvme/host/core.c
------------------------
ERROR: alloc_workqueue() must specify either WQ_PERCPU or WQ_UNBOUND
#5410: FILE: drivers/nvme/host/core.c:5410:
+ nvme_wq = alloc_workqueue("nvme-wq", wq_flags, 0);
ERROR: alloc_workqueue() must specify either WQ_PERCPU or WQ_UNBOUND
#5414: FILE: drivers/nvme/host/core.c:5414:
+ nvme_reset_wq = alloc_workqueue("nvme-reset-wq", wq_flags, 0);
ERROR: alloc_workqueue() must specify either WQ_PERCPU or WQ_UNBOUND
#5418: FILE: drivers/nvme/host/core.c:5418:
+ nvme_delete_wq = alloc_workqueue("nvme-delete-wq", wq_flags, 0);
---------------------
drivers/rapidio/rio.c
---------------------
ERROR: alloc_workqueue() must specify either WQ_PERCPU or WQ_UNBOUND
#1997: FILE: drivers/rapidio/rio.c:1997:
+ rio_wq = alloc_workqueue("riodisc", 0, 0);
------------------------------
drivers/thermal/thermal_core.c
------------------------------
ERROR: alloc_workqueue() must specify either WQ_PERCPU or WQ_UNBOUND
#1892: FILE: drivers/thermal/thermal_core.c:1892:
+ thermal_wq = alloc_workqueue("thermal_events", WQ_POWER_EFFICIENT, 0);
-------------------------
drivers/virt/acrn/irqfd.c
-------------------------
ERROR: alloc_workqueue() must specify either WQ_PERCPU or WQ_UNBOUND
#209: FILE: drivers/virt/acrn/irqfd.c:209:
+ vm->irqfd_wq = alloc_workqueue("acrn_irqfd-%u", 0, 0, vm->vmid);
------------------
fs/btrfs/disk-io.c
------------------
ERROR: alloc_workqueue() must specify either WQ_PERCPU or WQ_UNBOUND
#1950: FILE: fs/btrfs/disk-io.c:1950:
+ fs_info->endio_workers =
+ alloc_workqueue("btrfs-endio", flags, max_active);
ERROR: alloc_workqueue() must specify either WQ_PERCPU or WQ_UNBOUND
#1952: FILE: fs/btrfs/disk-io.c:1952:
+ fs_info->endio_meta_workers =
+ alloc_workqueue("btrfs-endio-meta", flags, max_active);
ERROR: alloc_workqueue() must specify either WQ_PERCPU or WQ_UNBOUND
#1954: FILE: fs/btrfs/disk-io.c:1954:
+ fs_info->rmw_workers = alloc_workqueue("btrfs-rmw", flags, max_active);
----------------
fs/btrfs/scrub.c
----------------
ERROR: alloc_workqueue() must specify either WQ_PERCPU or WQ_UNBOUND
#3050: FILE: fs/btrfs/scrub.c:3050:
+ scrub_workers = alloc_workqueue("btrfs-scrub", flags, max_active);
---------------
fs/ntfs/super.c
---------------
ERROR: alloc_workqueue() must specify either WQ_PERCPU or WQ_UNBOUND
#2652: FILE: fs/ntfs/super.c:2652:
+ ntfs_wq = alloc_workqueue("ntfs-bg-io", 0, 0);
---
scripts/checkpatch.pl | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 0492d6afc9a1..aed83ce4b552 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -7804,6 +7804,31 @@ sub process {
ERROR("UNINITIALIZED_PTR_WITH_FREE",
"pointer '$1' with __free attribute should be initialized\n" . $herecurr);
}
+
+# check alloc_workqueue() and devm_alloc_workqueue parameters for
+# WQ_PERCPU and WQ_UNBOUND uses
+ if (defined($stat) &&
+ $stat =~ /^[ \+]\s*(?:$Lval\s*=\s*)?((?:devm_)?alloc_workqueue)\s*($balanced_parens)/) {
+ my $func = $1;
+ my $args = $2;
+ my $has_percpu = $args =~ /\bWQ_PERCPU\b/;
+ my $has_unbound = $args =~ /\bWQ_UNBOUND\b/;
+ my $error_msg;
+
+ if ($has_percpu && $has_unbound) {
+ $error_msg = "$func() should not contain both WQ_PERCPU and WQ_UNBOUND\n";
+ } elsif (!$has_percpu && !$has_unbound) {
+ $error_msg = "$func() must specify either WQ_PERCPU or WQ_UNBOUND\n";
+ }
+
+ if (defined($error_msg)) {
+ my $stmt_cnt = statement_rawlines($stat);
+ my $herectx = get_stat_here($linenr, $stmt_cnt, $here);
+ ERROR("ALLOC_WORKQUEUE_FLAGS",
+ $error_msg . $herectx);
+ }
+
+ }
}
# If we have no input at all, then there is nothing to report on
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] checkpatch: Check WQ_PERCPU or WQ_UNBOUND presence in alloc_workqueue() users
2026-06-04 5:08 ` Joe Perches
@ 2026-06-04 9:31 ` Marco Crivellari
2026-06-04 14:09 ` Joe Perches
0 siblings, 1 reply; 5+ messages in thread
From: Marco Crivellari @ 2026-06-04 9:31 UTC (permalink / raw)
To: Joe Perches
Cc: linux-kernel, Andy Whitcroft, Dwaipayan Ray, Lukas Bulwahn,
Tejun Heo, Frederic Weisbecker, Michal Hocko, Breno Leitao
Hi,
On Thu, Jun 4, 2026 at 7:08 AM Joe Perches <joe@perches.com> wrote:
> [...]
> OK but a couple comments:
>
> Add devm_alloc_workqueue as well?
No I don't think it would be useful / needed. There is only 1 user of
that macro, devm_alloc_ordered_workqueue(), which already specifies
the WQ_UNBOUND flag and it is part of the workqueue code.
Also, we're adding this in checkpatch, because it reflects what is
going to be present in the workqueue code:
https://lore.kernel.org/all/20260529130640.220328-3-marco.crivellari@suse.com/
> Avoid using $line here as $stat isn't populated on multi-line uses
> of alloc_workqueue. Just test $stat
Aha, noted. I will remove that test.
> Using the patch below gives a few matches treewide with a few
> false positives as the flags are stored in a variable in
> drivers/nvme/host/... and fs/btrfs/...
Yeah, those false positives were expected. I thought about adding a
message about that, indeed.
> -----------------
> block/blk-zoned.c
> -----------------
> ERROR: alloc_workqueue() must specify either WQ_PERCPU or WQ_UNBOUND
> #1926: FILE: block/blk-zoned.c:1926:
> + disk->zone_wplugs_wq =
> + alloc_workqueue("%s_zwplugs", WQ_MEM_RECLAIM | WQ_HIGHPRI,
> + pool_size, disk->disk_name);
Interestingly, my Coccinelle script didn't match this.
> scripts/checkpatch.pl | 25 +++++++++++++++++++++++++
> 1 file changed, 25 insertions(+)
>
> diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
> index 0492d6afc9a1..aed83ce4b552 100755
> --- a/scripts/checkpatch.pl
> +++ b/scripts/checkpatch.pl
> @@ -7804,6 +7804,31 @@ sub process {
> ERROR("UNINITIALIZED_PTR_WITH_FREE",
> "pointer '$1' with __free attribute should be initialized\n" . $herecurr);
> }
> +
> +# check alloc_workqueue() and devm_alloc_workqueue parameters for
> +# WQ_PERCPU and WQ_UNBOUND uses
> + if (defined($stat) &&
> + $stat =~ /^[ \+]\s*(?:$Lval\s*=\s*)?((?:devm_)?alloc_workqueue)\s*($balanced_parens)/) {
> + my $func = $1;
> + my $args = $2;
> + my $has_percpu = $args =~ /\bWQ_PERCPU\b/;
> + my $has_unbound = $args =~ /\bWQ_UNBOUND\b/;
> + my $error_msg;
> +
> + if ($has_percpu && $has_unbound) {
> + $error_msg = "$func() should not contain both WQ_PERCPU and WQ_UNBOUND\n";
> + } elsif (!$has_percpu && !$has_unbound) {
> + $error_msg = "$func() must specify either WQ_PERCPU or WQ_UNBOUND\n";
> + }
> +
> + if (defined($error_msg)) {
> + my $stmt_cnt = statement_rawlines($stat);
> + my $herectx = get_stat_here($linenr, $stmt_cnt, $here);
> + ERROR("ALLOC_WORKQUEUE_FLAGS",
> + $error_msg . $herectx);
> + }
> +
> + }
> }
>
> # If we have no input at all, then there is nothing to report on
I will integrate my code with this!
Thanks!
--
Marco Crivellari
SUSE Labs
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] checkpatch: Check WQ_PERCPU or WQ_UNBOUND presence in alloc_workqueue() users
2026-06-04 9:31 ` Marco Crivellari
@ 2026-06-04 14:09 ` Joe Perches
2026-06-04 14:18 ` Marco Crivellari
0 siblings, 1 reply; 5+ messages in thread
From: Joe Perches @ 2026-06-04 14:09 UTC (permalink / raw)
To: Marco Crivellari
Cc: linux-kernel, Andy Whitcroft, Dwaipayan Ray, Lukas Bulwahn,
Tejun Heo, Frederic Weisbecker, Michal Hocko, Breno Leitao
On Thu, 2026-06-04 at 11:31 +0200, Marco Crivellari wrote:
> On Thu, Jun 4, 2026 at 7:08 AM Joe Perches <[joe@perches.com](mailto:joe@perches.com)> wrote:
> [...]
> > OK but a couple comments:
> >
> > Add devm_alloc_workqueue as well?
>
> No I don't think it would be useful / needed. There is only 1 user of
> that macro, devm_alloc_ordered_workqueue(), which already specifies
> the WQ_UNBOUND flag and it is part of the workqueue code.
drivers/power/supply/ipaq_micro_battery.c: mb->wq = devm_alloc_workqueue(&pdev->dev, "ipaq-battery-wq",
Maybe there will be more.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] checkpatch: Check WQ_PERCPU or WQ_UNBOUND presence in alloc_workqueue() users
2026-06-04 14:09 ` Joe Perches
@ 2026-06-04 14:18 ` Marco Crivellari
0 siblings, 0 replies; 5+ messages in thread
From: Marco Crivellari @ 2026-06-04 14:18 UTC (permalink / raw)
To: Joe Perches
Cc: linux-kernel, Andy Whitcroft, Dwaipayan Ray, Lukas Bulwahn,
Tejun Heo, Frederic Weisbecker, Michal Hocko, Breno Leitao
On Thu, Jun 4, 2026 at 4:09 PM Joe Perches <joe@perches.com> wrote:
>
> On Thu, 2026-06-04 at 11:31 +0200, Marco Crivellari wrote:
> > On Thu, Jun 4, 2026 at 7:08 AM Joe Perches <[joe@perches.com](mailto:joe@perches.com)> wrote:
> > [...]
> > > OK but a couple comments:
> > >
> > > Add devm_alloc_workqueue as well?
> >
> > No I don't think it would be useful / needed. There is only 1 user of
> > that macro, devm_alloc_ordered_workqueue(), which already specifies
> > the WQ_UNBOUND flag and it is part of the workqueue code.
>
> drivers/power/supply/ipaq_micro_battery.c: mb->wq = devm_alloc_workqueue(&pdev->dev, "ipaq-battery-wq",
>
> Maybe there will be more.
Yes it is the only one in v7.1-rc6.
BTW, let's keep the new regex for both macros, it's not a problem, so
we can cover both cases.
Thanks!
--
Marco Crivellari
SUSE Labs
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-06-04 14:18 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-06-03 14:09 [PATCH] checkpatch: Check WQ_PERCPU or WQ_UNBOUND presence in alloc_workqueue() users Marco Crivellari
2026-06-04 5:08 ` Joe Perches
2026-06-04 9:31 ` Marco Crivellari
2026-06-04 14:09 ` Joe Perches
2026-06-04 14:18 ` Marco Crivellari
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®