[libvirt] [PATCH 3/4] qemu: hot-plug of watchdog

Michal Privoznik mprivozn at redhat.com
Tue Sep 5 11:45:14 UTC 2017


https://bugzilla.redhat.com/show_bug.cgi?id=1447169

Once again, since domain can have at most one watchdog it
simplifies things a bit. However, since we must be able to set
the watchdog action as well, new monitor command needs to be
used.

Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
---
 src/qemu/qemu_alias.c                              | 15 ++++-
 src/qemu/qemu_alias.h                              |  2 +
 src/qemu/qemu_command.c                            |  2 +-
 src/qemu/qemu_command.h                            |  3 +
 src/qemu/qemu_driver.c                             | 10 +++-
 src/qemu/qemu_hotplug.c                            | 64 ++++++++++++++++++++++
 src/qemu/qemu_hotplug.h                            |  3 +
 src/qemu/qemu_monitor.c                            | 12 ++++
 src/qemu/qemu_monitor.h                            |  2 +
 src/qemu/qemu_monitor_json.c                       | 28 ++++++++++
 src/qemu/qemu_monitor_json.h                       |  3 +
 tests/qemuhotplugtest.c                            |  9 ++-
 .../qemuhotplug-watchdog.xml                       |  1 +
 .../qemuhotplug-base-live+watchdog.xml             | 55 +++++++++++++++++++
 14 files changed, 205 insertions(+), 4 deletions(-)
 create mode 100644 tests/qemuhotplugtestdevices/qemuhotplug-watchdog.xml
 create mode 100644 tests/qemuhotplugtestdomains/qemuhotplug-base-live+watchdog.xml

diff --git a/src/qemu/qemu_alias.c b/src/qemu/qemu_alias.c
index 914b2b94d..63f69e80f 100644
--- a/src/qemu/qemu_alias.c
+++ b/src/qemu/qemu_alias.c
@@ -405,6 +405,19 @@ qemuAssignDeviceShmemAlias(virDomainDefPtr def,
 }
 
 
