[libvirt] [PATCH] [Changelog]:If there is a process with a client which registers event callbacks, and it calls libvirt's API which uses the same virConnectPtr in that callback function. When this process exit abnormally lead to client disconnect, there is a possibility that the libvirtd's main thread is use virServerClient to send event just after the virServerClient been freed by job thread. Following is backtrace:

xinhua.Cao caoxinhua at huawei.com
Wed Mar 8 06:39:46 UTC 2017


    #0  0x00007fda223d66d8 in virClassIsDerivedFrom (klass=0xdeadbeef, parent=0x7fda24c81b40) at util/virobject.c:169
    #1  0x00007fda223d6a1e in virObjectIsClass (anyobj=anyobj at entry=0x7fd9e575b400, klass=<optimized out>) at util/virobject.c:365
    #2  0x00007fda223d6a44 in virObjectLock (anyobj=0x7fd9e575b400) at util/virobject.c:317
    #3  0x00007fda22507f71 in virNetServerClientSendMessage (client=client at entry=0x7fd9e575b400, msg=msg at entry=0x7fd9ec30de90)
    at rpc/virnetserverclient.c:1422
    #4  0x00007fda230d714d in remoteDispatchObjectEventSend (client=0x7fd9e575b400, program=0x7fda24c844e0, procnr=348,
    proc=0x7fda2310e5e0 <xdr_remote_domain_event_callback_tunable_msg>, data=0x7ffc3857fdb0) at remote.c:3803
    #5  0x00007fda230dd71b in remoteRelayDomainEventTunable (conn=<optimized out>, dom=0x7fda27cd7660, params=0x7fda27f3aae0, nparams=1,opaque=0x7fd9e6c99e00) at remote.c:1033
    #6  0x00007fda224484cb in virDomainEventDispatchDefaultFunc (conn=0x7fda27cd0120, event=0x7fda2736ea00,
    cb=0x7fda230dd610 <remoteRelayDomainEventTunable>, cbopaque=0x7fd9e6c99e00) at conf/domain_event.c:1910
    #7  0x00007fda22446871 in virObjectEventStateDispatchCallbacks (callbacks=<optimized out>, callbacks=<optimized out>, event=0x7fda2736ea00,state=0x7fda24ca3960) at conf/object_event.c:722
    #8  virObjectEventStateQueueDispatch (callbacks=0x7fda24c65800, queue=0x7ffc3857fe90, state=0x7fda24ca3960) at conf/object_event.c:736
    #9  virObjectEventStateFlush (state=0x7fda24ca3960) at conf/object_event.c:814
    #10 virObjectEventTimer (timer=<optimized out>, opaque=0x7fda24ca3960) at conf/object_event.c:560
    #11 0x00007fda223ae8b9 in virEventPollDispatchTimeouts () at util/vireventpoll.c:458
    #12 virEventPollRunOnce () at util/vireventpoll.c:654
    #13 0x00007fda223ad1d2 in virEventRunDefaultImpl () at util/virevent.c:314
    #14 0x00007fda225046cd in virNetDaemonRun (dmn=0x7fda24c775c0) at rpc/virnetdaemon.c:818
    #15 0x00007fda230d6351 in main (argc=<optimized out>, argv=<optimized out>) at libvirtd.c:1623

    Let's clean all event callback when client close.

    Signed-off-by: xinhua.Cao <caoxinhua at huawei.com>

    this patch resolved the bug which reported by Wang King. and the prior patch link is  http://www.redhat.com/archives/libvir-list/2017-February/msg00452.html
---
 daemon/remote.c | 60 +++++++++++++++++++++++++++------------------------------
 1 file changed, 28 insertions(+), 32 deletions(-)

