]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
Support multiple watchdog devices
authorMartin Kletzander <mkletzan@redhat.com>
Tue, 8 Nov 2022 08:10:57 +0000 (09:10 +0100)
committerMartin Kletzander <mkletzan@redhat.com>
Thu, 26 Jan 2023 15:40:30 +0000 (16:40 +0100)
This is already possible with qemu, and actually already happening with
q35 machines and a specified watchdog since q35 already includes a
watchdog we do not include in the XML.  In order to express such
posibility multiple watchdogs need to be supported.

Signed-off-by: Martin Kletzander <mkletzan@redhat.com>
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
17 files changed:
src/conf/domain_conf.c
src/conf/domain_conf.h
src/conf/schemas/domaincommon.rng
src/libvirt_private.syms
src/qemu/qemu_alias.c
src/qemu/qemu_alias.h
src/qemu/qemu_command.c
src/qemu/qemu_domain_address.c
src/qemu/qemu_driver.c
src/qemu/qemu_hotplug.c
src/qemu/qemu_process.c
src/qemu/qemu_validate.c
tests/qemuxml2argvdata/watchdog-q35-multiple.x86_64-latest.args [new file with mode: 0644]
tests/qemuxml2argvdata/watchdog-q35-multiple.xml [new file with mode: 0644]
tests/qemuxml2argvtest.c
tests/qemuxml2xmloutdata/watchdog-q35-multiple.x86_64-latest.xml [new file with mode: 0644]
tests/qemuxml2xmltest.c

index 89672deb38c3c431dfe4f4d496ab31f15bca9820..00a42abd30d34139c50304f2cb512ba489689700 100644 (file)
@@ -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;
+}
index d99bbbc3ff79ba2341b124fcb21533564be8872a..2b04e0c3e0208bca8dc48e5d9285f7d8da0646ce 100644 (file)
@@ -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);
index 14044811c00ef7a4d3a9930f03ef18ce0a90e54e..524d57884ca85ab3372c0462ab068d6a9f1f5c9b 100644 (file)
             <ref name="crypto"/>
           </choice>
         </zeroOrMore>
-        <optional>
+        <zeroOrMore>
           <ref name="watchdog"/>
-        </optional>
+        </zeroOrMore>
         <optional>
           <ref name="memballoon"/>
         </optional>
index ac2e51e60619e46d93ac3c8854cfcd2e17671f9d..7ca8b472be928a3991d8881f16042a10fd6673a5 100644 (file)
@@ -699,6 +699,7 @@ virDomainVsockDefFree;
 virDomainVsockDefNew;
 virDomainWatchdogActionTypeFromString;
 virDomainWatchdogActionTypeToString;
+virDomainWatchdogDefFind;
 virDomainWatchdogDefFree;
 virDomainWatchdogModelTypeFromString;
 virDomainWatchdogModelTypeToString;
index c74c68a939a1fa21a5351f8943227cb92b76b679..a9809797d5e3c18fa9273d114fa5cd2ff2aac69e 100644 (file)
@@ -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)
+        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++;
+    }
 
-    if (!watchdog->info.alias)
-        watchdog->info.alias = g_strdup("watchdog0");
+    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) {
index af9c3f62d3531e7535671749bf56c3756e208de6..f13f4cc5f86a06b37d8b6f0c3265617a71494783 100644 (file)
@@ -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,
index 4ba978f3e668d3ded0d65d3478828bd67e4bfa4e..987c9d20db96db2b7e04927d9502d0e938f302e8 100644 (file)
@@ -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;
index 9529bd9a8d32d90161549c17a50b425e6311359c..e26ce9c0e6456ddab92e5972b78f21f223e9036a 100644 (file)
@@ -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;
     }
 
index 0e2320426f58ade6cda12900af9f3bd3c4a31c87..f3f64d34116fca92bb2ca0326786eedc3a9931df 100644 (file)
@@ -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:
index e153e4806d31228fc4d894706fa466b924024e92..538fa502c40b62e3384e6c18cfe6458946ee45da 100644 (file)
@@ -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;
-
-    *detach = watchdog = vm->def->watchdog;
+    ssize_t idx = virDomainWatchdogDefFind(vm->def, match);
 
-    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;
     }
 
