[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] [HVM] Rate limit guest accesses to the qemu virtual serial port. This stops
# HG changeset patch # User Steven Smith <ssmith@xxxxxxxxxxxxx> # Node ID 1d3f52eb256e3522edc12daca91039b319dbbbe5 # Parent b7b653e36d20811831f26bb951ea66dca5854b17 [HVM] Rate limit guest accesses to the qemu virtual serial port. This stops grub's boot menu from hammering dom0. Signed-off-by: Steven Smith <sos22@xxxxxxxxx> --- tools/ioemu/hw/serial.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 68 insertions(+) diff -r b7b653e36d20 -r 1d3f52eb256e tools/ioemu/hw/serial.c --- a/tools/ioemu/hw/serial.c Mon Sep 25 16:31:02 2006 +0100 +++ b/tools/ioemu/hw/serial.c Mon Sep 25 17:27:18 2006 +0100 @@ -22,6 +22,9 @@ * THE SOFTWARE. */ #include "vl.h" +#include <sys/time.h> +#include <time.h> +#include <assert.h> //#define DEBUG_SERIAL @@ -138,6 +141,67 @@ static void serial_update_parameters(Ser printf("speed=%d parity=%c data=%d stop=%d\n", speed, parity, data_bits, stop_bits); #endif +} + +/* Rate limit serial requests so that e.g. grub on a serial console + doesn't kill dom0. Simple token bucket. If we get some actual + data from the user, instantly refil the bucket. */ + +/* How long it takes to generate a token, in microseconds. */ +#define TOKEN_PERIOD 1000 +/* Maximum and initial size of token bucket */ +#define TOKENS_MAX 100000 + +static int tokens_avail; + +static void serial_get_token(void) +{ + static struct timeval last_refil_time; + static int started; + + assert(tokens_avail >= 0); + if (!tokens_avail) { + struct timeval delta, now; + int generated; + + if (!started) { + gettimeofday(&last_refil_time, NULL); + tokens_avail = TOKENS_MAX; + started = 1; + return; + } + retry: + gettimeofday(&now, NULL); + delta.tv_sec = now.tv_sec - last_refil_time.tv_sec; + delta.tv_usec = now.tv_usec - last_refil_time.tv_usec; + if (delta.tv_usec < 0) { + delta.tv_usec += 1000000; + delta.tv_sec--; + } + assert(delta.tv_usec >= 0 && delta.tv_sec >= 0); + if (delta.tv_usec < TOKEN_PERIOD) { + struct timespec ts; + /* Wait until at least one token is available. */ + ts.tv_sec = TOKEN_PERIOD / 1000000; + ts.tv_nsec = (TOKEN_PERIOD % 1000000) * 1000; + while (nanosleep(&ts, &ts) < 0 && errno == EINTR) + ; + goto retry; + } + generated = (delta.tv_sec * 1000000) / TOKEN_PERIOD; + generated += + ((delta.tv_sec * 1000000) % TOKEN_PERIOD + delta.tv_usec) / TOKEN_PERIOD; + assert(generated > 0); + + last_refil_time.tv_usec += (generated * TOKEN_PERIOD) % 1000000; + last_refil_time.tv_sec += last_refil_time.tv_usec / 1000000; + last_refil_time.tv_usec %= 1000000; + last_refil_time.tv_sec += (generated * TOKEN_PERIOD) / 1000000; + if (generated > TOKENS_MAX) + generated = TOKENS_MAX; + tokens_avail = generated; + } + tokens_avail--; } static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val) @@ -245,9 +309,11 @@ static uint32_t serial_ioport_read(void ret = s->mcr; break; case 5: + serial_get_token(); ret = s->lsr; break; case 6: + serial_get_token(); if (s->mcr & UART_MCR_LOOP) { /* in loopback, the modem output pins are connected to the inputs */ @@ -296,12 +362,14 @@ static void serial_receive1(void *opaque static void serial_receive1(void *opaque, const uint8_t *buf, int size) { SerialState *s = opaque; + tokens_avail = TOKENS_MAX; serial_receive_byte(s, buf[0]); } static void serial_event(void *opaque, int event) { SerialState *s = opaque; + tokens_avail = TOKENS_MAX; if (event == CHR_EVENT_BREAK) serial_receive_break(s); } _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |