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 | |
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>
-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) |