From: Dan Magenheimer Date: Wed, 12 Oct 2011 18:21:55 +0000 (-0700) Subject: xen: Fix selfballooning and ensure it doesn't go too far X-Git-Tag: v2.6.39-400.9.0~863 X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=29c9dfe6761b34ffbf240e0586503d88ae43b0c7;p=users%2Fjedix%2Flinux-maple.git 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 bloated 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: Dan Magenheimer --- diff --git a/drivers/xen/xen-selfballoon.c b/drivers/xen/xen-selfballoon.c index c4475967b5e9..6fd41c4f511c 100644 --- a/drivers/xen/xen-selfballoon.c +++ b/drivers/xen/xen-selfballoon.c @@ -95,10 +95,13 @@ static unsigned int selfballoon_uphysteresis __read_mostly = 1; static unsigned int selfballoon_interval __read_mostly = 5; /* - * Scale factor for safety margin for minimum selfballooning target for balloon. - * Default adds about 3% (4/128) of max_pfn. + * 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_safety_margin = 4; +static unsigned int selfballoon_min_usable_mb; static void selfballoon_process(struct work_struct *work); static DECLARE_DELAYED_WORK(selfballoon_worker, selfballoon_process); @@ -196,6 +199,8 @@ 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 @@ -203,12 +208,14 @@ __setup("selfballooning", xen_selfballooning_setup); static void selfballoon_process(struct work_struct *work) { unsigned long cur_pages, goal_pages, tgt_pages, floor_pages; + unsigned long useful_pages; bool reset_timer = false; if (xen_selfballooning_enabled) { cur_pages = totalram_pages; 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) + + totalreserve_pages; #ifdef CONFIG_FRONTSWAP /* allow space for frontswap pages to be repatriated */ if (frontswap_selfshrinking && frontswap_enabled) @@ -223,9 +230,22 @@ static void selfballoon_process(struct work_struct *work) ((goal_pages - cur_pages) / selfballoon_uphysteresis); /* else if cur_pages == goal_pages, no change */ - floor_pages = totalreserve_pages + - ((roundup_pow_of_two(max_pfn) / 128) * - selfballoon_safety_margin); + 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 + @@ -352,9 +372,10 @@ 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_safety_margin, "%d\n", selfballoon_safety_margin); +SELFBALLOON_SHOW(selfballoon_min_usable_mb, "%d\n", + selfballoon_min_usable_mb); -static ssize_t store_selfballoon_safety_margin(struct sys_device *dev, +static ssize_t store_selfballoon_min_usable_mb(struct sys_device *dev, struct sysdev_attribute *attr, const char *buf, size_t count) @@ -365,15 +386,15 @@ static ssize_t store_selfballoon_safety_margin(struct sys_device *dev, if (!capable(CAP_SYS_ADMIN)) return -EPERM; err = strict_strtoul(buf, 10, &val); - if (err || val == 0 || val > 128) + if (err || val == 0) return -EINVAL; - selfballoon_safety_margin = val; + selfballoon_min_usable_mb = val; return count; } -static SYSDEV_ATTR(selfballoon_safety_margin, S_IRUGO | S_IWUSR, - show_selfballoon_safety_margin, - store_selfballoon_safety_margin); +static SYSDEV_ATTR(selfballoon_min_usable_mb, S_IRUGO | S_IWUSR, + show_selfballoon_min_usable_mb, + store_selfballoon_min_usable_mb); #ifdef CONFIG_FRONTSWAP @@ -457,7 +478,7 @@ static struct attribute *selfballoon_attrs[] = { &attr_selfballoon_interval.attr, &attr_selfballoon_downhysteresis.attr, &attr_selfballoon_uphysteresis.attr, - &attr_selfballoon_safety_margin.attr, + &attr_selfballoon_min_usable_mb.attr, #ifdef CONFIG_FRONTSWAP &attr_frontswap_selfshrinking.attr, &attr_frontswap_hysteresis.attr,