diff options
| -rw-r--r-- | kernel/sched/core.c | 29 |
1 files changed, 26 insertions, 3 deletions
diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 0902e4d72671..9b786704d34b 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c | |||
| @@ -5183,24 +5183,47 @@ static void migrate_tasks(struct rq *dead_rq) | |||
| 5183 | break; | 5183 | break; |
| 5184 | 5184 | ||
| 5185 | /* | 5185 | /* |
| 5186 | * Ensure rq->lock covers the entire task selection | 5186 | * pick_next_task assumes pinned rq->lock. |
| 5187 | * until the migration. | ||
| 5188 | */ | 5187 | */ |
| 5189 | lockdep_pin_lock(&rq->lock); | 5188 | lockdep_pin_lock(&rq->lock); |
| 5190 | next = pick_next_task(rq, &fake_task); | 5189 | next = pick_next_task(rq, &fake_task); |
| 5191 | BUG_ON(!next); | 5190 | BUG_ON(!next); |
| 5192 | next->sched_class->put_prev_task(rq, next); | 5191 | next->sched_class->put_prev_task(rq, next); |
| 5193 | 5192 | ||
| 5193 | /* | ||
| 5194 | * Rules for changing task_struct::cpus_allowed are holding | ||
| 5195 | * both pi_lock and rq->lock, such that holding either | ||
| 5196 | * stabilizes the mask. | ||
| 5197 | * | ||
| 5198 | * Drop rq->lock is not quite as disastrous as it usually is | ||
| 5199 | * because !cpu_active at this point, which means load-balance | ||
| 5200 | * will not interfere. Also, stop-machine. | ||
| 5201 | */ | ||
| 5202 | lockdep_unpin_lock(&rq->lock); | ||
| 5203 | raw_spin_unlock(&rq->lock); | ||
| 5204 | raw_spin_lock(&next->pi_lock); | ||
| 5205 | raw_spin_lock(&rq->lock); | ||
| 5206 | |||
| 5207 | /* | ||
| 5208 | * Since we're inside stop-machine, _nothing_ should have | ||
| 5209 | * changed the task, WARN if weird stuff happened, because in | ||
| 5210 | * that case the above rq->lock drop is a fail too. | ||
| 5211 | */ | ||
| 5212 | if (WARN_ON(task_rq(next) != rq || !task_on_rq_queued(next))) { | ||
| 5213 | raw_spin_unlock(&next->pi_lock); | ||
| 5214 | continue; | ||
| 5215 | } | ||
| 5216 | |||
| 5194 | /* Find suitable destination for @next, with force if needed. */ | 5217 | /* Find suitable destination for @next, with force if needed. */ |
| 5195 | dest_cpu = select_fallback_rq(dead_rq->cpu, next); | 5218 | dest_cpu = select_fallback_rq(dead_rq->cpu, next); |
| 5196 | 5219 | ||
| 5197 | lockdep_unpin_lock(&rq->lock); | ||
| 5198 | rq = __migrate_task(rq, next, dest_cpu); | 5220 | rq = __migrate_task(rq, next, dest_cpu); |
| 5199 | if (rq != dead_rq) { | 5221 | if (rq != dead_rq) { |
| 5200 | raw_spin_unlock(&rq->lock); | 5222 | raw_spin_unlock(&rq->lock); |
| 5201 | rq = dead_rq; | 5223 | rq = dead_rq; |
| 5202 | raw_spin_lock(&rq->lock); | 5224 | raw_spin_lock(&rq->lock); |
| 5203 | } | 5225 | } |
| 5226 | raw_spin_unlock(&next->pi_lock); | ||
| 5204 | } | 5227 | } |
| 5205 | 5228 | ||
| 5206 | rq->stop = stop; | 5229 | rq->stop = stop; |
