From 08ed6188e6e73c5558be17e527f84b10e0b95be9 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 30 Sep 2011 11:57:58 +0200 Subject: workqueue: Fix cpuhotplug trainwreck The current workqueue code does crazy stuff on cpu unplug, it relies on forced affine breakage, thereby violating per-cpu expectations. Worse, it tries to re-attach to a cpu if the thing comes up again before all previously queued works are finished. This breaks (admittedly bonkers) cpu-hotplug use that relies on a down-up cycle to push all usage away. Introduce a new WQ_NON_AFFINE flag that indicates a per-cpu workqueue will not respect cpu affinity and use this to migrate all its pending works to whatever cpu is doing cpu-down. This also adds a warning for queue_on_cpu() users which warns when its used on WQ_NON_AFFINE workqueues for the API implies you care about what cpu things are ran on when such workqueues cannot guarantee this. For the rest, simply flush all per-cpu works and don't mess about. This also means that currently all workqueues that are manually flushing things on cpu-down in order to provide the per-cpu guarantee no longer need to do so. In short, we tell the WQ what we want it to do, provide validation for this and loose ~250 lines of code. Signed-off-by: Peter Zijlstra Signed-off-by: Thomas Gleixner --- include/linux/cpu.h | 6 ++++-- include/linux/workqueue.h | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/include/linux/cpu.h b/include/linux/cpu.h index c46ec3ecd661..72e90bbf625a 100644 --- a/include/linux/cpu.h +++ b/include/linux/cpu.h @@ -66,8 +66,10 @@ enum { /* migration should happen before other stuff but after perf */ CPU_PRI_PERF = 20, CPU_PRI_MIGRATION = 10, - /* prepare workqueues for other notifiers */ - CPU_PRI_WORKQUEUE = 5, + + CPU_PRI_WORKQUEUE_ACTIVE = 5, /* prepare workqueues for others */ + CPU_PRI_NORMAL = 0, + CPU_PRI_WORKQUEUE_INACTIVE = -5, /* flush workqueues after others */ }; #define CPU_ONLINE 0x0002 /* CPU (unsigned)v is up */ diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index 0d556deb497b..d68ead81b52b 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -254,9 +254,10 @@ enum { WQ_MEM_RECLAIM = 1 << 3, /* may be used for memory reclaim */ WQ_HIGHPRI = 1 << 4, /* high priority */ WQ_CPU_INTENSIVE = 1 << 5, /* cpu instensive workqueue */ + WQ_NON_AFFINE = 1 << 6, /* free to move works around cpus */ - WQ_DRAINING = 1 << 6, /* internal: workqueue is draining */ - WQ_RESCUER = 1 << 7, /* internal: workqueue has rescuer */ + WQ_DRAINING = 1 << 7, /* internal: workqueue is draining */ + WQ_RESCUER = 1 << 8, /* internal: workqueue has rescuer */ WQ_MAX_ACTIVE = 512, /* I like 512, better ideas? */ WQ_MAX_UNBOUND_PER_CPU = 4, /* 4 * #cpus for unbound wq */ -- cgit v1.2.3