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

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