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.
---
Changes in V2:
* added rerror_policy to domaincommon.rng
* added "report" to the list of possible policies and to docs
* fix qemuParseCommandLineDisk to set rerror_policy and error_policy
separately.
* add a new xml2argv & argv2xml test that sets error_policy='report'
rerror_policy='ignore'.
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 +
...gv-disk-drive-error-policy-wreport-rignore.args | 6 +++
...rgv-disk-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 593adcb..b15f9e2 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -1008,9 +1008,21 @@
</li>
<li>
The optional <code>error_policy</code> attribute controls
- how the hypervisor will behave on an error, possible
- values are "stop", "ignore", and "enospace".
- <span class="since">Since 0.8.0</span>
+ how the hypervisor will behave on a disk read or write
+ error, possible values are "stop", "report",
"ignore", and
+ "enospace".<span class="since">Since 0.8.0,
"report" since
+ 0.9.7</span> The default setting of error_policy is
"report".
+ There is also an
+ optional <code>rerror_policy</code> that controls behavior
+ for read errors only. <span class="since">Since
+ 0.9.7</space>. If no rerror_policy is given, error_policy
+ is used for both read and write errors. If rerror_policy
+ is given, it overrides the <code>error_policy</code> for
+ read errors. Also note that "enospace" is not a valid
+ policy for read errors, so if <code>error_policy</code> is
+ set to "enospace" and no <code>rerror_policy</code> is
+ given, the read error policy will be left at its default,
+ which is "report".
</li>
<li>
The optional <code>io</code> attribute controls specific
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index cffaac2..492a41d 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -820,6 +820,9 @@
<ref name="driverErrorPolicy"/>
</optional>
<optional>
+ <ref name="driverRerrorPolicy"/>
+ </optional>
+ <optional>
<ref name="driverIO"/>
</optional>
<optional>
@@ -856,11 +859,21 @@
<attribute name="error_policy">
<choice>
<value>stop</value>
+ <value>report</value>
<value>ignore</value>
<value>enospace</value>
</choice>
</attribute>
</define>
+ <define name="driverRerrorPolicy">
+ <attribute name="rerror_policy">
+ <choice>
+ <value>stop</value>
+ <value>report</value>
+ <value>ignore</value>
+ </choice>
+ </attribute>
+ </define>
<define name="driverIO">
<attribute name="io">
<choice>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 55e6c34..a537251 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 bc41d34..56c9777 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; /* virDomainDiskErrorPolicy */
+ int rerror_policy; /* virDomainDiskErrorPolicy */
int bootIndex;
int iomode;
int ioeventfd;
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 5f729a4..cf99f89 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 6a79630..807a771 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 0000000..4879576
--- /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 0000000..70068aa
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-disk-drive-error-policy-wreport-rignore.xml
@@ -0,0 +1,33 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory>219136</memory>
+ <currentMemory>219136</currentMemory>
+ <vcpu>1</vcpu>
+ <os>
+ <type arch='i686' machine='pc'>hvm</type>
+ <boot dev='hd'/>
+ </os>
+ <clock offset='utc'/>
+ <on_poweroff>destroy</on_poweroff>
+ <on_reboot>restart</on_reboot>
+ <on_crash>destroy</on_crash>
+ <devices>
+ <emulator>/usr/bin/qemu</emulator>
+ <disk type='block' device='disk'>
+ <driver name='qemu' type='qcow2' cache='none'
error_policy='report' rerror_policy='ignore'/>
+ <source dev='/dev/HostVG/QEMUGuest1'/>
+ <target dev='hda' bus='ide'/>
+ <address type='drive' controller='0' bus='0'
unit='0'/>
+ </disk>
+ <disk type='block' device='cdrom'>
+ <driver name='qemu' type='raw'/>
+ <source dev='/dev/HostVG/QEMUGuest2'/>
+ <target dev='hdc' bus='ide'/>
+ <readonly/>
+ <address type='drive' controller='0' bus='1'
unit='0'/>
+ </disk>
+ <controller type='ide' index='0'/>
+ <memballoon model='virtio'/>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index 24e831c..3d65d5f 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,
--
1.7.3.4