]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
xen: Fix selfballooning and ensure it doesn't go too far
authorDan Magenheimer <dan.magenheimer@oracle.com>
Wed, 12 Oct 2011 18:21:55 +0000 (11:21 -0700)
committerMaxim Uvarov <maxim.uvarov@oracle.com>
Wed, 12 Oct 2011 18:26:30 +0000 (11:26 -0700)
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 <dan.magenheimer@oracle.com>
drivers/xen/xen-selfballoon.c

index c4475967b5e923ab6f4fb0d0530e0db9c1bc645b..6fd41c4f511c6fad88c64e7f46b16b1322e2b6d4 100644 (file)
@@ -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,