|
|
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 |
|