Pablo Greco 40546a
From 874617d278b58554feee567b2e79d208aaef214c Mon Sep 17 00:00:00 2001
Pablo Greco 40546a
Message-Id: <874617d278b58554feee567b2e79d208aaef214c@dist-git>
Pablo Greco 40546a
From: Michal Privoznik <mprivozn@redhat.com>
Pablo Greco 40546a
Date: Tue, 6 Aug 2019 13:29:22 +0200
Pablo Greco 40546a
Subject: [PATCH] virDomainObjListAddLocked: Produce better error message than
Pablo Greco 40546a
 'Duplicate key'
Pablo Greco 40546a
MIME-Version: 1.0
Pablo Greco 40546a
Content-Type: text/plain; charset=UTF-8
Pablo Greco 40546a
Content-Transfer-Encoding: 8bit
Pablo Greco 40546a
Pablo Greco 40546a
If there are two concurrent threads, one of which is removing a
Pablo Greco 40546a
domain from the list and the other is trying to add it back they
Pablo Greco 40546a
may serialize in the following order:
Pablo Greco 40546a
Pablo Greco 40546a
1) vm->removing is set and @vm is unlocked.
Pablo Greco 40546a
2) The tread that's trying to add the domain onto the list locks
Pablo Greco 40546a
   the list and tries to find, if the domain already exists.
Pablo Greco 40546a
3) Our lookup functions say it doesn't, so the thread proceeds to
Pablo Greco 40546a
   virHashAddEntry() which fails with 'Duplicate key' error.
Pablo Greco 40546a
Pablo Greco 40546a
This is obviously not helpful error message at all.
Pablo Greco 40546a
Pablo Greco 40546a
The problem lies in our lookup functions
Pablo Greco 40546a
(virDomainObjListFindByUUIDLocked() and
Pablo Greco 40546a
virDomainObjListFindByNameLocked()) which return NULL even if the
Pablo Greco 40546a
object is still on the list. They do this so that the object is
Pablo Greco 40546a
not mistakenly looked up by some driver. The fix consists of
Pablo Greco 40546a
moving 'removing' check one level up and thus allowing
Pablo Greco 40546a
virDomainObjListAddLocked() to produce meaningful error message.
Pablo Greco 40546a
Pablo Greco 40546a
Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Pablo Greco 40546a
Reviewed-by: Cole Robinson <crobinso@redhat.com>
Pablo Greco 40546a
(cherry picked from commit a5c71129bf2c12a827f1bc00149acd1c572ffe9c)
Pablo Greco 40546a
Pablo Greco 40546a
Signed-off-by: Ján Tomko <jtomko@redhat.com>
Pablo Greco 40546a
RHEL-8.1.0: https://bugzilla.redhat.com/show_bug.cgi?id=1737790
Pablo Greco 40546a
Message-Id: <c63ca487bf56af5240e273b5a112a753c2bc85a3.1565090956.git.jtomko@redhat.com>
Pablo Greco 40546a
Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
Pablo Greco 40546a
---
Pablo Greco 40546a
 src/conf/virdomainobjlist.c | 35 +++++++++++++++++++++--------------
Pablo Greco 40546a
 1 file changed, 21 insertions(+), 14 deletions(-)
Pablo Greco 40546a
Pablo Greco 40546a
diff --git a/src/conf/virdomainobjlist.c b/src/conf/virdomainobjlist.c
Pablo Greco 40546a
index e7c3e326ca..3b388e2ba2 100644
Pablo Greco 40546a
--- a/src/conf/virdomainobjlist.c
Pablo Greco 40546a
+++ b/src/conf/virdomainobjlist.c
Pablo Greco 40546a
@@ -142,14 +142,9 @@ virDomainObjListFindByUUIDLocked(virDomainObjListPtr doms,
Pablo Greco 40546a
 
Pablo Greco 40546a
     virUUIDFormat(uuid, uuidstr);
Pablo Greco 40546a
     obj = virHashLookup(doms->objs, uuidstr);
Pablo Greco 40546a
-    virObjectRef(obj);
Pablo Greco 40546a
     if (obj) {
Pablo Greco 40546a
+        virObjectRef(obj);
Pablo Greco 40546a
         virObjectLock(obj);
Pablo Greco 40546a
-        if (obj->removing) {
Pablo Greco 40546a
-            virObjectUnlock(obj);
Pablo Greco 40546a
-            virObjectUnref(obj);
Pablo Greco 40546a
-            obj = NULL;
Pablo Greco 40546a
-        }
Pablo Greco 40546a
     }
Pablo Greco 40546a
     return obj;
Pablo Greco 40546a
 }
