|
|
5544c1 |
From 52d73aa49799848042c09be1c64c1bff2159a5e1 Mon Sep 17 00:00:00 2001
|
|
|
5544c1 |
From: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
|
|
|
5544c1 |
Date: Mon, 20 Aug 2012 10:14:35 +0100
|
|
|
5544c1 |
Subject: [PATCH] net: EAGAIN handling for net/socket.c TCP
|
|
|
5544c1 |
|
|
|
5544c1 |
Replace spinning send_all() with a proper non-blocking send. When the
|
|
|
5544c1 |
socket write buffer limit is reached, we should stop trying to send and
|
|
|
5544c1 |
wait for the socket to become writable again.
|
|
|
5544c1 |
|
|
|
5544c1 |
Non-blocking TCP sockets can return in two different ways when the write
|
|
|
5544c1 |
buffer limit is reached:
|
|
|
5544c1 |
|
|
|
5544c1 |
1. ret = -1 and errno = EAGAIN/EWOULDBLOCK. No data has been written.
|
|
|
5544c1 |
|
|
|
5544c1 |
2. ret < total_size. Short write, only part of the message was
|
|
|
5544c1 |
transmitted.
|
|
|
5544c1 |
|
|
|
5544c1 |
Handle both cases and keep track of how many bytes have been written in
|
|
|
5544c1 |
s->send_index. (This includes the 'length' header before the actual
|
|
|
5544c1 |
payload buffer.)
|
|
|
5544c1 |
|
|
|
5544c1 |
Signed-off-by: Stefan Hajnoczi <stefanha@linux.vnet.ibm.com>
|
|
|
5544c1 |
(cherry picked from commit 45a7f54a8bb3928ffa58d522e0d61acaee8277bb)
|
|
|
5544c1 |
|
|
|
5544c1 |
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
|
|
|
5544c1 |
---
|
|
|
5544c1 |
net/socket.c | 36 +++++++++++++++++++++++++++++++-----
|
|
|
5544c1 |
1 file changed, 31 insertions(+), 5 deletions(-)
|
|
|
5544c1 |
|
|
|
5544c1 |
diff --git a/net/socket.c b/net/socket.c
|
|
|
5544c1 |
index e5e4e8d..c3e55b8 100644
|
|
|
5544c1 |
--- a/net/socket.c
|
|
|
5544c1 |
+++ b/net/socket.c
|
|
|
5544c1 |
@@ -32,6 +32,7 @@
|
|
|
5544c1 |
#include "qemu-error.h"
|
|
|
5544c1 |
#include "qemu-option.h"
|
|
|
5544c1 |
#include "qemu_socket.h"
|
|
|
5544c1 |
+#include "iov.h"
|
|
|
5544c1 |
|
|
|
5544c1 |
typedef struct NetSocketState {
|
|
|
5544c1 |
NetClientState nc;
|
|
|
5544c1 |
@@ -40,6 +41,7 @@ typedef struct NetSocketState {
|
|
|
5544c1 |
int state; /* 0 = getting length, 1 = getting data */
|
|
|
5544c1 |
unsigned int index;
|
|
|
5544c1 |
unsigned int packet_len;
|
|
|
5544c1 |
+ unsigned int send_index; /* number of bytes sent (only SOCK_STREAM) */
|
|
|
5544c1 |
uint8_t buf[4096];
|
|
|
5544c1 |
struct sockaddr_in dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */
|
|
|
5544c1 |
IOHandler *send_fn; /* differs between SOCK_STREAM/SOCK_DGRAM */
|
|
|
5544c1 |
@@ -88,15 +90,39 @@ static void net_socket_writable(void *opaque)
|
|
|
5544c1 |
qemu_flush_queued_packets(&s->nc);
|
|
|
5544c1 |
}
|
|
|
5544c1 |
|
|
|
5544c1 |
-/* XXX: we consider we can send the whole packet without blocking */
|
|
|
5544c1 |
static ssize_t net_socket_receive(NetClientState *nc, const uint8_t *buf, size_t size)
|
|
|
5544c1 |
{
|
|
|
5544c1 |
NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc);
|
|
|
5544c1 |
- uint32_t len;
|
|
|
5544c1 |
- len = htonl(size);
|
|
|
5544c1 |
+ uint32_t len = htonl(size);
|
|
|
5544c1 |
+ struct iovec iov[] = {
|
|
|
5544c1 |
+ {
|
|
|
5544c1 |
+ .iov_base = &len,
|
|
|
5544c1 |
+ .iov_len = sizeof(len),
|
|
|
5544c1 |
+ }, {
|
|
|
5544c1 |
+ .iov_base = (void *)buf,
|
|
|
5544c1 |
+ .iov_len = size,
|
|
|
5544c1 |
+ },
|
|
|
5544c1 |
+ };
|
|
|
5544c1 |
+ size_t remaining;
|
|
|
5544c1 |
+ ssize_t ret;
|
|
|
5544c1 |
+
|
|
|
5544c1 |
+ remaining = iov_size(iov, 2) - s->send_index;
|
|
|
5544c1 |
+ ret = iov_send(s->fd, iov, 2, s->send_index, remaining);
|
|
|
5544c1 |
|
|
|
5544c1 |
- send_all(s->fd, (const uint8_t *)&len, sizeof(len));
|
|
|
5544c1 |
- return send_all(s->fd, buf, size);
|
|
|
5544c1 |
+ if (ret == -1 && errno == EAGAIN) {
|
|
|
5544c1 |
+ ret = 0; /* handled further down */
|
|
|
5544c1 |
+ }
|
|
|
5544c1 |
+ if (ret == -1) {
|
|
|
5544c1 |
+ s->send_index = 0;
|
|
|
5544c1 |
+ return -errno;
|
|
|
5544c1 |
+ }
|
|
|
5544c1 |
+ if (ret < (ssize_t)remaining) {
|
|
|
5544c1 |
+ s->send_index += ret;
|
|
|
5544c1 |
+ net_socket_write_poll(s, true);
|
|
|
5544c1 |
+ return 0;
|
|
|
5544c1 |
+ }
|
|
|
5544c1 |
+ s->send_index = 0;
|
|
|
5544c1 |
+ return size;
|
|
|
5544c1 |
}
|
|
|
5544c1 |
|
|
|
5544c1 |
static ssize_t net_socket_receive_dgram(NetClientState *nc, const uint8_t *buf, size_t size)
|
|
|
5544c1 |
--
|
|
|
5544c1 |
1.7.12.1
|
|
|
5544c1 |
|