[libvirt] [PATCH] Automatically pause QEMU guests when an error occurs
Daniel Veillard
veillard at redhat.com
Wed Feb 17 21:32:24 UTC 2010
On Tue, Feb 16, 2010 at 05:04:04PM +0000, Daniel P. Berrange wrote:
> With the QMP mode monitor, it is possible to get a notification
> that a disk I/O error occurs ina guest. This patch enables such
> reporting and when receiving an error updates libvirt's view
> of the guest to indicate that it is now paused. It also emits
> an event
>
> VIR_DOMAIN_EVENT_SUSPENDED
>
> with a detail of:
>
> VIR_DOMAIN_EVENT_SUSPENDED_IOERROR
>
> * include/libvirt/libvirt.h.in: Add VIR_DOMAIN_EVENT_SUSPENDED_IOERROR
> * src/qemu/qemu_driver.c: Update VM state to paused when IO error
> occurrs
> * src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h,
> src/qemu/qemu_monitor_json.c: Wire up handlers for disk IO errors
> ---
> include/libvirt/libvirt.h.in | 1 +
> src/qemu/qemu_conf.c | 7 +++++--
> src/qemu/qemu_conf.h | 2 +-
> src/qemu/qemu_driver.c | 38 +++++++++++++++++++++++++++++++++++---
> src/qemu/qemu_monitor.c | 16 ++++++++++++++++
> src/qemu/qemu_monitor.h | 5 +++++
> src/qemu/qemu_monitor_json.c | 6 ++++++
> 7 files changed, 69 insertions(+), 6 deletions(-)
>
> diff --git a/include/libvirt/libvirt.h.in b/include/libvirt/libvirt.h.in
> index 260505e..b7a6922 100644
> --- a/include/libvirt/libvirt.h.in
> +++ b/include/libvirt/libvirt.h.in
> @@ -1361,6 +1361,7 @@ typedef enum {
> typedef enum {
> VIR_DOMAIN_EVENT_SUSPENDED_PAUSED = 0, /* Normal suspend due to admin pause */
> VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED = 1, /* Suspended for offline migration */
> + VIR_DOMAIN_EVENT_SUSPENDED_IOERROR = 2, /* Suspended due to a disk I/O error */
> } virDomainEventSuspendedDetailType;
>
> /**
> diff --git a/src/qemu/qemu_conf.c b/src/qemu/qemu_conf.c
> index c9fe55b..20076bc 100644
> --- a/src/qemu/qemu_conf.c
> +++ b/src/qemu/qemu_conf.c
> @@ -2385,6 +2385,9 @@ qemuBuildDriveStr(virDomainDiskDefPtr disk,
> } else if (disk->shared && !disk->readonly) {
> virBufferAddLit(&opt, ",cache=off");
> }
> + if (qemuCmdFlags & QEMUD_CMD_FLAG_MONITOR_JSON) {
> + virBufferVSprintf(&opt, ",werror=stop,rerror=stop");
> + }
>
> if (virBufferError(&opt)) {
> virReportOOMError();
> @@ -2400,7 +2403,7 @@ error:
>
>
> char *
> -qemuBuildDriveDevStr(virDomainDiskDefPtr disk)
> +qemuBuildDriveDevStr(virDomainDiskDefPtr disk, int qemuCmdFlags ATTRIBUTE_UNUSED)
> {
> virBuffer opt = VIR_BUFFER_INITIALIZER;
> const char *bus = virDomainDiskQEMUBusTypeToString(disk->bus);
> @@ -3578,7 +3581,7 @@ int qemudBuildCommandLine(virConnectPtr conn,
> } else {
> ADD_ARG_LIT("-device");
>
> - if (!(optstr = qemuBuildDriveDevStr(disk)))
> + if (!(optstr = qemuBuildDriveDevStr(disk, qemuCmdFlags)))
> goto error;
> ADD_ARG(optstr);
> }
> diff --git a/src/qemu/qemu_conf.h b/src/qemu/qemu_conf.h
> index 7041489..ec8033a 100644
> --- a/src/qemu/qemu_conf.h
> +++ b/src/qemu/qemu_conf.h
> @@ -214,7 +214,7 @@ char *qemuBuildDriveStr(virDomainDiskDefPtr disk,
> unsigned long long qemuCmdFlags);
>
> /* Current, best practice */
> -char * qemuBuildDriveDevStr(virDomainDiskDefPtr disk);
> +char * qemuBuildDriveDevStr(virDomainDiskDefPtr disk, int qemuCmdFlags);
> /* Current, best practice */
> char * qemuBuildControllerDevStr(virDomainControllerDefPtr def);
>
> diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
> index 77306f3..23073bc 100644
> --- a/src/qemu/qemu_driver.c
> +++ b/src/qemu/qemu_driver.c
> @@ -824,9 +824,41 @@ cleanup:
> return ret;
> }
>
> +
> +static int
> +qemuHandleDiskIOError(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
> + virDomainObjPtr vm,
> + const char *diskalias ATTRIBUTE_UNUSED)
> +{
> + struct qemud_driver *driver = qemu_driver;
> + virDomainEventPtr event = NULL;
> +
> + VIR_DEBUG("Received IO error on %p '%s': %s", vm, vm->def->name, diskalias);
> + virDomainObjLock(vm);
> +
> + vm->state = VIR_DOMAIN_PAUSED;
> + event = virDomainEventNewFromObj(vm,
> + VIR_DOMAIN_EVENT_SUSPENDED,
> + VIR_DOMAIN_EVENT_SUSPENDED_IOERROR);
> +
> + if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
> + VIR_WARN("Unable to save status on vm %s after IO error", vm->def->name);
> +
> + virDomainObjUnlock(vm);
> +
> + if (event) {
> + qemuDriverLock(driver);
> + qemuDomainEventQueue(driver, event);
> + qemuDriverUnlock(driver);
> + }
> + return 0;
> +}
> +
> +
> static qemuMonitorCallbacks monitorCallbacks = {
> .eofNotify = qemuHandleMonitorEOF,
> .diskSecretLookup = findVolumeQcowPassphrase,
> + .diskIOError = qemuHandleDiskIOError,
> };
>
> static int
> @@ -5353,7 +5385,7 @@ static int qemudDomainAttachPciDiskDevice(struct qemud_driver *driver,
> if (!(drivestr = qemuBuildDriveStr(disk, 0, qemuCmdFlags)))
> goto error;
>
> - if (!(devstr = qemuBuildDriveDevStr(disk)))
> + if (!(devstr = qemuBuildDriveDevStr(disk, qemuCmdFlags)))
> goto error;
> }
>
> @@ -5548,7 +5580,7 @@ static int qemudDomainAttachSCSIDisk(struct qemud_driver *driver,
> if (qemuCmdFlags & QEMUD_CMD_FLAG_DEVICE) {
> if (qemuAssignDeviceDiskAlias(disk, qemuCmdFlags) < 0)
> goto error;
> - if (!(devstr = qemuBuildDriveDevStr(disk)))
> + if (!(devstr = qemuBuildDriveDevStr(disk, qemuCmdFlags)))
> goto error;
> }
>
> @@ -5652,7 +5684,7 @@ static int qemudDomainAttachUsbMassstorageDevice(struct qemud_driver *driver,
> goto error;
> if (!(drivestr = qemuBuildDriveStr(disk, 0, qemuCmdFlags)))
> goto error;
> - if (!(devstr = qemuBuildDriveDevStr(disk)))
> + if (!(devstr = qemuBuildDriveDevStr(disk, qemuCmdFlags)))
> goto error;
> }
>
> diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
> index b88532c..3f8772a 100644
> --- a/src/qemu/qemu_monitor.c
> +++ b/src/qemu/qemu_monitor.c
> @@ -791,6 +791,22 @@ int qemuMonitorEmitStop(qemuMonitorPtr mon)
> }
>
>
> +int qemuMonitorEmitDiskIOError(qemuMonitorPtr mon, const char *deviceAlias)
> +{
> + int ret = -1;
> + VIR_DEBUG("mon=%p deviceAlias=%s", mon, deviceAlias);
> +
> + qemuMonitorRef(mon);
> + qemuMonitorUnlock(mon);
> + if (mon->cb && mon->cb->diskIOError)
> + ret = mon->cb->diskIOError(mon, mon->vm, deviceAlias);
> + qemuMonitorLock(mon);
> + qemuMonitorUnref(mon);
> +
> + return ret;
> +}
> +
> +
> int qemuMonitorSetCapabilities(qemuMonitorPtr mon)
> {
> int ret;
> diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
> index 0ac3957..6b9fd50 100644
> --- a/src/qemu/qemu_monitor.h
> +++ b/src/qemu/qemu_monitor.h
> @@ -86,6 +86,10 @@ struct _qemuMonitorCallbacks {
> virDomainObjPtr vm);
> int (*domainStop)(qemuMonitorPtr mon,
> virDomainObjPtr vm);
> +
> + int (*diskIOError)(qemuMonitorPtr mon,
> + virDomainObjPtr vm,
> + const char *diskAlias);
> };
>
>
> @@ -122,6 +126,7 @@ int qemuMonitorEmitShutdown(qemuMonitorPtr mon);
> int qemuMonitorEmitReset(qemuMonitorPtr mon);
> int qemuMonitorEmitPowerdown(qemuMonitorPtr mon);
> int qemuMonitorEmitStop(qemuMonitorPtr mon);
> +int qemuMonitorEmitDiskIOError(qemuMonitorPtr mon, const char *deviceAlias);
>
> int qemuMonitorStartCPUs(qemuMonitorPtr mon,
> virConnectPtr conn);
> diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
> index 49e0370..c20d063 100644
> --- a/src/qemu/qemu_monitor_json.c
> +++ b/src/qemu/qemu_monitor_json.c
> @@ -49,6 +49,7 @@ static void qemuMonitorJSONHandleShutdown(qemuMonitorPtr mon, virJSONValuePtr da
> static void qemuMonitorJSONHandleReset(qemuMonitorPtr mon, virJSONValuePtr data);
> static void qemuMonitorJSONHandlePowerdown(qemuMonitorPtr mon, virJSONValuePtr data);
> static void qemuMonitorJSONHandleStop(qemuMonitorPtr mon, virJSONValuePtr data);
> +static void qemuMonitorJSONHandleDiskIOError(qemuMonitorPtr mon, virJSONValuePtr data);
>
> struct {
> const char *type;
> @@ -58,6 +59,7 @@ struct {
> { "RESET", qemuMonitorJSONHandleReset, },
> { "POWERDOWN", qemuMonitorJSONHandlePowerdown, },
> { "STOP", qemuMonitorJSONHandleStop, },
> + { "BLOCK_IO_ERROR", qemuMonitorJSONHandleDiskIOError, },
> };
>
>
> @@ -495,6 +497,10 @@ static void qemuMonitorJSONHandleStop(qemuMonitorPtr mon, virJSONValuePtr data A
> qemuMonitorEmitStop(mon);
> }
>
> +static void qemuMonitorJSONHandleDiskIOError(qemuMonitorPtr mon, virJSONValuePtr data ATTRIBUTE_UNUSED)
> +{
> + qemuMonitorEmitDiskIOError(mon, NULL);
> +}
>
> int
> qemuMonitorJSONSetCapabilities(qemuMonitorPtr mon)
> --
> 1.6.2.5
>
ACK, I think that adding this unconditionally if supported is the
right thing to do.
Daniel
--
Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/
daniel at veillard.com | Rpmfind RPM search engine http://rpmfind.net/
http://veillard.com/ | virtualization library http://libvirt.org/
More information about the libvir-list
mailing list