aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark McLoughlin <markmc@redhat.com>2009-06-18 18:21:32 +0100
committerAnthony Liguori <aliguori@us.ibm.com>2009-06-22 10:15:30 -0500
commit1f7babf6d5ca24460694556d617cd17ae8be2ed4 (patch)
tree50f9190ebc04eba36802a8f56f321197a4f613cc
parentb664e3673c6c2ca228ce025292e32b34f73df5f5 (diff)
net: handle EAGAIN from tapfd write()
If a write() on tapfd returns EAGAIN, return zero so that the packet gets queued (in the case of async send) and enable polling tapfd for writing. When tapfd becomes writable, disable write polling and flush any queued packets. Signed-off-by: Mark McLoughlin <markmc@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
-rw-r--r--net.c27
1 files changed, 25 insertions, 2 deletions
diff --git a/net.c b/net.c
index 8e75a29d98..dd6981a4d9 100644
--- a/net.c
+++ b/net.c
@@ -1044,19 +1044,21 @@ typedef struct TAPState {
char down_script_arg[128];
uint8_t buf[4096];
unsigned int read_poll : 1;
+ unsigned int write_poll : 1;
} TAPState;
static int launch_script(const char *setup_script, const char *ifname, int fd);
static int tap_can_send(void *opaque);
static void tap_send(void *opaque);
+static void tap_writable(void *opaque);
static void tap_update_fd_handler(TAPState *s)
{
qemu_set_fd_handler2(s->fd,
s->read_poll ? tap_can_send : NULL,
s->read_poll ? tap_send : NULL,
- NULL,
+ s->write_poll ? tap_writable : NULL,
s);
}
@@ -1066,6 +1068,21 @@ static void tap_read_poll(TAPState *s, int enable)
tap_update_fd_handler(s);
}
+static void tap_write_poll(TAPState *s, int enable)
+{
+ s->write_poll = !!enable;
+ tap_update_fd_handler(s);
+}
+
+static void tap_writable(void *opaque)
+{
+ TAPState *s = opaque;
+
+ tap_write_poll(s, 0);
+
+ qemu_flush_queued_packets(s->vc);
+}
+
static ssize_t tap_receive_iov(VLANClientState *vc, const struct iovec *iov,
int iovcnt)
{
@@ -1074,7 +1091,12 @@ static ssize_t tap_receive_iov(VLANClientState *vc, const struct iovec *iov,
do {
len = writev(s->fd, iov, iovcnt);
- } while (len == -1 && (errno == EINTR || errno == EAGAIN));
+ } while (len == -1 && errno == EINTR);
+
+ if (len == -1 && errno == EAGAIN) {
+ tap_write_poll(s, 1);
+ return 0;
+ }
return len;
}
@@ -1150,6 +1172,7 @@ static void tap_cleanup(VLANClientState *vc)
launch_script(s->down_script, s->down_script_arg, s->fd);
tap_read_poll(s, 0);
+ tap_write_poll(s, 0);
close(s->fd);
qemu_free(s);
}