+int
+qemuAssignDeviceWatchdogAlias(virDomainWatchdogDefPtr watchdog)
+{
+    const int idx = 0;
+
+    /* Currently, there's just one watchdog per domain */
+
+    if (virAsprintf(&watchdog->info.alias, "watchdog%d", idx) < 0)
+        return -1;
+    return 0;
+}
+
+
 int
 qemuAssignDeviceAliases(virDomainDefPtr def, virQEMUCapsPtr qemuCaps)
 {
@@ -482,7 +495,7 @@ qemuAssignDeviceAliases(virDomainDefPtr def, virQEMUCapsPtr qemuCaps)
             return -1;
     }
     if (def->watchdog) {
-        if (virAsprintf(&def->watchdog->info.alias, "watchdog%d", 0) < 0)
+        if (qemuAssignDeviceWatchdogAlias(def->watchdog) < 0)
             return -1;
     }
     if (def->memballoon) {
diff --git a/src/qemu/qemu_alias.h b/src/qemu/qemu_alias.h
index 300fd4de5..652ffea0c 100644
--- a/src/qemu/qemu_alias.h
+++ b/src/qemu/qemu_alias.h
@@ -65,6 +65,8 @@ int qemuAssignDeviceShmemAlias(virDomainDefPtr def,
                                virDomainShmemDefPtr shmem,
                                int idx);
 
+int qemuAssignDeviceWatchdogAlias(virDomainWatchdogDefPtr watchdog);
+
 int qemuAssignDeviceAliases(virDomainDefPtr def, virQEMUCapsPtr qemuCaps);
 
 int qemuDomainDeviceAliasIndex(const virDomainDeviceInfo *info,
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 9a27987d4..eb9df044b 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -3921,7 +3921,7 @@ qemuBuildHostNetStr(virDomainNetDefPtr net,
 }
 
 
-static char *
+char *
 qemuBuildWatchdogDevStr(const virDomainDef *def,
                         virDomainWatchdogDefPtr dev,
                         virQEMUCapsPtr qemuCaps)
diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h
index 6fbfb3e5f..4b504f685 100644
--- a/src/qemu/qemu_command.h
+++ b/src/qemu/qemu_command.h
@@ -206,5 +206,8 @@ char *qemuBuildShmemDevStr(virDomainDefPtr def,
     ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
 
 
+char * qemuBuildWatchdogDevStr(const virDomainDef *def,
+                               virDomainWatchdogDefPtr dev,
+                               virQEMUCapsPtr qemuCaps);
 
 #endif /* __QEMU_COMMAND_H__*/
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 85b4be360..626148dba 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -7593,12 +7593,20 @@ qemuDomainAttachDeviceLive(virDomainObjPtr vm,
         }
         break;
 
+    case VIR_DOMAIN_DEVICE_WATCHDOG:
+        ret = qemuDomainAttachWatchdog(driver, vm,
+                                       dev->data.watchdog);
+        if (!ret) {
+            alias = dev->data.watchdog->info.alias;
+            dev->data.watchdog = NULL;
+        }
+        break;
+
     case VIR_DOMAIN_DEVICE_NONE:
     case VIR_DOMAIN_DEVICE_FS:
     case VIR_DOMAIN_DEVICE_INPUT:
     case VIR_DOMAIN_DEVICE_SOUND:
     case VIR_DOMAIN_DEVICE_VIDEO:
-    case VIR_DOMAIN_DEVICE_WATCHDOG:
     case VIR_DOMAIN_DEVICE_GRAPHICS:
     case VIR_DOMAIN_DEVICE_HUB:
     case VIR_DOMAIN_DEVICE_SMARTCARD:
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index b365078ec..989146eb9 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -2866,6 +2866,70 @@ qemuDomainAttachShmemDevice(virQEMUDriverPtr driver,
 }
 
 
+int
+qemuDomainAttachWatchdog(virQEMUDriverPtr driver,
+                         virDomainObjPtr vm,
+                         virDomainWatchdogDefPtr watchdog)
+{
+    int ret = -1;
+    qemuDomainObjPrivatePtr priv = vm->privateData;
+    virDomainDeviceDef dev = { VIR_DOMAIN_DEVICE_WATCHDOG, { .watchdog = watchdog } };
+    virDomainWatchdogAction actualAction = watchdog->action;
+    char *watchdogstr = NULL;
+    bool releaseAddress = false;
+    int rv;
+
+    if (vm->def->watchdog) {
+        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                       _("domain already has a watchdog"));
+        return -1;
+    }
+
+    if (qemuAssignDeviceWatchdogAlias(watchdog) < 0)
+        return -1;
+
+    if (!(watchdogstr = qemuBuildWatchdogDevStr(vm->def, watchdog, priv->qemuCaps)))
+        return -1;
+
+    if (watchdog->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI) {
+        if (qemuDomainEnsurePCIAddress(vm, &dev, driver) < 0)
+            goto cleanup;
+        releaseAddress = true;
+    }
+
+    /* 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 (actualAction == VIR_DOMAIN_WATCHDOG_ACTION_DUMP)
+        actualAction = VIR_DOMAIN_WATCHDOG_ACTION_PAUSE;
+
+    qemuDomainObjEnterMonitor(driver, vm);
+
+    rv = qemuMonitorSetWatchdogAction(priv->mon, actualAction);
+
+    if (rv >= 0)
+        rv = qemuMonitorAddDevice(priv->mon, watchdogstr);
+
+    if (qemuDomainObjExitMonitor(driver, vm) < 0) {
+        releaseAddress = false;
+        goto cleanup;
+    }
+
+    if (rv < 0)
+        goto cleanup;
+
+    releaseAddress = false;
+    vm->def->watchdog = watchdog;
+    ret = 0;
+
+ cleanup:
+    if (releaseAddress)
+        qemuDomainReleaseDeviceAddress(vm, &watchdog->info, NULL);
+    VIR_FREE(watchdogstr);
+    return ret;
+}
+
+
 static int
 qemuDomainChangeNetBridge(virDomainObjPtr vm,
                           virDomainNetDefPtr olddev,
diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h
index 985c6733f..a9dfd8f7a 100644
--- a/src/qemu/qemu_hotplug.h
+++ b/src/qemu/qemu_hotplug.h
@@ -80,6 +80,9 @@ int qemuDomainAttachHostDevice(virConnectPtr conn,
 int qemuDomainAttachShmemDevice(virQEMUDriverPtr driver,
                                 virDomainObjPtr vm,
                                 virDomainShmemDefPtr shmem);
+int qemuDomainAttachWatchdog(virQEMUDriverPtr driver,
+                             virDomainObjPtr vm,
+                             virDomainWatchdogDefPtr watchdog);
 int qemuDomainFindGraphicsIndex(virDomainDefPtr def,
                                 virDomainGraphicsDefPtr dev);
 int qemuDomainAttachMemory(virQEMUDriverPtr driver,
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 19082d8bf..5d3f9df47 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -4343,3 +4343,15 @@ qemuMonitorEventPanicInfoFree(qemuMonitorEventPanicInfoPtr info)
 
     VIR_FREE(info);
 }
+
+
+int
+qemuMonitorSetWatchdogAction(qemuMonitorPtr mon,
+                             virDomainWatchdogAction watchdogAction)
+{
+    VIR_DEBUG("watchdogAction=%d", watchdogAction);
+
+    QEMU_CHECK_MONITOR_JSON(mon);
+
+    return qemuMonitorJSONSetWatchdogAction(mon, watchdogAction);
+}
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 9805a3390..b8c9409e5 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -1132,4 +1132,6 @@ int qemuMonitorSetBlockThreshold(qemuMonitorPtr mon,
 
 virJSONValuePtr qemuMonitorQueryNamedBlockNodes(qemuMonitorPtr mon);
 
+int qemuMonitorSetWatchdogAction(qemuMonitorPtr mon,
+                                 virDomainWatchdogAction watchdogAction);
 #endif /* QEMU_MONITOR_H */
diff --git a/src/qemu/qemu_monitor_json.c b/src/qemu/qemu_monitor_json.c
index df5fb7c8f..02ba701e6 100644
--- a/src/qemu/qemu_monitor_json.c
+++ b/src/qemu/qemu_monitor_json.c
@@ -7679,3 +7679,31 @@ qemuMonitorJSONQueryNamedBlockNodes(qemuMonitorPtr mon)
 
     return ret;
 }
+
+
+int
+qemuMonitorJSONSetWatchdogAction(qemuMonitorPtr mon,
+                                 virDomainWatchdogAction watchdogAction)
+{
+    virJSONValuePtr cmd;
+    virJSONValuePtr reply = NULL;
+    const char *action = virDomainWatchdogActionTypeToString(watchdogAction);
+    int ret = -1;
+
+    if (!(cmd = qemuMonitorJSONMakeCommand("watchdog-set-action",
+                                           "s:action", action,
+                                           NULL)))
+        return -1;
+    if (qemuMonitorJSONCommand(mon, cmd, &reply) < 0)
+        goto cleanup;
+
+    if (qemuMonitorJSONCheckError(cmd, reply) < 0)
+        goto cleanup;
+
+    ret = 0;
+
+ cleanup:
+    virJSONValueFree(cmd);
+    virJSONValueFree(reply);
+    return ret;
+}
diff --git a/src/qemu/qemu_monitor_json.h b/src/qemu/qemu_monitor_json.h
index 7462967b5..a7a43d7b8 100644
--- a/src/qemu/qemu_monitor_json.h
+++ b/src/qemu/qemu_monitor_json.h
@@ -524,4 +524,7 @@ int qemuMonitorJSONSetBlockThreshold(qemuMonitorPtr mon,
 virJSONValuePtr qemuMonitorJSONQueryNamedBlockNodes(qemuMonitorPtr mon)
     ATTRIBUTE_NONNULL(1);
 
+int qemuMonitorJSONSetWatchdogAction(qemuMonitorPtr mon,
+                                     virDomainWatchdogAction watchdogAction)
+    ATTRIBUTE_NONNULL(1);
 #endif /* QEMU_MONITOR_JSON_H */
diff --git a/tests/qemuhotplugtest.c b/tests/qemuhotplugtest.c
index 23a498617..b02ae8034 100644
--- a/tests/qemuhotplugtest.c
+++ b/tests/qemuhotplugtest.c
@@ -127,6 +127,9 @@ testQemuHotplugAttach(virDomainObjPtr vm,
     case VIR_DOMAIN_DEVICE_SHMEM:
         ret = qemuDomainAttachShmemDevice(&driver, vm, dev->data.shmem);
         break;
+    case VIR_DOMAIN_DEVICE_WATCHDOG:
+        ret = qemuDomainAttachWatchdog(&driver, vm, dev->data.watchdog);
+        break;
     default:
         VIR_TEST_VERBOSE("device type '%s' cannot be attached\n",
                 virDomainDeviceTypeToString(dev->type));
@@ -811,10 +814,14 @@ mymain(void)
                    "device_del", QMP_OK,
                    "object-del", QMP_OK);
     DO_TEST_ATTACH("base-live+disk-scsi-wwn",
-                   "disk-scsi-duplicate-wwn", false, true,
+                   "disk-scsi-duplicate-wwn", false, false,
                    "human-monitor-command", HMP("OK\\r\\n"),
                    "device_add", QMP_OK);
 
+    DO_TEST_ATTACH("base-live", "watchdog", false, false,
+                   "watchdog-set-action", QMP_OK,
+                   "device_add", QMP_OK);
+
 #define DO_TEST_CPU_GROUP(prefix, vcpus, modernhp, expectfail)                 \
     do {                                                                       \
         cpudata.test = prefix;                                                 \
diff --git a/tests/qemuhotplugtestdevices/qemuhotplug-watchdog.xml b/tests/qemuhotplugtestdevices/qemuhotplug-watchdog.xml
new file mode 100644
index 000000000..7e0e0a863
--- /dev/null
+++ b/tests/qemuhotplugtestdevices/qemuhotplug-watchdog.xml
@@ -0,0 +1 @@
+<watchdog model='ib700' action='poweroff'/>
diff --git a/tests/qemuhotplugtestdomains/qemuhotplug-base-live+watchdog.xml b/tests/qemuhotplugtestdomains/qemuhotplug-base-live+watchdog.xml
new file mode 100644
index 000000000..f884eec50
--- /dev/null
+++ b/tests/qemuhotplugtestdomains/qemuhotplug-base-live+watchdog.xml
@@ -0,0 +1,55 @@
+<domain type='kvm' id='7'>
+  <name>hotplug</name>
+  <uuid>d091ea82-29e6-2e34-3005-f02617b36e87</uuid>
+  <memory unit='KiB'>4194304</memory>
+  <currentMemory unit='KiB'>4194304</currentMemory>
+  <vcpu placement='static'>4</vcpu>
+  <os>
+    <type arch='x86_64' machine='pc'>hvm</type>
+    <boot dev='hd'/>
+  </os>
+  <features>
+    <acpi/>
+    <apic/>
+    <pae/>
+  </features>
+  <clock offset='utc'/>
+  <on_poweroff>destroy</on_poweroff>
+  <on_reboot>restart</on_reboot>
+  <on_crash>restart</on_crash>
+  <devices>
+    <emulator>/usr/bin/qemu-system-x86_64</emulator>
+    <controller type='usb' index='0'>
+      <alias name='usb'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
+    </controller>
+    <controller type='ide' index='0'>
+      <alias name='ide'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
+    </controller>
+    <controller type='scsi' index='0' model='virtio-scsi'>
+      <alias name='scsi0'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
+    </controller>
+    <controller type='pci' index='0' model='pci-root'>
+      <alias name='pci'/>
+    </controller>
+    <controller type='virtio-serial' index='0'>
+      <alias name='virtio-serial0'/>
+      <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
+    </controller>
+    <input type='mouse' bus='ps2'>
+      <alias name='input0'/>
+    </input>
+    <input type='keyboard' bus='ps2'>
+      <alias name='input1'/>
+    </input>
+    <watchdog model='ib700' action='poweroff'>
+      <alias name='watchdog0'/>
+    </watchdog>
+    <memballoon model='none'>
+      <alias name='balloon0'/>
+    </memballoon>
+  </devices>
+  <seclabel type='none' model='none'/>
+</domain>
-- 
2.13.5




More information about the libvir-list mailing list