[libvirt] [PATCH v4 8/9] qemu: Implement chardev hotplug on live level

Michal Privoznik mprivozn at redhat.com
Wed Jul 10 17:02:58 UTC 2013


Since previous patches has prepared everything for us, we may now
implement live hotplug of a character device.
---
 src/qemu/qemu_command.c |  38 ++++++++++++++++-
 src/qemu/qemu_driver.c  |  26 ++++++++++--
 src/qemu/qemu_hotplug.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/qemu/qemu_hotplug.h |   6 +++
 4 files changed, 173 insertions(+), 5 deletions(-)

diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 063d76b..6842cab 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -863,8 +863,41 @@ qemuAssignDeviceControllerAlias(virDomainControllerDefPtr controller)
     return virAsprintf(&controller->info.alias, "%s%d", prefix, controller->idx);
 }
 
+static ssize_t
+qemuGetNextChrDevIndex(virDomainDefPtr def,
+                       virDomainChrDefPtr chr,
+                       const char *prefix)
+{
+    virDomainChrDefPtr **arrPtr;
+    size_t *cntPtr;
+    size_t i;
+    ssize_t idx = 0;
+    const char *prefix2 = NULL;
+
+    if (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE)
+        prefix2 = "serial";
+
+    virDomainChrGetDomainPtrs(def, chr, &arrPtr, &cntPtr);
+
+    for (i = 0; i < *cntPtr; i++) {
+        ssize_t thisidx;
+        if (((thisidx = qemuDomainDeviceAliasIndex(&(*arrPtr)[i]->info, prefix)) < 0) &&
+            (prefix2 &&
+             (thisidx = qemuDomainDeviceAliasIndex(&(*arrPtr)[i]->info, prefix2)) < 0)) {
+            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                           _("Unable to determine device index for character device"));
+            return -1;
+        }
+        if (thisidx >= idx)
+            idx = thisidx + 1;
+    }
+
+    return idx;
+}
+
+
 int
-qemuAssignDeviceChrAlias(virDomainDefPtr def ATTRIBUTE_UNUSED,
+qemuAssignDeviceChrAlias(virDomainDefPtr def,
                          virDomainChrDefPtr chr,
                          ssize_t idx)
 {
@@ -891,6 +924,9 @@ qemuAssignDeviceChrAlias(virDomainDefPtr def ATTRIBUTE_UNUSED,
         return -1;
     }
 
+    if (idx == -1 && (idx = qemuGetNextChrDevIndex(def, chr, prefix)) < 0)
+        return -1;
+
     return virAsprintf(&chr->info.alias, "%s%zd", prefix, idx);
 }
 
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index d858131..486de4e 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -6387,6 +6387,13 @@ qemuDomainAttachDeviceLive(virDomainObjPtr vm,
             dev->data.redirdev = NULL;
         break;
 
+    case VIR_DOMAIN_DEVICE_CHR:
+        ret = qemuDomainAttachChrDevice(driver, vm,
+                                        dev->data.chr);
+        if (!ret)
+            dev->data.chr = NULL;
+        break;
+
     default:
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                        _("device type '%s' cannot be attached"),
@@ -6474,6 +6481,9 @@ qemuDomainDetachDeviceLive(virDomainObjPtr vm,
     case VIR_DOMAIN_DEVICE_HOSTDEV:
         ret = qemuDomainDetachHostDevice(driver, vm, dev);
         break;
+    case VIR_DOMAIN_DEVICE_CHR:
+        ret = qemuDomainDetachChrDevice(driver, vm, dev->data.chr);
+        break;
     default:
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                        "%s", _("This type of device cannot be hot unplugged"));
@@ -6890,7 +6900,7 @@ static int qemuDomainAttachDeviceFlags(virDomainPtr dom, const char *xml,
     virDomainDefPtr vmdef = NULL;
     virDomainDeviceDefPtr dev = NULL, dev_copy = NULL;
     int ret = -1;
-    unsigned int affect;
+    unsigned int affect, parse_flags = 0;
     virQEMUCapsPtr qemuCaps = NULL;
     qemuDomainObjPrivatePtr priv;
     virQEMUDriverConfigPtr cfg = NULL;
@@ -6938,9 +6948,13 @@ static int qemuDomainAttachDeviceFlags(virDomainPtr dom, const char *xml,
          goto endjob;
     }
 
+    if ((flags & VIR_DOMAIN_AFFECT_CONFIG) &&
+        !(flags & VIR_DOMAIN_AFFECT_LIVE))
+        parse_flags |= VIR_DOMAIN_XML_INACTIVE;
+
     dev = dev_copy = virDomainDeviceDefParse(xml, vm->def,
                                              caps, driver->xmlopt,
-                                             VIR_DOMAIN_XML_INACTIVE);
+                                             parse_flags);
     if (dev == NULL)
         goto endjob;
 
@@ -7168,7 +7182,7 @@ static int qemuDomainDetachDeviceFlags(virDomainPtr dom, const char *xml,
     virDomainDefPtr vmdef = NULL;
     virDomainDeviceDefPtr dev = NULL, dev_copy = NULL;
     int ret = -1;
-    unsigned int affect;
+    unsigned int affect, parse_flags = 0;
     virQEMUCapsPtr qemuCaps = NULL;
     qemuDomainObjPrivatePtr priv;
     virQEMUDriverConfigPtr cfg = NULL;
@@ -7216,9 +7230,13 @@ static int qemuDomainDetachDeviceFlags(virDomainPtr dom, const char *xml,
          goto endjob;
     }
 
+    if ((flags & VIR_DOMAIN_AFFECT_CONFIG) &&
+        !(flags & VIR_DOMAIN_AFFECT_LIVE))
+        parse_flags |= VIR_DOMAIN_XML_INACTIVE;
+
     dev = dev_copy = virDomainDeviceDefParse(xml, vm->def,
                                              caps, driver->xmlopt,
-                                             VIR_DOMAIN_XML_INACTIVE);
+                                             parse_flags);
     if (dev == NULL)
         goto endjob;
 
diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c
index cc8779d..237afe9 100644
--- a/src/qemu/qemu_hotplug.c
+++ b/src/qemu/qemu_hotplug.c
@@ -1160,6 +1160,67 @@ error:
 
 }
 
+int qemuDomainAttachChrDevice(virQEMUDriverPtr driver,
+                              virDomainObjPtr vm,
+                              virDomainChrDefPtr chr)
+{
+    int ret = -1;
+    qemuDomainObjPrivatePtr priv = vm->privateData;
+    virDomainDefPtr vmdef = vm->def;
+    char *devstr = NULL;
+    char *charAlias = NULL;
+    bool remove = false;
+
+    if (virDomainChrFind(vmdef, chr)) {
+        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                       _("chardev already exists"));
+        return ret;
+    }
+
+    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE)) {
+        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                       _("qemu does not support -device"));
+        return ret;
+    }
+
+    if (qemuAssignDeviceChrAlias(vmdef, chr, -1) < 0)
+        return ret;
+
+    if (qemuBuildChrDeviceStr(&devstr, vm->def, chr, priv->qemuCaps) < 0)
+        return ret;
+
+    if (virAsprintf(&charAlias, "char%s", chr->info.alias) < 0) {
+        virReportOOMError();
+        goto cleanup;
+    }
+
+    if (virDomainChrInsert(vmdef, chr) < 0)
+        goto cleanup;
+    remove = true;
+
+    qemuDomainObjEnterMonitor(driver, vm);
+    if (qemuMonitorAttachCharDev(priv->mon, charAlias, &chr->source) < 0) {
+        qemuDomainObjExitMonitor(driver, vm);
+        goto cleanup;
+    }
+
+    if (devstr && qemuMonitorAddDevice(priv->mon, devstr) < 0) {
+        /* detach associated chardev on error */
+        qemuMonitorDetachCharDev(priv->mon, charAlias);
+        qemuDomainObjExitMonitor(driver, vm);
+        goto cleanup;
+    }
+    qemuDomainObjExitMonitor(driver, vm);
+
+    ret = 0;
+cleanup:
+    if (ret < 0 && remove)
+        virDomainChrRemove(vmdef, chr);
+    VIR_FREE(charAlias);
+    VIR_FREE(devstr);
+    return ret;
+}
+
 int qemuDomainAttachHostUsbDevice(virQEMUDriverPtr driver,
                                   virDomainObjPtr vm,
                                   virDomainHostdevDefPtr hostdev)
