aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2015-03-09 09:22:28 -0400
committerTejun Heo <tj@kernel.org>2015-03-09 09:22:28 -0400
commite2dca7adff8f3fae0ab250a6362798550b3c79ee (patch)
tree3b86a4dfbc600872645c856d3d45b8b3af4d3cff /kernel
parent8603e1b30027f943cc9c1eef2b291d42c3347af1 (diff)
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>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/workqueue.c47
1 files changed, 31 insertions, 16 deletions
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 41ff75b478c6..6b9b0dc3dea5 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -230,7 +230,7 @@ struct wq_device;
230 */ 230 */
231struct workqueue_struct { 231struct workqueue_struct {
232 struct list_head pwqs; /* WR: all pwqs of this wq */ 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 struct mutex mutex; /* protects this wq */ 235 struct mutex mutex; /* protects this wq */
236 int work_color; /* WQ: current work color */ 236 int work_color; /* WQ: current work color */
@@ -257,6 +257,13 @@ struct workqueue_struct {
257#endif 257#endif
258 char name[WQ_NAME_LEN]; /* I: workqueue name */ 258 char name[WQ_NAME_LEN]; /* I: workqueue name */
259 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;
266
260 /* hot fields used during command issue, aligned to cacheline */ 267 /* hot fields used during command issue, aligned to cacheline */
261 unsigned int flags ____cacheline_aligned; /* WQ: WQ_* flags */ 268 unsigned int flags ____cacheline_aligned; /* WQ: WQ_* flags */
262 struct pool_workqueue __percpu *cpu_pwqs; /* I: per-cpu pwqs */ 269 struct pool_workqueue __percpu *cpu_pwqs; /* I: per-cpu pwqs */
@@ -288,7 +295,7 @@ static struct workqueue_attrs *wq_update_unbound_numa_attrs_buf;
288static DEFINE_MUTEX(wq_pool_mutex); /* protects pools and workqueues list */ 295static DEFINE_MUTEX(wq_pool_mutex); /* protects pools and workqueues list */
289static DEFINE_SPINLOCK(wq_mayday_lock); /* protects wq->maydays list */ 296static DEFINE_SPINLOCK(wq_mayday_lock); /* protects wq->maydays list */
290 297
291static LIST_HEAD(workqueues); /* PL: list of all workqueues */ 298static LIST_HEAD(workqueues); /* PR: list of all workqueues */
292static bool workqueue_freezing; /* PL: have wqs started freezing? */ 299static bool workqueue_freezing; /* PL: have wqs started freezing? */
293 300
294/* the per-cpu worker pools */ 301/* the per-cpu worker pools */
@@ -3424,6 +3431,20 @@ static int init_worker_pool(struct worker_pool *pool)
3424 return 0; 3431 return 0;
3425} 3432}
3426 3433
3434static void rcu_free_wq(struct rcu_head *rcu)
3435{
3436 struct workqueue_struct *wq =
3437 container_of(rcu, struct workqueue_struct, rcu);
3438
3439 if (!(wq->flags & WQ_UNBOUND))
3440 free_percpu(wq->cpu_pwqs);
3441 else
3442 free_workqueue_attrs(wq->unbound_attrs);
3443
3444 kfree(wq->rescuer);
3445 kfree(wq);
3446}
3447
3427static void rcu_free_pool(struct rcu_head *rcu) 3448static void rcu_free_pool(struct rcu_head *rcu)
3428{ 3449{
3429 struct worker_pool *pool = container_of(rcu, struct worker_pool, rcu); 3450 struct worker_pool *pool = container_of(rcu, struct worker_pool, rcu);
@@ -3601,12 +3622,10 @@ static void pwq_unbound_release_workfn(struct work_struct *work)
3601 3622
3602 /* 3623 /*
3603 * If we're the last pwq going away, @wq is already dead and no one 3624 * If we're the last pwq going away, @wq is already dead and no one
3604 * is gonna access it anymore. Free it. 3625 * is gonna access it anymore. Schedule RCU free.
3605 */ 3626 */
3606 if (is_last) { 3627 if (is_last)
3607 free_workqueue_attrs(wq->unbound_attrs); 3628 call_rcu_sched(&wq->rcu, rcu_free_wq);
3608 kfree(wq);
3609 }
3610} 3629}
3611 3630
3612/** 3631/**
@@ -4143,7 +4162,7 @@ struct workqueue_struct *__alloc_workqueue_key(const char *fmt,
4143 pwq_adjust_max_active(pwq); 4162 pwq_adjust_max_active(pwq);
4144 mutex_unlock(&wq->mutex); 4163 mutex_unlock(&wq->mutex);
4145 4164
4146 list_add(&wq->list, &workqueues); 4165 list_add_tail_rcu(&wq->list, &workqueues);
4147 4166
4148 mutex_unlock(&wq_pool_mutex); 4167 mutex_unlock(&wq_pool_mutex);
4149 4168
@@ -4199,24 +4218,20 @@ void destroy_workqueue(struct workqueue_struct *wq)
4199 * flushing is complete in case freeze races us. 4218 * flushing is complete in case freeze races us.
4200 */ 4219 */
4201 mutex_lock(&wq_pool_mutex); 4220 mutex_lock(&wq_pool_mutex);
4202 list_del_init(&wq->list); 4221 list_del_rcu(&wq->list);
4203 mutex_unlock(&wq_pool_mutex); 4222 mutex_unlock(&wq_pool_mutex);
4204 4223
4205 workqueue_sysfs_unregister(wq); 4224 workqueue_sysfs_unregister(wq);
4206 4225
4207 if (wq->rescuer) { 4226 if (wq->rescuer)
4208 kthread_stop(wq->rescuer->task); 4227 kthread_stop(wq->rescuer->task);
4209 kfree(wq->rescuer);
4210 wq->rescuer = NULL;
4211 }
4212 4228
4213 if (!(wq->flags & WQ_UNBOUND)) { 4229 if (!(wq->flags & WQ_UNBOUND)) {
4214 /* 4230 /*
4215 * The base ref is never dropped on per-cpu pwqs. Directly 4231 * The base ref is never dropped on per-cpu pwqs. Directly
4216 * free the pwqs and wq. 4232 * schedule RCU free.
4217 */ 4233 */
4218 free_percpu(wq->cpu_pwqs); 4234 call_rcu_sched(&wq->rcu, rcu_free_wq);
4219 kfree(wq);
4220 } else { 4235 } else {
4221 /* 4236 /*
4222 * We're the sole accessor of @wq at this point. Directly 4237 * We're the sole accessor of @wq at this point. Directly