Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

workqueue: make the workqueues list RCU walkable

The workqueues list is protected by wq_pool_mutex and a workqueue and
its subordinate data structures are freed directly on destruction. We
want to add the ability dump workqueues from a sysrq callback which
requires walking all workqueues without grabbing wq_pool_mutex. This
patch makes freeing of workqueues RCU protected and makes the
workqueues list walkable while holding RCU read lock.

Note that pool_workqueues and pools are already sched-RCU protected.
For consistency, workqueues are also protected with sched-RCU.

While at it, reverse the workqueues list so that a workqueue which is
created earlier comes before. The order of the list isn't significant
functionally but this makes the planned sysrq dump list system
workqueues first.

Signed-off-by: Tejun Heo <tj@kernel.org>

Tejun Heo e2dca7ad 8603e1b3

+31 -16
+31 -16
kernel/workqueue.c
··· 230 230 */ 231 231 struct workqueue_struct { 232 232 struct list_head pwqs; /* WR: all pwqs of this wq */ 233 - struct list_head list; /* PL: list of all workqueues */ 233 + struct list_head list; /* PR: list of all workqueues */ 234 234 235 235 struct mutex mutex; /* protects this wq */ 236 236 int work_color; /* WQ: current work color */ ··· 256 256 struct lockdep_map lockdep_map; 257 257 #endif 258 258 char name[WQ_NAME_LEN]; /* I: workqueue name */ 259 + 260 + /* 261 + * Destruction of workqueue_struct is sched-RCU protected to allow 262 + * walking the workqueues list without grabbing wq_pool_mutex. 263 + * This is used to dump all workqueues from sysrq. 264 + */ 265 + struct rcu_head rcu; 259 266 260 267 /* hot fields used during command issue, aligned to cacheline */ 261 268 unsigned int flags ____cacheline_aligned; /* WQ: WQ_* flags */ ··· 295 288 static DEFINE_MUTEX(wq_pool_mutex); /* protects pools and workqueues list */ 296 289 static DEFINE_SPINLOCK(wq_mayday_lock); /* protects wq->maydays list */ 297 290 298 - static LIST_HEAD(workqueues); /* PL: list of all workqueues */ 291 + static LIST_HEAD(workqueues); /* PR: list of all workqueues */ 299 292 static bool workqueue_freezing; /* PL: have wqs started freezing? */ 300 293 301 294 /* the per-cpu worker pools */ ··· 3431 3424 return 0; 3432 3425 } 3433 3426 3427 + static void rcu_free_wq(struct rcu_head *rcu) 3428 + { 3429 + struct workqueue_struct *wq = 3430 + container_of(rcu, struct workqueue_struct, rcu); 3431 + 3432 + if (!(wq->flags & WQ_UNBOUND)) 3433 + free_percpu(wq->cpu_pwqs); 3434 + else 3435 + free_workqueue_attrs(wq->unbound_attrs); 3436 + 3437 + kfree(wq->rescuer); 3438 + kfree(wq); 3439 + } 3440 + 3434 3441 static void rcu_free_pool(struct rcu_head *rcu) 3435 3442 { 3436 3443 struct worker_pool *pool = container_of(rcu, struct worker_pool, rcu); ··· 3622 3601 3623 3602 /* 3624 3603 * If we're the last pwq going away, @wq is already dead and no one 3625 - * is gonna access it anymore. Free it. 3604 + * is gonna access it anymore. Schedule RCU free. 3626 3605 */ 3627 - if (is_last) { 3628 - free_workqueue_attrs(wq->unbound_attrs); 3629 - kfree(wq); 3630 - } 3606 + if (is_last) 3607 + call_rcu_sched(&wq->rcu, rcu_free_wq); 3631 3608 } 3632 3609 3633 3610 /** ··· 4162 4143 pwq_adjust_max_active(pwq); 4163 4144 mutex_unlock(&wq->mutex); 4164 4145 4165 - list_add(&wq->list, &workqueues); 4146 + list_add_tail_rcu(&wq->list, &workqueues); 4166 4147 4167 4148 mutex_unlock(&wq_pool_mutex); 4168 4149 ··· 4218 4199 * flushing is complete in case freeze races us. 4219 4200 */ 4220 4201 mutex_lock(&wq_pool_mutex); 4221 - list_del_init(&wq->list); 4202 + list_del_rcu(&wq->list); 4222 4203 mutex_unlock(&wq_pool_mutex); 4223 4204 4224 4205 workqueue_sysfs_unregister(wq); 4225 4206 4226 - if (wq->rescuer) { 4207 + if (wq->rescuer) 4227 4208 kthread_stop(wq->rescuer->task); 4228 - kfree(wq->rescuer); 4229 - wq->rescuer = NULL; 4230 - } 4231 4209 4232 4210 if (!(wq->flags & WQ_UNBOUND)) { 4233 4211 /* 4234 4212 * The base ref is never dropped on per-cpu pwqs. Directly 4235 - * free the pwqs and wq. 4213 + * schedule RCU free. 4236 4214 */ 4237 - free_percpu(wq->cpu_pwqs); 4238 - kfree(wq); 4215 + call_rcu_sched(&wq->rcu, rcu_free_wq); 4239 4216 } else { 4240 4217 /* 4241 4218 * We're the sole accessor of @wq at this point. Directly