[libvirt] [PATCH 01/10] fdstream: Emit stream abort callback even if poll() doesnt.

Peter Krempa pkrempa at redhat.com
Wed Oct 12 13:43:11 UTC 2011


This patch causes the fdstream driver to call the stream event callback
if virStreamAbort() is issued on a stream using this driver. This
prohibited to abort streams from the daemon, as the daemon remote
handler installs a callback to watch for stream errors as the only mean
of detecting changes in the stream.
---
 src/fdstream.c |   52 +++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 47 insertions(+), 5 deletions(-)

diff --git a/src/fdstream.c b/src/fdstream.c
index b60162c..8fb5e78 100644
--- a/src/fdstream.c
+++ b/src/fdstream.c
@@ -55,6 +55,7 @@ struct virFDStreamData {
     unsigned long long length;

     int watch;
+    int events;         /* events the stream callback is subscribed for */
     bool cbRemoved;
     bool dispatching;
     bool closed;
@@ -62,6 +63,9 @@ struct virFDStreamData {
     void *opaque;
     virFreeCallback ff;

+    /* don't call the abort callback more than once */
+    bool abortCallbackCalled;
+
     virMutex lock;
 };

@@ -92,6 +96,7 @@ static int virFDStreamRemoveCallback(virStreamPtr stream)
     fdst->watch = 0;
     fdst->ff = NULL;
     fdst->cb = NULL;
+    fdst->events = 0;
     fdst->opaque = NULL;

     ret = 0;
@@ -120,6 +125,7 @@ static int virFDStreamUpdateCallback(virStreamPtr stream, int events)
     }

     virEventUpdateHandle(fdst->watch, events);
+    fdst->events = events;

     ret = 0;

@@ -214,6 +220,8 @@ virFDStreamAddCallback(virStreamPtr st,
     fdst->cb = cb;
     fdst->opaque = opaque;
     fdst->ff = ff;
+    fdst->events = events;
+    fdst->abortCallbackCalled = false;
     virStreamRef(st);

     ret = 0;
@@ -223,18 +231,40 @@ cleanup:
     return ret;
 }

-
 static int
-virFDStreamClose(virStreamPtr st)
+virFDStreamCloseInt(virStreamPtr st, bool streamAbort)
 {
-    struct virFDStreamData *fdst = st->privateData;
+    struct virFDStreamData *fdst;
     int ret;

     VIR_DEBUG("st=%p", st);

-    if (!fdst)
+    if (!st || !(fdst = st->privateData))
         return 0;

+    /* aborting the stream, ensure the callback is called if it's
+     * registered for stream error event */
+    if (streamAbort &&
+        fdst->cb &&
+        (fdst->events & VIR_STREAM_EVENT_ERROR)) {
+        /* don't enter this function accidentaly from the callback again */
+        virMutexLock(&fdst->lock);
+        if (fdst->abortCallbackCalled) {
+            virMutexUnlock(&fdst->lock);
+            return 0;
+        }
+
+        fdst->abortCallbackCalled = true;
+        virMutexUnlock(&fdst->lock);
+
+        /* call failure callback, poll does report nothing on closed fd */
+        (fdst->cb)(st, VIR_STREAM_EVENT_ERROR, fdst->opaque);
+
+        /* re-check the pointer, someone could tamper with it in the callback */
+        if (!(fdst = st->privateData))
+            return 0;
+    }
+
     virMutexLock(&fdst->lock);

     ret = VIR_CLOSE(fdst->fd);
@@ -282,6 +312,18 @@ virFDStreamClose(virStreamPtr st)
     return ret;
 }

+static int
+virFDStreamClose(virStreamPtr st)
+{
+    return virFDStreamCloseInt(st, false);
+}
+
+static int
+virFDStreamAbort(virStreamPtr st)
+{
+    return virFDStreamCloseInt(st, true);
+}
+
 static int virFDStreamWrite(virStreamPtr st, const char *bytes, size_t nbytes)
 {
     struct virFDStreamData *fdst = st->privateData;
@@ -388,7 +430,7 @@ static virStreamDriver virFDStreamDrv = {
     .streamSend = virFDStreamWrite,
     .streamRecv = virFDStreamRead,
     .streamFinish = virFDStreamClose,
-    .streamAbort = virFDStreamClose,
+    .streamAbort = virFDStreamAbort,
     .streamAddCallback = virFDStreamAddCallback,
     .streamUpdateCallback = virFDStreamUpdateCallback,
     .streamRemoveCallback = virFDStreamRemoveCallback
-- 
1.7.3.4




More information about the libvir-list mailing list