carlwgeorge / rpms / qemu

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