Oops in clockevents_notify()'s BUG_ON

From: OGAWA Hirofumi
Date: Fri Dec 25 2009 - 13:11:15 EST


Hi,

In poweroff process, I've got Oops in clockevents_notify()'s
BUG_ON. After some investigation, "hpet" clockevent hits BUG_ON().

On x86_64, hpet_legacy_clockevent_register() registers clockevent as


hpet_legacy_clockevent_register()
[...]
/*
* Start hpet with the boot cpu mask and make it
* global after the IO_APIC has been initialized.
*/
hpet_clockevent.cpumask = cpumask_of(smp_processor_id());
clockevents_register_device(&hpet_clockevent);


The comment says "boot cpu". But it's not true on x86_64, and one of my
machine is "second cpu" actually. [This might be one of problems]

And on that machine, hpet is used as oneshot_broadcast.

Then, in poweroff process, it calls cpu_down() for the nonboot cpus if
CONFIG_HOTPLUG_CPU is y. And clockevents_notify() checks clockevent
in clockevent_devices

So, the following code see hpet for broadcast on clockevent_devices. And
like mentioned above, hpet has cpumask like percpu clockevent, but it
is using as broadcast. So, this hits BUG_ON().


clockevents_notify()
[...]
list_for_each_entry_safe(dev, tmp, &clockevent_devices, list) {
if (cpumask_test_cpu(cpu, dev->cpumask) &&
cpumask_weight(dev->cpumask) == 1) {
BUG_ON(dev->mode != CLOCK_EVT_MODE_UNUSED);
list_del(&dev->list);
}
}


Well, so, attached patch fixes the problem on my machine. But I'm not
sure if it's right thing. Can you check it?

Thanks.
--
OGAWA Hirofumi <hirofumi@xxxxxxxxxxxxxxxxxx>



Signed-off-by: OGAWA Hirofumi <hirofumi@xxxxxxxxxxxxxxxxxx>
---

kernel/time/clockevents.c | 3 +++
1 file changed, 3 insertions(+)

diff -puN kernel/time/clockevents.c~hpet-shutdown-fix kernel/time/clockevents.c
--- linux-2.6/kernel/time/clockevents.c~hpet-shutdown-fix 2009-12-26 02:47:07.000000000 +0900
+++ linux-2.6-hirofumi/kernel/time/clockevents.c 2009-12-26 02:47:07.000000000 +0900
@@ -258,6 +258,9 @@ void clockevents_notify(unsigned long re
*/
cpu = *((int *)arg);
list_for_each_entry_safe(dev, tmp, &clockevent_devices, list) {
+ if (tick_is_broadcast_device(dev))
+ continue;
+
if (cpumask_test_cpu(cpu, dev->cpumask) &&
cpumask_weight(dev->cpumask) == 1) {
BUG_ON(dev->mode != CLOCK_EVT_MODE_UNUSED);
_
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/