43fe83
From ecc34514032017857dcf514d8b7a83973f084e41 Mon Sep 17 00:00:00 2001
43fe83
Message-Id: <ecc34514032017857dcf514d8b7a83973f084e41.1380112457.git.jdenemar@redhat.com>
43fe83
From: Eric Blake <eblake@redhat.com>
43fe83
Date: Mon, 23 Sep 2013 11:10:06 -0600
43fe83
Subject: [PATCH] qemu: don't leak vm on failure
43fe83
43fe83
https://bugzilla.redhat.com/show_bug.cgi?id=1010617
43fe83
43fe83
Failure to attach to a domain during 'virsh qemu-attach' left
43fe83
the list of domains in an odd state:
43fe83
43fe83
$ virsh qemu-attach 4176
43fe83
error: An error occurred, but the cause is unknown
43fe83
43fe83
$ virsh list --all
43fe83
 Id    Name                           State
43fe83
----------------------------------------------------
43fe83
 2     foo                            shut off
43fe83
43fe83
$ virsh qemu-attach 4176
43fe83
error: Requested operation is not valid: domain is already active as 'foo'
43fe83
43fe83
$ virsh undefine foo
43fe83
error: Failed to undefine domain foo
43fe83
error: Requested operation is not valid: cannot undefine transient domain
43fe83
43fe83
$ virsh shutdown foo
43fe83
error: Failed to shutdown domain foo
43fe83
error: invalid argument: monitor must not be NULL
43fe83
43fe83
It all stems from leaving the list of domains unmodified on
43fe83
the initial failure; we should follow the lead of createXML
43fe83
which removes vm on failure (the actual initial failure still
43fe83
needs to be fixed in a later patch, but at least this patch
43fe83
gets us to the point where we aren't getting stuck with an
43fe83
unremovable "shut off" transient domain).
43fe83
43fe83
While investigating, I also found a leak in qemuDomainCreateXML;
43fe83
the two functions should behave similarly.  Note that there are
43fe83
still two unusual paths: if dom is not allocated, the user will
43fe83
see an OOM error even though the vm remains registered (but oom
43fe83
errors already indicate tricky cleanup); and if the vm starts
43fe83
and then quits again all before the job ends, it is possible
43fe83
to return a non-NULL dom even though the dom will no longer be
43fe83
useful for anything (but this at least lets the user know their
43fe83
short-lived vm ran).
43fe83
43fe83
* src/qemu/qemu_driver.c (qemuDomainCreateXML): Don't leak vm on
43fe83
failure to obtain job.
43fe83
(qemuDomainQemuAttach): Match cleanup of qemuDomainCreateXML.
43fe83
43fe83
Signed-off-by: Eric Blake <eblake@redhat.com>
43fe83
(cherry picked from commit d047b2d9835cbe5090e9eedb11ab69e7e4522f76)
43fe83
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
43fe83
---
43fe83
 src/qemu/qemu_driver.c | 33 ++++++++++++++++++++-------------
43fe83
 1 file changed, 20 insertions(+), 13 deletions(-)
43fe83
43fe83
diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c
43fe83
index eb1a2ce..693dd85 100644
43fe83
--- a/src/qemu/qemu_driver.c
43fe83
+++ b/src/qemu/qemu_driver.c
43fe83
@@ -1602,8 +1602,11 @@ static virDomainPtr qemuDomainCreateXML(virConnectPtr conn,
43fe83
 
43fe83
     def = NULL;
43fe83
 
43fe83
-    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
43fe83
-        goto cleanup; /* XXXX free the 'vm' we created ? */
43fe83
+    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0) {
43fe83
+        qemuDomainRemoveInactive(driver, vm);
43fe83
+        vm = NULL;
43fe83
+        goto cleanup;
43fe83
+    }
43fe83
 
43fe83
     if (qemuProcessStart(conn, driver, vm, NULL, -1, NULL, NULL,
43fe83
                          VIR_NETDEV_VPORT_PROFILE_OP_CREATE,
43fe83
@@ -1631,10 +1634,10 @@ static virDomainPtr qemuDomainCreateXML(virConnectPtr conn,
43fe83
     virDomainAuditStart(vm, "booted", true);
43fe83
 
43fe83
     dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
43fe83
-    if (dom) dom->id = vm->def->id;
43fe83
+    if (dom)
43fe83
+        dom->id = vm->def->id;
43fe83
 
43fe83
-    if (vm &&
43fe83
-        qemuDomainObjEndJob(driver, vm) == 0)
43fe83
+    if (qemuDomainObjEndJob(driver, vm) == 0)
43fe83
         vm = NULL;
43fe83
 
43fe83
 cleanup:
43fe83
@@ -13885,34 +13888,38 @@ static virDomainPtr qemuDomainQemuAttach(virConnectPtr conn,
43fe83
 
43fe83
     def = NULL;
43fe83
 
43fe83
-    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
43fe83
+    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0) {
43fe83
+        qemuDomainRemoveInactive(driver, vm);
43fe83
+        vm = NULL;
43fe83
         goto cleanup;
43fe83
+    }
43fe83
 
43fe83
     if (qemuProcessAttach(conn, driver, vm, pid,
43fe83
                           pidfile, monConfig, monJSON) < 0) {
43fe83
+        if (qemuDomainObjEndJob(driver, vm) > 0)
43fe83
+            qemuDomainRemoveInactive(driver, vm);
43fe83
+        vm = NULL;
43fe83
         monConfig = NULL;
43fe83
-        goto endjob;
43fe83
+        goto cleanup;
43fe83
     }
43fe83
 
43fe83
     monConfig = NULL;
43fe83
 
43fe83
     dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
43fe83
-    if (dom) dom->id = vm->def->id;
43fe83
+    if (dom)
43fe83
+        dom->id = vm->def->id;
43fe83
 
43fe83
-endjob:
43fe83
-    if (qemuDomainObjEndJob(driver, vm) == 0) {
43fe83
+    if (qemuDomainObjEndJob(driver, vm) == 0)
43fe83
         vm = NULL;
43fe83
-        goto cleanup;
43fe83
-    }
43fe83
 
43fe83
 cleanup:
43fe83
     virDomainDefFree(def);
43fe83
-    virObjectUnref(qemuCaps);
43fe83
     virDomainChrSourceDefFree(monConfig);
43fe83
     if (vm)
43fe83
         virObjectUnlock(vm);
43fe83
     VIR_FREE(pidfile);
43fe83
     virObjectUnref(caps);
43fe83
+    virObjectUnref(qemuCaps);
43fe83
     return dom;
43fe83
 }
43fe83
 
43fe83
-- 
43fe83
1.8.3.2
43fe83