diff -aur -X diff-exclude 2.6.9-orig/arch/um/drivers/mconsole_kern.c 2.6.9-limiter/arch/um/drivers/mconsole_kern.c --- 2.6.9-orig/arch/um/drivers/mconsole_kern.c 2004-10-18 17:53:06.000000000 -0400 +++ 2.6.9-limiter/arch/um/drivers/mconsole_kern.c 2004-11-23 00:52:11.990223328 -0500 @@ -31,6 +31,7 @@ #include "os.h" #include "umid.h" #include "irq_kern.h" +#include "ubd_user.h" static int do_unlink_socket(struct notifier_block *notifier, unsigned long what, void *data) @@ -209,6 +210,9 @@ go - continue the UML after a 'stop' \n\ log - make UML enter into the kernel log\n\ proc - returns the contents of the UML's /proc/\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) @@ -538,6 +542,51 @@ 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); +} + /* * 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 diff-exclude 2.6.9-orig/arch/um/drivers/mconsole_user.c 2.6.9-limiter/arch/um/drivers/mconsole_user.c --- 2.6.9-orig/arch/um/drivers/mconsole_user.c 2004-10-18 17:53:22.000000000 -0400 +++ 2.6.9-limiter/arch/um/drivers/mconsole_user.c 2004-11-23 00:52:11.990223328 -0500 @@ -30,6 +30,9 @@ { "go", mconsole_go, MCONSOLE_INTR }, { "log", mconsole_log, MCONSOLE_INTR }, { "proc", mconsole_proc, MCONSOLE_PROC }, + { "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 diff-exclude 2.6.9-orig/arch/um/drivers/ubd_user.c 2.6.9-limiter/arch/um/drivers/ubd_user.c --- 2.6.9-orig/arch/um/drivers/ubd_user.c 2004-10-18 17:53:43.000000000 -0400 +++ 2.6.9-limiter/arch/um/drivers/ubd_user.c 2004-11-23 00:53:19.344352351 -0500 @@ -26,6 +26,10 @@ #include #include +#include +#include +#include "init.h" + static int same_backing_files(char *from_cmdline, char *from_cow, char *cow) { struct uml_stat buf1, buf2; @@ -306,12 +310,23 @@ /* Only changed by the io thread */ int io_count = 0; +/* Are set by the kernel and read from the io_thread or vice-versa */ +int token_refill = 2000;// add this many tokens to the bucket every second +int token_delay = 1000000000 / 2000; +int token_max = 60000; // max tokens in bucket +int io_tokens = 60000; // token bucket +int io_count_last = 0; // snapshot of io_count last time in io_alarm() +int io_rate = 0; // calculated io ops per second + int io_thread(void *arg) { struct io_thread_req req; int n; signal(SIGWINCH, SIG_IGN); + signal(SIGALRM, io_alarm); + io_alarm(14); + while(1){ n = os_read_file(kernel_fd, &req, sizeof(req)); if(n != sizeof(req)){ @@ -326,6 +341,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", @@ -365,6 +381,103 @@ return(err); } +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); */ + + alarm(1); +} + +void io_delay() +{ + io_tokens--; + if (io_tokens <= 0) { + struct timespec ts; + ts.tv_sec = 0; + ts.tv_nsec = token_delay; + nanosleep(&ts, NULL); + } +} + +int set_token_refill(int tokens) +{ + token_refill = tokens; + + token_delay = 1000; + if (token_refill) + token_delay = (token_refill > 1) ? 1000000000 / token_refill : 999999999; + + 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; +} + +static int cmdline_token_max(char *name, int *add) +{ + set_token_max(atoi(name)); + 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" +); + + +static int cmdline_token_refill(char *name, int *add) +{ + set_token_refill(atoi(name)); + return(0); +} + +__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" +); + /* * 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 diff-exclude 2.6.9-orig/arch/um/include/mconsole.h 2.6.9-limiter/arch/um/include/mconsole.h --- 2.6.9-orig/arch/um/include/mconsole.h 2004-10-18 17:53:51.000000000 -0400 +++ 2.6.9-limiter/arch/um/include/mconsole.h 2004-11-23 00:52:11.991223093 -0500 @@ -81,6 +81,9 @@ extern void mconsole_go(struct mc_request *req); extern void mconsole_log(struct mc_request *req); extern void mconsole_proc(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 diff-exclude 2.6.9-orig/arch/um/include/ubd_user.h 2.6.9-limiter/arch/um/include/ubd_user.h --- 2.6.9-orig/arch/um/include/ubd_user.h 2004-10-18 17:54:31.000000000 -0400 +++ 2.6.9-limiter/arch/um/include/ubd_user.h 2004-11-23 00:52:11.992222857 -0500 @@ -42,6 +42,18 @@ extern int start_io_thread(unsigned long sp, int *fds_out); extern void do_io(struct io_thread_req *req); +static int cmdline_token_max(char *name, int *add); +static int cmdline_token_refill(char *name, int *add); +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); + static inline int ubd_test_bit(__u64 bit, unsigned char *data) { __u64 n; diff -aur -X diff-exclude 2.6.9-orig/fs/proc/proc_misc.c 2.6.9-limiter/fs/proc/proc_misc.c --- 2.6.9-orig/fs/proc/proc_misc.c 2004-10-18 17:53:21.000000000 -0400 +++ 2.6.9-limiter/fs/proc/proc_misc.c 2004-11-23 00:52:17.018038593 -0500 @@ -50,6 +50,8 @@ #include #include +#include "ubd_user.h" + #define LOAD_INT(x) ((x) >> FSHIFT) #define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100) /* @@ -247,6 +249,26 @@ .release = seq_release, }; +static int io_status_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len; + char str[256]; + + sprintf(str, "io_count=%d io_rate=%d io_tokens=%d token_refill=%d token_max=%d\n", + get_io_count(), + get_io_rate(), + get_io_tokens(), + get_token_refill(), + get_token_max() + ); + + strcpy(page, str); + len = strlen(page); + + return proc_calc_metrics(page, start, off, count, eof, len); +} + static int version_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -595,6 +617,7 @@ {"cmdline", cmdline_read_proc}, {"locks", locks_read_proc}, {"execdomains", execdomains_read_proc}, + {"io_status", io_status_read_proc}, {NULL,} }; for (p = simple_ones; p->name; p++)