diff options
author | Richard W.M. Jones <rjones@redhat.com> | 2010-09-24 16:08:06 +0100 |
---|---|---|
committer | Blue Swirl <blauwirbel@gmail.com> | 2010-12-12 13:10:55 +0000 |
commit | 36888c6335422f07bbc50bf3443a39f24b90c7c6 (patch) | |
tree | dc83339d92d931d8e3e96c82052e507975d40ac6 /hw/wdt_i6300esb.c | |
parent | 962630f207a33b7de4316022884b5241e05491cd (diff) |
Watchdog: disable watchdog timer when hard-rebooting a guest.
This commit causes the watchdog timer to be reset when a guest is
hard-rebooted.
The failure case previously was as follows:
(a) guest boots, watchdog is enabled
(b) guest does a reset eg:
echo 'b' > /proc/sysrq-trigger
(note that an ordinary /sbin/reboot wouldn't hit this case
since as the watchdog daemon is shut down, the daemon would
properly disable the watchdog device)
(c) the reboot takes longer than the remaining time on the
watchdog
(d) the watchdog therefore fires during the reboot
(e) probably the VM would just reboot again at this point which
is pretty benign, but it could depend on the action that the
user had selected for the watchdog
Now we use the qdev reset function to register a reset handler
which disables the timer. Note the handler is called _either_
just after init _or_ when the guest reboots.
In the i6300esb case there is a small refactoring of the code so
that the device's internal state is now fully restored to defaults
on a reboot.
Signed-off-by: Richard W.M. Jones <rjones@redhat.com>
Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
Diffstat (limited to 'hw/wdt_i6300esb.c')
-rw-r--r-- | hw/wdt_i6300esb.c | 5 |
1 files changed, 4 insertions, 1 deletions
diff --git a/hw/wdt_i6300esb.c b/hw/wdt_i6300esb.c index 8443b41890..90bf5f65a7 100644 --- a/hw/wdt_i6300esb.c +++ b/hw/wdt_i6300esb.c @@ -149,6 +149,8 @@ static void i6300esb_reset(DeviceState *dev) i6300esb_disable_timer(d); + /* NB: Don't change d->previous_reboot_flag in this function. */ + d->reboot_enabled = 1; d->clock_scale = CLOCK_SCALE_1KHZ; d->int_type = INT_TYPE_IRQ; @@ -159,7 +161,6 @@ static void i6300esb_reset(DeviceState *dev) d->timer2_preload = 0xfffff; d->stage = 1; d->unlock_state = 0; - d->previous_reboot_flag = 0; } /* This function is called when the watchdog expires. Note that @@ -193,6 +194,7 @@ static void i6300esb_timer_expired(void *vp) if (d->reboot_enabled) { d->previous_reboot_flag = 1; watchdog_perform_action(); /* This reboots, exits, etc */ + i6300esb_reset(&d->dev.qdev); } /* In "free running mode" we start stage 1 again. */ @@ -409,6 +411,7 @@ static int i6300esb_init(PCIDevice *dev) i6300esb_debug("I6300State = %p\n", d); d->timer = qemu_new_timer(vm_clock, i6300esb_timer_expired, d); + d->previous_reboot_flag = 0; pci_conf = d->dev.config; pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_INTEL); |