source: trunk/packages/xen-common/xen-common/tools/ioemu/patches/serial-port-rate-limit @ 34

Last change on this file since 34 was 34, checked in by hartmans, 17 years ago

Add xen and xen-common

File size: 3.4 KB
Line 
1# HG changeset patch
2# User Steven Smith <ssmith@xensource.com>
3# Node ID 1d3f52eb256e3522edc12daca91039b319dbbbe5
4# Parent  b7b653e36d20811831f26bb951ea66dca5854b17
5[HVM] Rate limit guest accesses to the qemu virtual serial port.  This stops
6grub's boot menu from hammering dom0.
7
8Signed-off-by: Steven Smith <sos22@cam.ac.uk>
9
10--- ioemu/hw/serial.c   Mon Sep 25 16:31:02 2006 +0100
11+++ ioemu/hw/serial.c   Mon Sep 25 17:27:18 2006 +0100
12@@ -22,6 +22,9 @@
13  * THE SOFTWARE.
14  */
15 #include "vl.h"
16+#include <sys/time.h>
17+#include <time.h>
18+#include <assert.h>
19 
20 //#define DEBUG_SERIAL
21 
22@@ -138,6 +141,67 @@ static void serial_update_parameters(Ser
23     printf("speed=%d parity=%c data=%d stop=%d\n",
24            speed, parity, data_bits, stop_bits);
25 #endif
26+}
27+
28+/* Rate limit serial requests so that e.g. grub on a serial console
29+   doesn't kill dom0.  Simple token bucket.  If we get some actual
30+   data from the user, instantly refil the bucket. */
31+
32+/* How long it takes to generate a token, in microseconds. */
33+#define TOKEN_PERIOD 1000
34+/* Maximum and initial size of token bucket */
35+#define TOKENS_MAX 100000
36+
37+static int tokens_avail;
38+
39+static void serial_get_token(void)
40+{
41+    static struct timeval last_refil_time;
42+    static int started;
43+
44+    assert(tokens_avail >= 0);
45+    if (!tokens_avail) {
46+       struct timeval delta, now;
47+       int generated;
48+
49+       if (!started) {
50+           gettimeofday(&last_refil_time, NULL);
51+           tokens_avail = TOKENS_MAX;
52+           started = 1;
53+           return;
54+       }
55+    retry:
56+       gettimeofday(&now, NULL);
57+       delta.tv_sec = now.tv_sec - last_refil_time.tv_sec;
58+       delta.tv_usec = now.tv_usec - last_refil_time.tv_usec;
59+       if (delta.tv_usec < 0) {
60+           delta.tv_usec += 1000000;
61+           delta.tv_sec--;
62+       }
63+       assert(delta.tv_usec >= 0 && delta.tv_sec >= 0);
64+       if (delta.tv_usec < TOKEN_PERIOD) {
65+           struct timespec ts;
66+           /* Wait until at least one token is available. */
67+           ts.tv_sec = TOKEN_PERIOD / 1000000;
68+           ts.tv_nsec = (TOKEN_PERIOD % 1000000) * 1000;
69+           while (nanosleep(&ts, &ts) < 0 && errno == EINTR)
70+               ;
71+           goto retry;
72+       }
73+       generated = (delta.tv_sec * 1000000) / TOKEN_PERIOD;
74+       generated +=
75+           ((delta.tv_sec * 1000000) % TOKEN_PERIOD + delta.tv_usec) / TOKEN_PERIOD;
76+       assert(generated > 0);
77+
78+       last_refil_time.tv_usec += (generated * TOKEN_PERIOD) % 1000000;
79+       last_refil_time.tv_sec  += last_refil_time.tv_usec / 1000000;
80+       last_refil_time.tv_usec %= 1000000;
81+       last_refil_time.tv_sec  += (generated * TOKEN_PERIOD) / 1000000;
82+       if (generated > TOKENS_MAX)
83+           generated = TOKENS_MAX;
84+       tokens_avail = generated;
85+    }
86+    tokens_avail--;
87 }
88 
89 static void serial_ioport_write(void *opaque, uint32_t addr, uint32_t val)
90@@ -245,9 +309,11 @@ static uint32_t serial_ioport_read(void
91         ret = s->mcr;
92         break;
93     case 5:
94+       serial_get_token();
95         ret = s->lsr;
96         break;
97     case 6:
98+       serial_get_token();
99         if (s->mcr & UART_MCR_LOOP) {
100             /* in loopback, the modem output pins are connected to the
101                inputs */
102@@ -296,12 +362,14 @@ static void serial_receive1(void *opaque
103 static void serial_receive1(void *opaque, const uint8_t *buf, int size)
104 {
105     SerialState *s = opaque;
106+    tokens_avail = TOKENS_MAX;
107     serial_receive_byte(s, buf[0]);
108 }
109 
110 static void serial_event(void *opaque, int event)
111 {
112     SerialState *s = opaque;
113+    tokens_avail = TOKENS_MAX;
114     if (event == CHR_EVENT_BREAK)
115         serial_receive_break(s);
116 }
Note: See TracBrowser for help on using the repository browser.