ia64/xen-unstable

changeset 11623:1d3f52eb256e

[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@cam.ac.uk>
author Steven Smith <ssmith@xensource.com>
date Mon Sep 25 17:27:18 2006 +0100 (2006-09-25)
parents b7b653e36d20
children f5fd563bcc84
files tools/ioemu/hw/serial.c
line diff
     1.1 --- a/tools/ioemu/hw/serial.c	Mon Sep 25 16:31:02 2006 +0100
     1.2 +++ b/tools/ioemu/hw/serial.c	Mon Sep 25 17:27:18 2006 +0100
     1.3 @@ -22,6 +22,9 @@
     1.4   * THE SOFTWARE.
     1.5   */
     1.6  #include "vl.h"
     1.7 +#include <sys/time.h>
     1.8 +#include <time.h>
     1.9 +#include <assert.h>
    1.10  
    1.11  //#define DEBUG_SERIAL
    1.12  
    1.13 @@ -140,6 +143,67 @@ static void serial_update_parameters(Ser
    1.14  #endif
    1.15  }
    1.16  
    1.17 +/* Rate limit serial requests so that e.g. grub on a serial console
    1.18 +   doesn't kill dom0.  Simple token bucket.  If we get some actual
    1.19 +   data from the user, instantly refil the bucket. */
    1.20 +
    1.21 +/* How long it takes to generate a token, in microseconds. */
    1.22 +#define TOKEN_PERIOD 1000
    1.23 +/* Maximum and initial size of token bucket */
    1.24 +#define TOKENS_MAX 100000
    1.25 +
    1.26 +static int tokens_avail;
    1.27 +
    1.28 +static void serial_get_token(void)
    1.29 +{
    1.30 +    static struct timeval last_refil_time;
    1.31 +    static int started;
    1.32 +
    1.33 +    assert(tokens_avail >= 0);
    1.34 +    if (!tokens_avail) {
    1.35 +	struct timeval delta, now;
    1.36 +	int generated;
    1.37 +
    1.38 +	if (!started) {
    1.39 +	    gettimeofday(&last_refil_time, NULL);
    1.40 +	    tokens_avail = TOKENS_MAX;
    1.41 +	    started = 1;
    1.42 +	    return;
    1.43 +	}
    1.44 +    retry:
    1.45 +	gettimeofday(&now, NULL);
    1.46 +	delta.tv_sec = now.tv_sec - last_refil_time.tv_sec;
    1.47 +	delta.tv_usec = now.tv_usec - last_refil_time.tv_usec;
    1.48 +	if (delta.tv_usec < 0) {
    1.49 +	    delta.tv_usec += 1000000;
    1.50 +	    delta.tv_sec--;
    1.51 +	}
    1.52 +	assert(delta.tv_usec >= 0 && delta.tv_sec >= 0);
    1.53 +	if (delta.tv_usec < TOKEN_PERIOD) {
    1.54 +	    struct timespec ts;
    1.55 +	    /* Wait until at least one token is available. */
    1.56 +	    ts.tv_sec = TOKEN_PERIOD / 1000000;
    1.57 +	    ts.tv_nsec = (TOKEN_PERIOD % 1000000) * 1000;
    1.58 +	    while (nanosleep(&ts, &ts) < 0 && errno == EINTR)
    1.59 +		;
    1.60 +	    goto retry;
    1.61 +	}
    1.62 +	generated = (delta.tv_sec * 1000000) / TOKEN_PERIOD;
    1.63 +	generated +=
    1.64 +	    ((delta.tv_sec * 1000000) % TOKEN_PERIOD + delta.tv_usec) / TOKEN_PERIOD;
    1.65 +	assert(generated > 0);
    1.66 +
    1.67 +	last_refil_time.tv_usec += (generated * TOKEN_PERIOD) % 1000000;
    1.68 +	last_refil_time.tv_sec  += last_refil_time.tv_usec / 1000000;
    1.69 +	last_refil_time.tv_usec %= 1000000;
    1.70 +	last_refil_time.tv_sec  += (generated * TOKEN_PERIOD) / 1000000;
    1.71 +	if (generated > TOKENS_MAX)
    1.72 +	    generated = TOKENS_MAX;
    1.73 +	tokens_avail = generated;
    1.74 +    }
    1.75 +    tokens_avail--;
    1.76 +}
    1.77 +
    1.78  static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val)
    1.79  {
    1.80      SerialState *s = opaque;
    1.81 @@ -245,9 +309,11 @@ static uint32_t serial_ioport_read(void 
    1.82          ret = s->mcr;
    1.83          break;
    1.84      case 5:
    1.85 +	serial_get_token();
    1.86          ret = s->lsr;
    1.87          break;
    1.88      case 6:
    1.89 +	serial_get_token();
    1.90          if (s->mcr & UART_MCR_LOOP) {
    1.91              /* in loopback, the modem output pins are connected to the
    1.92                 inputs */
    1.93 @@ -296,12 +362,14 @@ static int serial_can_receive1(void *opa
    1.94  static void serial_receive1(void *opaque, const uint8_t *buf, int size)
    1.95  {
    1.96      SerialState *s = opaque;
    1.97 +    tokens_avail = TOKENS_MAX;
    1.98      serial_receive_byte(s, buf[0]);
    1.99  }
   1.100  
   1.101  static void serial_event(void *opaque, int event)
   1.102  {
   1.103      SerialState *s = opaque;
   1.104 +    tokens_avail = TOKENS_MAX;
   1.105      if (event == CHR_EVENT_BREAK)
   1.106          serial_receive_break(s);
   1.107  }