diff --git a/daemon/remote.c b/daemon/remote.c
index 4aa43c223..22330307f 100644
--- a/daemon/remote.c
+++ b/daemon/remote.c
@@ -100,6 +100,7 @@ static void make_nonnull_node_device(remote_nonnull_node_device *dev_dst, virNod
 static void make_nonnull_secret(remote_nonnull_secret *secret_dst, virSecretPtr secret_src);
 static void make_nonnull_nwfilter(remote_nonnull_nwfilter *net_dst, virNWFilterPtr nwfilter_src);
 static void make_nonnull_domain_snapshot(remote_nonnull_domain_snapshot *snapshot_dst, virDomainSnapshotPtr snapshot_src);
+static void remoteClientCleanEventCallbacks(struct daemonClientPrivate *priv);
 
 static int
 remoteSerializeDomainDiskErrors(virDomainDiskErrorPtr errors,
@@ -1389,24 +1390,15 @@ void remoteRelayConnectionClosedEvent(virConnectPtr conn ATTRIBUTE_UNUSED, int r
                                   &msg);
 }
 
-/*
- * You must hold lock for at least the client
- * We don't free stuff here, merely disconnect the client's
- * network socket & resources.
- * We keep the libvirt connection open until any async
- * jobs have finished, then clean it up elsewhere
- */
-void remoteClientFreeFunc(void *data)
+static void remoteClientCleanEventCallbacks(struct daemonClientPrivate *priv)
 {
-    struct daemonClientPrivate *priv = data;
-
     /* Deregister event delivery callback */
-    if (priv->conn) {
-        virIdentityPtr sysident = virIdentityGetSystem();
+    if (priv && priv->conn) {
         size_t i;
-
+        virIdentityPtr sysident = virIdentityGetSystem();
         virIdentitySetCurrent(sysident);
 
+        virMutexLock(&priv->lock);
         for (i = 0; i < priv->ndomainEventCallbacks; i++) {
             int callbackID = priv->domainEventCallbacks[i]->callbackID;
             if (callbackID < 0) {
@@ -1420,6 +1412,7 @@ void remoteClientFreeFunc(void *data)
                 VIR_WARN("unexpected domain event deregister failure");
         }
         VIR_FREE(priv->domainEventCallbacks);
+        priv->ndomainEventCallbacks = 0;
 
         for (i = 0; i < priv->nnetworkEventCallbacks; i++) {
             int callbackID = priv->networkEventCallbacks[i]->callbackID;
@@ -1435,21 +1428,7 @@ void remoteClientFreeFunc(void *data)
                 VIR_WARN("unexpected network event deregister failure");
         }
         VIR_FREE(priv->networkEventCallbacks);
-
-        for (i = 0; i < priv->nstorageEventCallbacks; i++) {
-            int callbackID = priv->storageEventCallbacks[i]->callbackID;
-            if (callbackID < 0) {
-                VIR_WARN("unexpected incomplete storage pool callback %zu", i);
-                continue;
-            }
-            VIR_DEBUG("Deregistering remote storage pool event relay %d",
-                      callbackID);
-            priv->storageEventCallbacks[i]->callbackID = -1;
-            if (virConnectStoragePoolEventDeregisterAny(priv->conn,
-                                                        callbackID) < 0)
-                VIR_WARN("unexpected storage pool event deregister failure");
-        }
-        VIR_FREE(priv->storageEventCallbacks);
+        priv->nnetworkEventCallbacks = 0;
 
         for (i = 0; i < priv->nqemuEventCallbacks; i++) {
             int callbackID = priv->qemuEventCallbacks[i]->callbackID;
@@ -1465,28 +1444,45 @@ void remoteClientFreeFunc(void *data)
                 VIR_WARN("unexpected qemu monitor event deregister failure");
         }
         VIR_FREE(priv->qemuEventCallbacks);
+        priv->nqemuEventCallbacks = 0;
 
         if (priv->closeRegistered) {
             if (virConnectUnregisterCloseCallback(priv->conn,
                                                   remoteRelayConnectionClosedEvent) < 0)
                 VIR_WARN("unexpected close callback event deregister failure");
         }
-
-        virConnectClose(priv->conn);
-
+        virMutexUnlock(&priv->lock);
         virIdentitySetCurrent(NULL);
         virObjectUnref(sysident);
     }
+}
+
+
+/*
+ * You must hold lock for at least the client
+ * We don't free stuff here, merely disconnect the client's
+ * network socket & resources.
+ * We keep the libvirt connection open until any async
+ * jobs have finished, then clean it up elsewhere
+ */
+void remoteClientFreeFunc(void *data)
+{
+    struct daemonClientPrivate *priv = data;
+    if (!priv || !priv->conn)
+        return;
+
+    remoteClientCleanEventCallbacks(priv);
+    virConnectClose(priv->conn);
 
     VIR_FREE(priv);
 }
 
-
 static void remoteClientCloseFunc(virNetServerClientPtr client)
 {
     struct daemonClientPrivate *priv = virNetServerClientGetPrivateData(client);
 
     daemonRemoveAllClientStreams(priv->streams);
+    remoteClientCleanEventCallbacks(priv);
 }
 
 
-- 
2.12.0.windows.1





More information about the libvir-list mailing list