2023-05-09 02:06:16

by Tejun Heo

[permalink] [raw]
Subject: [PATCHSET v2 wq/for-6.5-cleanup-ordered] workqueue: Ordered workqueue creation cleanup

Hello,

v2: Acked patches are applied to wq/for-6.5-cleanup-ordered. Some conversion
patches were dropped (e.g. because they were using WQ_SYSFS and thus
can't be ordered) and fixed. The final patch to remove implicit ordered
promotion logic was broken and could trigger WARN spuriously. Fixed.

When multiple work items are queued to a workqueue, their execution order
doesn't match the queueing order. They may get executed in any order and
simultaneously. When fully serialized execution - one by one in the queueing
order - is needed, an ordered workqueue should be used which can be created
with alloc_ordered_workqueue().

However, alloc_ordered_workqueue() was a later addition. Before it, an
ordered workqueue could be obtained by creating an UNBOUND workqueue with
@max_active==1. This originally was an implementation side-effect which was
broken by 4c16bd327c74 ("workqueue: restore WQ_UNBOUND/max_active==1 to be
ordered"). Because there were users that depended on the ordered execution,
5c0338c68706 ("workqueue: restore WQ_UNBOUND/max_active==1 to be ordered")
made workqueue allocation path to implicitly promote UNBOUND workqueues w/
@max_active==1 to ordered workqueues.

While this has worked okay, overloading the UNBOUND allocation interface
this way creates other issues. It's difficult to tell whether a given
workqueue actually needs to be ordered and users that legitimately want a
min concurrency level wq unexpectedly gets an ordered one instead. With
planned UNBOUND workqueue updates to improve execution locality and more
prevalence of chiplet designs which can benefit from such improvements, this
isn't a state we wanna be in forever.

This patch series audits all callsites that create an UNBOUND workqueue w/
@max_active==1 and converts them to alloc_ordered_workqueue() as necessary
and contains the following 13 patches on top of wq/for-6.5-cleanup-ordered
branch.

0001-scsi-ncr53c8xx-Use-default-max_active-for-hostdata-w.patch
0002-wifi-mwifiex-Use-default-max_active-for-workqueues.patch
0003-dm-integrity-Use-alloc_ordered_workqueue-to-create-o.patch
0004-media-amphion-Use-alloc_ordered_workqueue-to-create-.patch
0005-wifi-ath10-11-12k-Use-alloc_ordered_workqueue-to-cre.patch
0006-net-wwan-t7xx-Use-alloc_ordered_workqueue-to-create-.patch
0007-soc-qcom-qmi-Use-alloc_ordered_workqueue-to-create-o.patch
0008-btrfs-Use-alloc_ordered_workqueue-to-create-ordered-.patch
0009-net-qrtr-Use-alloc_ordered_workqueue-to-create-order.patch
0010-rxrpc-Use-alloc_ordered_workqueue-to-create-ordered-.patch
0011-crypto-octeontx2-Use-alloc_ordered_workqueue-to-crea.patch
0012-media-coda-Use-alloc_ordered_workqueue-to-create-ord.patch
0013-workqueue-Don-t-implicitly-make-UNBOUND-workqueues-w.patch

0001-0012 convert the existing users and 0013 drops the implicit ordered
promotion logic from alloc_workqueue(). I'll keep an eye out for a while
after merging 0022. Thankfully, these are pretty easy to grep for. The
patches can also be found in the following git branch.

git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq.git cleanup-ordered-v2

diffstat follows. Thanks.

drivers/crypto/marvell/octeontx2/otx2_cptpf_main.c | 12 ++++++------
drivers/crypto/marvell/octeontx2/otx2_cptvf_main.c | 6 +++---
drivers/md/dm-integrity.c | 4 ++--
drivers/md/dm.c | 2 +-
drivers/media/platform/amphion/vpu_core.c | 2 +-
drivers/media/platform/amphion/vpu_v4l2.c | 2 +-
drivers/media/platform/chips-media/coda-common.c | 2 +-
drivers/net/wireless/ath/ath10k/qmi.c | 3 +--
drivers/net/wireless/ath/ath11k/qmi.c | 3 +--
drivers/net/wireless/ath/ath12k/qmi.c | 3 +--
drivers/net/wireless/marvell/mwifiex/cfg80211.c | 4 ++--
drivers/net/wireless/marvell/mwifiex/main.c | 8 ++++----
drivers/net/wwan/t7xx/t7xx_hif_cldma.c | 13 +++++++------
drivers/net/wwan/t7xx/t7xx_hif_dpmaif_tx.c | 5 +++--
drivers/scsi/NCR5380.c | 2 +-
drivers/soc/qcom/qmi_interface.c | 2 +-
fs/btrfs/disk-io.c | 2 +-
fs/btrfs/scrub.c | 6 ++++--
include/linux/workqueue.h | 4 +---
kernel/workqueue.c | 23 ++++-------------------
net/qrtr/ns.c | 2 +-
net/rxrpc/af_rxrpc.c | 2 +-
22 files changed, 48 insertions(+), 64 deletions(-)


2023-05-09 02:12:53

by Tejun Heo

[permalink] [raw]
Subject: [PATCH 09/13] net: qrtr: Use alloc_ordered_workqueue() to create ordered workqueues

BACKGROUND
==========

When multiple work items are queued to a workqueue, their execution order
doesn't match the queueing order. They may get executed in any order and
simultaneously. When fully serialized execution - one by one in the queueing
order - is needed, an ordered workqueue should be used which can be created
with alloc_ordered_workqueue().

However, alloc_ordered_workqueue() was a later addition. Before it, an
ordered workqueue could be obtained by creating an UNBOUND workqueue with
@max_active==1. This originally was an implementation side-effect which was
broken by 4c16bd327c74 ("workqueue: restore WQ_UNBOUND/max_active==1 to be
ordered"). Because there were users that depended on the ordered execution,
5c0338c68706 ("workqueue: restore WQ_UNBOUND/max_active==1 to be ordered")
made workqueue allocation path to implicitly promote UNBOUND workqueues w/
@max_active==1 to ordered workqueues.

While this has worked okay, overloading the UNBOUND allocation interface
this way creates other issues. It's difficult to tell whether a given
workqueue actually needs to be ordered and users that legitimately want a
min concurrency level wq unexpectedly gets an ordered one instead. With
planned UNBOUND workqueue updates to improve execution locality and more
prevalence of chiplet designs which can benefit from such improvements, this
isn't a state we wanna be in forever.

This patch series audits all callsites that create an UNBOUND workqueue w/
@max_active==1 and converts them to alloc_ordered_workqueue() as necessary.

WHAT TO LOOK FOR
================

The conversions are from

alloc_workqueue(WQ_UNBOUND | flags, 1, args..)

to

alloc_ordered_workqueue(flags, args...)

which don't cause any functional changes. If you know that fully ordered
execution is not ncessary, please let me know. I'll drop the conversion and
instead add a comment noting the fact to reduce confusion while conversion
is in progress.

If you aren't fully sure, it's completely fine to let the conversion
through. The behavior will stay exactly the same and we can always
reconsider later.

As there are follow-up workqueue core changes, I'd really appreciate if the
patch can be routed through the workqueue tree w/ your acks. Thanks.

Signed-off-by: Tejun Heo <[email protected]>
Cc: Manivannan Sadhasivam <[email protected]>
Cc: "David S. Miller" <[email protected]>
Cc: Eric Dumazet <[email protected]>
Cc: Jakub Kicinski <[email protected]>
Cc: Paolo Abeni <[email protected]>
Cc: [email protected]
Cc: [email protected]
---
net/qrtr/ns.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/qrtr/ns.c b/net/qrtr/ns.c
index 0f25a386138c..0f7a729f1a1f 100644
--- a/net/qrtr/ns.c
+++ b/net/qrtr/ns.c
@@ -783,7 +783,7 @@ int qrtr_ns_init(void)
goto err_sock;
}

- qrtr_ns.workqueue = alloc_workqueue("qrtr_ns_handler", WQ_UNBOUND, 1);
+ qrtr_ns.workqueue = alloc_ordered_workqueue("qrtr_ns_handler", 0);
if (!qrtr_ns.workqueue) {
ret = -ENOMEM;
goto err_sock;
--
2.40.1

2023-05-09 02:14:31

by Tejun Heo

[permalink] [raw]
Subject: [PATCH 07/13] soc: qcom: qmi: Use alloc_ordered_workqueue() to create ordered workqueues

BACKGROUND
==========

When multiple work items are queued to a workqueue, their execution order
doesn't match the queueing order. They may get executed in any order and
simultaneously. When fully serialized execution - one by one in the queueing
order - is needed, an ordered workqueue should be used which can be created
with alloc_ordered_workqueue().

However, alloc_ordered_workqueue() was a later addition. Before it, an
ordered workqueue could be obtained by creating an UNBOUND workqueue with
@max_active==1. This originally was an implementation side-effect which was
broken by 4c16bd327c74 ("workqueue: restore WQ_UNBOUND/max_active==1 to be
ordered"). Because there were users that depended on the ordered execution,
5c0338c68706 ("workqueue: restore WQ_UNBOUND/max_active==1 to be ordered")
made workqueue allocation path to implicitly promote UNBOUND workqueues w/
@max_active==1 to ordered workqueues.

While this has worked okay, overloading the UNBOUND allocation interface
this way creates other issues. It's difficult to tell whether a given
workqueue actually needs to be ordered and users that legitimately want a
min concurrency level wq unexpectedly gets an ordered one instead. With
planned UNBOUND workqueue updates to improve execution locality and more
prevalence of chiplet designs which can benefit from such improvements, this
isn't a state we wanna be in forever.

This patch series audits all callsites that create an UNBOUND workqueue w/
@max_active==1 and converts them to alloc_ordered_workqueue() as necessary.

WHAT TO LOOK FOR
================

The conversions are from

alloc_workqueue(WQ_UNBOUND | flags, 1, args..)

to

alloc_ordered_workqueue(flags, args...)

which don't cause any functional changes. If you know that fully ordered
execution is not ncessary, please let me know. I'll drop the conversion and
instead add a comment noting the fact to reduce confusion while conversion
is in progress.

If you aren't fully sure, it's completely fine to let the conversion
through. The behavior will stay exactly the same and we can always
reconsider later.

As there are follow-up workqueue core changes, I'd really appreciate if the
patch can be routed through the workqueue tree w/ your acks. Thanks.

Signed-off-by: Tejun Heo <[email protected]>
Cc: Andy Gross <[email protected]>
Cc: Bjorn Andersson <[email protected]>
Cc: Konrad Dybcio <[email protected]>
Cc: [email protected]
---
drivers/soc/qcom/qmi_interface.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/soc/qcom/qmi_interface.c b/drivers/soc/qcom/qmi_interface.c
index 820bdd9f8e46..78d7361fdcf2 100644
--- a/drivers/soc/qcom/qmi_interface.c
+++ b/drivers/soc/qcom/qmi_interface.c
@@ -650,7 +650,7 @@ int qmi_handle_init(struct qmi_handle *qmi, size_t recv_buf_size,
if (!qmi->recv_buf)
return -ENOMEM;

- qmi->wq = alloc_workqueue("qmi_msg_handler", WQ_UNBOUND, 1);
+ qmi->wq = alloc_ordered_workqueue("qmi_msg_handler", 0);
if (!qmi->wq) {
ret = -ENOMEM;
goto err_free_recv_buf;
--
2.40.1

2023-05-25 22:41:10

by Tejun Heo

[permalink] [raw]
Subject: Re: [PATCH 09/13] net: qrtr: Use alloc_ordered_workqueue() to create ordered workqueues

On Mon, May 08, 2023 at 03:50:28PM -1000, Tejun Heo wrote:
...
> Signed-off-by: Tejun Heo <[email protected]>
> Cc: Manivannan Sadhasivam <[email protected]>
> Cc: "David S. Miller" <[email protected]>
> Cc: Eric Dumazet <[email protected]>
> Cc: Jakub Kicinski <[email protected]>
> Cc: Paolo Abeni <[email protected]>
> Cc: [email protected]
> Cc: [email protected]

Hey, I'm going to apply this to wq/for-6.5-cleanup-ordered. As it's an
identity conversion, it shouldn't break anything. Please holler if you have
any concerns.

Thanks.

--
tejun