diff -aur -X work/diff-exclude 2.6.16.1-orig/arch/um/drivers/mconsole_kern.c 2.6.16.1-linode18/arch/um/drivers/mconsole_kern.c --- 2.6.16.1-orig/arch/um/drivers/mconsole_kern.c 2006-03-30 23:21:40.596972777 -0500 +++ 2.6.16.1-linode18/arch/um/drivers/mconsole_kern.c 2006-03-30 23:34:01.314505841 -0500 @@ -35,6 +35,7 @@ #include "umid.h" #include "irq_kern.h" #include "choose-mode.h" +#include "ubd_user.h" static int do_unlink_socket(struct notifier_block *notifier, unsigned long what, void *data) @@ -308,6 +309,9 @@ log - make UML enter into the kernel log\n" EXEC_HELPTEXT "\ proc - returns the contents of the UML's /proc/\n\ stack - returns the stack of the specified pid\n\ + io_status - Return current I/O status and settings\n\ + io_token_max - sets the bucket size\n\ + io_token_refill - number of tokens to add each second\n\ " void mconsole_help(struct mc_request *req) @@ -803,3 +807,49 @@ } EXPORT_SYMBOL(mconsole_notify_socket); + +void mconsole_io_status(struct mc_request *req) +{ + char str[256]; + + sprintf(str, "io_count=%d io_rate=%d io_tokens=%d token_refill=%d token_max=%d", + get_io_count(), + get_io_rate(), + get_io_tokens(), + get_token_refill(), + get_token_max() + ); + + mconsole_reply(req, str, 0, 0); +} + +void mconsole_io_token_refill(struct mc_request *req) +{ + char *end; + int n; + + char *ptr = req->request.data; + + ptr += strlen("io_token_refill "); + n = simple_strtoul(ptr, &end, 0); + if (n>0) + set_token_refill(n); + + mconsole_io_status(req); + } + + void mconsole_io_token_max(struct mc_request *req) + { + char *end; + int n; + + char *ptr = req->request.data; + ptr += strlen("io_token_max "); + n = simple_strtoul(ptr, &end, 0); + + if (n>0) + set_token_max(n); + + mconsole_io_status(req); +} + diff -aur -X work/diff-exclude 2.6.16.1-orig/arch/um/drivers/mconsole_user.c 2.6.16.1-linode18/arch/um/drivers/mconsole_user.c --- 2.6.16.1-orig/arch/um/drivers/mconsole_user.c 2006-03-30 23:21:40.597972544 -0500 +++ 2.6.16.1-linode18/arch/um/drivers/mconsole_user.c 2006-03-30 23:29:38.583685408 -0500 @@ -35,6 +35,9 @@ #ifdef UML_CONFIG_MCONSOLE_EXEC { "exec", mconsole_exec, MCONSOLE_PROC }, #endif + { "io_status", mconsole_io_status, MCONSOLE_INTR }, + { "io_token_refill", mconsole_io_token_refill, MCONSOLE_INTR }, + { "io_token_max", mconsole_io_token_max, MCONSOLE_INTR }, }; /* Initialized in mconsole_init, which is an initcall */ diff -aur -X work/diff-exclude 2.6.16.1-orig/arch/um/drivers/ubd_kern.c 2.6.16.1-linode18/arch/um/drivers/ubd_kern.c --- 2.6.16.1-orig/arch/um/drivers/ubd_kern.c 2006-03-28 01:49:02.000000000 -0500 +++ 2.6.16.1-linode18/arch/um/drivers/ubd_kern.c 2006-03-30 23:27:40.417199626 -0500 @@ -1367,7 +1367,15 @@ int kernel_fd = -1; /* Only changed by the io thread */ -int io_count = 0; +static int io_count = 0; + +/* Are set by the kernel and read from the io_thread or vice-versa */ +static int token_refill = 512; // add this many tokens to the bucket every second +static int token_delay = 1000000000 / 2000; +static int token_max = 400000; // max tokens in bucket +static int io_tokens = 400000; // token bucket +static int io_count_last = 0; // snapshot of io_count last time in io_alarm() +static int io_rate = 0; // calculated io ops per second int io_thread(void *arg) { @@ -1375,6 +1383,7 @@ int n; ignore_sigwinch_sig(); + io_thread_token_setup(); while(1){ n = os_read_file(kernel_fd, &req, sizeof(req)); if(n != sizeof(req)){ @@ -1389,6 +1398,7 @@ } io_count++; do_io(&req); + io_delay(); n = os_write_file(kernel_fd, &req, sizeof(req)); if(n != sizeof(req)) printk("io_thread - write failed, fd = %d, err = %d\n", @@ -1397,3 +1407,113 @@ return 0; } + + +void io_alarm(int sig) +{ + io_rate = io_count - io_count_last; + io_count_last = io_count; + + io_tokens += token_refill; + if (io_tokens > token_max){ + io_tokens = token_max; + } + + /* printk("io_alarm - current speed: %d, io_tokens : %d \n", + io_rate, io_tokens); */ + + io_set_alarm(); +} + +int set_token_refill(int tokens) +{ + token_refill = tokens; + + token_delay = 1000; + if (token_refill) + token_delay = 1000000000 / token_refill; + + return 0; +} + +int get_token_refill() +{ + return token_refill; +} + +int get_io_count() +{ + return io_count; +} + +int set_token_max(int tokens) +{ + token_max = tokens; + return 0; +} + +int get_token_max() +{ + return token_max; +} + +int get_io_rate() +{ + return io_rate; +} + +int get_io_tokens() +{ + return io_tokens; +} + + +int set_io_tokens(int tokens) +{ + io_tokens = tokens; + return 0; +} + +int get_token_delay() +{ + return token_delay; +} + +int set_token_delay(int delay) +{ + token_delay = delay; + return 0; +} + +static int cmdline_token_max(char *name, int *add) +{ + char *end; + + set_token_max(simple_strtoul(name, &end, 0)); + return(0); +} + +static int cmdline_token_refill(char *name, int *add) +{ + char *end; + + set_token_refill(simple_strtoul(name, &end, 0)); + return(0); +} + +__uml_setup("token_max=", cmdline_token_max, +"token_max=60000\n" \ +" This sets the maximum tokens in the token-bucket I/O request limiter.\n" \ +" Each io_thread request subtracts one token from the bucket. The bucket\n" \ +" is supplied with tokens every second. When the bucket\n" \ +" becomes empty, I/O requests are throttled to the rate.\n\n" +); + + +__uml_setup("token_refill=", cmdline_token_refill, +"token_refill=2000\n" \ +" This sets the bucket's refill rate, adding tokens to the\n" \ +" bucket every second. This becomes the I/O request rate when the bucket\n" \ +" becomes empty.\n\n" +); + diff -aur -X work/diff-exclude 2.6.16.1-orig/arch/um/drivers/ubd_user.c 2.6.16.1-linode18/arch/um/drivers/ubd_user.c --- 2.6.16.1-orig/arch/um/drivers/ubd_user.c 2006-03-28 01:49:02.000000000 -0500 +++ 2.6.16.1-linode18/arch/um/drivers/ubd_user.c 2006-03-30 23:22:01.991991968 -0500 @@ -26,6 +26,9 @@ #include #include +#include +#include + void ignore_sigwinch_sig(void) { signal(SIGWINCH, SIG_IGN); @@ -63,6 +66,40 @@ return(err); } + +void io_thread_token_setup(void) +{ + signal(SIGALRM, io_alarm); + io_alarm(14); +} + +void io_set_alarm(void) +{ + alarm(1); +} + +void io_delay() +{ + int io_tokens = get_io_tokens(); + int token_delay = get_token_delay(); + + set_io_tokens(--io_tokens); + + if (io_tokens <= 0) { + struct timespec ts; + ts.tv_sec = 0; + ts.tv_nsec = token_delay; + + // fix for when token_refill == 1 + if (token_delay == 1000000000) { + ts.tv_sec = 1; + ts.tv_nsec = 0; + } + + nanosleep(&ts, NULL); + } +} + /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff -aur -X work/diff-exclude 2.6.16.1-orig/arch/um/include/mconsole.h 2.6.16.1-linode18/arch/um/include/mconsole.h --- 2.6.16.1-orig/arch/um/include/mconsole.h 2006-03-30 23:21:40.620967191 -0500 +++ 2.6.16.1-linode18/arch/um/include/mconsole.h 2006-03-30 23:23:15.136963298 -0500 @@ -85,6 +85,9 @@ extern void mconsole_exec(struct mc_request *req); extern void mconsole_proc(struct mc_request *req); extern void mconsole_stack(struct mc_request *req); +extern void mconsole_io_status(struct mc_request *req); +extern void mconsole_io_token_refill(struct mc_request *req); +extern void mconsole_io_token_max(struct mc_request *req); extern int mconsole_get_request(int fd, struct mc_request *req); extern int mconsole_notify(char *sock_name, int type, const void *data, diff -aur -X work/diff-exclude 2.6.16.1-orig/arch/um/include/os.h 2.6.16.1-linode18/arch/um/include/os.h --- 2.6.16.1-orig/arch/um/include/os.h 2006-03-30 23:21:40.621966958 -0500 +++ 2.6.16.1-linode18/arch/um/include/os.h 2006-03-30 23:22:01.992991736 -0500 @@ -29,6 +29,8 @@ #define OS_ACC_R_OK 4 /* Test for read permission. */ #define OS_ACC_RW_OK (OS_ACC_W_OK | OS_ACC_R_OK) /* Test for RW permission */ +extern void io_delay(void); + /* * types taken from stat_file() in hostfs_user.c * (if they are wrong here, they are wrong there...). diff -aur -X work/diff-exclude 2.6.16.1-orig/arch/um/include/ubd_user.h 2.6.16.1-linode18/arch/um/include/ubd_user.h --- 2.6.16.1-orig/arch/um/include/ubd_user.h 2006-03-28 01:49:02.000000000 -0500 +++ 2.6.16.1-linode18/arch/um/include/ubd_user.h 2006-03-30 23:22:01.992991736 -0500 @@ -12,6 +12,23 @@ extern int io_thread(void *arg); extern int kernel_fd; +static int cmdline_token_max(char *name, int *add); +static int cmdline_token_refill(char *name, int *add); +extern void io_thread_token_setup(void); +extern void io_delay(void); +extern void io_alarm(int sig); +extern int set_token_refill(int tokens); +extern int get_token_refill(void); +extern int set_token_max(int tokens); +extern int get_token_max(void); +extern int get_io_count(void); +extern int get_io_tokens(void); +extern int get_io_rate(void); +extern int set_io_tokens(int tokens); +extern int get_token_delay(void); +extern int set_token_delay(int delay); +extern void io_set_alarm(void); + #endif /*