@@ -2992,3 +3053,50 @@ int qemuDomainDetachLease(virQEMUDriverPtr driver,
     virDomainLeaseDefFree(det_lease);
     return 0;
 }
+
+int qemuDomainDetachChrDevice(virQEMUDriverPtr driver,
+                              virDomainObjPtr vm,
+                              virDomainChrDefPtr chr)
+{
+    int ret = -1;
+    qemuDomainObjPrivatePtr priv = vm->privateData;
+    virDomainDefPtr vmdef = vm->def;
+    virDomainChrDefPtr tmpChr;
+    char *charAlias = NULL;
+    char *devstr = NULL;
+
+    if (!(tmpChr = virDomainChrFind(vmdef, chr))) {
+        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
+                       _("device not present in domain configuration"));
+        return ret;
+    }
+
+    if (qemuBuildChrDeviceStr(&devstr, vm->def, chr, priv->qemuCaps) < 0)
+        return ret;
+
+    if (virAsprintf(&charAlias, "char%s", tmpChr->info.alias) < 0) {
+        virReportOOMError();
+        return ret;
+    }
+
+    qemuDomainObjEnterMonitor(driver, vm);
+    if (devstr && qemuMonitorDelDevice(priv->mon, tmpChr->info.alias) < 0) {
+        qemuDomainObjExitMonitor(driver, vm);
+        goto cleanup;
+    }
+
+    if (qemuMonitorDetachCharDev(priv->mon, charAlias) < 0) {
+        qemuDomainObjExitMonitor(driver, vm);
+        goto cleanup;
+    }
+    qemuDomainObjExitMonitor(driver, vm);
+
+    virDomainChrRemove(vmdef, tmpChr);
+    virDomainChrDefFree(tmpChr);
+    ret = 0;
+
+cleanup:
+    VIR_FREE(devstr);
+    VIR_FREE(charAlias);
+    return ret;
+}
diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h
index da20eb1..46cd129 100644
--- a/src/qemu/qemu_hotplug.h
+++ b/src/qemu/qemu_hotplug.h
@@ -104,6 +104,12 @@ int qemuDomainAttachLease(virQEMUDriverPtr driver,
 int qemuDomainDetachLease(virQEMUDriverPtr driver,
                           virDomainObjPtr vm,
                           virDomainLeaseDefPtr lease);
+int qemuDomainAttachChrDevice(virQEMUDriverPtr driver,
+                              virDomainObjPtr vm,
+                              virDomainChrDefPtr chr);
+int qemuDomainDetachChrDevice(virQEMUDriverPtr driver,
+                              virDomainObjPtr vm,
+                              virDomainChrDefPtr chr);
 
 
 #endif /* __QEMU_HOTPLUG_H__ */
-- 
1.8.1.5




More information about the libvir-list mailing list