From c27ff60871aff588a35e51d1a90faed410993e55 Mon Sep 17 00:00:00 2001 From: Jan Kiszka Date: Fri, 8 May 2009 12:34:17 +0200 Subject: [PATCH] net: Fix and improved ordered packet delivery Fix a race in qemu_send_packet when delivering deferred packets and add proper deferring also to qemu_sendv_packet. Signed-off-by: Jan Kiszka Signed-off-by: Mark McLoughlin --- net.c | 57 ++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/net.c b/net.c index 42b6b93247..6563b424ce 100644 --- a/net.c +++ b/net.c @@ -438,8 +438,8 @@ void qemu_send_packet(VLANClientState *vc, const uint8_t *buf, int size) vlan->delivering = 1; qemu_deliver_packet(vc, buf, size); while ((packet = vlan->send_queue) != NULL) { - qemu_deliver_packet(packet->sender, packet->data, packet->size); vlan->send_queue = packet->next; + qemu_deliver_packet(packet->sender, packet->data, packet->size); qemu_free(packet); } vlan->delivering = 0; @@ -476,30 +476,57 @@ static ssize_t calc_iov_length(const struct iovec *iov, int iovcnt) return offset; } -ssize_t qemu_sendv_packet(VLANClientState *vc1, const struct iovec *iov, +ssize_t qemu_sendv_packet(VLANClientState *sender, const struct iovec *iov, int iovcnt) { - VLANState *vlan = vc1->vlan; + VLANState *vlan = sender->vlan; VLANClientState *vc; + VLANPacket *packet; ssize_t max_len = 0; + int i; - if (vc1->link_down) + if (sender->link_down) return calc_iov_length(iov, iovcnt); - for (vc = vlan->first_client; vc != NULL; vc = vc->next) { - ssize_t len = 0; + if (vlan->delivering) { + max_len = calc_iov_length(iov, iovcnt); - if (vc == vc1) - continue; + packet = qemu_malloc(sizeof(VLANPacket) + max_len); + packet->next = vlan->send_queue; + packet->sender = sender; + packet->size = 0; + for (i = 0; i < iovcnt; i++) { + size_t len = iov[i].iov_len; + + memcpy(packet->data + packet->size, iov[i].iov_base, len); + packet->size += len; + } + vlan->send_queue = packet; + } else { + vlan->delivering = 1; + + for (vc = vlan->first_client; vc != NULL; vc = vc->next) { + ssize_t len = 0; - if (vc->link_down) - len = calc_iov_length(iov, iovcnt); - else if (vc->fd_readv) - len = vc->fd_readv(vc->opaque, iov, iovcnt); - else if (vc->fd_read) - len = vc_sendv_compat(vc, iov, iovcnt); + if (vc == sender) { + continue; + } + if (vc->link_down) { + len = calc_iov_length(iov, iovcnt); + } else if (vc->fd_readv) { + len = vc->fd_readv(vc->opaque, iov, iovcnt); + } else if (vc->fd_read) { + len = vc_sendv_compat(vc, iov, iovcnt); + } + max_len = MAX(max_len, len); + } - max_len = MAX(max_len, len); + while ((packet = vlan->send_queue) != NULL) { + vlan->send_queue = packet->next; + qemu_deliver_packet(packet->sender, packet->data, packet->size); + qemu_free(packet); + } + vlan->delivering = 0; } return max_len; -- GitLab