diff options
author | Jan Kiszka <jan.kiszka@siemens.com> | 2009-05-08 12:34:17 +0200 |
---|---|---|
committer | Mark McLoughlin <markmc@redhat.com> | 2009-06-09 11:38:48 +0100 |
commit | c27ff60871aff588a35e51d1a90faed410993e55 (patch) | |
tree | 1573d7f0e1f986346d87f69b2c64d57228f2bff2 /net.c | |
parent | c8aa237c643e7cb44fe878eeb76399ff8b73821a (diff) |
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 <jan.kiszka@siemens.com>
Signed-off-by: Mark McLoughlin <markmc@redhat.com>
Diffstat (limited to 'net.c')
-rw-r--r-- | net.c | 57 |
1 files changed, 42 insertions, 15 deletions
@@ -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; |