From 4bb4109f7b012feedf8b0fb22a9ccd41883e9b7b Mon Sep 17 00:00:00 2001 From: Laine Stump Date: Tue, 4 Oct 2011 14:17:06 -0400 Subject: [PATCH] qemu: add separate rerror_policy for disk errors Previously libvirt's disk device XML only had a single attribute, error_policy, to control both read and write error policy, but qemu has separate options for controlling read and write. In one case (enospc) a policy is allowed for write errors but not read errors. This patch adds a separate attribute that sets only the read error policy. If just error_policy is set, it will apply to both read and write error policy (previous behavior), but if the new rerror_policy attribute is set, it will override error_policy for read errors only. Possible values for rerror_policy are "stop", "report", and "ignore" ("report" is the qemu-controlled default for rerror_policy when error_policy isn't specified). For consistency, the value "report" has been added to the possible values for error_policy as well. --- docs/formatdomain.html.in | 18 ++++++++-- docs/schemas/domaincommon.rng | 13 ++++++++ src/conf/domain_conf.c | 17 ++++++++++ src/conf/domain_conf.h | 4 ++- src/qemu/qemu_command.c | 17 ++++++++-- tests/qemuargv2xmltest.c | 1 + ...sk-drive-error-policy-wreport-rignore.args | 6 ++++ ...isk-drive-error-policy-wreport-rignore.xml | 33 +++++++++++++++++++ tests/qemuxml2argvtest.c | 2 ++ 9 files changed, 105 insertions(+), 6 deletions(-) create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-drive-error-policy-wreport-rignore.args create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-drive-error-policy-wreport-rignore.xml diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 593adcbacc..b15f9e20f1 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -1008,9 +1008,21 @@
  • The optional error_policy attribute controls - how the hypervisor will behave on an error, possible - values are "stop", "ignore", and "enospace". - Since 0.8.0 + how the hypervisor will behave on a disk read or write + error, possible values are "stop", "report", "ignore", and + "enospace".Since 0.8.0, "report" since + 0.9.7 The default setting of error_policy is "report". + There is also an + optional rerror_policy that controls behavior + for read errors only. Since + 0.9.7. If no rerror_policy is given, error_policy + is used for both read and write errors. If rerror_policy + is given, it overrides the error_policy for + read errors. Also note that "enospace" is not a valid + policy for read errors, so if error_policy is + set to "enospace" and no rerror_policy is + given, the read error policy will be left at its default, + which is "report".
  • The optional io attribute controls specific diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index cffaac2fe7..492a41dee2 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -819,6 +819,9 @@ + + + @@ -856,11 +859,21 @@ stop + report ignore enospace + + + + stop + report + ignore + + + diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 55e6c3433d..a537251f3d 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -176,6 +176,7 @@ VIR_ENUM_IMPL(virDomainDiskCache, VIR_DOMAIN_DISK_CACHE_LAST, VIR_ENUM_IMPL(virDomainDiskErrorPolicy, VIR_DOMAIN_DISK_ERROR_POLICY_LAST, "default", "stop", + "report", "ignore", "enospace") @@ -2297,6 +2298,7 @@ virDomainDiskDefParseXML(virCapsPtr caps, char *bus = NULL; char *cachetag = NULL; char *error_policy = NULL; + char *rerror_policy = NULL; char *iotag = NULL; char *ioeventfd = NULL; char *event_idx = NULL; @@ -2416,6 +2418,7 @@ virDomainDiskDefParseXML(virCapsPtr caps, driverType = virXMLPropString(cur, "type"); cachetag = virXMLPropString(cur, "cache"); error_policy = virXMLPropString(cur, "error_policy"); + rerror_policy = virXMLPropString(cur, "rerror_policy"); iotag = virXMLPropString(cur, "io"); ioeventfd = virXMLPropString(cur, "ioeventfd"); event_idx = virXMLPropString(cur, "event_idx"); @@ -2560,6 +2563,16 @@ virDomainDiskDefParseXML(virCapsPtr caps, goto error; } + if (rerror_policy && + (((def->rerror_policy + = virDomainDiskErrorPolicyTypeFromString(rerror_policy)) <= 0) || + (def->rerror_policy == VIR_DOMAIN_DISK_ERROR_POLICY_ENOSPACE))) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, + _("unknown disk read error policy '%s'"), + rerror_policy); + goto error; + } + if (iotag) { if ((def->iomode = virDomainDiskIoTypeFromString(iotag)) < 0 || def->iomode == VIR_DOMAIN_DISK_IO_DEFAULT) { @@ -2667,6 +2680,7 @@ cleanup: VIR_FREE(driverName); VIR_FREE(cachetag); VIR_FREE(error_policy); + VIR_FREE(rerror_policy); VIR_FREE(iotag); VIR_FREE(ioeventfd); VIR_FREE(event_idx); @@ -9127,6 +9141,7 @@ virDomainDiskDefFormat(virBufferPtr buf, const char *bus = virDomainDiskBusTypeToString(def->bus); const char *cachemode = virDomainDiskCacheTypeToString(def->cachemode); const char *error_policy = virDomainDiskErrorPolicyTypeToString(def->error_policy); + const char *rerror_policy = virDomainDiskErrorPolicyTypeToString(def->rerror_policy); const char *iomode = virDomainDiskIoTypeToString(def->iomode); const char *ioeventfd = virDomainIoEventFdTypeToString(def->ioeventfd); const char *event_idx = virDomainVirtioEventIdxTypeToString(def->event_idx); @@ -9177,6 +9192,8 @@ virDomainDiskDefFormat(virBufferPtr buf, virBufferAsprintf(buf, " cache='%s'", cachemode); if (def->error_policy) virBufferAsprintf(buf, " error_policy='%s'", error_policy); + if (def->rerror_policy) + virBufferAsprintf(buf, " rerror_policy='%s'", rerror_policy); if (def->iomode) virBufferAsprintf(buf, " io='%s'", iomode); if (def->ioeventfd) diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index bc41d34d62..e07fd2f718 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -209,6 +209,7 @@ enum virDomainDiskCache { enum virDomainDiskErrorPolicy { VIR_DOMAIN_DISK_ERROR_POLICY_DEFAULT, VIR_DOMAIN_DISK_ERROR_POLICY_STOP, + VIR_DOMAIN_DISK_ERROR_POLICY_REPORT, VIR_DOMAIN_DISK_ERROR_POLICY_IGNORE, VIR_DOMAIN_DISK_ERROR_POLICY_ENOSPACE, @@ -284,7 +285,8 @@ struct _virDomainDiskDef { char *driverType; char *serial; int cachemode; - int error_policy; + int error_policy; /* enum virDomainDiskErrorPolicy */ + int rerror_policy; /* enum virDomainDiskErrorPolicy */ int bootIndex; int iomode; int ioeventfd; diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 5f729a4fa1..cf99f89e0c 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -1696,6 +1696,8 @@ qemuBuildDriveStr(virDomainDiskDefPtr disk, if (disk->error_policy) wpolicy = virDomainDiskErrorPolicyTypeToString(disk->error_policy); + if (disk->rerror_policy) + rpolicy = virDomainDiskErrorPolicyTypeToString(disk->rerror_policy); if (disk->error_policy == VIR_DOMAIN_DISK_ERROR_POLICY_ENOSPACE) { /* in the case of enospace, the option is spelled @@ -5631,14 +5633,22 @@ qemuParseCommandLineDisk(virCapsPtr caps, def->cachemode = VIR_DOMAIN_DISK_CACHE_DIRECTSYNC; else if (STREQ(values[i], "unsafe")) def->cachemode = VIR_DOMAIN_DISK_CACHE_UNSAFE; - } else if (STREQ(keywords[i], "werror") || - STREQ(keywords[i], "rerror")) { + } else if (STREQ(keywords[i], "werror")) { if (STREQ(values[i], "stop")) def->error_policy = VIR_DOMAIN_DISK_ERROR_POLICY_STOP; + else if (STREQ(values[i], "report")) + def->error_policy = VIR_DOMAIN_DISK_ERROR_POLICY_REPORT; else if (STREQ(values[i], "ignore")) def->error_policy = VIR_DOMAIN_DISK_ERROR_POLICY_IGNORE; else if (STREQ(values[i], "enospc")) def->error_policy = VIR_DOMAIN_DISK_ERROR_POLICY_ENOSPACE; + } else if (STREQ(keywords[i], "rerror")) { + if (STREQ(values[i], "stop")) + def->rerror_policy = VIR_DOMAIN_DISK_ERROR_POLICY_STOP; + else if (STREQ(values[i], "report")) + def->rerror_policy = VIR_DOMAIN_DISK_ERROR_POLICY_REPORT; + else if (STREQ(values[i], "ignore")) + def->rerror_policy = VIR_DOMAIN_DISK_ERROR_POLICY_IGNORE; } else if (STREQ(keywords[i], "index")) { if (virStrToLong_i(values[i], NULL, 10, &idx) < 0) { virDomainDiskDefFree(def); @@ -5674,6 +5684,9 @@ qemuParseCommandLineDisk(virCapsPtr caps, } } + if (def->rerror_policy == def->error_policy) + def->rerror_policy = 0; + if (!def->src && def->device == VIR_DOMAIN_DISK_DEVICE_DISK && def->type != VIR_DOMAIN_DISK_TYPE_NETWORK) { diff --git a/tests/qemuargv2xmltest.c b/tests/qemuargv2xmltest.c index 6a79630865..807a771f23 100644 --- a/tests/qemuargv2xmltest.c +++ b/tests/qemuargv2xmltest.c @@ -165,6 +165,7 @@ mymain(void) DO_TEST("disk-drive-cache-v1-none"); DO_TEST("disk-drive-error-policy-stop"); DO_TEST("disk-drive-error-policy-enospace"); + DO_TEST("disk-drive-error-policy-wreport-rignore"); DO_TEST("disk-drive-cache-v2-wt"); DO_TEST("disk-drive-cache-v2-wb"); DO_TEST("disk-drive-cache-v2-none"); diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-error-policy-wreport-rignore.args b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-error-policy-wreport-rignore.args new file mode 100644 index 0000000000..48795760f5 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-error-policy-wreport-rignore.args @@ -0,0 +1,6 @@ +LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu -S -M \ +pc -m 214 -smp 1 -nographic -monitor unix:/tmp/test-monitor,server,nowait \ +-no-acpi -boot c -drive file=/dev/HostVG/QEMUGuest1,if=ide,bus=0,unit=0,\ +format=qcow2,cache=off,werror=report,rerror=ignore -drive \ +file=/dev/HostVG/QEMUGuest2,if=ide,media=cdrom,bus=1,unit=0,format=raw -net \ +none -serial none -parallel none -usb diff --git a/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-error-policy-wreport-rignore.xml b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-error-policy-wreport-rignore.xml new file mode 100644 index 0000000000..70068aa4d6 --- /dev/null +++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-error-policy-wreport-rignore.xml @@ -0,0 +1,33 @@ + + QEMUGuest1 + c7a5fdbd-edaf-9455-926a-d65c16db1809 + 219136 + 219136 + 1 + + hvm + + + + destroy + restart + destroy + + /usr/bin/qemu + + + + +
    + + + + + + +
    + + + + + diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 24e831cf0a..3d65d5f64b 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -334,6 +334,8 @@ mymain(void) QEMU_CAPS_DRIVE, QEMU_CAPS_MONITOR_JSON, QEMU_CAPS_DRIVE_FORMAT); DO_TEST("disk-drive-error-policy-enospace", false, QEMU_CAPS_DRIVE, QEMU_CAPS_MONITOR_JSON, QEMU_CAPS_DRIVE_FORMAT); + DO_TEST("disk-drive-error-policy-wreport-rignore", false, + QEMU_CAPS_DRIVE, QEMU_CAPS_MONITOR_JSON, QEMU_CAPS_DRIVE_FORMAT); DO_TEST("disk-drive-cache-v2-wt", false, QEMU_CAPS_DRIVE, QEMU_CAPS_DRIVE_CACHE_V2, QEMU_CAPS_DRIVE_FORMAT); DO_TEST("disk-drive-cache-v2-wb", false,