[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@xxxxxxx> Signed-off-by: Eric Blake <eblake@xxxxxxxxxx> --- 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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list