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/sched_rt.c | |
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/sched_rt.c')
-rw-r--r-- | kernel/sched_rt.c | 109 |
1 files changed, 104 insertions, 5 deletions
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 | ||