add self-ballooning to balloon driver
PATCH 1/1 add self-ballooning to balloon driver
The attached patch adds a "self-ballooning" feature to the balloon driver. Currently it only works when the balloon driver is compiled into the kernel (e.g. not as a pv-on-hvm driver) because, alas, the key kernel global variable is not exported.
It can be turned on with "echo 1 > /proc/xen/balloon" and off again with "echo 0 > /proc/xen/balloon". It defaults off.
I've tested it with a program that randomly eats memory and it seems to work pretty well balancing two domains and surrendering lots of memory (but not too much) when a domain is idle. The only deleterious effect I've seen is that performance suffers for a second or so when a big memory app is launched on a previously ballooned-down system (due to swapping). But this is a small price to pay in some real world environments.
It obviously shouldn't be used on a domain that doesn't have a (virtual) swap disk configured. If you foresee other issues, please let me know.
I've got lots of ideas for building on this (for example rate-limiting memory surrendering) but thought I'd submit the basic patch for others to try/test.
Dan
===================================
If Xen could save time in a bottle / then clocks wouldn't virtually skew / It would save every tick / for VMs that aren't quick /
and Xen then would send them anew
(with apologies to the late great Jim Croce)
drivers/xen/balloon/balloon.c +51 -9
@@ -6,6 +6,7 @@* Copyright (c) 2003, B Dragovic * Copyright (c) 2003-2004, M Williamson, K Fraser * Copyright (c) 2005 Dan M. Smith, IBM Corporation +* Copyright (c) 2008 Dan Magenheimer, Oracle Corp (added self-ballooning) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version 2
@@ -78,6 +79,13 @@ DEFINE_SPINLOCK(balloon_lock);struct balloon_stats balloon_stats; +/* +* use vm_committed_space as an approximation for balloon target, repeating +* every second. Disabled if compiled as MODULE because kernel doesn't +* currently export vm_committed_space +*/ +static int selfballoon =0 ; +/* We increase/decrease in batches which fit in a page */ static unsigned long frame_list[PAGE_SIZE /sizeof (unsigned long )];
@@ -86,11 +94,14 @@ extern unsigned long totalram_pages;#ifndef MODULE extern unsigned long totalhigh_pages; +extern atomic_t vm_committed_space;#define inc_totalhigh_pages () (totalhigh_pages++)#define dec_totalhigh_pages () (totalhigh_pages--)#else #define inc_totalhigh_pages () ((void)0)#define dec_totalhigh_pages () ((void)0) +#undef atomic_read +#define atomic_read (x) (0)#endif /* List of ballooned pages, threaded through the mem_map array. */
@@ -381,6 +392,16 @@ static int decrease_reservation(unsignedreturn need_sleep; } +/* Resets the Xen limit and sets new target. */ +void balloon_set_new_target (unsigned long target) +{ +if (!target)return ;/* compiled as module, selfballoon on */ +/* No need for lock. Not read-modify-write updates. */ + bs.hard_limit = ~0UL ; + bs.target_pages =max (target,minimum_target ()); +} + +/* * We avoid multiple worker processes conflicting via the balloon mutex. * We may of course race updates of the target counts (which are protected
@@ -391,9 +412,16 @@ static void balloon_process(void *unused {int need_sleep =0 ;long credit; +unsigned long target_pages;mutex_lock (&balloon_mutex); +if (selfballoon) { + target_pages =atomic_read (&vm_committed_space); +balloon_set_new_target (target_pages); +// IPRINTK("setting new self-ballooning target=%ld kB\n", +// target_pages << (PAGE_SHIFT - 10)); + } do { credit = current_target() - bs.current_pages; if (credit > 0)
@@ -408,18 +436,17 @@ static void balloon_process(void *unused }while ((credit !=0 ) && !need_sleep);/* Schedule more work if there is some still to be done. */ -if (current_target () != bs.current_pages) +if ((current_target () != bs.current_pages) || selfballoon) {mod_timer (&balloon_timer, jiffies +HZ ); + }mutex_unlock (&balloon_mutex); }/* Resets the Xen limit, sets new target, and kicks off processing. */ -void balloon_set_new_target (unsigned long target) +void balloon_start_new_target (unsigned long target) { -/* No need for lock. Not read-modify-write updates. */ - bs.hard_limit = ~0UL ; - bs.target_pages =max (target,minimum_target ()); +balloon_set_new_target (target);schedule_work (&balloon_worker); }
@@ -433,7 +460,7 @@ static void watch_target(struct xenbus_w const char **vec, unsigned int len) {unsigned long long new_target; -int err; +int err =1 ; err =xenbus_scanf (XBT_NIL ,"memory" ,"target" ,"%llu" , &new_target);if (err !=1 ) {
@@ -444,7 +471,7 @@ static void watch_target(struct xenbus_w/* The given memory/target value is in KiB, so it needs converting to * pages. PAGE_SHIFT converts bytes to pages, hence PAGE_SHIFT - 10. */ -balloon_set_new_target (new_target >> (PAGE_SHIFT -10 )); +balloon_start_new_target (new_target >> (PAGE_SHIFT -10 )); } static int balloon_init_watcher(struct notifier_block *notifier,
@@ -466,11 +493,12 @@ static int balloon_write(struct file *fi {char memstring[64 ], *endchar;unsigned long long target_bytes; +unsigned long vm_pages;if (!capable (CAP_SYS_ADMIN ))return -EPERM ; -if (count <=1 ) +if (!count)return -EBADMSG ;/* runt */ if (count >sizeof (memstring))return -EFBIG ;/* too long */
@@ -480,7 +508,19 @@ static int balloon_write(struct file *fi memstring[sizeof (memstring)-1 ] ='\0' ; target_bytes =memparse (memstring, &endchar); -balloon_set_new_target (target_bytes >>PAGE_SHIFT ); +if (!target_bytes) { + selfballoon =0 ; +IPRINTK ("self-ballooning disabled\n" ); + } +else if (target_bytes ==1 ) { + selfballoon =1 ; + vm_pages =atomic_read (&vm_committed_space); +IPRINTK ("self-ballooning enabled, new target=%ld kB\n" , + vm_pages << (PAGE_SHIFT -10 )); +balloon_start_new_target (vm_pages); + } +else +balloon_start_new_target (target_bytes >>PAGE_SHIFT );return count; }
@@ -492,12 +532,14 @@ static int balloon_read(char *page, char len =sprintf ( page, +"Self-ballooning: %s\n" "Current allocation: %8lu kB\n" "Requested target: %8lu kB\n" "Low-mem balloon: %8lu kB\n" "High-mem balloon: %8lu kB\n" "Driver pages: %8lu kB\n" "Xen hard limit: " , + (selfballoon?"on" :"off" ),PAGES2KB (bs.current_pages),PAGES2KB (bs.target_pages),PAGES2KB (bs.balloon_low),PAGES2KB (bs.balloon_high),PAGES2KB (bs.driver_pages));
_______________________________________________
Xen-devel mailing list
[email protected]
http://lists.xensource.com/xen-devel