diff options
author | Peter Zijlstra <a.p.zijlstra@chello.nl> | 2008-06-05 08:49:58 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-06-10 06:17:28 -0400 |
commit | 7def2be1dc679984f4c4fb3ef19a8a081b2454ec (patch) | |
tree | 5be15957919d095cdbbc9ed3217d9dec939b234b /kernel | |
parent | e958b3600484533ff801920290468adc8135f89d (diff) |
sched: fix hotplug cpus on ia64
Cliff Wickman wrote:
> I built an ia64 kernel from Andrew's tree (2.6.26-rc2-mm1)
> and get a very predictable hotplug cpu problem.
> billberry1:/tmp/cpw # ./dis
> disabled cpu 17
> enabled cpu 17
> billberry1:/tmp/cpw # ./dis
> disabled cpu 17
> enabled cpu 17
> billberry1:/tmp/cpw # ./dis
>
> The script that disables the cpu always hangs (unkillable)
> on the 3rd attempt.
>
> And a bit further:
> The kstopmachine thread always sits on the run queue (real time) for about
> 30 minutes before running.
this fix solves some (but not all) issues between CPU hotplug and
RT bandwidth throttling.
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/sched.c | 15 | ||||
-rw-r--r-- | kernel/sched_rt.c | 109 |
2 files changed, 115 insertions, 9 deletions
diff --git a/kernel/sched.c b/kernel/sched.c index 727bdef76161..e9c24a128655 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
@@ -7513,21 +7513,28 @@ int sched_create_sysfs_power_savings_entries(struct sysdev_class *cls) | |||
7513 | static int update_sched_domains(struct notifier_block *nfb, | 7513 | static int update_sched_domains(struct notifier_block *nfb, |
7514 | unsigned long action, void *hcpu) | 7514 | unsigned long action, void *hcpu) |
7515 | { | 7515 | { |
7516 | int cpu = (int)(long)hcpu; | ||
7517 | |||
7516 | switch (action) { | 7518 | switch (action) { |
7517 | case CPU_UP_PREPARE: | ||
7518 | case CPU_UP_PREPARE_FROZEN: | ||
7519 | case CPU_DOWN_PREPARE: | 7519 | case CPU_DOWN_PREPARE: |
7520 | case CPU_DOWN_PREPARE_FROZEN: | 7520 | case CPU_DOWN_PREPARE_FROZEN: |
7521 | disable_runtime(cpu_rq(cpu)); | ||
7522 | /* fall-through */ | ||
7523 | case CPU_UP_PREPARE: | ||
7524 | case CPU_UP_PREPARE_FROZEN: | ||
7521 | detach_destroy_domains(&cpu_online_map); | 7525 | detach_destroy_domains(&cpu_online_map); |
7522 | free_sched_domains(); | 7526 | free_sched_domains(); |
7523 | return NOTIFY_OK; | 7527 | return NOTIFY_OK; |
7524 | 7528 | ||
7525 | case CPU_UP_CANCELED: | 7529 | |
7526 | case CPU_UP_CANCELED_FROZEN: | ||
7527 | case CPU_DOWN_FAILED: | 7530 | case CPU_DOWN_FAILED: |
7528 | case CPU_DOWN_FAILED_FROZEN: | 7531 | case CPU_DOWN_FAILED_FROZEN: |
7529 | case CPU_ONLINE: | 7532 | case CPU_ONLINE: |
7530 | case CPU_ONLINE_FROZEN: | 7533 | case CPU_ONLINE_FROZEN: |
7534 | enable_runtime(cpu_rq(cpu)); | ||
7535 | /* fall-through */ | ||
7536 | case CPU_UP_CANCELED: | ||
7537 | case CPU_UP_CANCELED_FROZEN: | ||
7531 | case CPU_DEAD: | 7538 | case CPU_DEAD: |
7532 | case CPU_DEAD_FROZEN: | 7539 | case CPU_DEAD_FROZEN: |
7533 | /* | 7540 | /* |
diff --git a/kernel/sched_rt.c b/kernel/sched_rt.c index eaa606071d51..8ae3416e0bb4 100644 --- a/kernel/sched_rt.c +++ b/kernel/sched_rt.c | |||
@@ -286,6 +286,9 @@ static int balance_runtime(struct rt_rq *rt_rq) | |||
286 | continue; | 286 | continue; |
287 | 287 | ||
288 | spin_lock(&iter->rt_runtime_lock); | 288 | spin_lock(&iter->rt_runtime_lock); |
289 | if (iter->rt_runtime == RUNTIME_INF) | ||
290 | goto next; | ||
291 | |||
289 | diff = iter->rt_runtime - iter->rt_time; | 292 | diff = iter->rt_runtime - iter->rt_time; |
290 | if (diff > 0) { | 293 | if (diff > 0) { |
291 | do_div(diff, weight); | 294 | do_div(diff, weight); |
@@ -299,12 +302,105 @@ static int balance_runtime(struct rt_rq *rt_rq) | |||
299 | break; | 302 | break; |
300 | } | 303 | } |
301 | } | 304 | } |
305 | next: | ||
302 | spin_unlock(&iter->rt_runtime_lock); | 306 | spin_unlock(&iter->rt_runtime_lock); |
303 | } | 307 | } |
304 | spin_unlock(&rt_b->rt_runtime_lock); | 308 | spin_unlock(&rt_b->rt_runtime_lock); |
305 | 309 | ||
306 | return more; | 310 | return more; |
307 | } | 311 | } |
312 | |||
313 | static void __disable_runtime(struct rq *rq) | ||
314 | { | ||
315 | struct root_domain *rd = rq->rd; | ||
316 | struct rt_rq *rt_rq; | ||
317 | |||
318 | if (unlikely(!scheduler_running)) | ||
319 | return; | ||
320 | |||
321 | for_each_leaf_rt_rq(rt_rq, rq) { | ||
322 | struct rt_bandwidth *rt_b = sched_rt_bandwidth(rt_rq); | ||
323 | s64 want; | ||
324 | int i; | ||
325 | |||
326 | spin_lock(&rt_b->rt_runtime_lock); | ||
327 | spin_lock(&rt_rq->rt_runtime_lock); | ||
328 | if (rt_rq->rt_runtime == RUNTIME_INF || | ||
329 | rt_rq->rt_runtime == rt_b->rt_runtime) | ||
330 | goto balanced; | ||
331 | spin_unlock(&rt_rq->rt_runtime_lock); | ||
332 | |||
333 | want = rt_b->rt_runtime - rt_rq->rt_runtime; | ||
334 | |||
335 | for_each_cpu_mask(i, rd->span) { | ||
336 | struct rt_rq *iter = sched_rt_period_rt_rq(rt_b, i); | ||
337 | s64 diff; | ||
338 | |||
339 | if (iter == rt_rq) | ||
340 | continue; | ||
341 | |||
342 | spin_lock(&iter->rt_runtime_lock); | ||
343 | if (want > 0) { | ||
344 | diff = min_t(s64, iter->rt_runtime, want); | ||
345 | iter->rt_runtime -= diff; | ||
346 | want -= diff; | ||
347 | } else { | ||
348 | iter->rt_runtime -= want; | ||
349 | want -= want; | ||
350 | } | ||
351 | spin_unlock(&iter->rt_runtime_lock); | ||
352 | |||
353 | if (!want) | ||
354 | break; | ||
355 | } | ||
356 | |||
357 | spin_lock(&rt_rq->rt_runtime_lock); | ||
358 | BUG_ON(want); | ||
359 | balanced: | ||
360 | rt_rq->rt_runtime = RUNTIME_INF; | ||
361 | spin_unlock(&rt_rq->rt_runtime_lock); | ||
362 | spin_unlock(&rt_b->rt_runtime_lock); | ||
363 | } | ||
364 | } | ||
365 | |||
366 | static void disable_runtime(struct rq *rq) | ||
367 | { | ||
368 | unsigned long flags; | ||
369 | |||
370 | spin_lock_irqsave(&rq->lock, flags); | ||
371 | __disable_runtime(rq); | ||
372 | spin_unlock_irqrestore(&rq->lock, flags); | ||
373 | } | ||
374 | |||
375 | static void __enable_runtime(struct rq *rq) | ||
376 | { | ||
377 | struct root_domain *rd = rq->rd; | ||
378 | struct rt_rq *rt_rq; | ||
379 | |||
380 | if (unlikely(!scheduler_running)) | ||
381 | return; | ||
382 | |||
383 | for_each_leaf_rt_rq(rt_rq, rq) { | ||
384 | struct rt_bandwidth *rt_b = sched_rt_bandwidth(rt_rq); | ||
385 | |||
386 | spin_lock(&rt_b->rt_runtime_lock); | ||
387 | spin_lock(&rt_rq->rt_runtime_lock); | ||
388 | rt_rq->rt_runtime = rt_b->rt_runtime; | ||
389 | rt_rq->rt_time = 0; | ||
390 | spin_unlock(&rt_rq->rt_runtime_lock); | ||
391 | spin_unlock(&rt_b->rt_runtime_lock); | ||
392 | } | ||
393 | } | ||
394 | |||
395 | static void enable_runtime(struct rq *rq) | ||
396 | { | ||
397 | unsigned long flags; | ||
398 | |||
399 | spin_lock_irqsave(&rq->lock, flags); | ||
400 | __enable_runtime(rq); | ||
401 | spin_unlock_irqrestore(&rq->lock, flags); | ||
402 | } | ||
403 | |||
308 | #endif | 404 | #endif |
309 | 405 | ||
310 | static inline int rt_se_prio(struct sched_rt_entity *rt_se) | 406 | static inline int rt_se_prio(struct sched_rt_entity *rt_se) |
@@ -334,14 +430,13 @@ static int sched_rt_runtime_exceeded(struct rt_rq *rt_rq) | |||
334 | 430 | ||
335 | #ifdef CONFIG_SMP | 431 | #ifdef CONFIG_SMP |
336 | if (rt_rq->rt_time > runtime) { | 432 | if (rt_rq->rt_time > runtime) { |
337 | int more; | ||
338 | |||
339 | spin_unlock(&rt_rq->rt_runtime_lock); | 433 | spin_unlock(&rt_rq->rt_runtime_lock); |
340 | more = balance_runtime(rt_rq); | 434 | balance_runtime(rt_rq); |
341 | spin_lock(&rt_rq->rt_runtime_lock); | 435 | spin_lock(&rt_rq->rt_runtime_lock); |
342 | 436 | ||
343 | if (more) | 437 | runtime = sched_rt_runtime(rt_rq); |
344 | runtime = sched_rt_runtime(rt_rq); | 438 | if (runtime == RUNTIME_INF) |
439 | return 0; | ||
345 | } | 440 | } |
346 | #endif | 441 | #endif |
347 | 442 | ||
@@ -1174,6 +1269,8 @@ static void rq_online_rt(struct rq *rq) | |||
1174 | if (rq->rt.overloaded) | 1269 | if (rq->rt.overloaded) |
1175 | rt_set_overload(rq); | 1270 | rt_set_overload(rq); |
1176 | 1271 | ||
1272 | __enable_runtime(rq); | ||
1273 | |||
1177 | cpupri_set(&rq->rd->cpupri, rq->cpu, rq->rt.highest_prio); | 1274 | cpupri_set(&rq->rd->cpupri, rq->cpu, rq->rt.highest_prio); |
1178 | } | 1275 | } |
1179 | 1276 | ||
@@ -1183,6 +1280,8 @@ static void rq_offline_rt(struct rq *rq) | |||
1183 | if (rq->rt.overloaded) | 1280 | if (rq->rt.overloaded) |
1184 | rt_clear_overload(rq); | 1281 | rt_clear_overload(rq); |
1185 | 1282 | ||
1283 | __disable_runtime(rq); | ||
1284 | |||
1186 | cpupri_set(&rq->rd->cpupri, rq->cpu, CPUPRI_INVALID); | 1285 | cpupri_set(&rq->rd->cpupri, rq->cpu, CPUPRI_INVALID); |
1187 | } | 1286 | } |
1188 | 1287 | ||