diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 89672deb38..00a42abd30 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -3899,7 +3899,9 @@ void virDomainDefFree(virDomainDef *def) def->blkio.ndevices); g_free(def->blkio.devices); - virDomainWatchdogDefFree(def->watchdog); + for (i = 0; i < def->nwatchdogs; i++) + virDomainWatchdogDefFree(def->watchdogs[i]); + g_free(def->watchdogs); virDomainMemballoonDefFree(def->memballoon); virDomainNVRAMDefFree(def->nvram); @@ -4676,10 +4678,10 @@ virDomainDeviceInfoIterateFlags(virDomainDef *def, if ((rc = cb(def, &device, &def->fss[i]->info, opaque)) != 0) return rc; } - if (def->watchdog) { - device.type = VIR_DOMAIN_DEVICE_WATCHDOG; - device.data.watchdog = def->watchdog; - if ((rc = cb(def, &device, &def->watchdog->info, opaque)) != 0) + device.type = VIR_DOMAIN_DEVICE_WATCHDOG; + for (i = 0; i < def->nwatchdogs; i++) { + device.data.watchdog = def->watchdogs[i]; + if ((rc = cb(def, &device, &def->watchdogs[i]->info, opaque)) != 0) return rc; } if (def->memballoon) { @@ -18909,24 +18911,21 @@ virDomainDefParseXML(xmlXPathContextPtr ctxt, VIR_FREE(nodes); /* analysis of the watchdog devices */ - def->watchdog = NULL; - if ((n = virXPathNodeSet("./devices/watchdog", ctxt, &nodes)) < 0) + n = virXPathNodeSet("./devices/watchdog", ctxt, &nodes); + if (n < 0) return NULL; - if (n > 1) { - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("only a single watchdog device is supported")); - return NULL; - } - if (n > 0) { + if (n) + def->watchdogs = g_new0(virDomainWatchdogDef *, n); + for (i = 0; i < n; i++) { virDomainWatchdogDef *watchdog; - watchdog = virDomainWatchdogDefParseXML(xmlopt, nodes[0], ctxt, flags); + watchdog = virDomainWatchdogDefParseXML(xmlopt, nodes[i], ctxt, flags); if (!watchdog) return NULL; - def->watchdog = watchdog; - VIR_FREE(nodes); + def->watchdogs[def->nwatchdogs++] = watchdog; } + VIR_FREE(nodes); /* analysis of the memballoon devices */ def->memballoon = NULL; @@ -21370,18 +21369,18 @@ virDomainDefCheckABIStabilityFlags(virDomainDef *src, dst->redirfilter)) goto error; - if ((!src->watchdog && dst->watchdog) || - (src->watchdog && !dst->watchdog)) { + + if (src->nwatchdogs != dst->nwatchdogs) { virReportError(VIR_ERR_CONFIG_UNSUPPORTED, - _("Target domain watchdog count %d " - "does not match source %d"), - dst->watchdog ? 1 : 0, src->watchdog ? 1 : 0); + _("Target domain watchdog device count %zu does not match source %zu"), + dst->nwatchdogs, src->nwatchdogs); goto error; } - if (src->watchdog && - !virDomainWatchdogDefCheckABIStability(src->watchdog, dst->watchdog)) - goto error; + for (i = 0; i < src->nwatchdogs; i++) { + if (!virDomainWatchdogDefCheckABIStability(src->watchdogs[i], dst->watchdogs[i])) + goto error; + } if ((!src->memballoon && dst->memballoon) || (src->memballoon && !dst->memballoon)) { @@ -27672,8 +27671,8 @@ virDomainDefFormatInternalSetRootName(virDomainDef *def, return -1; } - if (def->watchdog) - virDomainWatchdogDefFormat(buf, def->watchdog, flags); + for (n = 0; n < def->nwatchdogs; n++) + virDomainWatchdogDefFormat(buf, def->watchdogs[n], flags); if (def->memballoon) virDomainMemballoonDefFormat(buf, def->memballoon, flags); @@ -30736,3 +30735,33 @@ virDomainDefHasSpiceGraphics(const virDomainDef *def) return false; } + + +ssize_t +virDomainWatchdogDefFind(const virDomainDef *def, + const virDomainWatchdogDef *watchdog) +{ + size_t i; + + for (i = 0; i < def->nwatchdogs; i++) { + const virDomainWatchdogDef *tmp = def->watchdogs[i]; + + if (tmp->model != watchdog->model) + continue; + + if (tmp->action != watchdog->action) + continue; + + if (watchdog->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE && + !virDomainDeviceInfoAddressIsEqual(&watchdog->info, &tmp->info)) + continue; + + if (watchdog->info.alias && + STRNEQ_NULLABLE(watchdog->info.alias, tmp->info.alias)) + continue; + + return i; + } + + return -1; +} diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index d99bbbc3ff..2b04e0c3e0 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -3092,15 +3092,18 @@ struct _virDomainDef { size_t nsysinfo; virSysinfoDef **sysinfo; + size_t ncryptos; virDomainCryptoDef **cryptos; + size_t nwatchdogs; + virDomainWatchdogDef **watchdogs; + /* At maximum 2 TPMs on the domain if a TPM Proxy is present. */ size_t ntpms; virDomainTPMDef **tpms; /* Only 1 */ - virDomainWatchdogDef *watchdog; virDomainMemballoonDef *memballoon; virDomainNVRAMDef *nvram; virCPUDef *cpu; @@ -3562,6 +3565,10 @@ virDomainSoundDef *virDomainSoundDefRemove(virDomainDef *def, size_t idx); void virDomainAudioDefFree(virDomainAudioDef *def); void virDomainMemballoonDefFree(virDomainMemballoonDef *def); void virDomainNVRAMDefFree(virDomainNVRAMDef *def); +ssize_t +virDomainWatchdogDefFind(const virDomainDef *def, + const virDomainWatchdogDef *watchdog) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) G_GNUC_WARN_UNUSED_RESULT; void virDomainWatchdogDefFree(virDomainWatchdogDef *def); virDomainVideoDef *virDomainVideoDefNew(virDomainXMLOption *xmlopt); void virDomainVideoDefFree(virDomainVideoDef *def); diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng index 14044811c0..524d57884c 100644 --- a/src/conf/schemas/domaincommon.rng +++ b/src/conf/schemas/domaincommon.rng @@ -6429,9 +6429,9 @@ - + - + diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index ac2e51e606..7ca8b472be 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -699,6 +699,7 @@ virDomainVsockDefFree; virDomainVsockDefNew; virDomainWatchdogActionTypeFromString; virDomainWatchdogActionTypeToString; +virDomainWatchdogDefFind; virDomainWatchdogDefFree; virDomainWatchdogModelTypeFromString; virDomainWatchdogModelTypeToString; diff --git a/src/qemu/qemu_alias.c b/src/qemu/qemu_alias.c index c74c68a939..a9809797d5 100644 --- a/src/qemu/qemu_alias.c +++ b/src/qemu/qemu_alias.c @@ -555,12 +555,26 @@ qemuAssignDeviceShmemAlias(virDomainDef *def, void -qemuAssignDeviceWatchdogAlias(virDomainWatchdogDef *watchdog) +qemuAssignDeviceWatchdogAlias(virDomainDef *def, + virDomainWatchdogDef *watchdog, + int idx) { - /* Currently, there's just one watchdog per domain */ + ssize_t i = 0; - if (!watchdog->info.alias) - watchdog->info.alias = g_strdup("watchdog0"); + if (watchdog->info.alias) + return; + + if (idx == -1) { + for (i = 0; i < def->nwatchdogs; i++) { + int cur_idx = qemuDomainDeviceAliasIndex(&def->watchdogs[i]->info, "watchdog"); + if (cur_idx > idx) + idx = cur_idx; + } + + idx++; + } + + watchdog->info.alias = g_strdup_printf("watchdog%d", idx); } @@ -686,8 +700,8 @@ qemuAssignDeviceAliases(virDomainDef *def) for (i = 0; i < def->nsmartcards; i++) { qemuAssignDeviceSmartcardAlias(def->smartcards[i], i); } - if (def->watchdog) { - qemuAssignDeviceWatchdogAlias(def->watchdog); + for (i = 0; i < def->nwatchdogs; i++) { + qemuAssignDeviceWatchdogAlias(def, def->watchdogs[i], i); } if (def->memballoon && def->memballoon->model != VIR_DOMAIN_MEMBALLOON_MODEL_NONE) { diff --git a/src/qemu/qemu_alias.h b/src/qemu/qemu_alias.h index af9c3f62d3..f13f4cc5f8 100644 --- a/src/qemu/qemu_alias.h +++ b/src/qemu/qemu_alias.h @@ -61,7 +61,10 @@ void qemuAssignDeviceShmemAlias(virDomainDef *def, virDomainShmemDef *shmem, int idx); -void qemuAssignDeviceWatchdogAlias(virDomainWatchdogDef *watchdog); +void +qemuAssignDeviceWatchdogAlias(virDomainDef *def, + virDomainWatchdogDef *watchdog, + int idx); void qemuAssignDeviceInputAlias(virDomainDef *def, virDomainInputDef *input, diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 4ba978f3e6..987c9d20db 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -4050,26 +4050,34 @@ qemuBuildWatchdogCommandLine(virCommand *cmd, const virDomainDef *def, virQEMUCaps *qemuCaps) { - virDomainWatchdogDef *watchdog = def->watchdog; - g_autoptr(virJSONValue) props = NULL; + virDomainWatchdogDef *watchdog = NULL; const char *action; int actualAction; + ssize_t i = 0; - if (!def->watchdog) + if (def->nwatchdogs == 0) return 0; - if (qemuCommandAddExtDevice(cmd, &def->watchdog->info, def, qemuCaps) < 0) - return -1; + for (i = 0; i < def->nwatchdogs; i++) { + g_autoptr(virJSONValue) props = NULL; - if (!(props = qemuBuildWatchdogDevProps(def, watchdog))) - return -1; + watchdog = def->watchdogs[i]; - if (qemuBuildDeviceCommandlineFromJSON(cmd, props, def, qemuCaps)) - return -1; + if (qemuCommandAddExtDevice(cmd, &watchdog->info, def, qemuCaps) < 0) + return -1; + + if (!(props = qemuBuildWatchdogDevProps(def, watchdog))) + return -1; + + if (qemuBuildDeviceCommandlineFromJSON(cmd, props, def, qemuCaps)) + return -1; + } /* qemu doesn't have a 'dump' action; we tell qemu to 'pause', then libvirt listens for the watchdog event, and we perform the dump - ourselves. so convert 'dump' to 'pause' for the qemu cli */ + ourselves. so convert 'dump' to 'pause' for the qemu cli. The + validator already checked that all watchdogs have the same action. + */ actualAction = watchdog->action; if (watchdog->action == VIR_DOMAIN_WATCHDOG_ACTION_DUMP) actualAction = VIR_DOMAIN_WATCHDOG_ACTION_PAUSE; diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 9529bd9a8d..e26ce9c0e6 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -2342,10 +2342,10 @@ qemuDomainAssignDevicePCISlots(virDomainDef *def, } /* A watchdog - check if it is a PCI device */ - if (def->watchdog && - def->watchdog->model == VIR_DOMAIN_WATCHDOG_MODEL_I6300ESB && - virDeviceInfoPCIAddressIsWanted(&def->watchdog->info)) { - if (qemuDomainPCIAddressReserveNextAddr(addrs, &def->watchdog->info) < 0) + for (i = 0; i < def->nwatchdogs; i++) { + if (def->watchdogs[i]->model == VIR_DOMAIN_WATCHDOG_MODEL_I6300ESB && + virDeviceInfoPCIAddressIsWanted(&def->watchdogs[i]->info) && + qemuDomainPCIAddressReserveNextAddr(addrs, &def->watchdogs[i]->info) < 0) return -1; } diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 0e2320426f..f3f64d3411 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -7260,12 +7260,13 @@ qemuDomainAttachDeviceConfig(virDomainDef *vmdef, break; case VIR_DOMAIN_DEVICE_WATCHDOG: - if (vmdef->watchdog) { + if (virDomainWatchdogDefFind(vmdef, dev->data.watchdog) >= 0) { virReportError(VIR_ERR_OPERATION_INVALID, "%s", - _("domain already has a watchdog")); + _("device is already in the domain configuration")); return -1; } - vmdef->watchdog = g_steal_pointer(&dev->data.watchdog); + + VIR_APPEND_ELEMENT(vmdef->watchdogs, vmdef->nwatchdogs, dev->data.watchdog); break; case VIR_DOMAIN_DEVICE_INPUT: @@ -7460,12 +7461,13 @@ qemuDomainDetachDeviceConfig(virDomainDef *vmdef, case VIR_DOMAIN_DEVICE_WATCHDOG: - if (!vmdef->watchdog) { + idx = virDomainWatchdogDefFind(vmdef, dev->data.watchdog); + if (idx < 0) { virReportError(VIR_ERR_DEVICE_MISSING, "%s", - _("domain has no watchdog")); + _("no matching watchdog was found")); return -1; } - g_clear_pointer(&vmdef->watchdog, virDomainWatchdogDefFree); + VIR_DELETE_ELEMENT(vmdef->watchdogs, idx, vmdef->nwatchdogs); break; case VIR_DOMAIN_DEVICE_INPUT: diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index e153e4806d..538fa502c4 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -2926,15 +2926,9 @@ qemuDomainAttachWatchdog(virDomainObj *vm, virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_WATCHDOG, { .watchdog = watchdog } }; g_autoptr(virJSONValue) props = NULL; bool releaseAddress = false; - int rv; + int rv = 0; - if (vm->def->watchdog) { - virReportError(VIR_ERR_OPERATION_INVALID, "%s", - _("domain already has a watchdog")); - return -1; - } - - qemuAssignDeviceWatchdogAlias(watchdog); + qemuAssignDeviceWatchdogAlias(vm->def, watchdog, -1); if (watchdog->model != VIR_DOMAIN_WATCHDOG_MODEL_I6300ESB) { virReportError(VIR_ERR_OPERATION_UNSUPPORTED, @@ -2952,10 +2946,13 @@ qemuDomainAttachWatchdog(virDomainObj *vm, qemuDomainObjEnterMonitor(vm); - /* QEMU doesn't have a 'dump' action; we tell qemu to 'pause', then - libvirt listens for the watchdog event, and we perform the dump - ourselves. so convert 'dump' to 'pause' for the qemu cli */ - if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_SET_ACTION)) { + if (vm->def->nwatchdogs) { + /* Domain already has a watchdog and all must have the same action. */ + rv = 0; + } else if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_SET_ACTION)) { + /* QEMU doesn't have a 'dump' action; we tell qemu to 'pause', then + libvirt listens for the watchdog event, and we perform the dump + ourselves. so convert 'dump' to 'pause' for the qemu cli */ qemuMonitorActionWatchdog watchdogaction = QEMU_MONITOR_ACTION_WATCHDOG_KEEP; switch (watchdog->action) { @@ -3013,7 +3010,7 @@ qemuDomainAttachWatchdog(virDomainObj *vm, goto cleanup; releaseAddress = false; - vm->def->watchdog = watchdog; + VIR_APPEND_ELEMENT_COPY(vm->def->watchdogs, vm->def->nwatchdogs, watchdog); ret = 0; cleanup: @@ -4846,11 +4843,20 @@ static int qemuDomainRemoveWatchdog(virDomainObj *vm, virDomainWatchdogDef *watchdog) { + size_t i = 0; + VIR_DEBUG("Removing watchdog %s from domain %p %s", watchdog->info.alias, vm, vm->def->name); + for (i = 0; i < vm->def->nwatchdogs; i++) { + if (vm->def->watchdogs[i] == watchdog) + break; + } + qemuDomainReleaseDeviceAddress(vm, &watchdog->info); - g_clear_pointer(&vm->def->watchdog, virDomainWatchdogDefFree); + virDomainWatchdogDefFree(watchdog); + VIR_DELETE_ELEMENT(vm->def->watchdogs, i, vm->def->nwatchdogs); + return 0; } @@ -5603,33 +5609,20 @@ qemuDomainDetachPrepWatchdog(virDomainObj *vm, virDomainWatchdogDef *match, virDomainWatchdogDef **detach) { - virDomainWatchdogDef *watchdog; + ssize_t idx = virDomainWatchdogDefFind(vm->def, match); - *detach = watchdog = vm->def->watchdog; - - if (!watchdog) { - virReportError(VIR_ERR_DEVICE_MISSING, "%s", - _("watchdog device not present in domain configuration")); + if (idx < 0) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("no matching watchdog was found")); return -1; } - /* While domains can have up to one watchdog, the one supplied by the user - * doesn't necessarily match the one domain has. Refuse to detach in such - * case. */ - if (!(watchdog->model == match->model && - watchdog->action == match->action && - virDomainDeviceInfoAddressIsEqual(&match->info, &watchdog->info))) { - virReportError(VIR_ERR_DEVICE_MISSING, - _("model '%s' watchdog device not present " - "in domain configuration"), - virDomainWatchdogModelTypeToString(watchdog->model)); - return -1; - } + *detach = vm->def->watchdogs[idx]; - if (watchdog->model != VIR_DOMAIN_WATCHDOG_MODEL_I6300ESB) { + if ((*detach)->model != VIR_DOMAIN_WATCHDOG_MODEL_I6300ESB) { virReportError(VIR_ERR_OPERATION_UNSUPPORTED, _("hot unplug of watchdog of model %s is not supported"), - virDomainWatchdogModelTypeToString(watchdog->model)); + virDomainWatchdogModelTypeToString((*detach)->model)); return -1; } diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 9ac6b45e75..4afd12e3fa 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -804,7 +804,8 @@ qemuProcessHandleWatchdog(qemuMonitor *mon G_GNUC_UNUSED, qemuDomainSaveStatus(vm); } - if (vm->def->watchdog->action == VIR_DOMAIN_WATCHDOG_ACTION_DUMP) { + if (vm->def->nwatchdogs && + vm->def->watchdogs[0]->action == VIR_DOMAIN_WATCHDOG_ACTION_DUMP) { qemuProcessEventSubmit(vm, QEMU_PROCESS_EVENT_WATCHDOG, VIR_DOMAIN_WATCHDOG_ACTION_DUMP, 0, NULL); } diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index 9829c4e7ff..134ab0437c 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -1188,6 +1188,28 @@ qemuValidateDomainDefTPMs(const virDomainDef *def) } +static int +qemuValidateDomainDefWatchdogs(const virDomainDef *def) +{ + ssize_t i = 0; + + for (i = 1; i < def->nwatchdogs; i++) { + /* We could theoretically support different watchdogs having dump and + * pause, but let's be honest, we support multiple watchdogs only + * because we need to be able to add a second, implicit one, not because + * it is a brilliant idea to have multiple watchdogs. */ + if (def->watchdogs[i]->action != def->watchdogs[0]->action) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("watchdogs with different actions are not supported " + "with this QEMU binary")); + return -1; + } + } + + return 0; +} + + int qemuValidateLifecycleAction(virDomainLifecycleAction onPoweroff, virDomainLifecycleAction onReboot, @@ -1388,6 +1410,9 @@ qemuValidateDomainDef(const virDomainDef *def, if (qemuValidateDomainDefTPMs(def) < 0) return -1; + if (qemuValidateDomainDefWatchdogs(def) < 0) + return -1; + if (def->sec) { switch ((virDomainLaunchSecurity) def->sec->sectype) { case VIR_DOMAIN_LAUNCH_SECURITY_SEV: diff --git a/tests/qemuxml2argvdata/watchdog-q35-multiple.x86_64-latest.args b/tests/qemuxml2argvdata/watchdog-q35-multiple.x86_64-latest.args new file mode 100644 index 0000000000..eccf5a2e11 --- /dev/null +++ b/tests/qemuxml2argvdata/watchdog-q35-multiple.x86_64-latest.args @@ -0,0 +1,39 @@ +LC_ALL=C \ +PATH=/bin \ +HOME=/tmp/lib/domain--1-QEMUGuest1 \ +USER=test \ +LOGNAME=test \ +XDG_DATA_HOME=/tmp/lib/domain--1-QEMUGuest1/.local/share \ +XDG_CACHE_HOME=/tmp/lib/domain--1-QEMUGuest1/.cache \ +XDG_CONFIG_HOME=/tmp/lib/domain--1-QEMUGuest1/.config \ +/usr/bin/qemu-system-x86_64 \ +-name guest=QEMUGuest1,debug-threads=on \ +-S \ +-object '{"qom-type":"secret","id":"masterKey0","format":"raw","file":"/tmp/lib/domain--1-QEMUGuest1/master-key.aes"}' \ +-machine q35,usb=off,dump-guest-core=off,memory-backend=pc.ram \ +-accel tcg \ +-cpu qemu64 \ +-m 214 \ +-object '{"qom-type":"memory-backend-ram","id":"pc.ram","size":224395264}' \ +-overcommit mem-lock=off \ +-smp 1,sockets=1,cores=1,threads=1 \ +-uuid c7a5fdbd-edaf-9455-926a-d65c16db1809 \ +-display none \ +-no-user-config \ +-nodefaults \ +-chardev socket,id=charmonitor,fd=1729,server=on,wait=off \ +-mon chardev=charmonitor,id=monitor,mode=control \ +-rtc base=utc \ +-no-shutdown \ +-no-acpi \ +-boot strict=on \ +-device '{"driver":"pcie-root-port","port":8,"chassis":1,"id":"pci.1","bus":"pcie.0","multifunction":true,"addr":"0x1"}' \ +-device '{"driver":"pcie-pci-bridge","id":"pci.2","bus":"pci.1","addr":"0x0"}' \ +-device '{"driver":"pcie-root-port","port":9,"chassis":3,"id":"pci.3","bus":"pcie.0","addr":"0x1.0x1"}' \ +-device '{"driver":"piix3-usb-uhci","id":"usb","bus":"pci.2","addr":"0x1"}' \ +-audiodev '{"id":"audio1","driver":"none"}' \ +-device '{"driver":"ib700","id":"watchdog0"}' \ +-device '{"driver":"i6300esb","id":"watchdog1","bus":"pci.2","addr":"0x2"}' \ +-watchdog-action poweroff \ +-sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \ +-msg timestamp=on diff --git a/tests/qemuxml2argvdata/watchdog-q35-multiple.xml b/tests/qemuxml2argvdata/watchdog-q35-multiple.xml new file mode 100644 index 0000000000..af0cb169f0 --- /dev/null +++ b/tests/qemuxml2argvdata/watchdog-q35-multiple.xml @@ -0,0 +1,25 @@ + + QEMUGuest1 + c7a5fdbd-edaf-9455-926a-d65c16db1809 + 219100 + 219100 + 1 + + hvm + + + + destroy + restart + destroy + + /usr/bin/qemu-system-x86_64 + + + + + + + + + diff --git a/tests/qemuxml2argvtest.c b/tests/qemuxml2argvtest.c index 3e58a73e41..ae0afb6f1c 100644 --- a/tests/qemuxml2argvtest.c +++ b/tests/qemuxml2argvtest.c @@ -1756,6 +1756,7 @@ mymain(void) DO_TEST_CAPS_LATEST("watchdog-device"); DO_TEST_CAPS_LATEST("watchdog-dump"); DO_TEST_CAPS_LATEST("watchdog-injectnmi"); + DO_TEST_CAPS_LATEST("watchdog-q35-multiple"); DO_TEST_CAPS_ARCH_LATEST("watchdog-diag288", "s390x"); DO_TEST_NOCAPS("balloon-device"); DO_TEST("balloon-device-deflate", diff --git a/tests/qemuxml2xmloutdata/watchdog-q35-multiple.x86_64-latest.xml b/tests/qemuxml2xmloutdata/watchdog-q35-multiple.x86_64-latest.xml new file mode 100644 index 0000000000..e507576085 --- /dev/null +++ b/tests/qemuxml2xmloutdata/watchdog-q35-multiple.x86_64-latest.xml @@ -0,0 +1,50 @@ + + QEMUGuest1 + c7a5fdbd-edaf-9455-926a-d65c16db1809 + 219100 + 219100 + 1 + + hvm + + + + qemu64 + + + destroy + restart + destroy + + /usr/bin/qemu-system-x86_64 + + +
+ + +
+ + + + +
+ + + +
+ + + + +
+ + + +