ia64/xen-unstable

changeset 16265:955ee4fa1345

xenconsoled: Rate-limit activity caused by each domU.
Allow each domU to fire its event channel at most 30 times every 200ms.
Signed-off by: Daniel P. Berrange <berrange@redhat.com>
author Keir Fraser <keir@xensource.com>
date Mon Oct 29 14:43:19 2007 +0000 (2007-10-29)
parents 3bb94bb35dad
children ba8c2bbaad79
files tools/console/daemon/io.c
line diff
     1.1 --- a/tools/console/daemon/io.c	Mon Oct 29 12:56:27 2007 +0000
     1.2 +++ b/tools/console/daemon/io.c	Mon Oct 29 14:43:19 2007 +0000
     1.3 @@ -35,6 +35,7 @@
     1.4  #include <termios.h>
     1.5  #include <stdarg.h>
     1.6  #include <sys/mman.h>
     1.7 +#include <sys/time.h>
     1.8  #if defined(__NetBSD__) || defined(__OpenBSD__)
     1.9  #include <util.h>
    1.10  #elif defined(__linux__) || defined(__Linux__)
    1.11 @@ -47,6 +48,11 @@
    1.12  /* Each 10 bits takes ~ 3 digits, plus one, plus one for nul terminator. */
    1.13  #define MAX_STRLEN(x) ((sizeof(x) * CHAR_BIT + CHAR_BIT-1) / 10 * 3 + 2)
    1.14  
    1.15 +/* How many events are allowed in each time period */
    1.16 +#define RATE_LIMIT_ALLOWANCE 30
    1.17 +/* Duration of each time period in ms */
    1.18 +#define RATE_LIMIT_PERIOD 200
    1.19 +
    1.20  extern int log_reload;
    1.21  extern int log_guest;
    1.22  extern int log_hv;
    1.23 @@ -82,6 +88,8 @@ struct domain
    1.24  	evtchn_port_or_error_t remote_port;
    1.25  	int xce_handle;
    1.26  	struct xencons_interface *interface;
    1.27 +	int event_count;
    1.28 +	long long next_period;
    1.29  };
    1.30  
    1.31  static struct domain *dom_head;
    1.32 @@ -494,6 +502,13 @@ static struct domain *create_domain(int 
    1.33  {
    1.34  	struct domain *dom;
    1.35  	char *s;
    1.36 +	struct timeval tv;
    1.37 +
    1.38 +	if (gettimeofday(&tv, NULL) < 0) {
    1.39 +		dolog(LOG_ERR, "Cannot get time of day %s:%s:L%d",
    1.40 +		      __FILE__, __FUNCTION__, __LINE__);
    1.41 +		return NULL;
    1.42 +	}
    1.43  
    1.44  	dom = (struct domain *)malloc(sizeof(struct domain));
    1.45  	if (dom == NULL) {
    1.46 @@ -529,6 +544,8 @@ static struct domain *create_domain(int 
    1.47  	dom->buffer.size = 0;
    1.48  	dom->buffer.capacity = 0;
    1.49  	dom->buffer.max_capacity = 0;
    1.50 +	dom->event_count = 0;
    1.51 +	dom->next_period = (tv.tv_sec * 1000) + (tv.tv_usec / 1000) + RATE_LIMIT_PERIOD;
    1.52  	dom->next = NULL;
    1.53  
    1.54  	dom->ring_ref = -1;
    1.55 @@ -720,9 +737,12 @@ static void handle_ring_read(struct doma
    1.56  	if ((port = xc_evtchn_pending(dom->xce_handle)) == -1)
    1.57  		return;
    1.58  
    1.59 +	dom->event_count++;
    1.60 +
    1.61  	buffer_append(dom);
    1.62  
    1.63 -	(void)xc_evtchn_unmask(dom->xce_handle, port);
    1.64 +	if (dom->event_count < RATE_LIMIT_ALLOWANCE)
    1.65 +		(void)xc_evtchn_unmask(dom->xce_handle, port);
    1.66  }
    1.67  
    1.68  static void handle_xs(void)
    1.69 @@ -820,6 +840,9 @@ void handle_io(void)
    1.70  	for (;;) {
    1.71  		struct domain *d, *n;
    1.72  		int max_fd = -1;
    1.73 +		struct timeval timeout;
    1.74 +		struct timeval tv;
    1.75 +		long long now, next_timeout = 0;
    1.76  
    1.77  		FD_ZERO(&readfds);
    1.78  		FD_ZERO(&writefds);
    1.79 @@ -832,8 +855,33 @@ void handle_io(void)
    1.80  			max_fd = MAX(xc_evtchn_fd(xce_handle), max_fd);
    1.81  		}
    1.82  
    1.83 +		if (gettimeofday(&tv, NULL) < 0)
    1.84 +			return;
    1.85 +		now = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
    1.86 +
    1.87 +		/* Re-calculate any event counter allowances & unblock
    1.88 +		   domains with new allowance */
    1.89  		for (d = dom_head; d; d = d->next) {
    1.90 -			if (d->xce_handle != -1) {
    1.91 +			/* Add 5ms of fuzz since select() often returns
    1.92 +			   a couple of ms sooner than requested. Without
    1.93 +			   the fuzz we typically do an extra spin in select()
    1.94 +			   with a 1/2 ms timeout every other iteration */
    1.95 +			if ((now+5) > d->next_period) {
    1.96 +				d->next_period = now + RATE_LIMIT_PERIOD;
    1.97 +				if (d->event_count >= RATE_LIMIT_ALLOWANCE) {
    1.98 +					(void)xc_evtchn_unmask(d->xce_handle, d->local_port);
    1.99 +				}
   1.100 +				d->event_count = 0;
   1.101 +			}
   1.102 +		}
   1.103 +
   1.104 +		for (d = dom_head; d; d = d->next) {
   1.105 +			if (d->event_count >= RATE_LIMIT_ALLOWANCE) {
   1.106 +				/* Determine if we're going to be the next time slice to expire */
   1.107 +				if (!next_timeout ||
   1.108 +				    d->next_period < next_timeout)
   1.109 +					next_timeout = d->next_period;
   1.110 +			} else if (d->xce_handle != -1) {
   1.111  				int evtchn_fd = xc_evtchn_fd(d->xce_handle);
   1.112  				FD_SET(evtchn_fd, &readfds);
   1.113  				max_fd = MAX(evtchn_fd, max_fd);
   1.114 @@ -849,7 +897,19 @@ void handle_io(void)
   1.115  			}
   1.116  		}
   1.117  
   1.118 -		ret = select(max_fd + 1, &readfds, &writefds, 0, NULL);
   1.119 +		/* If any domain has been rate limited, we need to work
   1.120 +		   out what timeout to supply to select */
   1.121 +		if (next_timeout) {
   1.122 +			long long duration = (next_timeout - now);
   1.123 +			if (duration <= 0) /* sanity check */
   1.124 +				duration = 1;
   1.125 +			timeout.tv_sec = duration / 1000;
   1.126 +			timeout.tv_usec = ((duration - (timeout.tv_sec * 1000))
   1.127 +					   * 1000);
   1.128 +		}
   1.129 +
   1.130 +		ret = select(max_fd + 1, &readfds, &writefds, 0,
   1.131 +			     next_timeout ? &timeout : NULL);
   1.132  
   1.133  		if (log_reload) {
   1.134  			handle_log_reload();
   1.135 @@ -877,9 +937,11 @@ void handle_io(void)
   1.136  
   1.137  		for (d = dom_head; d; d = n) {
   1.138  			n = d->next;
   1.139 -			if (d->xce_handle != -1 &&
   1.140 -			    FD_ISSET(xc_evtchn_fd(d->xce_handle), &readfds))
   1.141 -				handle_ring_read(d);
   1.142 +			if (d->event_count < RATE_LIMIT_ALLOWANCE) {
   1.143 +				if (d->xce_handle != -1 &&
   1.144 +				    FD_ISSET(xc_evtchn_fd(d->xce_handle), &readfds))
   1.145 +					handle_ring_read(d);
   1.146 +			}
   1.147  
   1.148  			if (d->tty_fd != -1 && FD_ISSET(d->tty_fd, &readfds))
   1.149  				handle_tty_read(d);