qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH v2 5/6] net: defer nested call to BH


From: Liu Ping Fan
Subject: [Qemu-devel] [PATCH v2 5/6] net: defer nested call to BH
Date: Thu, 13 Jun 2013 17:03:05 +0800

From: Liu Ping Fan <address@hidden>

Nested call caused by ->receive() will raise issue like deadlock,
so postphone it to BH.

Signed-off-by: Liu Ping Fan <address@hidden>
---
 net/queue.c | 40 ++++++++++++++++++++++++++++++++++++++--
 1 file changed, 38 insertions(+), 2 deletions(-)

diff --git a/net/queue.c b/net/queue.c
index 58222b0..9c343ab 100644
--- a/net/queue.c
+++ b/net/queue.c
@@ -24,6 +24,8 @@
 #include "net/queue.h"
 #include "qemu/queue.h"
 #include "net/net.h"
+#include "block/aio.h"
+#include "qemu/main-loop.h"
 
 /* The delivery handler may only return zero if it will call
  * qemu_net_queue_flush() when it determines that it is once again able
@@ -183,6 +185,22 @@ static ssize_t qemu_net_queue_deliver_iov(NetQueue *queue,
     return ret;
 }
 
+typedef struct NetQueBH {
+    QEMUBH *bh;
+    NetClientState *nc;
+} NetQueBH;
+
+static void qemu_net_queue_send_bh(void *opaque)
+{
+    NetQueBH *q_bh = opaque;
+    NetQueue *queue = q_bh->nc->send_queue;
+
+    qemu_net_queue_flush(queue);
+    netclient_unref(q_bh->nc);
+    qemu_bh_delete(q_bh->bh);
+    g_slice_free(NetQueBH, q_bh);
+}
+
 ssize_t qemu_net_queue_send(NetQueue *queue,
                             NetClientState *sender,
                             unsigned flags,
@@ -192,8 +210,17 @@ ssize_t qemu_net_queue_send(NetQueue *queue,
 {
     ssize_t ret;
 
-    if (queue->delivering || !qemu_can_send_packet_nolock(sender)) {
+    if (queue->delivering || !qemu_can_send_packet_nolock(sender)
+        || sender->send_queue->delivering) {
         qemu_net_queue_append(queue, sender, flags, data, size, sent_cb);
+        /* Nested call will be deferred to BH */
+        if (sender->send_queue->delivering) {
+            NetQueBH *que_bh = g_slice_new(NetQueBH);
+            que_bh->bh = qemu_bh_new(qemu_net_queue_send_bh, que_bh);
+            que_bh->nc = queue->opaque;
+            netclient_ref(queue->opaque);
+            qemu_bh_schedule(que_bh->bh);
+        }
         return 0;
     }
 
@@ -217,8 +244,17 @@ ssize_t qemu_net_queue_send_iov(NetQueue *queue,
 {
     ssize_t ret;
 
-    if (queue->delivering || !qemu_can_send_packet_nolock(sender)) {
+    if (queue->delivering || !qemu_can_send_packet_nolock(sender)
+        || sender->send_queue->delivering) {
         qemu_net_queue_append_iov(queue, sender, flags, iov, iovcnt, sent_cb);
+        /* Nested call will be deferred to BH */
+        if (sender->send_queue->delivering) {
+            NetQueBH *que_bh = g_slice_new(NetQueBH);
+            que_bh->bh = qemu_bh_new(qemu_net_queue_send_bh, que_bh);
+            que_bh->nc = queue->opaque;
+            netclient_ref(queue->opaque);
+            qemu_bh_schedule(que_bh->bh);
+        }
         return 0;
     }
 
-- 
1.8.1.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]