History

workqueue: prepare flush_workqueue() for dynamic creation and destrucion of unbound pool_workqueues

Unbound pwqs (pool_workqueues) will be dynamically created and destroyed with the scheduled unbound workqueue w/ custom attributes support. This patch synchronizes pwq linking and unlinking against flush_workqueue() so that its operation isn't disturbed by pwqs coming and going. Linking and unlinking a pwq into wq->pwqs is now protected also by wq->flush_mutex and a new pwq's work_color is initialized to wq->work_color during linking. This ensures that pwqs changes don't disturb flush_workqueue() in progress and the new pwq's work coloring stays in sync with the rest of the workqueue. flush_mutex during unlinking isn't strictly necessary but it's simpler to do it anyway.

Tejun Heo committed 13 years ago

Commit 75ccf591 parent 8864b4e1 file · +23 −2Browse files

Showing the changes to kernel/workqueue.c (1 of 1 file). Show all

Unified · Split

kernel/workqueue.c+23−2
@@ -122,6 +122,9 @@ enum { · 121 unmodified lines
122122 * W: workqueue_lock protected.
123123 *
124124 * R: workqueue_lock protected for writes. Sched-RCU protected for reads.
125+ *
126+ * FR: wq->flush_mutex and workqueue_lock protected for writes. Sched-RCU
127+ * protected for reads.
125128 */
126129
127130 /* struct worker is defined in workqueue_internal.h */
@@ -185,7 +188,7 @@ struct pool_workqueue { · 57 unmodified lines
185188 int nr_active; /* L: nr of active works */
186189 int max_active; /* L: max active works */
187190 struct list_head delayed_works; /* L: delayed works */
188− struct list_head pwqs_node; /* R: node on wq->pwqs */
191+ struct list_head pwqs_node; /* FR: node on wq->pwqs */
189192 struct list_head mayday_node; /* W: node on wq->maydays */
190193
191194 /*
@@ -214,7 +217,7 @@ struct wq_flusher { · 22 unmodified lines
214217 struct workqueue_struct {
215218 unsigned int flags; /* W: WQ_* flags */
216219 struct pool_workqueue __percpu *cpu_pwqs; /* I: per-cpu pwq's */
217− struct list_head pwqs; /* R: all pwqs of this wq */
220+ struct list_head pwqs; /* FR: all pwqs of this wq */
218221 struct list_head list; /* W: list of all workqueues */
219222
220223 struct mutex flush_mutex; /* protects wq flushing */
@@ -3402,9 +3405,16 @@ static void pwq_unbound_release_workfn(struct work_struct *work) · 3181 unmodified lines
34023405 if (WARN_ON_ONCE(!(wq->flags & WQ_UNBOUND)))
34033406 return;
34043407
3408+ /*
3409+ * Unlink @pwq. Synchronization against flush_mutex isn't strictly
3410+ * necessary on release but do it anyway. It's easier to verify
3411+ * and consistent with the linking path.
3412+ */
3413+ mutex_lock(&wq->flush_mutex);
34053414 spin_lock_irq(&workqueue_lock);
34063415 list_del_rcu(&pwq->pwqs_node);
34073416 spin_unlock_irq(&workqueue_lock);
3417+ mutex_unlock(&wq->flush_mutex);
34083418
34093419 put_unbound_pool(pool);
34103420 call_rcu_sched(&pwq->rcu, rcu_free_pwq);
@@ -3432,7 +3442,18 @@ static void init_and_link_pwq(struct pool_workqueue *pwq, · 21 unmodified lines
34323442 INIT_LIST_HEAD(&pwq->mayday_node);
34333443 INIT_WORK(&pwq->unbound_release_work, pwq_unbound_release_workfn);
34343444
3445+ /*
3446+ * Link @pwq and set the matching work_color. This is synchronized
3447+ * with flush_mutex to avoid confusing flush_workqueue().
3448+ */
3449+ mutex_lock(&wq->flush_mutex);
3450+ spin_lock_irq(&workqueue_lock);
3451+
3452+ pwq->work_color = wq->work_color;
34353453 list_add_tail_rcu(&pwq->pwqs_node, &wq->pwqs);
3454+
3455+ spin_unlock_irq(&workqueue_lock);
3456+ mutex_unlock(&wq->flush_mutex);
34363457 }
34373458
34383459 static int alloc_and_link_pwqs(struct workqueue_struct *wq)

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t