Commit 38a1ed4f authored by Dan Magenheimer's avatar Dan Magenheimer Committed by Konrad Rzeszutek Wilk

xen: Fix selfballooning and ensure it doesn't go too far

The balloon driver's "current_pages" is very different from
totalram_pages.  Self-ballooning needs to be driven by
the latter.  Also, Committed_AS doesn't account for pages
used by the kernel so:
1) Add totalreserve_pages to Committed_AS for the normal target.
2) Enforce a floor for when there are little or no user-space threads
   using memory (e.g. single-user mode) to avoid OOMs.  The floor
   function includes a "min_usable_mb" tuneable in case we discover
   later that the floor function is still too aggressive in some
   workloads, though likely it will not be needed.

Changes since version 4:
- change floor calculation so that it is not as aggressive; this version
  uses a piecewise linear function similar to minimum_target in the 2.6.18
  balloon driver, but modified to add to totalreserve_pages instead of
  subtract from max_pfn, the 2.6.18 version causes OOMs on recent kernels
  because the kernel has expanded over time
- change safety_margin to min_usable_mb and comment on its use
- since committed_as does NOT include kernel space (and other reserved
  pages), totalreserve_pages is now added to committed_as.  The result is
  less aggressive self-ballooning, but theoretically more appropriate.
Changes since version 3:
- missing include causes compile problem when CONFIG_FRONTSWAP is disabled
- add comments after includes
Changes since version 2:
- missing include causes compile problem only on 32-bit
Changes since version 1:
- tuneable safety margin added

[v5: avi.miller@oracle.com: still too aggressive, seeing some OOMs]
[v4: konrad.wilk@oracle.com: fix compile when CONFIG_FRONTSWAP is disabled]
[v3: guru.anbalagane@oracle.com: fix 32-bit compile]
[v2: konrad.wilk@oracle.com: make safety margin tuneable]
Signed-off-by: default avatarDan Magenheimer <dan.magenheimer@oracle.com>
[v1: Altered description and added an extra include]
Signed-off-by: default avatarKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>
parent 1f1503ba
...@@ -68,6 +68,8 @@ ...@@ -68,6 +68,8 @@
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/bootmem.h>
#include <linux/swap.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/mman.h> #include <linux/mman.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
...@@ -92,6 +94,15 @@ static unsigned int selfballoon_uphysteresis __read_mostly = 1; ...@@ -92,6 +94,15 @@ static unsigned int selfballoon_uphysteresis __read_mostly = 1;
/* In HZ, controls frequency of worker invocation. */ /* In HZ, controls frequency of worker invocation. */
static unsigned int selfballoon_interval __read_mostly = 5; 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 void selfballoon_process(struct work_struct *work);
static DECLARE_DELAYED_WORK(selfballoon_worker, selfballoon_process); static DECLARE_DELAYED_WORK(selfballoon_worker, selfballoon_process);
...@@ -188,20 +199,23 @@ static int __init xen_selfballooning_setup(char *s) ...@@ -188,20 +199,23 @@ static int __init xen_selfballooning_setup(char *s)
__setup("selfballooning", xen_selfballooning_setup); __setup("selfballooning", xen_selfballooning_setup);
#endif /* CONFIG_FRONTSWAP */ #endif /* CONFIG_FRONTSWAP */
#define MB2PAGES(mb) ((mb) << (20 - PAGE_SHIFT))
/* /*
* Use current balloon size, the goal (vm_committed_as), and hysteresis * Use current balloon size, the goal (vm_committed_as), and hysteresis
* parameters to set a new target balloon size * parameters to set a new target balloon size
*/ */
static void selfballoon_process(struct work_struct *work) 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; bool reset_timer = false;
if (xen_selfballooning_enabled) { if (xen_selfballooning_enabled) {
cur_pages = balloon_stats.current_pages; cur_pages = totalram_pages;
tgt_pages = cur_pages; /* default is no change */ tgt_pages = cur_pages; /* default is no change */
goal_pages = percpu_counter_read_positive(&vm_committed_as) + goal_pages = percpu_counter_read_positive(&vm_committed_as) +
balloon_stats.current_pages - totalram_pages; totalreserve_pages;
#ifdef CONFIG_FRONTSWAP #ifdef CONFIG_FRONTSWAP
/* allow space for frontswap pages to be repatriated */ /* allow space for frontswap pages to be repatriated */
if (frontswap_selfshrinking && frontswap_enabled) if (frontswap_selfshrinking && frontswap_enabled)
...@@ -216,7 +230,26 @@ static void selfballoon_process(struct work_struct *work) ...@@ -216,7 +230,26 @@ static void selfballoon_process(struct work_struct *work)
((goal_pages - cur_pages) / ((goal_pages - cur_pages) /
selfballoon_uphysteresis); selfballoon_uphysteresis);
/* else if cur_pages == goal_pages, no change */ /* 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; reset_timer = true;
} }
#ifdef CONFIG_FRONTSWAP #ifdef CONFIG_FRONTSWAP
...@@ -339,6 +372,31 @@ static ssize_t store_selfballoon_uphys(struct sys_device *dev, ...@@ -339,6 +372,31 @@ static ssize_t store_selfballoon_uphys(struct sys_device *dev,
static SYSDEV_ATTR(selfballoon_uphysteresis, S_IRUGO | S_IWUSR, static SYSDEV_ATTR(selfballoon_uphysteresis, S_IRUGO | S_IWUSR,
show_selfballoon_uphys, store_selfballoon_uphys); 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 #ifdef CONFIG_FRONTSWAP
SELFBALLOON_SHOW(frontswap_selfshrinking, "%d\n", frontswap_selfshrinking); SELFBALLOON_SHOW(frontswap_selfshrinking, "%d\n", frontswap_selfshrinking);
...@@ -420,6 +478,7 @@ static struct attribute *selfballoon_attrs[] = { ...@@ -420,6 +478,7 @@ static struct attribute *selfballoon_attrs[] = {
&attr_selfballoon_interval.attr, &attr_selfballoon_interval.attr,
&attr_selfballoon_downhysteresis.attr, &attr_selfballoon_downhysteresis.attr,
&attr_selfballoon_uphysteresis.attr, &attr_selfballoon_uphysteresis.attr,
&attr_selfballoon_min_usable_mb.attr,
#ifdef CONFIG_FRONTSWAP #ifdef CONFIG_FRONTSWAP
&attr_frontswap_selfshrinking.attr, &attr_frontswap_selfshrinking.attr,
&attr_frontswap_hysteresis.attr, &attr_frontswap_hysteresis.attr,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment