From 7ec5f1490c84fce3c63cedfd0c9da45cb1297db8 Mon Sep 17 00:00:00 2001 From: Amit Shah Date: Fri, 4 Feb 2011 08:20:41 -0200 Subject: [RHEL6 qemu-kvm PATCH 10/27] virtio-serial: Add support for flow control RH-Author: Amit Shah Message-id: <181eb3013a7bde8c711023a8b6c489d893c56bf9.1296806194.git.amit.shah@redhat.com> Patchwork-id: 17711 O-Subject: [RHEL6.1 qemu PATCH v5 10/19] virtio-serial: Add support for flow control Bugzilla: 588916 RH-Acked-by: Alon Levy RH-Acked-by: Juan Quintela RH-Acked-by: Jes Sorensen RH-Acked-by: Michael S. Tsirkin This commit lets apps signal an incomplete write. When that happens, stop sending out any more data to the app and wait for it to unthrottle the port. Signed-off-by: Amit Shah (cherry picked from commit f1925dff7e6c4799f5951cf167a437c0737a266c) Signed-off-by: Amit Shah --- hw/virtio-serial-bus.c | 49 +++++++++++++++++++++++++++++++++++++---------- hw/virtio-serial.h | 17 ++++++++++++++++ 2 files changed, 55 insertions(+), 11 deletions(-) Signed-off-by: Eduardo Habkost --- hw/virtio-serial-bus.c | 49 +++++++++++++++++++++++++++++++++++++---------- hw/virtio-serial.h | 17 ++++++++++++++++ 2 files changed, 55 insertions(+), 11 deletions(-) diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c index e23b4eb..554bb99 100644 --- a/hw/virtio-serial-bus.c +++ b/hw/virtio-serial-bus.c @@ -129,24 +129,49 @@ static void discard_vq_data(VirtQueue *vq, VirtIODevice *vdev) static void do_flush_queued_data(VirtIOSerialPort *port, VirtQueue *vq, VirtIODevice *vdev) { - VirtQueueElement elem; - assert(port); assert(virtio_queue_ready(vq)); - while (!port->throttled && virtqueue_pop(vq, &elem)) { + while (!port->throttled) { unsigned int i; - for (i = 0; i < elem.out_num; i++) { - size_t buf_size; - - buf_size = elem.out_sg[i].iov_len; + /* Pop an elem only if we haven't left off a previous one mid-way */ + if (!port->elem.out_num) { + if (!virtqueue_pop(vq, &port->elem)) { + break; + } + port->iov_idx = 0; + port->iov_offset = 0; + } - port->info->have_data(port, - elem.out_sg[i].iov_base, - buf_size); + for (i = port->iov_idx; i < port->elem.out_num; i++) { + size_t buf_size; + ssize_t ret; + + buf_size = port->elem.out_sg[i].iov_len - port->iov_offset; + ret = port->info->have_data(port, + port->elem.out_sg[i].iov_base + + port->iov_offset, + buf_size); + if (ret < 0 && ret != -EAGAIN) { + /* We don't handle any other type of errors here */ + abort(); + } + if (ret == -EAGAIN || (ret >= 0 && ret < buf_size)) { + virtio_serial_throttle_port(port, true); + port->iov_idx = i; + if (ret > 0) { + port->iov_offset += ret; + } + break; + } + port->iov_offset = 0; } - virtqueue_push(vq, &elem, 0); + if (port->throttled) { + break; + } + virtqueue_push(vq, &port->elem, 0); + port->elem.out_num = 0; } virtio_notify(vdev, vq); } @@ -719,6 +744,8 @@ static int virtser_port_qdev_init(DeviceState *qdev, DeviceInfo *base) port->guest_connected = true; } + port->elem.out_num = 0; + QTAILQ_INSERT_TAIL(&port->vser->ports, port, next); port->ivq = port->vser->ivqs[port->id]; port->ovq = port->vser->ovqs[port->id]; diff --git a/hw/virtio-serial.h b/hw/virtio-serial.h index 89078d9..de624c3 100644 --- a/hw/virtio-serial.h +++ b/hw/virtio-serial.h @@ -107,6 +107,23 @@ struct VirtIOSerialPort { */ uint32_t id; + /* + * This is the elem that we pop from the virtqueue. A slow + * backend that consumes guest data (e.g. the file backend for + * qemu chardevs) can cause the guest to block till all the output + * is flushed. This isn't desired, so we keep a note of the last + * element popped and continue consuming it once the backend + * becomes writable again. + */ + VirtQueueElement elem; + + /* + * The index and the offset into the iov buffer that was popped in + * elem above. + */ + uint32_t iov_idx; + uint64_t iov_offset; + /* Identify if this is a port that binds with hvc in the guest */ uint8_t is_console; -- 1.7.3.2