Skip to content

Commit 90fd673

Browse files
Peter Zijlstragregkh
authored andcommitted
sched/cpuset/pm: Fix cpuset vs. suspend-resume bugs
commit 50e76632339d4655859523a39249dd95ee5e93e7 upstream. Cpusets vs. suspend-resume is _completely_ broken. And it got noticed because it now resulted in non-cpuset usage breaking too. On suspend cpuset_cpu_inactive() doesn't call into cpuset_update_active_cpus() because it doesn't want to move tasks about, there is no need, all tasks are frozen and won't run again until after we've resumed everything. But this means that when we finally do call into cpuset_update_active_cpus() after resuming the last frozen cpu in cpuset_cpu_active(), the top_cpuset will not have any difference with the cpu_active_mask and this it will not in fact do _anything_. So the cpuset configuration will not be restored. This was largely hidden because we would unconditionally create identity domains and mobile users would not in fact use cpusets much. And servers what do use cpusets tend to not suspend-resume much. An addition problem is that we'd not in fact wait for the cpuset work to finish before resuming the tasks, allowing spurious migrations outside of the specified domains. Fix the rebuild by introducing cpuset_force_rebuild() and fix the ordering with cpuset_wait_for_hotplug(). Reported-by: Andy Lutomirski <luto@kernel.org> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: <stable@vger.kernel.org> Cc: Andy Lutomirski <luto@amacapital.net> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Mike Galbraith <efault@gmx.de> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Rafael J. Wysocki <rjw@rjwysocki.net> Cc: Tejun Heo <tj@kernel.org> Cc: Thomas Gleixner <tglx@linutronix.de> Fixes: deb7aa3 ("cpuset: reorganize CPU / memory hotplug handling") Link: http://lkml.kernel.org/r/20170907091338.orwxrqkbfkki3c24@hirez.programming.kicks-ass.net Signed-off-by: Ingo Molnar <mingo@kernel.org> Signed-off-by: Mike Galbraith <efault@gmx.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 6d1400b commit 90fd673

4 files changed

Lines changed: 28 additions & 6 deletions

File tree

include/linux/cpuset.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,9 @@ static inline void cpuset_dec(void)
4343

4444
extern int cpuset_init(void);
4545
extern void cpuset_init_smp(void);
46+
extern void cpuset_force_rebuild(void);
4647
extern void cpuset_update_active_cpus(bool cpu_online);
48+
extern void cpuset_wait_for_hotplug(void);
4749
extern void cpuset_cpus_allowed(struct task_struct *p, struct cpumask *mask);
4850
extern void cpuset_cpus_allowed_fallback(struct task_struct *p);
4951
extern nodemask_t cpuset_mems_allowed(struct task_struct *p);
@@ -147,11 +149,15 @@ static inline bool cpusets_enabled(void) { return false; }
147149
static inline int cpuset_init(void) { return 0; }
148150
static inline void cpuset_init_smp(void) {}
149151

152+
static inline void cpuset_force_rebuild(void) { }
153+
150154
static inline void cpuset_update_active_cpus(bool cpu_online)
151155
{
152156
partition_sched_domains(1, NULL, NULL);
153157
}
154158

159+
static inline void cpuset_wait_for_hotplug(void) { }
160+
155161
static inline void cpuset_cpus_allowed(struct task_struct *p,
156162
struct cpumask *mask)
157163
{

kernel/cpuset.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2281,6 +2281,13 @@ static void cpuset_hotplug_update_tasks(struct cpuset *cs)
22812281
mutex_unlock(&cpuset_mutex);
22822282
}
22832283

2284+
static bool force_rebuild;
2285+
2286+
void cpuset_force_rebuild(void)
2287+
{
2288+
force_rebuild = true;
2289+
}
2290+
22842291
/**
22852292
* cpuset_hotplug_workfn - handle CPU/memory hotunplug for a cpuset
22862293
*
@@ -2355,8 +2362,10 @@ static void cpuset_hotplug_workfn(struct work_struct *work)
23552362
}
23562363

23572364
/* rebuild sched domains if cpus_allowed has changed */
2358-
if (cpus_updated)
2365+
if (cpus_updated || force_rebuild) {
2366+
force_rebuild = false;
23592367
rebuild_sched_domains();
2368+
}
23602369
}
23612370

23622371
void cpuset_update_active_cpus(bool cpu_online)
@@ -2375,6 +2384,11 @@ void cpuset_update_active_cpus(bool cpu_online)
23752384
schedule_work(&cpuset_hotplug_work);
23762385
}
23772386

2387+
void cpuset_wait_for_hotplug(void)
2388+
{
2389+
flush_work(&cpuset_hotplug_work);
2390+
}
2391+
23782392
/*
23792393
* Keep top_cpuset.mems_allowed tracking node_states[N_MEMORY].
23802394
* Call this routine anytime after node_states[N_MEMORY] changes.

kernel/power/process.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@
1818
#include <linux/workqueue.h>
1919
#include <linux/kmod.h>
2020
#include <trace/events/power.h>
21+
#include <linux/cpuset.h>
2122

22-
/*
23+
/*
2324
* Timeout for stopping processes
2425
*/
2526
unsigned int __read_mostly freeze_timeout_msecs = 20 * MSEC_PER_SEC;
@@ -198,6 +199,8 @@ void thaw_processes(void)
198199
__usermodehelper_set_disable_depth(UMH_FREEZING);
199200
thaw_workqueues();
200201

202+
cpuset_wait_for_hotplug();
203+
201204
read_lock(&tasklist_lock);
202205
for_each_process_thread(g, p) {
203206
/* No other threads should have PF_SUSPEND_TASK set */

kernel/sched/core.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7286,17 +7286,16 @@ static int cpuset_cpu_active(struct notifier_block *nfb, unsigned long action,
72867286
* operation in the resume sequence, just build a single sched
72877287
* domain, ignoring cpusets.
72887288
*/
7289-
num_cpus_frozen--;
7290-
if (likely(num_cpus_frozen)) {
7291-
partition_sched_domains(1, NULL, NULL);
7289+
partition_sched_domains(1, NULL, NULL);
7290+
if (--num_cpus_frozen)
72927291
break;
7293-
}
72947292

72957293
/*
72967294
* This is the last CPU online operation. So fall through and
72977295
* restore the original sched domains by considering the
72987296
* cpuset configurations.
72997297
*/
7298+
cpuset_force_rebuild();
73007299

73017300
case CPU_ONLINE:
73027301
cpuset_update_active_cpus(true);

0 commit comments

Comments
 (0)