summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorDinakar Guniguntala <dino@in.ibm.com>2009-10-22 18:08:00 +0530
committerThomas Gleixner <tglx@linutronix.de>2009-10-29 09:08:26 +0100
commit465a3c40221645220ddd83a612d3d695ff4a2468 (patch)
treed36c34b97bf02bd6bd98d7d313608e1584e8caf9 /kernel
parent1e2ea8a1c5fbcfea1ea85cf2c33475f08ed2c46c (diff)
downloadlwn-465a3c40221645220ddd83a612d3d695ff4a2468.tar.gz
lwn-465a3c40221645220ddd83a612d3d695ff4a2468.zip
sched: Fix dynamic power-balancing crash
This crash: [ 1774.088275] divide error: 0000 [#1] SMP [ 1774.100355] CPU 13 [ 1774.102498] Modules linked in: [ 1774.105631] Pid: 30881, comm: hackbench Not tainted 2.6.31-rc8-tip-01308-g484d664-dirty #1629 X8DTN [ 1774.114807] RIP: 0010:[<ffffffff81041c38>] [<ffffffff81041c38>] sched_balance_self+0x19b/0x2d4 Triggers because update_group_power() modifies the sd tree and does temporary calculations there - not considering that other CPUs could observe intermediate values, such as the zero initial value. Calculate it in a temporary variable instead. (we need no memory barrier as these are all statistical values anyway) Got the same oops with the backport to -rt Signed-off-by: Dinakar Guniguntala <dino@in.ibm.com> Cc: John Stultz <johnstul@us.ibm.com> Cc: Darren Hart <dvhltc@us.ibm.com> Cc: John Kacur <jkacur@redhat.com> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/sched.c7
1 files changed, 5 insertions, 2 deletions
diff --git a/kernel/sched.c b/kernel/sched.c
index 2b346fbd10ae..c78dcfed504b 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -3864,19 +3864,22 @@ static void update_group_power(struct sched_domain *sd, int cpu)
{
struct sched_domain *child = sd->child;
struct sched_group *group, *sdg = sd->groups;
+ unsigned long power;
if (!child) {
update_cpu_power(sd, cpu);
return;
}
- sdg->cpu_power = 0;
+ power = 0;
group = child->groups;
do {
- sdg->cpu_power += group->cpu_power;
+ power += group->cpu_power;
group = group->next;
} while (group != child->groups);
+
+ sdg->cpu_power = power;
}
/**