Blame SOURCES/libvirt-virDomainObjListAddLocked-Produce-better-error-message-than-Duplicate-key.patch

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