[Problem]
Currently, guest OS's messages can be logged to a local disk of host OS
by creating chadevs with options below.
-chardev file,id=charserial0,path=<log file's path> -device
isa-serial,chardev=chardevserial0,id=serial0
When a hardware failure happens in the disk, qemu-kvm can't create the
chardevs. In this case, guest OS doesn't boot up.
Actually, there are users who don't desire that guest OS goes down due
to a hardware failure of a log disk only. Therefore, qemu should offer
some way to boot guest OS up even if the log disk is broken.
[Solution]
This patch supports startupPolicy for chardev.
The starupPolicy is introduced just in cases where chardev is "file"
because this patch aims for making guest OS boot up when a hardware
failure happens.
In other cases (pty, dev, pipe and unix) it is not introduced
because they don't access to hardware.
The policy works as follows.
- If the value is "optional", guestOS boots up by dropping the chardev.
- If other values are specified, guestOS fails to boot up. (the default)
Description about original startupPolicy attribute:
http://libvirt.org/git/?p=libvirt.git;a=commitdiff;h=e5a84d74a278
Signed-off-by: Seiji Aguchi <seiji.aguchi(a)hds.com>
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
Change from v2
- To pass "make check", add followings.
- Add serial source optional testing.
- check if startupPolicy is NULL in virDomainChrSourceDefParseXML().
- Add xml format of startupPolicy in virDomainChrSourceDefFormat().
Patch v2 and comment from Eric Blake
-
https://www.redhat.com/archives/libvir-list/2013-May/msg01814.html
-
https://www.redhat.com/archives/libvir-list/2013-May/msg01943.html
---
docs/formatdomain.html.in | 16 ++++++++-
docs/schemas/domaincommon.rng | 3 ++
src/conf/domain_conf.c | 22 +++++++++++-
src/conf/domain_conf.h | 1 +
src/qemu/qemu_process.c | 25 +++++++++++++-
.../qemuxml2argv-serial-source-optional.args | 9 +++++
.../qemuxml2argv-serial-source-optional.xml | 35 ++++++++++++++++++++
tests/qemuxml2argvtest.c | 2 +
tests/qemuxml2xmltest.c | 1 +
tests/virt-aa-helper-test | 3 ++
10 files changed, 113 insertions(+), 4 deletions(-)
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-source-optional.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-serial-source-optional.xml
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 7601aaa..5c9d4fb 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -4281,13 +4281,27 @@ qemu-kvm -net nic,model=? /dev/null
<p>
A file is opened and all data sent to the character
device is written to the file.
+ <span class="since">Since 1.0.6</span>, it is possible to
define
+ policy on what happens if the file is not accessible when
+ booting or migrating. This is done by
+ a <code>startupPolicy</code> attribute:
</p>
+ <ul>
+ <li>If the value is "mandatory" (the default), the guest fails
+ to boot or migrate if the file is not found.</li>
+ <li>If the value is "optional", a missing file is at boot or
+ migration is substituted with /dev/null, so the guest still sees
+ the device but the host no longer tracks guest data on the device.</li>
+ <li>If the value is "requisite", the file is required for
+ booting, but optional on migration.</li>
+ </ul>
+
<pre>
...
<devices>
<serial type="file">
- <source path="/var/log/vm/vm-serial.log"/>
+ <source path="/var/log/vm/vm-serial.log"
startupPolicy="optional"/>
<target port="1"/>
</serial>
</devices>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 745b959..10b3365 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -2817,6 +2817,9 @@
</optional>
<optional>
<attribute name="path"/>
+ <optional>
+ <ref name="startupPolicy"/>
+ </optional>
</optional>
<optional>
<attribute name="host"/>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 10cb7f6..279ff9e 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -6819,6 +6819,7 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def,
char *path = NULL;
char *mode = NULL;
char *protocol = NULL;
+ char *startupPolicy = NULL;
int remaining = 0;
while (cur != NULL) {
@@ -6839,6 +6840,9 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def,
!(flags & VIR_DOMAIN_XML_INACTIVE)))
path = virXMLPropString(cur, "path");
+ if (startupPolicy == NULL &&
+ def->type == VIR_DOMAIN_CHR_TYPE_FILE)
+ startupPolicy = virXMLPropString(cur,
"startupPolicy");
break;
case VIR_DOMAIN_CHR_TYPE_UDP:
@@ -6911,6 +6915,13 @@ virDomainChrSourceDefParseXML(virDomainChrSourceDefPtr def,
def->data.file.path = path;
path = NULL;
+
+ if (startupPolicy) {
+ def->data.file.startupPolicy =
+ virDomainStartupPolicyTypeFromString(startupPolicy);
+ startupPolicy = NULL;
+ }
+
break;
case VIR_DOMAIN_CHR_TYPE_STDIO:
@@ -15014,8 +15025,15 @@ virDomainChrSourceDefFormat(virBufferPtr buf,
if (def->type != VIR_DOMAIN_CHR_TYPE_PTY ||
(def->data.file.path &&
!(flags & VIR_DOMAIN_XML_INACTIVE))) {
- virBufferEscapeString(buf, " <source
path='%s'/>\n",
- def->data.file.path);
+ virBufferEscapeString(buf, " <source path='%s'",
+ def->data.file.path);
+
+ if (def->data.file.path && def->data.file.startupPolicy) {
+ const char *policy =
+virDomainStartupPolicyTypeToString(def->data.file.startupPolicy);
+ virBufferAsprintf(buf, " startupPolicy='%s'", policy);
+ }
+ virBufferAddLit(buf, "/>\n");
}
break;
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index f265966..0899556 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1102,6 +1102,7 @@ struct _virDomainChrSourceDef {
/* no <source> for null, vc, stdio */
struct {
char *path;
+ int startupPolicy; /* enum virDomainStartupPolicy */
} file; /* pty, file, pipe, or device */
struct {
char *host;
diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c
index a46d944..35d63d5 100644
--- a/src/qemu/qemu_process.c
+++ b/src/qemu/qemu_process.c
@@ -2511,7 +2511,30 @@ qemuProcessPrepareChardevDevice(virDomainDefPtr def
ATTRIBUTE_UNUSED,
virReportSystemError(errno,
_("Unable to pre-create chardev file
'%s'"),
dev->source.data.file.path);
- return -1;
+ if (dev->source.data.file.startupPolicy !=
+ VIR_DOMAIN_STARTUP_POLICY_OPTIONAL) {
+ return -1;
+ }
+ VIR_FREE(dev->source.data.file.path);
+ /*
+ * Change a destination to /dev/null to boot guest OS up
+ * even if a log disk is broken.
+ */
+ VIR_WARN("Switch the destination to /dev/null");
+ dev->source.data.file.path = strdup("/dev/null");
+
+ if (!(dev->source.data.file.path)) {
+ virReportOOMError();
+ return -1;
+ }
+
+ if ((fd = open(dev->source.data.file.path,
+ O_CREAT | O_APPEND, S_IRUSR|S_IWUSR)) < 0) {
+ virReportSystemError(errno,
+ _("Unable to pre-create chardev file
'%s'"),
+ dev->source.data.file.path);
+ return -1;
+ }
}
VIR_FORCE_CLOSE(fd);
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-source-optional.args
b/tests/qemuxml2argvdata/qemuxml2argv-serial-source-optional.args
new file mode 100644
index 0000000..9ffe8de
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-source-optional.args
@@ -0,0 +1,9 @@
+LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test /usr/bin/qemu \
+-S -M \
+pc -m 214 -smp 1 -nographic -nodefconfig -nodefaults \
+-chardev socket,id=charmonitor,path=/tmp/test-monitor,server,nowait \
+-mon chardev=charmonitor,id=monitor,mode=readline \
+-no-acpi -boot c -usb -hdc /tmp/idedisk.img \
+-chardev file,id=charserial0,path=/tmp/serial.log \
+-device isa-serial,chardev=charserial0,id=serial0 \
+-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-serial-source-optional.xml
b/tests/qemuxml2argvdata/qemuxml2argv-serial-source-optional.xml
new file mode 100644
index 0000000..1aeb82a
--- /dev/null
+++ b/tests/qemuxml2argvdata/qemuxml2argv-serial-source-optional.xml
@@ -0,0 +1,35 @@
+<domain type='qemu'>
+ <name>QEMUGuest1</name>
+ <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+ <memory unit='KiB'>219136</memory>
+ <currentMemory unit='KiB'>219136</currentMemory>
+ <vcpu placement='static'>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='file' device='disk'>
+ <source file='/tmp/idedisk.img'/>
+ <target dev='hdc' bus='ide'/>
+ <address type='drive' controller='0' bus='0'
target='0' unit='2'/>
+ </disk>
+ <controller type='usb' index='0'/>
+ <controller type='ide' index='0'/>
+ <controller type='pci' index='0' model='pci-root'/>
+ <serial type='file'>
+ <source path='/tmp/serial.log' startupPolicy='optional'/>
+ <target port='0'/>
+ </serial>
+ <console type='file'>
+ <source path='/tmp/serial.log' startupPolicy='optional'/>
+ <target type='serial' port='0'/>
+ </console>
+ <memballoon model='virtio'/>
+ </devices>
+</domain>
diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c
index 0f96eef..588c922 100644
--- a/tests/qemuxml2argvtest.c
+++ b/tests/qemuxml2argvtest.c
@@ -728,6 +728,8 @@ mymain(void)
QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG);
DO_TEST("console-compat-chardev",
QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG);
+ DO_TEST("serial-source-optional",
+ QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG);
DO_TEST("channel-guestfwd",
QEMU_CAPS_CHARDEV, QEMU_CAPS_DEVICE, QEMU_CAPS_NODEFCONFIG);
diff --git a/tests/qemuxml2xmltest.c b/tests/qemuxml2xmltest.c
index 77cac3f..9faca1f 100644
--- a/tests/qemuxml2xmltest.c
+++ b/tests/qemuxml2xmltest.c
@@ -234,6 +234,7 @@ mymain(void)
DO_TEST("console-virtio-many");
DO_TEST("channel-guestfwd");
DO_TEST("channel-virtio");
+ DO_TEST("serial-source-optional");
DO_TEST("hostdev-usb-address");
DO_TEST("hostdev-pci-address");
diff --git a/tests/virt-aa-helper-test b/tests/virt-aa-helper-test
index af91c61..7172fd6 100755
--- a/tests/virt-aa-helper-test
+++ b/tests/virt-aa-helper-test
@@ -255,6 +255,9 @@ testme "0" "disk (empty cdrom)" "-r -u
$valid_uuid" "$test_xml"
sed -e "s,###UUID###,$uuid,g" -e "s,###DISK###,$disk1,g" -e
"s,</devices>,<serial type='file'><source
path='$tmpdir/serial.log'/><target
port='0'/></serial></devices>,g" "$template_xml"
> "$test_xml"
testme "0" "serial" "-r -u $valid_uuid"
"$test_xml"
+sed -e "s,###UUID###,$uuid,g" -e "s,###DISK###,$disk1,g" -e
"s,</devices>,<serial type='file'><source
path='$tmpdir/serial.log' startupPolicy='optional'/><target
port='0'/></serial></devices>,g" "$template_xml"
> "$test_xml"
+testme "0" "serial" "-r -u $valid_uuid"
"$test_xml"
+
sed -e "s,###UUID###,$uuid,g" -e "s,###DISK###,$disk1,g" -e
"s,</devices>,<serial type='pty'><target
port='0'/></serial></devices>,g" "$template_xml"
> "$test_xml"
testme "0" "serial (pty)" "-r -u $valid_uuid"
"$test_xml"
-- 1.7.1