diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 836a0e5664a0..d3a864d3f201 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -2091,7 +2091,15 @@ void force_compatible_cpus_allowed_ptr(struct task_struct *p) cpumask_var_t new_mask; const struct cpumask *override_mask = task_cpu_possible_mask(p); - if (!alloc_cpumask_var(&new_mask, GFP_KERNEL)) + alloc_cpumask_var(&new_mask, GFP_KERNEL); + + /* + * __migrate_task() can fail silently in the face of concurrent + * offlining of the chosen destination CPU, so take the hotplug + * lock to ensure that the migration succeeds. + */ + cpus_read_lock(); + if (!cpumask_available(new_mask)) goto out_set_mask; if (!restrict_cpus_allowed_ptr(p, new_mask, override_mask)) @@ -2111,8 +2119,9 @@ void force_compatible_cpus_allowed_ptr(struct task_struct *p) cpumask_pr_args(override_mask)); } - set_cpus_allowed_ptr(p, override_mask); + WARN_ON(set_cpus_allowed_ptr(p, override_mask)); out_free_mask: + cpus_read_unlock(); free_cpumask_var(new_mask); }