Blame 0108-spice-qemu-char.c-add-throttling.patch

22d63f
From bffc95c205b473df9bba81dbf676504d0981d392 Mon Sep 17 00:00:00 2001
22d63f
Message-Id: <bffc95c205b473df9bba81dbf676504d0981d392.1354903384.git.crobinso@redhat.com>
22d63f
In-Reply-To: <9f0944a25bc1094fa7a74ac9df14e184e2c5c82d.1354903384.git.crobinso@redhat.com>
22d63f
References: <9f0944a25bc1094fa7a74ac9df14e184e2c5c82d.1354903384.git.crobinso@redhat.com>
22d63f
From: Alon Levy <alevy@redhat.com>
22d63f
Date: Tue, 22 Mar 2011 12:27:59 +0200
22d63f
Subject: [PATCH] spice-qemu-char.c: add throttling
22d63f
22d63f
BZ: 672191
22d63f
22d63f
upstream: not submitted (explained below)
22d63f
22d63f
Adds throttling support to spicevmc chardev. Uses a timer to avoid recursing:
22d63f
1. spice-server: reds.c:            read_from_vdi_port
22d63f
2. qemu:         spice-qemu-char.c: vmc_read
22d63f
3.                                  chr_write_unblocked
22d63f
                                (calls virtio_serial_throttle_port(port, false))
22d63f
4. qemu:         virtio ...
22d63f
5. qemu:         spice-qemu-char.c: spice_chr_write
22d63f
6. qemu:         spice-qemu-char.c: wakeup (calls into spice-server)
22d63f
7. spice-server: ...
22d63f
8. qemu:         spice-qemu-char.c: vmc_read
22d63f
22d63f
Instead, in vmc_read if we were throttled and we are just about to return
22d63f
all the bytes we will set a timer to be triggered immediately to call
22d63f
chr_write_unblocked. Then we return after 2 above, and 3 is called from the
22d63f
timer callback. This also means we can later remove some ugly recursion protection
22d63f
from spice-server.
22d63f
22d63f
The other tricky point in this patch is not returning the leftover chunk twice.
22d63f
When we throttle, by definition we have data that spice server didn't consume.
22d63f
It is being kept by virtio-serial, and by us. The next vmc_read callback needs
22d63f
to not return it, but just do unthrottling. Then virtio will give us the remaining
22d63f
chunk as usual in spice_chr_write, and we will pass it to spice server in the
22d63f
next vmc_read.
22d63f
22d63f
This patch relies on Amit's series to expose throttling to chardev's, which
22d63f
was not accepted upstream, and will not be accepted upstream until the mainloop
22d63f
is reworked to use glib.
22d63f
22d63f
Signed-off-by: Cole Robinson <crobinso@redhat.com>
22d63f
---
22d63f
 spice-qemu-char.c | 39 +++++++++++++++++++++++++++++++++++----
22d63f
 1 file changed, 35 insertions(+), 4 deletions(-)
22d63f
22d63f
diff --git a/spice-qemu-char.c b/spice-qemu-char.c
22d63f
index 09aa22d..fba2bfb 100644
22d63f
--- a/spice-qemu-char.c
22d63f
+++ b/spice-qemu-char.c
22d63f
@@ -1,4 +1,6 @@
22d63f
 #include "config-host.h"
22d63f
+#include "qemu-common.h"
22d63f
+#include "qemu-timer.h"
22d63f
 #include "trace.h"
22d63f
 #include "ui/qemu-spice.h"
22d63f
 #include <spice.h>
22d63f
@@ -25,6 +27,7 @@ typedef struct SpiceCharDriver {
22d63f
     uint8_t               *datapos;
22d63f
     ssize_t               bufsize, datalen;
22d63f
     uint32_t              debug;
22d63f
+    QEMUTimer             *unblock_timer;
22d63f
 } SpiceCharDriver;
22d63f
 
22d63f
 static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
22d63f
@@ -50,6 +53,17 @@ static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len)
22d63f
     return out;
22d63f
 }
22d63f
 
22d63f
+static void spice_chr_unblock(void *opaque)
22d63f
+{
22d63f
+    SpiceCharDriver *scd = opaque;
22d63f
+
22d63f
+    if (scd->chr->chr_write_unblocked == NULL) {
22d63f
+        dprintf(scd, 1, "%s: backend doesn't support unthrottling.\n", __func__);
22d63f
+        return;
22d63f
+    }
22d63f
+    scd->chr->chr_write_unblocked(scd->chr->handler_opaque);
22d63f
+}
22d63f
+
22d63f
 static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len)
22d63f
 {
22d63f
     SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin);
22d63f
@@ -61,9 +75,16 @@ static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len)
22d63f
         scd->datapos += bytes;
22d63f
         scd->datalen -= bytes;
22d63f
         assert(scd->datalen >= 0);
22d63f
-        if (scd->datalen == 0) {
22d63f
-            scd->datapos = 0;
22d63f
-        }
22d63f
+    }
22d63f
+    if (scd->datalen == 0 && scd->chr->write_blocked) {
22d63f
+        dprintf(scd, 1, "%s: unthrottling (%d)\n", __func__, bytes);
22d63f
+        scd->chr->write_blocked = false;
22d63f
+        /*
22d63f
+         * set a timer instead of calling scd->chr->chr_write_unblocked directly,
22d63f
+         * because that will call back into spice_chr_write (see
22d63f
+         * virtio-console.c:chr_write_unblocked), which is unwanted.
22d63f
+         */
22d63f
+        qemu_mod_timer(scd->unblock_timer, 0);
22d63f
     }
22d63f
     trace_spice_vmc_read(bytes, len);
22d63f
     return bytes;
22d63f
@@ -135,6 +156,7 @@ static void vmc_unregister_interface(SpiceCharDriver *scd)
22d63f
 static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
22d63f
 {
22d63f
     SpiceCharDriver *s = chr->opaque;
22d63f
+    int read_bytes;
22d63f
 
22d63f
     dprintf(s, 2, "%s: %d\n", __func__, len);
22d63f
     vmc_register_interface(s);
22d63f
@@ -147,7 +169,15 @@ static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
22d63f
     s->datapos = s->buffer;
22d63f
     s->datalen = len;
22d63f
     spice_server_char_device_wakeup(&s->sin);
22d63f
-    return len;
22d63f
+    read_bytes = len - s->datalen;
22d63f
+    if (read_bytes != len) {
22d63f
+        dprintf(s, 1, "%s: throttling: %d < %d (%zd)\n", __func__,
22d63f
+                read_bytes, len, s->bufsize);
22d63f
+        s->chr->write_blocked = true;
22d63f
+        /* We'll get passed in the unconsumed data with the next call */
22d63f
+        s->datalen = 0;
22d63f
+    }
22d63f
+    return read_bytes;
22d63f
 }
22d63f
 
22d63f
 static void spice_chr_close(struct CharDriverState *chr)
22d63f
@@ -225,6 +255,7 @@ CharDriverState *qemu_chr_open_spice(QemuOpts *opts)
22d63f
     chr->chr_close = spice_chr_close;
22d63f
     chr->chr_guest_open = spice_chr_guest_open;
22d63f
     chr->chr_guest_close = spice_chr_guest_close;
22d63f
+    s->unblock_timer = qemu_new_timer_ms(vm_clock, spice_chr_unblock, s);
22d63f
 
22d63f
 #if SPICE_SERVER_VERSION < 0x000901
22d63f
     /* See comment in vmc_state() */
22d63f
-- 
22d63f
1.8.0
22d63f