]> xenbits.xensource.com Git - people/dariof/libvirt.git/commitdiff
qemu: Fix domain ID numbering race condition
authorPeter Krempa <pkrempa@redhat.com>
Thu, 8 Nov 2012 12:48:37 +0000 (13:48 +0100)
committerPeter Krempa <pkrempa@redhat.com>
Thu, 8 Nov 2012 23:12:38 +0000 (00:12 +0100)
When the libvirt daemon is restarted it tries to reconnect to running
qemu domains. Since commit d38897a5d4b1880e1998394b2a37bba979bbdff1 the
re-connection code runs in separate threads. In the original
implementation the maximum of domain ID's (that is used as an
initializer for numbering guests created next) while libvirt was
reconnecting to the guest.

With the threaded implementation this opens a possibility for race
conditions with the thread that is autostarting guests. When there's a
guest running with id 1 and the daemon is restarted. The autostart code
is reached first and spawns the first guest that should be autostarted
as id 1. This results into the following unwanted situation:

 # virsh list
   Id    Name                           State
  ----------------------------------------------------
   1     guest1                         running
   1     guest2                         running

This patch extracts the detection code before the re-connection threads
are started so that the maximum id of the guests being reconnected to is
known.

The only semantic change created by this is if the guest with greatest ID
quits before we are able to reconnect it's ID is used anyway as the
greatest one as without this patch the greatest ID of a process we could
successfuly reconnect to would be used.

src/qemu/qemu_driver.c
src/qemu/qemu_process.c

index 3309f346429bb3655373dbff37829a1446352e5d..3279a99f4b01e023a50e2e62f91b0208176a2c09 100644 (file)
@@ -590,6 +590,20 @@ qemuDomainNetsRestart(void *payload,
     virDomainObjUnlock(vm);
 }
 
+
+static void
+qemuDomainFindMaxID(void *payload,
+                    const void *name ATTRIBUTE_UNUSED,
+                    void *data)
+{
+    virDomainObjPtr vm = payload;
+    int *driver_maxid = data;
+
+    if (vm->def->id >= *driver_maxid)
+        *driver_maxid = vm->def->id + 1;
+}
+
+
 /**
  * qemudStartup:
  *
@@ -863,6 +877,13 @@ qemudStartup(int privileged) {
                                 NULL, NULL) < 0)
         goto error;
 
+    /* find the maximum ID from active and transient configs to initialize
+     * the driver with. This is to avoid race between autostart and reconnect
+     * threads */
+    virHashForEach(qemu_driver->domains.objs,
+                   qemuDomainFindMaxID,
+                   &qemu_driver->nextvmid);
+
     virHashForEach(qemu_driver->domains.objs, qemuDomainNetsRestart, NULL);
 
     conn = virConnectOpen(qemu_driver->uri);
index d8cf4c31ac4c98267dbf0d3781da3cf342ba52ff..8bf80e7dbef8dee0fd21a212fa91bcb2113429b5 100644 (file)
@@ -3230,9 +3230,6 @@ qemuProcessReconnect(void *opaque)
             goto error;
     }
 
-    if (obj->def->id >= driver->nextvmid)
-        driver->nextvmid = obj->def->id + 1;
-
 endjob:
     if (!qemuDomainObjEndJob(driver, obj))
         obj = NULL;