diff options
Diffstat (limited to 'drivers/xen/xen-selfballoon.c')
| -rw-r--r-- | drivers/xen/xen-selfballoon.c | 67 | 
1 files changed, 63 insertions, 4 deletions
diff --git a/drivers/xen/xen-selfballoon.c b/drivers/xen/xen-selfballoon.c index 6ea852e2516..d93c70857e0 100644 --- a/drivers/xen/xen-selfballoon.c +++ b/drivers/xen/xen-selfballoon.c @@ -68,6 +68,8 @@   */  #include <linux/kernel.h> +#include <linux/bootmem.h> +#include <linux/swap.h>  #include <linux/mm.h>  #include <linux/mman.h>  #include <linux/module.h> @@ -93,6 +95,15 @@ static unsigned int selfballoon_uphysteresis __read_mostly = 1;  /* In HZ, controls frequency of worker invocation. */  static unsigned int selfballoon_interval __read_mostly = 5; +/* + * Minimum usable RAM in MB for selfballooning target for balloon. + * If non-zero, it is added to totalreserve_pages and self-ballooning + * will not balloon below the sum.  If zero, a piecewise linear function + * is calculated as a minimum and added to totalreserve_pages.  Note that + * setting this value indiscriminately may cause OOMs and crashes. + */ +static unsigned int selfballoon_min_usable_mb; +  static void selfballoon_process(struct work_struct *work);  static DECLARE_DELAYED_WORK(selfballoon_worker, selfballoon_process); @@ -189,20 +200,23 @@ static int __init xen_selfballooning_setup(char *s)  __setup("selfballooning", xen_selfballooning_setup);  #endif /* CONFIG_FRONTSWAP */ +#define MB2PAGES(mb)	((mb) << (20 - PAGE_SHIFT)) +  /*   * Use current balloon size, the goal (vm_committed_as), and hysteresis   * parameters to set a new target balloon size   */  static void selfballoon_process(struct work_struct *work)  { -	unsigned long cur_pages, goal_pages, tgt_pages; +	unsigned long cur_pages, goal_pages, tgt_pages, floor_pages; +	unsigned long useful_pages;  	bool reset_timer = false;  	if (xen_selfballooning_enabled) { -		cur_pages = balloon_stats.current_pages; +		cur_pages = totalram_pages;  		tgt_pages = cur_pages; /* default is no change */  		goal_pages = percpu_counter_read_positive(&vm_committed_as) + -			balloon_stats.current_pages - totalram_pages; +				totalreserve_pages;  #ifdef CONFIG_FRONTSWAP  		/* allow space for frontswap pages to be repatriated */  		if (frontswap_selfshrinking && frontswap_enabled) @@ -217,7 +231,26 @@ static void selfballoon_process(struct work_struct *work)  				((goal_pages - cur_pages) /  				  selfballoon_uphysteresis);  		/* else if cur_pages == goal_pages, no change */ -		balloon_set_new_target(tgt_pages); +		useful_pages = max_pfn - totalreserve_pages; +		if (selfballoon_min_usable_mb != 0) +			floor_pages = totalreserve_pages + +					MB2PAGES(selfballoon_min_usable_mb); +		/* piecewise linear function ending in ~3% slope */ +		else if (useful_pages < MB2PAGES(16)) +			floor_pages = max_pfn; /* not worth ballooning */ +		else if (useful_pages < MB2PAGES(64)) +			floor_pages = totalreserve_pages + MB2PAGES(16) + +					((useful_pages - MB2PAGES(16)) >> 1); +		else if (useful_pages < MB2PAGES(512)) +			floor_pages = totalreserve_pages + MB2PAGES(40) + +					((useful_pages - MB2PAGES(40)) >> 3); +		else /* useful_pages >= MB2PAGES(512) */ +			floor_pages = totalreserve_pages + MB2PAGES(99) + +					((useful_pages - MB2PAGES(99)) >> 5); +		if (tgt_pages < floor_pages) +			tgt_pages = floor_pages; +		balloon_set_new_target(tgt_pages + +			balloon_stats.current_pages - totalram_pages);  		reset_timer = true;  	}  #ifdef CONFIG_FRONTSWAP @@ -340,6 +373,31 @@ static ssize_t store_selfballoon_uphys(struct sys_device *dev,  static SYSDEV_ATTR(selfballoon_uphysteresis, S_IRUGO | S_IWUSR,  		   show_selfballoon_uphys, store_selfballoon_uphys); +SELFBALLOON_SHOW(selfballoon_min_usable_mb, "%d\n", +				selfballoon_min_usable_mb); + +static ssize_t store_selfballoon_min_usable_mb(struct sys_device *dev, +					       struct sysdev_attribute *attr, +					       const char *buf, +					       size_t count) +{ +	unsigned long val; +	int err; + +	if (!capable(CAP_SYS_ADMIN)) +		return -EPERM; +	err = strict_strtoul(buf, 10, &val); +	if (err || val == 0) +		return -EINVAL; +	selfballoon_min_usable_mb = val; +	return count; +} + +static SYSDEV_ATTR(selfballoon_min_usable_mb, S_IRUGO | S_IWUSR, +		   show_selfballoon_min_usable_mb, +		   store_selfballoon_min_usable_mb); + +  #ifdef CONFIG_FRONTSWAP  SELFBALLOON_SHOW(frontswap_selfshrinking, "%d\n", frontswap_selfshrinking); @@ -421,6 +479,7 @@ static struct attribute *selfballoon_attrs[] = {  	&attr_selfballoon_interval.attr,  	&attr_selfballoon_downhysteresis.attr,  	&attr_selfballoon_uphysteresis.attr, +	&attr_selfballoon_min_usable_mb.attr,  #ifdef CONFIG_FRONTSWAP  	&attr_frontswap_selfshrinking.attr,  	&attr_frontswap_hysteresis.attr,  |