[libvirt] [PATCH 08/15] Locking of the qemuMonitorPtr object

Daniel P. Berrange berrange at redhat.com
Tue Nov 3 19:50:02 UTC 2009


In preparation of the monitor I/O process becoming fully asynchronous,
it is neccessary to ensure all access to internals of the qemuMonitorPtr
object is protected by a mutex lock.

* src/qemu/qemu_monitor.c, src/qemu/qemu_monitor.h: Add mutex for locking
  monitor.
* src/qemu/qemu_driver.c: Add locking around all monitor commands
---
 src/qemu/qemu_driver.c  |  299 +++++++++++++++++++++++++++++++++++------------
 src/qemu/qemu_monitor.c |   19 +++
 src/qemu/qemu_monitor.h |    3 +
 3 files changed, 248 insertions(+), 73 deletions(-)

diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
index 0fbd20f..82cad69 100644
--- a/src/qemu/qemu_driver.c
+++ b/src/qemu/qemu_driver.c
@@ -141,6 +141,22 @@ static void qemuDomainObjPrivateFree(void *data)
 }
 
 
+static void qemuDomainObjEnterMonitor(virDomainObjPtr obj)
+{
+    qemuDomainObjPrivatePtr priv = obj->privateData;
+
+    qemuMonitorLock(priv->mon);
+}
+
+
+static void qemuDomainObjExitMonitor(virDomainObjPtr obj)
+{
+    qemuDomainObjPrivatePtr priv = obj->privateData;
+
+    qemuMonitorUnlock(priv->mon);
+}
+
+
 static int qemuCgroupControllerActive(struct qemud_driver *driver,
                                       int controller)
 {
@@ -1139,8 +1155,12 @@ qemuDetectVcpuPIDs(virConnectPtr conn,
 
     /* What follows is now all KVM specific */
 
-    if ((ncpupids = qemuMonitorGetCPUInfo(priv->mon, &cpupids)) < 0)
+    qemuDomainObjEnterMonitor(vm);
+    if ((ncpupids = qemuMonitorGetCPUInfo(priv->mon, &cpupids)) < 0) {
+        qemuDomainObjExitMonitor(vm);
         return -1;
+    }
+    qemuDomainObjExitMonitor(vm);
 
     /* Treat failure to get VCPU<->PID mapping as non-fatal */
     if (ncpupids == 0)
@@ -1197,14 +1217,18 @@ qemudInitCpus(virConnectPtr conn,
     }
 #endif /* HAVE_SCHED_GETAFFINITY */
 
+    /* XXX This resume doesn't really belong here. Move it up to caller */
     if (migrateFrom == NULL) {
         /* Allow the CPUS to start executing */
+        qemuDomainObjEnterMonitor(vm);
         if (qemuMonitorStartCPUs(priv->mon, conn) < 0) {
             if (virGetLastError() == NULL)
                 qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                                  "%s", _("resume operation failed"));
+            qemuDomainObjExitMonitor(vm);
             return -1;
         }
+        qemuDomainObjExitMonitor(vm);
     }
 
     return 0;
@@ -1221,10 +1245,12 @@ qemuInitPasswords(struct qemud_driver *driver,
         vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
         (vm->def->graphics[0]->data.vnc.passwd || driver->vncPassword)) {
 
+        qemuDomainObjEnterMonitor(vm);
         ret = qemuMonitorSetVNCPassword(priv->mon,
                                         vm->def->graphics[0]->data.vnc.passwd ?
                                         vm->def->graphics[0]->data.vnc.passwd :
                                         driver->vncPassword);
+        qemuDomainObjExitMonitor(vm);
     }
 
     return ret;
@@ -1910,6 +1936,7 @@ static int qemudStartVMDaemon(virConnectPtr conn,
     char ebuf[1024];
     char *pidfile = NULL;
     int logfile;
+    qemuDomainObjPrivatePtr priv = vm->privateData;
 
     struct qemudHookData hookData;
     hookData.conn = conn;
@@ -2082,26 +2109,37 @@ static int qemudStartVMDaemon(virConnectPtr conn,
         VIR_FREE(tapfds);
     }
 
-    if (ret == -1)
+    if (ret == -1) /* The VM failed to start */
         goto cleanup;
 
-    if ((qemudWaitForMonitor(conn, driver, vm, pos) < 0) ||
-        (qemuDetectVcpuPIDs(conn, vm) < 0) ||
-        (qemudInitCpus(conn, vm, migrateFrom) < 0) ||
-        (qemuInitPasswords(driver, vm) < 0) ||
-        (qemuMonitorSetBalloon(((qemuDomainObjPrivatePtr)vm->privateData)->mon, vm->def->memory) < 0) ||
-        (virDomainSaveStatus(conn, driver->stateDir, vm) < 0)) {
-        qemudShutdownVMDaemon(conn, driver, vm);
-        ret = -1;
-        /* No need for 'goto cleanup' now since qemudShutdownVMDaemon does enough */
+    if (qemudWaitForMonitor(conn, driver, vm, pos) < 0)
+        goto abort;
+
+    if (qemuDetectVcpuPIDs(conn, vm) < 0)
+        goto abort;
+
+    if (qemudInitCpus(conn, vm, migrateFrom) < 0)
+        goto abort;
+
+    if (qemuInitPasswords(driver, vm) < 0)
+        goto abort;
+
+    qemuDomainObjEnterMonitor(vm);
+    if (qemuMonitorSetBalloon(priv->mon, vm->def->memory) < 0) {
+        qemuDomainObjExitMonitor(vm);
+        goto abort;
     }
+    qemuDomainObjExitMonitor(vm);
 
-    if (logfile != -1)
-        close(logfile);
+    if (virDomainSaveStatus(conn, driver->stateDir, vm) < 0)
+        goto abort;
 
-    return ret;
+    return 0;
 
 cleanup:
+    /* We jump here if we failed to start the VM for any reason
+     * XXX investigate if we can kill this block and safely call
+     * qemudShutdownVMDaemon even though no PID is running */
     if (vm->def->seclabel.type == VIR_DOMAIN_SECLABEL_DYNAMIC) {
         VIR_FREE(vm->def->seclabel.model);
         VIR_FREE(vm->def->seclabel.label);
@@ -2116,6 +2154,16 @@ cleanup:
         close(logfile);
     vm->def->id = -1;
     return -1;
+
+abort:
+    /* We jump here if we failed to initialize the now running VM
+     * killing it off and pretend we never started it */
+    qemudShutdownVMDaemon(conn, driver, vm);
+
+    if (logfile != -1)
+        close(logfile);
+
+    return -1;
 }
 
 
@@ -2649,8 +2697,12 @@ static int qemudDomainSuspend(virDomainPtr dom) {
     }
     if (vm->state != VIR_DOMAIN_PAUSED) {
         qemuDomainObjPrivatePtr priv = vm->privateData;
-        if (qemuMonitorStopCPUs(priv->mon) < 0)
+        qemuDomainObjEnterMonitor(vm);
+        if (qemuMonitorStopCPUs(priv->mon) < 0) {
+            qemuDomainObjExitMonitor(vm);
             goto cleanup;
+        }
+        qemuDomainObjExitMonitor(vm);
         vm->state = VIR_DOMAIN_PAUSED;
         event = virDomainEventNewFromObj(vm,
                                          VIR_DOMAIN_EVENT_SUSPENDED,
@@ -2694,12 +2746,15 @@ static int qemudDomainResume(virDomainPtr dom) {
     }
     if (vm->state == VIR_DOMAIN_PAUSED) {
         qemuDomainObjPrivatePtr priv = vm->privateData;
+        qemuDomainObjEnterMonitor(vm);
         if (qemuMonitorStartCPUs(priv->mon, dom->conn) < 0) {
+            qemuDomainObjExitMonitor(vm);
             if (virGetLastError() == NULL)
                 qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
                                  "%s", _("resume operation failed"));
             goto cleanup;
         }
+        qemuDomainObjExitMonitor(vm);
         vm->state = VIR_DOMAIN_RUNNING;
         event = virDomainEventNewFromObj(vm,
                                          VIR_DOMAIN_EVENT_RESUMED,
@@ -2743,10 +2798,9 @@ static int qemudDomainShutdown(virDomainPtr dom) {
     }
 
     qemuDomainObjPrivatePtr priv = vm->privateData;
-    if (qemuMonitorSystemPowerdown(priv->mon) < 0)
-        goto cleanup;
-
-    ret = 0;
+    qemuDomainObjEnterMonitor(vm);
+    ret = qemuMonitorSystemPowerdown(priv->mon);
+    qemuDomainObjExitMonitor(vm);
 
 cleanup:
     if (vm)
@@ -2905,7 +2959,9 @@ static int qemudDomainSetMemory(virDomainPtr dom, unsigned long newmem) {
 
     if (virDomainObjIsActive(vm)) {
         qemuDomainObjPrivatePtr priv = vm->privateData;
+        qemuDomainObjEnterMonitor(vm);
         int r = qemuMonitorSetBalloon(priv->mon, newmem);
+        qemuDomainObjExitMonitor(vm);
         if (r < 0)
             goto cleanup;
 
@@ -2960,7 +3016,9 @@ static int qemudDomainGetInfo(virDomainPtr dom,
 
     if (virDomainObjIsActive(vm)) {
         qemuDomainObjPrivatePtr priv = vm->privateData;
+        qemuDomainObjEnterMonitor(vm);
         err = qemuMonitorGetBalloonInfo(priv->mon, &balloon);
+        qemuDomainObjExitMonitor(vm);
         if (err < 0)
             goto cleanup;
 
@@ -3069,8 +3127,12 @@ static int qemudDomainSave(virDomainPtr dom,
     if (vm->state == VIR_DOMAIN_RUNNING) {
         qemuDomainObjPrivatePtr priv = vm->privateData;
         header.was_running = 1;
-        if (qemuMonitorStopCPUs(priv->mon) < 0)
+        qemuDomainObjEnterMonitor(vm);
+        if (qemuMonitorStopCPUs(priv->mon) < 0) {
+            qemuDomainObjExitMonitor(vm);
             goto cleanup;
+        }
+        qemuDomainObjExitMonitor(vm);
         vm->state = VIR_DOMAIN_PAUSED;
     }
 
@@ -3113,7 +3175,9 @@ static int qemudDomainSave(virDomainPtr dom,
     if (header.compressed == QEMUD_SAVE_FORMAT_RAW) {
         const char *args[] = { "cat", NULL };
         qemuDomainObjPrivatePtr priv = vm->privateData;
+        qemuDomainObjEnterMonitor(vm);
         ret = qemuMonitorMigrateToCommand(priv->mon, 0, args, path);
+        qemuDomainObjExitMonitor(vm);
     } else {
         const char *prog = qemudSaveCompressionTypeToString(header.compressed);
         qemuDomainObjPrivatePtr priv = vm->privateData;
@@ -3122,7 +3186,9 @@ static int qemudDomainSave(virDomainPtr dom,
             "-c",
             NULL
         };
+        qemuDomainObjEnterMonitor(vm);
         ret = qemuMonitorMigrateToCommand(priv->mon, 0, args, path);
+        qemuDomainObjExitMonitor(vm);
     }
 
     if (ret < 0)
@@ -3193,12 +3259,18 @@ static int qemudDomainCoreDump(virDomainPtr dom,
 
     /* Pause domain for non-live dump */
     if (vm->state == VIR_DOMAIN_RUNNING) {
-        if (qemuMonitorStopCPUs(priv->mon) < 0)
+        qemuDomainObjEnterMonitor(vm);
+        if (qemuMonitorStopCPUs(priv->mon) < 0) {
+            qemuDomainObjExitMonitor(vm);
             goto cleanup;
+        }
+        qemuDomainObjExitMonitor(vm);
         paused = 1;
     }
 
+    qemuDomainObjEnterMonitor(vm);
     ret = qemuMonitorMigrateToCommand(priv->mon, 0, args, path);
+    qemuDomainObjExitMonitor(vm);
     paused = 1;
 cleanup:
 
@@ -3206,11 +3278,13 @@ cleanup:
        will support synchronous operations so we always get here after
        the migration is complete.  */
     if (resume && paused) {
+        qemuDomainObjEnterMonitor(vm);
         if (qemuMonitorStartCPUs(priv->mon, dom->conn) < 0) {
             if (virGetLastError() == NULL)
                 qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
                                  "%s", _("resuming after dump failed"));
         }
+        qemuDomainObjExitMonitor(vm);
     }
     if (vm)
         virDomainObjUnlock(vm);
@@ -3724,12 +3798,15 @@ static int qemudDomainRestore(virConnectPtr conn,
     /* If it was running before, resume it now. */
     if (header.was_running) {
         qemuDomainObjPrivatePtr priv = vm->privateData;
+        qemuDomainObjEnterMonitor(vm);
         if (qemuMonitorStartCPUs(priv->mon, conn) < 0) {
             if (virGetLastError() == NULL)
                 qemudReportError(conn, NULL, NULL, VIR_ERR_OPERATION_FAILED,
                                  "%s", _("failed to resume domain"));
+            qemuDomainObjExitMonitor(vm);
             goto cleanup;
         }
+        qemuDomainObjExitMonitor(vm);
         vm->state = VIR_DOMAIN_RUNNING;
         virDomainSaveStatus(conn, driver->stateDir, vm);
     }
@@ -3772,7 +3849,9 @@ static char *qemudDomainDumpXML(virDomainPtr dom,
     /* Refresh current memory based on balloon info */
     if (virDomainObjIsActive(vm)) {
         qemuDomainObjPrivatePtr priv = vm->privateData;
+        qemuDomainObjEnterMonitor(vm);
         err = qemuMonitorGetBalloonInfo(priv->mon, &balloon);
+        qemuDomainObjExitMonitor(vm);
         if (err < 0)
             goto cleanup;
         if (err > 0)
@@ -4343,11 +4422,13 @@ static int qemudDomainChangeEjectableMedia(virConnectPtr conn,
     }
 
     qemuDomainObjPrivatePtr priv = vm->privateData;
+    qemuDomainObjEnterMonitor(vm);
     if (newdisk->src) {
         ret = qemuMonitorChangeMedia(priv->mon, devname, newdisk->src);
     } else {
         ret = qemuMonitorEjectMedia(priv->mon, devname);
     }
+    qemuDomainObjExitMonitor(vm);
 
     if (ret == 0) {
         VIR_FREE(origdisk->src);
@@ -4364,7 +4445,7 @@ static int qemudDomainAttachPciDiskDevice(virConnectPtr conn,
                                           virDomainObjPtr vm,
                                           virDomainDeviceDefPtr dev)
 {
-    int i;
+    int i, ret;
     const char* type = virDomainDiskBusTypeToString(dev->data.disk->bus);
     qemuDomainObjPrivatePtr priv = vm->privateData;
 
@@ -4381,17 +4462,19 @@ static int qemudDomainAttachPciDiskDevice(virConnectPtr conn,
         return -1;
     }
 
-    if (qemuMonitorAddPCIDisk(priv->mon,
-                              dev->data.disk->src,
-                              type,
-                              &dev->data.disk->pci_addr.domain,
-                              &dev->data.disk->pci_addr.bus,
-                              &dev->data.disk->pci_addr.slot) < 0)
-        return -1;
+    qemuDomainObjEnterMonitor(vm);
+    ret = qemuMonitorAddPCIDisk(priv->mon,
+                                dev->data.disk->src,
+                                type,
+                                &dev->data.disk->pci_addr.domain,
+                                &dev->data.disk->pci_addr.bus,
+                                &dev->data.disk->pci_addr.slot);
+    qemuDomainObjExitMonitor(vm);
 
-    virDomainDiskInsertPreAlloced(vm->def, dev->data.disk);
+    if (ret == 0)
+        virDomainDiskInsertPreAlloced(vm->def, dev->data.disk);
 
-    return 0;
+    return ret;
 }
 
 static int qemudDomainAttachUsbMassstorageDevice(virConnectPtr conn,
@@ -4399,7 +4482,7 @@ static int qemudDomainAttachUsbMassstorageDevice(virConnectPtr conn,
                                                  virDomainDeviceDefPtr dev)
 {
     qemuDomainObjPrivatePtr priv = vm->privateData;
-    int i;
+    int i, ret;
 
     for (i = 0 ; i < vm->def->ndisks ; i++) {
         if (STREQ(vm->def->disks[i]->dst, dev->data.disk->dst)) {
@@ -4420,12 +4503,14 @@ static int qemudDomainAttachUsbMassstorageDevice(virConnectPtr conn,
         return -1;
     }
 
-    if (qemuMonitorAddUSBDisk(priv->mon, dev->data.disk->src) < 0)
-        return -1;
+    qemuDomainObjEnterMonitor(vm);
+    ret = qemuMonitorAddUSBDisk(priv->mon, dev->data.disk->src);
+    qemuDomainObjExitMonitor(vm);
 
-    virDomainDiskInsertPreAlloced(vm->def, dev->data.disk);
+    if (ret == 0)
+        virDomainDiskInsertPreAlloced(vm->def, dev->data.disk);
 
-    return 0;
+    return ret;
 }
 
 static int qemudDomainAttachNetDevice(virConnectPtr conn,
@@ -4481,16 +4566,24 @@ static int qemudDomainAttachNetDevice(virConnectPtr conn,
         if (virAsprintf(&tapfd_name, "fd-%s", net->hostnet_name) < 0)
             goto no_memory;
 
-        if (qemuMonitorSendFileHandle(priv->mon, tapfd_name, tapfd) < 0)
+        qemuDomainObjEnterMonitor(vm);
+        if (qemuMonitorSendFileHandle(priv->mon, tapfd_name, tapfd) < 0) {
+            qemuDomainObjExitMonitor(vm);
             goto cleanup;
+        }
+        qemuDomainObjExitMonitor(vm);
     }
 
     if (qemuBuildHostNetStr(conn, net, ' ',
                             net->vlan, tapfd_name, &netstr) < 0)
         goto try_tapfd_close;
 
-    if (qemuMonitorAddHostNetwork(priv->mon, netstr) < 0)
+    qemuDomainObjEnterMonitor(vm);
+    if (qemuMonitorAddHostNetwork(priv->mon, netstr) < 0) {
+        qemuDomainObjExitMonitor(vm);
         goto try_tapfd_close;
+    }
+    qemuDomainObjExitMonitor(vm);
 
     if (tapfd != -1)
         close(tapfd);
@@ -4499,11 +4592,15 @@ static int qemudDomainAttachNetDevice(virConnectPtr conn,
     if (qemuBuildNicStr(conn, net, NULL, net->vlan, &nicstr) < 0)
         goto try_remove;
 
+    qemuDomainObjEnterMonitor(vm);
     if (qemuMonitorAddPCINetwork(priv->mon, nicstr,
                                  &net->pci_addr.domain,
                                  &net->pci_addr.bus,
-                                 &net->pci_addr.slot) < 0)
+                                 &net->pci_addr.slot) < 0) {
+        qemuDomainObjExitMonitor(vm);
         goto try_remove;
+    }
+    qemuDomainObjExitMonitor(vm);
 
     ret = 0;
 
@@ -4521,15 +4618,22 @@ cleanup:
 try_remove:
     if (!net->hostnet_name || net->vlan == 0)
         VIR_WARN0(_("Unable to remove network backend\n"));
-    else if (qemuMonitorRemoveHostNetwork(priv->mon, net->vlan, net->hostnet_name) < 0)
-        VIR_WARN(_("Failed to remove network backend for vlan %d, net %s"),
-                 net->vlan, net->hostnet_name);
+    else {
+        qemuDomainObjEnterMonitor(vm);
+        if (qemuMonitorRemoveHostNetwork(priv->mon, net->vlan, net->hostnet_name) < 0)
+            VIR_WARN(_("Failed to remove network backend for vlan %d, net %s"),
+                     net->vlan, net->hostnet_name);
+        qemuDomainObjExitMonitor(vm);
+    }
     goto cleanup;
 
 try_tapfd_close:
-    if (tapfd_name &&
-        qemuMonitorCloseFileHandle(priv->mon, tapfd_name) < 0)
-        VIR_WARN(_("Failed to close tapfd with '%s'\n"), tapfd_name);
+    if (tapfd_name) {
+        qemuDomainObjEnterMonitor(vm);
+        if (qemuMonitorCloseFileHandle(priv->mon, tapfd_name) < 0)
+            VIR_WARN(_("Failed to close tapfd with '%s'\n"), tapfd_name);
+        qemuDomainObjExitMonitor(vm);
+    }
 
     goto cleanup;
 
@@ -4546,6 +4650,7 @@ static int qemudDomainAttachHostPciDevice(virConnectPtr conn,
     qemuDomainObjPrivatePtr priv = vm->privateData;
     virDomainHostdevDefPtr hostdev = dev->data.hostdev;
     pciDevice *pci;
+    int ret;
 
     if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs+1) < 0) {
         virReportOOMError(conn);
@@ -4571,14 +4676,17 @@ static int qemudDomainAttachHostPciDevice(virConnectPtr conn,
         return -1;
     }
 
-    if (qemuMonitorAddPCIHostDevice(priv->mon,
-                                    hostdev->source.subsys.u.pci.domain,
-                                    hostdev->source.subsys.u.pci.bus,
-                                    hostdev->source.subsys.u.pci.slot,
-                                    hostdev->source.subsys.u.pci.function,
-                                    &hostdev->source.subsys.u.pci.guest_addr.domain,
-                                    &hostdev->source.subsys.u.pci.guest_addr.bus,
-                                    &hostdev->source.subsys.u.pci.guest_addr.slot) < 0)
+    qemuDomainObjEnterMonitor(vm);
+    ret = qemuMonitorAddPCIHostDevice(priv->mon,
+                                      hostdev->source.subsys.u.pci.domain,
+                                      hostdev->source.subsys.u.pci.bus,
+                                      hostdev->source.subsys.u.pci.slot,
+                                      hostdev->source.subsys.u.pci.function,
+                                      &hostdev->source.subsys.u.pci.guest_addr.domain,
+                                      &hostdev->source.subsys.u.pci.guest_addr.bus,
+                                      &hostdev->source.subsys.u.pci.guest_addr.slot);
+    qemuDomainObjExitMonitor(vm);
+    if (ret < 0)
         goto error;
 
     vm->def->hostdevs[vm->def->nhostdevs++] = hostdev;
@@ -4603,6 +4711,7 @@ static int qemudDomainAttachHostUsbDevice(virConnectPtr conn,
         return -1;
     }
 
+    qemuDomainObjEnterMonitor(vm);
     if (dev->data.hostdev->source.subsys.u.usb.vendor) {
         ret = qemuMonitorAddUSBDeviceMatch(priv->mon,
                                            dev->data.hostdev->source.subsys.u.usb.vendor,
@@ -4612,6 +4721,7 @@ static int qemudDomainAttachHostUsbDevice(virConnectPtr conn,
                                            dev->data.hostdev->source.subsys.u.usb.bus,
                                            dev->data.hostdev->source.subsys.u.usb.device);
     }
+    qemuDomainObjExitMonitor(vm);
 
     if (ret != -1)
         vm->def->hostdevs[vm->def->nhostdevs++] = dev->data.hostdev;
@@ -4804,11 +4914,15 @@ static int qemudDomainDetachPciDiskDevice(virConnectPtr conn,
         goto cleanup;
     }
 
+    qemuDomainObjEnterMonitor(vm);
     if (qemuMonitorRemovePCIDevice(priv->mon,
                                    detach->pci_addr.domain,
                                    detach->pci_addr.bus,
-                                   detach->pci_addr.slot) < 0)
+                                   detach->pci_addr.slot) < 0) {
+        qemuDomainObjExitMonitor(vm);
         goto cleanup;
+    }
+    qemuDomainObjExitMonitor(vm);
 
     if (vm->def->ndisks > 1) {
         memmove(vm->def->disks + i,
@@ -4864,14 +4978,20 @@ qemudDomainDetachNetDevice(virConnectPtr conn,
         goto cleanup;
     }
 
+    qemuDomainObjEnterMonitor(vm);
     if (qemuMonitorRemovePCIDevice(priv->mon,
                                    detach->pci_addr.domain,
                                    detach->pci_addr.bus,
-                                   detach->pci_addr.slot) < 0)
+                                   detach->pci_addr.slot) < 0) {
+        qemuDomainObjExitMonitor(vm);
         goto cleanup;
+    }
 
-    if (qemuMonitorRemoveHostNetwork(priv->mon, detach->vlan, detach->hostnet_name) < 0)
+    if (qemuMonitorRemoveHostNetwork(priv->mon, detach->vlan, detach->hostnet_name) < 0) {
+        qemuDomainObjExitMonitor(vm);
         goto cleanup;
+    }
+    qemuDomainObjExitMonitor(vm);
 
     if (vm->def->nnets > 1) {
         memmove(vm->def->nets + i,
@@ -4935,11 +5055,15 @@ static int qemudDomainDetachHostPciDevice(virConnectPtr conn,
         return -1;
     }
 
+    qemuDomainObjEnterMonitor(vm);
     if (qemuMonitorRemovePCIDevice(priv->mon,
                                    detach->source.subsys.u.pci.guest_addr.domain,
                                    detach->source.subsys.u.pci.guest_addr.bus,
-                                   detach->source.subsys.u.pci.guest_addr.slot) < 0)
+                                   detach->source.subsys.u.pci.guest_addr.slot) < 0) {
+        qemuDomainObjExitMonitor(vm);
         return -1;
+    }
+    qemuDomainObjExitMonitor(vm);
 
     ret = 0;
 
@@ -5369,16 +5493,15 @@ qemudDomainBlockStats (virDomainPtr dom,
         goto cleanup;
 
     qemuDomainObjPrivatePtr priv = vm->privateData;
-    if (qemuMonitorGetBlockStatsInfo(priv->mon,
-                                     qemu_dev_name,
-                                     &stats->rd_req,
-                                     &stats->rd_bytes,
-                                     &stats->wr_req,
-                                     &stats->wr_bytes,
-                                     &stats->errs) < 0)
-        goto cleanup;
-
-    ret = 0;
+    qemuDomainObjEnterMonitor(vm);
+    ret = qemuMonitorGetBlockStatsInfo(priv->mon,
+                                       qemu_dev_name,
+                                       &stats->rd_req,
+                                       &stats->rd_bytes,
+                                       &stats->wr_req,
+                                       &stats->wr_bytes,
+                                       &stats->errs);
+    qemuDomainObjExitMonitor(vm);
 
 cleanup:
     VIR_FREE(qemu_dev_name);
@@ -5568,13 +5691,19 @@ qemudDomainMemoryPeek (virDomainPtr dom,
     }
 
     qemuDomainObjPrivatePtr priv = vm->privateData;
+    qemuDomainObjEnterMonitor(vm);
     if (flags == VIR_MEMORY_VIRTUAL) {
-        if (qemuMonitorSaveVirtualMemory(priv->mon, offset, size, tmp) < 0)
+        if (qemuMonitorSaveVirtualMemory(priv->mon, offset, size, tmp) < 0) {
+            qemuDomainObjExitMonitor(vm);
             goto cleanup;
+        }
     } else {
-        if (qemuMonitorSavePhysicalMemory(priv->mon, offset, size, tmp) < 0)
+        if (qemuMonitorSavePhysicalMemory(priv->mon, offset, size, tmp) < 0) {
+            qemuDomainObjExitMonitor(vm);
             goto cleanup;
+        }
     }
+    qemuDomainObjExitMonitor(vm);
 
     /* Read the memory file into buffer. */
     if (saferead (fd, buffer, size) == (ssize_t) -1) {
@@ -6346,12 +6475,17 @@ static int doNativeMigrate(virDomainPtr dom,
         goto cleanup;
     }
 
+    qemuDomainObjEnterMonitor(vm);
     if (resource > 0 &&
-        qemuMonitorSetMigrationSpeed(priv->mon, resource) < 0)
+        qemuMonitorSetMigrationSpeed(priv->mon, resource) < 0) {
+        qemuDomainObjExitMonitor(vm);
         goto cleanup;
+    }
 
-    if (qemuMonitorMigrateToHost(priv->mon, 0, uribits->server, uribits->port) < 0)
+    if (qemuMonitorMigrateToHost(priv->mon, 0, uribits->server, uribits->port) < 0) {
+        qemuDomainObjExitMonitor(vm);
         goto cleanup;
+    }
 
     /* it is also possible that the migrate didn't fail initially, but
      * rather failed later on.  Check the output of "info migrate"
@@ -6361,8 +6495,10 @@ static int doNativeMigrate(virDomainPtr dom,
                                       &transferred,
                                       &remaining,
                                       &total) < 0) {
+        qemuDomainObjExitMonitor(vm);
         goto cleanup;
     }
+    qemuDomainObjExitMonitor(vm);
 
     if (status != QEMU_MONITOR_MIGRATION_STATUS_COMPLETED) {
         qemudReportError (dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
@@ -6519,6 +6655,7 @@ static int doTunnelMigrate(virDomainPtr dom,
         goto cleanup;
 
     /*   3. start migration on source */
+    qemuDomainObjEnterMonitor(vm);
     if (qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_UNIX)
         internalret = qemuMonitorMigrateToUnix(priv->mon, 1, unixfile);
     else if (qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC) {
@@ -6527,6 +6664,7 @@ static int doTunnelMigrate(virDomainPtr dom,
     } else {
         internalret = -1;
     }
+    qemuDomainObjExitMonitor(vm);
     if (internalret < 0) {
         qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
                          "%s", _("tunnelled migration monitor command failed"));
@@ -6539,13 +6677,16 @@ static int doTunnelMigrate(virDomainPtr dom,
     /* it is also possible that the migrate didn't fail initially, but
      * rather failed later on.  Check the output of "info migrate"
      */
+    qemuDomainObjEnterMonitor(vm);
     if (qemuMonitorGetMigrationStatus(priv->mon,
                                       &status,
                                       &transferred,
                                       &remaining,
                                       &total) < 0) {
+        qemuDomainObjExitMonitor(vm);
         goto cancel;
     }
+    qemuDomainObjExitMonitor(vm);
 
     if (status == QEMU_MONITOR_MIGRATION_STATUS_ERROR) {
         qemudReportError(dom->conn, dom, NULL, VIR_ERR_OPERATION_FAILED,
@@ -6565,8 +6706,11 @@ static int doTunnelMigrate(virDomainPtr dom,
     retval = doTunnelSendAll(dom, st, client_sock);
 
 cancel:
-    if (retval != 0)
+    if (retval != 0) {
+        qemuDomainObjEnterMonitor(vm);
         qemuMonitorMigrateCancel(priv->mon);
+        qemuDomainObjExitMonitor(vm);
+    }
 
 finish:
     dname = dname ? dname : dom->name;
@@ -6729,8 +6873,12 @@ qemudDomainMigratePerform (virDomainPtr dom,
     if (!(flags & VIR_MIGRATE_LIVE)) {
         qemuDomainObjPrivatePtr priv = vm->privateData;
         /* Pause domain for non-live migration */
-        if (qemuMonitorStopCPUs(priv->mon) < 0)
+        qemuDomainObjEnterMonitor(vm);
+        if (qemuMonitorStopCPUs(priv->mon) < 0) {
+            qemuDomainObjExitMonitor(vm);
             goto cleanup;
+        }
+        qemuDomainObjExitMonitor(vm);
         paused = 1;
 
         event = virDomainEventNewFromObj(vm,
@@ -6768,6 +6916,7 @@ cleanup:
     if (paused) {
         qemuDomainObjPrivatePtr priv = vm->privateData;
         /* we got here through some sort of failure; start the domain again */
+        qemuDomainObjEnterMonitor(vm);
         if (qemuMonitorStartCPUs(priv->mon, dom->conn) < 0) {
             /* Hm, we already know we are in error here.  We don't want to
              * overwrite the previous error, though, so we just throw something
@@ -6776,6 +6925,7 @@ cleanup:
             VIR_ERROR(_("Failed to resume guest %s after failure\n"),
                       vm->def->name);
         }
+        qemuDomainObjExitMonitor(vm);
 
         event = virDomainEventNewFromObj(vm,
                                          VIR_DOMAIN_EVENT_RESUMED,
@@ -6853,12 +7003,15 @@ qemudDomainMigrateFinish2 (virConnectPtr dconn,
          * >= 0.10.6 to work properly.  This isn't strictly necessary on
          * older qemu's, but it also doesn't hurt anything there
          */
+        qemuDomainObjEnterMonitor(vm);
         if (qemuMonitorStartCPUs(priv->mon, dconn) < 0) {
             if (virGetLastError() == NULL)
                 qemudReportError(dconn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
                                  "%s", _("resume operation failed"));
+            qemuDomainObjExitMonitor(vm);
             goto cleanup;
         }
+        qemuDomainObjExitMonitor(vm);
 
         vm->state = VIR_DOMAIN_RUNNING;
         event = virDomainEventNewFromObj(vm,
diff --git a/src/qemu/qemu_monitor.c b/src/qemu/qemu_monitor.c
index 46d5d9f..fd1c5e9 100644
--- a/src/qemu/qemu_monitor.c
+++ b/src/qemu/qemu_monitor.c
@@ -39,6 +39,8 @@
 #define VIR_FROM_THIS VIR_FROM_QEMU
 
 struct _qemuMonitor {
+    virMutex lock;
+
     int fd;
     int watch;
     int hasSendFD;
@@ -49,6 +51,16 @@ struct _qemuMonitor {
     qemuMonitorDiskSecretLookup secretCB;
 };
 
+void qemuMonitorLock(qemuMonitorPtr mon)
+{
+    virMutexLock(&mon->lock);
+}
+
+void qemuMonitorUnlock(qemuMonitorPtr mon)
+{
+    virMutexUnlock(&mon->lock);
+}
+
 /* Return -1 for error, 1 to continue reading and 0 for success */
 typedef int qemuMonitorHandleOutput(virDomainObjPtr vm,
                                     const char *output);
@@ -292,6 +304,12 @@ qemuMonitorOpen(virDomainObjPtr vm,
         return NULL;
     }
 
+    if (virMutexInit(&mon->lock) < 0) {
+        qemudReportError(NULL, NULL, NULL, VIR_ERR_INTERNAL_ERROR, "%s",
+                         _("cannot initialize monitor mutex"));
+        VIR_FREE(mon);
+        return NULL;
+    }
     mon->fd = -1;
     mon->vm = vm;
     mon->eofCB = eofCB;
@@ -343,6 +361,7 @@ void qemuMonitorClose(qemuMonitorPtr mon)
 
     if (mon->fd != -1)
         close(mon->fd);
+    virMutexDestroy(&mon->lock);
     VIR_FREE(mon);
 }
 
diff --git a/src/qemu/qemu_monitor.h b/src/qemu/qemu_monitor.h
index 5f06155..a8d517c 100644
--- a/src/qemu/qemu_monitor.h
+++ b/src/qemu/qemu_monitor.h
@@ -54,6 +54,9 @@ qemuMonitorPtr qemuMonitorOpen(virDomainObjPtr vm,
 
 void qemuMonitorClose(qemuMonitorPtr mon);
 
+void qemuMonitorLock(qemuMonitorPtr mon);
+void qemuMonitorUnlock(qemuMonitorPtr mon);
+
 void qemuMonitorRegisterDiskSecretLookup(qemuMonitorPtr mon,
                                          qemuMonitorDiskSecretLookup secretCB);
 
-- 
1.6.2.5




More information about the libvir-list mailing list