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

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