qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Stefan Hajnoczi <stefanha@redhat.com>
To: qemu-devel@nongnu.org
Cc: "Dr. David Alan Gilbert" <dgilbert@redhat.com>
Subject: [Qemu-devel] [PATCH] tap: avoid deadlocking rx
Date: Sat,  8 Mar 2014 16:00:43 +0100	[thread overview]
Message-ID: <1394290843-18635-1-git-send-email-stefanha@redhat.com> (raw)

The net subsystem has a control flow mechanism so peer NetClientStates
can tell each other to stop sending packets.  This is used to stop
monitoring the tap file descriptor for incoming packets if the guest rx
ring has no spare buffers.

There is a corner case when tap_can_send() is true at the beginning of
an event loop iteration but becomes false before the tap_send() fd
handler is invoked.

tap_send() will read the packet from the tap file descriptor and attempt
to send it.  The net queue will hold on to the packet and return 0,
indicating that further I/O is not possible.  tap then stops monitoring
the file descriptor for reads.

This is unlike the normal case where tap_can_send() is the same before
and during the event loop iteration.  The event loop would simply not
monitor the file descriptor if tap_can_send() returns true.  Upon next
iteration it would check tap_can_send() again and begin monitoring if we
can send.

The deadlock happens because tap_send() explicitly disabled read_poll.
This is done with the expectation that the peer will call
qemu_net_queue_flush().  But hw/net/virtio-net.c does not monitor
vm_running transitions and issue the flush.  Hence we're left with a
broken tap device.

Cc: qemu-stable@nongnu.org
Reported-by: Neil Skrypuch <neil@tembosocial.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
 net/tap.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/net/tap.c b/net/tap.c
index 2d5099b..8847ce1 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -190,7 +190,7 @@ static void tap_send(void *opaque)
     TAPState *s = opaque;
     int size;
 
-    do {
+    while (qemu_can_send_packet(&s->nc)) {
         uint8_t *buf = s->buf;
 
         size = tap_read_packet(s->fd, s->buf, sizeof(s->buf));
@@ -206,8 +206,11 @@ static void tap_send(void *opaque)
         size = qemu_send_packet_async(&s->nc, buf, size, tap_send_completed);
         if (size == 0) {
             tap_read_poll(s, false);
+            break;
+        } else if (size < 0) {
+            break;
         }
-    } while (size > 0 && qemu_can_send_packet(&s->nc));
+    }
 }
 
 static bool tap_has_ufo(NetClientState *nc)
-- 
1.8.5.3

             reply	other threads:[~2014-03-08 15:00 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-03-08 15:00 Stefan Hajnoczi [this message]
2014-03-10 19:19 ` [Qemu-devel] [PATCH] tap: avoid deadlocking rx Neil Skrypuch
2014-03-11 12:25 ` Stefan Hajnoczi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1394290843-18635-1-git-send-email-stefanha@redhat.com \
    --to=stefanha@redhat.com \
    --cc=dgilbert@redhat.com \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).