diff options
| author | Peter Zijlstra <peterz@infradead.org> | 2008-04-29 04:02:46 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2008-05-05 17:56:18 -0400 |
| commit | b328ca182f01c2a04b85e0ee8a410720b104fbcc (patch) | |
| tree | d04ba3472a8f57788fb7e6e614e8e6b3c5a79b55 /kernel | |
| parent | 104f64549c961a797ff5f7c59946a7caa335c5b0 (diff) | |
sched: fix hrtick_start_fair and CPU-Hotplug
Gautham R Shenoy reported:
> While running the usual CPU-Hotplug stress tests on linux-2.6.25,
> I noticed the following in the console logs.
>
> This is a wee bit difficult to reproduce. In the past 10 runs I hit this
> only once.
>
> ------------[ cut here ]------------
>
> WARNING: at kernel/sched.c:962 hrtick+0x2e/0x65()
>
> Just wondering if we are doing a good job at handling the cancellation
> of any per-cpu scheduler timers during CPU-Hotplug.
This looks like its indeed not cancelled at all and migrates the it to
another cpu. Fix it via a proper hotplug notifier mechanism.
Reported-by: Gautham R Shenoy <ego@in.ibm.com>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: stable@kernel.org
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/sched.c | 66 |
1 files changed, 65 insertions, 1 deletions
diff --git a/kernel/sched.c b/kernel/sched.c index d941ddc9ec1d..bee9cbe13c15 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
| @@ -1191,6 +1191,7 @@ static inline void resched_rq(struct rq *rq) | |||
| 1191 | enum { | 1191 | enum { |
| 1192 | HRTICK_SET, /* re-programm hrtick_timer */ | 1192 | HRTICK_SET, /* re-programm hrtick_timer */ |
| 1193 | HRTICK_RESET, /* not a new slice */ | 1193 | HRTICK_RESET, /* not a new slice */ |
| 1194 | HRTICK_BLOCK, /* stop hrtick operations */ | ||
| 1194 | }; | 1195 | }; |
| 1195 | 1196 | ||
| 1196 | /* | 1197 | /* |
| @@ -1202,6 +1203,8 @@ static inline int hrtick_enabled(struct rq *rq) | |||
| 1202 | { | 1203 | { |
| 1203 | if (!sched_feat(HRTICK)) | 1204 | if (!sched_feat(HRTICK)) |
| 1204 | return 0; | 1205 | return 0; |
| 1206 | if (unlikely(test_bit(HRTICK_BLOCK, &rq->hrtick_flags))) | ||
| 1207 | return 0; | ||
| 1205 | return hrtimer_is_hres_active(&rq->hrtick_timer); | 1208 | return hrtimer_is_hres_active(&rq->hrtick_timer); |
| 1206 | } | 1209 | } |
| 1207 | 1210 | ||
| @@ -1284,7 +1287,63 @@ static enum hrtimer_restart hrtick(struct hrtimer *timer) | |||
| 1284 | return HRTIMER_NORESTART; | 1287 | return HRTIMER_NORESTART; |
| 1285 | } | 1288 | } |
| 1286 | 1289 | ||
| 1287 | static inline void init_rq_hrtick(struct rq *rq) | 1290 | static void hotplug_hrtick_disable(int cpu) |
| 1291 | { | ||
| 1292 | struct rq *rq = cpu_rq(cpu); | ||
| 1293 | unsigned long flags; | ||
| 1294 | |||
| 1295 | spin_lock_irqsave(&rq->lock, flags); | ||
| 1296 | rq->hrtick_flags = 0; | ||
| 1297 | __set_bit(HRTICK_BLOCK, &rq->hrtick_flags); | ||
| 1298 | spin_unlock_irqrestore(&rq->lock, flags); | ||
| 1299 | |||
| 1300 | hrtick_clear(rq); | ||
| 1301 | } | ||
| 1302 | |||
| 1303 | static void hotplug_hrtick_enable(int cpu) | ||
| 1304 | { | ||
| 1305 | struct rq *rq = cpu_rq(cpu); | ||
| 1306 | unsigned long flags; | ||
| 1307 | |||
| 1308 | spin_lock_irqsave(&rq->lock, flags); | ||
| 1309 | __clear_bit(HRTICK_BLOCK, &rq->hrtick_flags); | ||
| 1310 | spin_unlock_irqrestore(&rq->lock, flags); | ||
| 1311 | } | ||
| 1312 | |||
| 1313 | static int | ||
| 1314 | hotplug_hrtick(struct notifier_block *nfb, unsigned long action, void *hcpu) | ||
| 1315 | { | ||
| 1316 | int cpu = (int)(long)hcpu; | ||
| 1317 | |||
| 1318 | switch (action) { | ||
| 1319 | case CPU_UP_CANCELED: | ||
| 1320 | case CPU_UP_CANCELED_FROZEN: | ||
| 1321 | case CPU_DOWN_PREPARE: | ||
| 1322 | case CPU_DOWN_PREPARE_FROZEN: | ||
| 1323 | case CPU_DEAD: | ||
| 1324 | case CPU_DEAD_FROZEN: | ||
| 1325 | hotplug_hrtick_disable(cpu); | ||
| 1326 | return NOTIFY_OK; | ||
| 1327 | |||
| 1328 | case CPU_UP_PREPARE: | ||
| 1329 | case CPU_UP_PREPARE_FROZEN: | ||
| 1330 | case CPU_DOWN_FAILED: | ||
| 1331 | case CPU_DOWN_FAILED_FROZEN: | ||
| 1332 | case CPU_ONLINE: | ||
| 1333 | case CPU_ONLINE_FROZEN: | ||
| 1334 | hotplug_hrtick_enable(cpu); | ||
| 1335 | return NOTIFY_OK; | ||
| 1336 | } | ||
| 1337 | |||
| 1338 | return NOTIFY_DONE; | ||
| 1339 | } | ||
| 1340 | |||
| 1341 | static void init_hrtick(void) | ||
| 1342 | { | ||
| 1343 | hotcpu_notifier(hotplug_hrtick, 0); | ||
| 1344 | } | ||
| 1345 | |||
| 1346 | static void init_rq_hrtick(struct rq *rq) | ||
| 1288 | { | 1347 | { |
| 1289 | rq->hrtick_flags = 0; | 1348 | rq->hrtick_flags = 0; |
| 1290 | hrtimer_init(&rq->hrtick_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | 1349 | hrtimer_init(&rq->hrtick_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); |
| @@ -1321,6 +1380,10 @@ static inline void init_rq_hrtick(struct rq *rq) | |||
| 1321 | void hrtick_resched(void) | 1380 | void hrtick_resched(void) |
| 1322 | { | 1381 | { |
| 1323 | } | 1382 | } |
| 1383 | |||
| 1384 | static inline void init_hrtick(void) | ||
| 1385 | { | ||
| 1386 | } | ||
| 1324 | #endif | 1387 | #endif |
| 1325 | 1388 | ||
| 1326 | /* | 1389 | /* |
| @@ -7943,6 +8006,7 @@ void __init sched_init_smp(void) | |||
| 7943 | put_online_cpus(); | 8006 | put_online_cpus(); |
| 7944 | /* XXX: Theoretical race here - CPU may be hotplugged now */ | 8007 | /* XXX: Theoretical race here - CPU may be hotplugged now */ |
| 7945 | hotcpu_notifier(update_sched_domains, 0); | 8008 | hotcpu_notifier(update_sched_domains, 0); |
| 8009 | init_hrtick(); | ||
| 7946 | 8010 | ||
| 7947 | /* Move init over to a non-isolated CPU */ | 8011 | /* Move init over to a non-isolated CPU */ |
| 7948 | if (set_cpus_allowed_ptr(current, &non_isolated_cpus) < 0) | 8012 | if (set_cpus_allowed_ptr(current, &non_isolated_cpus) < 0) |