Pablo Greco 40546a
@@ -173,6 +168,12 @@ virDomainObjListFindByUUID(virDomainObjListPtr doms,
Pablo Greco 40546a
     obj = virDomainObjListFindByUUIDLocked(doms, uuid);
Pablo Greco 40546a
     virObjectRWUnlock(doms);
Pablo Greco 40546a
 
Pablo Greco 40546a
+    if (obj && obj->removing) {
Pablo Greco 40546a
+        virObjectUnlock(obj);
Pablo Greco 40546a
+        virObjectUnref(obj);
Pablo Greco 40546a
+        obj = NULL;
Pablo Greco 40546a
+    }
Pablo Greco 40546a
+
Pablo Greco 40546a
     return obj;
Pablo Greco 40546a
 }
Pablo Greco 40546a
 
Pablo Greco 40546a
@@ -184,14 +185,9 @@ virDomainObjListFindByNameLocked(virDomainObjListPtr doms,
Pablo Greco 40546a
     virDomainObjPtr obj;
Pablo Greco 40546a
 
Pablo Greco 40546a
     obj = virHashLookup(doms->objsName, name);
Pablo Greco 40546a
-    virObjectRef(obj);
Pablo Greco 40546a
     if (obj) {
Pablo Greco 40546a
+        virObjectRef(obj);
Pablo Greco 40546a
         virObjectLock(obj);
Pablo Greco 40546a
-        if (obj->removing) {
Pablo Greco 40546a
-            virObjectUnlock(obj);
Pablo Greco 40546a
-            virObjectUnref(obj);
Pablo Greco 40546a
-            obj = NULL;
Pablo Greco 40546a
-        }
Pablo Greco 40546a
     }
Pablo Greco 40546a
     return obj;
Pablo Greco 40546a
 }
Pablo Greco 40546a
@@ -215,6 +211,12 @@ virDomainObjListFindByName(virDomainObjListPtr doms,
Pablo Greco 40546a
     obj = virDomainObjListFindByNameLocked(doms, name);
Pablo Greco 40546a
     virObjectRWUnlock(doms);
Pablo Greco 40546a
 
Pablo Greco 40546a
+    if (obj && obj->removing) {
Pablo Greco 40546a
+        virObjectUnlock(obj);
Pablo Greco 40546a
+        virObjectUnref(obj);
Pablo Greco 40546a
+        obj = NULL;
Pablo Greco 40546a
+    }
Pablo Greco 40546a
+
Pablo Greco 40546a
     return obj;
Pablo Greco 40546a
 }
Pablo Greco 40546a
 
Pablo Greco 40546a
@@ -286,8 +288,13 @@ virDomainObjListAddLocked(virDomainObjListPtr doms,
Pablo Greco 40546a
 
Pablo Greco 40546a
     /* See if a VM with matching UUID already exists */
Pablo Greco 40546a
     if ((vm = virDomainObjListFindByUUIDLocked(doms, def->uuid))) {
Pablo Greco 40546a
-        /* UUID matches, but if names don't match, refuse it */
Pablo Greco 40546a
-        if (STRNEQ(vm->def->name, def->name)) {
Pablo Greco 40546a
+        if (vm->removing) {
Pablo Greco 40546a
+            virReportError(VIR_ERR_OPERATION_FAILED,
Pablo Greco 40546a
+                           _("domain '%s' is already being removed"),
Pablo Greco 40546a
+                           vm->def->name);
Pablo Greco 40546a
+            goto error;
Pablo Greco 40546a
+        } else if (STRNEQ(vm->def->name, def->name)) {
Pablo Greco 40546a
+            /* UUID matches, but if names don't match, refuse it */
Pablo Greco 40546a
             virUUIDFormat(vm->def->uuid, uuidstr);
Pablo Greco 40546a
             virReportError(VIR_ERR_OPERATION_FAILED,
Pablo Greco 40546a
                            _("domain '%s' is already defined with uuid %s"),
Pablo Greco 40546a
-- 
Pablo Greco 40546a
2.22.1
Pablo Greco 40546a