History

workqueue: fix mayday_mask handling on UP

All cpumasks are assumed to have cpu 0 permanently set on UP, so it can't be used to signify whether there's something to be done for the CPU. workqueue was using cpumask to track which CPU requested rescuer assistance and this led rescuer thread to think there always are pending mayday requests on UP, which resulted in infinite busy loops. This patch fixes the problem by introducing mayday_mask_t and associated helpers which wrap cpumask on SMP and emulates its behavior using bitops and unsigned long on UP.

Tejun Heo committed 16 years ago

Commit f2e005a1 parent 931ac771 file · +28 −7Browse files

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

Unified · Split

kernel/workqueue.c+28−7
@@ -185,6 +185,27 @@ struct wq_flusher { · 184 unmodified lines
185185 struct completion done; /* flush completion */
186186 };
187187
188+/*
189+ * All cpumasks are assumed to be always set on UP and thus can't be
190+ * used to determine whether there's something to be done.
191+ */
192+#ifdef CONFIG_SMP
193+typedef cpumask_var_t mayday_mask_t;
194+#define mayday_test_and_set_cpu(cpu, mask) \
195+ cpumask_test_and_set_cpu((cpu), (mask))
196+#define mayday_clear_cpu(cpu, mask) cpumask_clear_cpu((cpu), (mask))
197+#define for_each_mayday_cpu(cpu, mask) for_each_cpu((cpu), (mask))
198+#define alloc_mayday_mask(maskp, gfp) alloc_cpumask_var((maskp), (gfp))
199+#define free_mayday_mask(mask) free_cpumask_var((mask))
200+#else
201+typedef unsigned long mayday_mask_t;
202+#define mayday_test_and_set_cpu(cpu, mask) test_and_set_bit(0, &(mask))
203+#define mayday_clear_cpu(cpu, mask) clear_bit(0, &(mask))
204+#define for_each_mayday_cpu(cpu, mask) if ((cpu) = 0, (mask))
205+#define alloc_mayday_mask(maskp, gfp) true
206+#define free_mayday_mask(mask) do { } while (0)
207+#endif
208+
188209 /*
189210 * The externally visible workqueue abstraction is an array of
190211 * per-CPU workqueues:
@@ -206,7 +227,7 @@ struct workqueue_struct { · 15 unmodified lines
206227 struct list_head flusher_queue; /* F: flush waiters */
207228 struct list_head flusher_overflow; /* F: flush overflow list */
208229
209− cpumask_var_t mayday_mask; /* cpus requesting rescue */
230+ mayday_mask_t mayday_mask; /* cpus requesting rescue */
210231 struct worker *rescuer; /* I: rescue worker */
211232
212233 int saved_max_active; /* W: saved cwq max_active */
@@ -1387,7 +1408,7 @@ static bool send_mayday(struct work_struct *work) · 1174 unmodified lines
13871408 /* WORK_CPU_UNBOUND can't be set in cpumask, use cpu 0 instead */
13881409 if (cpu == WORK_CPU_UNBOUND)
13891410 cpu = 0;
1390− if (!cpumask_test_and_set_cpu(cpu, wq->mayday_mask))
1411+ if (!mayday_test_and_set_cpu(cpu, wq->mayday_mask))
13911412 wake_up_process(wq->rescuer->task);
13921413 return true;
13931414 }
@@ -1915,14 +1936,14 @@ repeat: · 521 unmodified lines
19151936 * See whether any cpu is asking for help. Unbounded
19161937 * workqueues use cpu 0 in mayday_mask for CPU_UNBOUND.
19171938 */
1918− for_each_cpu(cpu, wq->mayday_mask) {
1939+ for_each_mayday_cpu(cpu, wq->mayday_mask) {
19191940 unsigned int tcpu = is_unbound ? WORK_CPU_UNBOUND : cpu;
19201941 struct cpu_workqueue_struct *cwq = get_cwq(tcpu, wq);
19211942 struct global_cwq *gcwq = cwq->gcwq;
19221943 struct work_struct *work, *n;
19231944
19241945 __set_current_state(TASK_RUNNING);
1925− cpumask_clear_cpu(cpu, wq->mayday_mask);
1946+ mayday_clear_cpu(cpu, wq->mayday_mask);
19261947
19271948 /* migrate to the target cpu if possible */
19281949 rescuer->gcwq = gcwq;
@@ -2724,7 +2745,7 @@ struct workqueue_struct *__alloc_workqueue_key(const char *name, · 795 unmodified lines
27242745 if (flags & WQ_RESCUER) {
27252746 struct worker *rescuer;
27262747
2727− if (!alloc_cpumask_var(&wq->mayday_mask, GFP_KERNEL))
2748+ if (!alloc_mayday_mask(&wq->mayday_mask, GFP_KERNEL))
27282749 goto err;
27292750
27302751 wq->rescuer = rescuer = alloc_worker();
@@ -2759,7 +2780,7 @@ struct workqueue_struct *__alloc_workqueue_key(const char *name, · 28 unmodified lines
27592780 err:
27602781 if (wq) {
27612782 free_cwqs(wq);
2762− free_cpumask_var(wq->mayday_mask);
2783+ free_mayday_mask(wq->mayday_mask);
27632784 kfree(wq->rescuer);
27642785 kfree(wq);
27652786 }
@@ -2800,7 +2821,7 @@ void destroy_workqueue(struct workqueue_struct *wq) · 34 unmodified lines
28002821
28012822 if (wq->flags & WQ_RESCUER) {
28022823 kthread_stop(wq->rescuer->task);
2803− free_cpumask_var(wq->mayday_mask);
2824+ free_mayday_mask(wq->mayday_mask);
28042825 }
28052826
28062827 free_cwqs(wq);