From: Tejun Heo <tj@kernel.org>
To: jiangshanlai@gmail.com
Cc: linux-kernel@vger.kernel.org, kernel-team@meta.com,
Tejun Heo <tj@kernel.org>
Subject: [PATCH 4/4] workqueue: Make unbound pwq updates from CPU hotplug path asynchronous
Date: Fri, 2 Aug 2024 11:18:20 -1000 [thread overview]
Message-ID: <20240802211850.1211737-5-tj@kernel.org> (raw)
In-Reply-To: <20240802211850.1211737-1-tj@kernel.org>
84193c07105c ("workqueue: Generalize unbound CPU pods") and associated
commits added generalized affinity scope support. In the process, it added
synchronous calls to update_unbound_pwqs() from CPU hotplug path. When a CPU
comes online in an otherwise empty pod, this can lead to creation of a new
worker_pool involving creating new workers. Workqueues work correctly
without synchronous updates and there's no need to add additional fork
dependency to hotplug path. Make unbound pwq updates asynchronous.
This makes update_unbound_pwqs() called on all CPUs instead of the pod's
CPUs. However, when no-op, the call is pretty cheap and the additional calls
shouldn't be noticeable.
Signed-off-by: Tejun Heo <tj@kernel.org>
---
kernel/workqueue.c | 72 ++++++++++++++++++++++------------------------
1 file changed, 35 insertions(+), 37 deletions(-)
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 0f593f2884e0..33c6635bcb87 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -6544,6 +6544,39 @@ static void restore_unbound_workers_cpumask(struct worker_pool *pool, int cpu)
WARN_ON_ONCE(set_cpus_allowed_ptr(worker->task, &cpumask) < 0);
}
+static void hotplug_update_unbound_pwqs_workfn(struct work_struct *work)
+{
+ struct workqueue_struct *wq;
+
+ mutex_lock(&wq_pool_mutex);
+
+ /*
+ * CPUs have gone online or offline. Update the pod affinities of all
+ * unbound workqueues. While not optimal, workqueues operate correctly
+ * without these updates, so this can be done asynchronously, which
+ * avoids adding fork dependency from CPU hotplug path.
+ */
+ list_for_each_entry(wq, &workqueues, list) {
+ struct workqueue_attrs *attrs = wq->unbound_attrs;
+
+ if (attrs) {
+ int cpu;
+
+ for_each_possible_cpu(cpu)
+ update_unbound_pwqs(wq, cpu);
+
+ mutex_lock(&wq->mutex);
+ wq_update_node_max_active(wq);
+ mutex_unlock(&wq->mutex);
+ }
+ }
+
+ mutex_unlock(&wq_pool_mutex);
+}
+
+static DECLARE_WORK(hotplug_update_unbound_pwqs_work,
+ hotplug_update_unbound_pwqs_workfn);
+
int workqueue_prepare_cpu(unsigned int cpu)
{
struct worker_pool *pool;
@@ -6560,7 +6593,6 @@ int workqueue_prepare_cpu(unsigned int cpu)
int workqueue_online_cpu(unsigned int cpu)
{
struct worker_pool *pool;
- struct workqueue_struct *wq;
int pi;
mutex_lock(&wq_pool_mutex);
@@ -6580,22 +6612,7 @@ int workqueue_online_cpu(unsigned int cpu)
mutex_unlock(&wq_pool_attach_mutex);
}
- /* update pod affinity of unbound workqueues */
- list_for_each_entry(wq, &workqueues, list) {
- struct workqueue_attrs *attrs = wq->unbound_attrs;
-
- if (attrs) {
- const struct wq_pod_type *pt = wqattrs_pod_type(attrs);
- int tcpu;
-
- for_each_cpu(tcpu, pt->pod_cpus[pt->cpu_pod[cpu]])
- update_unbound_pwqs(wq, tcpu);
-
- mutex_lock(&wq->mutex);
- wq_update_node_max_active(wq);
- mutex_unlock(&wq->mutex);
- }
- }
+ schedule_work(&hotplug_update_unbound_pwqs_work);
mutex_unlock(&wq_pool_mutex);
return 0;
@@ -6603,34 +6620,15 @@ int workqueue_online_cpu(unsigned int cpu)
int workqueue_offline_cpu(unsigned int cpu)
{
- struct workqueue_struct *wq;
-
/* unbinding per-cpu workers should happen on the local CPU */
if (WARN_ON(cpu != smp_processor_id()))
return -1;
unbind_workers(cpu);
- /* update pod affinity of unbound workqueues */
mutex_lock(&wq_pool_mutex);
-
cpumask_clear_cpu(cpu, wq_online_cpumask);
-
- list_for_each_entry(wq, &workqueues, list) {
- struct workqueue_attrs *attrs = wq->unbound_attrs;
-
- if (attrs) {
- const struct wq_pod_type *pt = wqattrs_pod_type(attrs);
- int tcpu;
-
- for_each_cpu(tcpu, pt->pod_cpus[pt->cpu_pod[cpu]])
- update_unbound_pwqs(wq, tcpu);
-
- mutex_lock(&wq->mutex);
- wq_update_node_max_active(wq);
- mutex_unlock(&wq->mutex);
- }
- }
+ schedule_work(&hotplug_update_unbound_pwqs_work);
mutex_unlock(&wq_pool_mutex);
return 0;
--
2.45.2
prev parent reply other threads:[~2024-08-02 21:19 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-08-02 21:18 [PATCHSET wq/for-6.12] workqueue: Use wq_online_cpumask consistently and make CPU hotplug unbound pwq updates asynchronous Tejun Heo
2024-08-02 21:18 ` [PATCH 1/4] workqueue: Make wq_affn_dfl_set() use wq_online_cpumask Tejun Heo
2024-08-08 4:23 ` Lai Jiangshan
2024-08-13 19:40 ` Tejun Heo
2024-08-02 21:18 ` [PATCH 2/4] workqueue: Make wq_update_node_max_active() " Tejun Heo
2024-08-02 21:18 ` [PATCH 3/4] workqueue: s/unbound_wq_update_pwq/update_unbound_pwqs/ Tejun Heo
2024-08-02 21:18 ` Tejun Heo [this message]
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=20240802211850.1211737-5-tj@kernel.org \
--to=tj@kernel.org \
--cc=jiangshanlai@gmail.com \
--cc=kernel-team@meta.com \
--cc=linux-kernel@vger.kernel.org \
/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 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®