index 9ac6b45e75ed9e434f7c8e274b821ce4c54c1df8..4afd12e3fa859b613f7fd5f6f1f69ce315c1aae3 100644 (file)
@@ -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);
     }
index 9829c4e7ff365b33bc491f94c4f753d3ffd61519..134ab0437c42565b672bb6e62c4b9c6b38f371f2 100644 (file)
@@ -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 (file)
index 0000000..eccf5a2
--- /dev/null
@@ -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 (file)
index 0000000..af0cb16
--- /dev/null
@@ -0,0 +1,25 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory unit='KiB'>219100</memory>
+  <currentMemory unit='KiB'>219100</currentMemory>
+  <vcpu placement='static'>1</vcpu>
+  <os>
+    <type arch='x86_64' machine='q35'>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-system-x86_64</emulator>
+    <controller type='pci' index='0' model='pcie-root'/>
+    <controller type='usb' index='0'/>
+    <input type='mouse' bus='ps2'/>
+    <input type='keyboard' bus='ps2'/>
+    <watchdog model='ib700' action='poweroff'/>
+    <watchdog model='i6300esb' action='poweroff'/>
+    <memballoon model='none'/>
+  </devices>
+</domain>
index 3e58a73e41db143b35e82be97dcc1e7da7125762..ae0afb6f1cfc235b9f994be1d3b37d8c1fa33298 100644 (file)
@@ -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 (file)
index 0000000..e507576
--- /dev/null
@@ -0,0 +1,50 @@
+<domain type='qemu'>
+  <name>QEMUGuest1</name>
+  <uuid>c7a5fdbd-edaf-9455-926a-d65c16db1809</uuid>
+  <memory unit='KiB'>219100</memory>
+  <currentMemory unit='KiB'>219100</currentMemory>
+  <vcpu placement='static'>1</vcpu>
+  <os>
+    <type arch='x86_64' machine='q35'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <cpu mode='custom' match='exact' check='none'>
+    <model fallback='forbid'>qemu64</model>
+  </cpu>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>destroy</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu-system-x86_64</emulator>
+    <controller type='pci' index='0' model='pcie-root'/>
+    <controller type='usb' index='0' model='piix3-uhci'>
+      <address type='pci' domain='0x0000' bus='0x02' slot='0x01' function='0x0'/>
+    </controller>
+    <controller type='sata' index='0'>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x1f' function='0x2'/>
+    </controller>
+    <controller type='pci' index='1' model='pcie-root-port'>
+      <model name='pcie-root-port'/>
+      <target chassis='1' port='0x8'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x0' multifunction='on'/>
+    </controller>
+    <controller type='pci' index='2' model='pcie-to-pci-bridge'>
+      <model name='pcie-pci-bridge'/>
+      <address type='pci' domain='0x0000' bus='0x01' slot='0x00' function='0x0'/>
+    </controller>
+    <controller type='pci' index='3' model='pcie-root-port'>
+      <model name='pcie-root-port'/>
+      <target chassis='3' port='0x9'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
+    </controller>
+    <input type='mouse' bus='ps2'/>
+    <input type='keyboard' bus='ps2'/>
+    <audio id='1' type='none'/>
+    <watchdog model='ib700' action='poweroff'/>
+    <watchdog model='i6300esb' action='poweroff'>
+      <address type='pci' domain='0x0000' bus='0x02' slot='0x02' function='0x0'/>
+    </watchdog>
+    <memballoon model='none'/>
+  </devices>
+</domain>
index 9ab49b822c18f363d0775d0000583a25f87e8195..ae9716062d07b348e5798917bf4b634702ab3dd4 100644 (file)
@@ -489,6 +489,7 @@ mymain(void)
             QEMU_CAPS_HDA_DUPLEX,
             QEMU_CAPS_HDA_OUTPUT);
     DO_TEST_NOCAPS("watchdog");
+    DO_TEST_CAPS_LATEST("watchdog-q35-multiple");
     DO_TEST("net-bandwidth", QEMU_CAPS_DEVICE_VGA, QEMU_CAPS_VNC);
     DO_TEST("net-bandwidth2", QEMU_CAPS_DEVICE_VGA, QEMU_CAPS_VNC);
     DO_TEST_NOCAPS("net-mtu");