mm/page_alloc.c: calculate ‘available’ memory in a separate function [Linux 3.16.72]

This Linux kernel change "mm/page_alloc.c: calculate ‘available’ memory in a separate function" is included in the Linux 3.16.72 release. This change is authored by Igor Redko <redkoi [at] virtuozzo.com> on Thu Mar 17 14:19:05 2016 -0700. The commit for this change in Linux stable tree is 30416b6 (patch) which is from upstream commit d02bd27. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream d02bd27.

mm/page_alloc.c: calculate 'available' memory in a separate function

commit d02bd27bd33dd7e8d22594cd568b81be0cb584cd upstream.

Add a new field, VIRTIO_BALLOON_S_AVAIL, to virtio_balloon memory
statistics protocol, corresponding to 'Available' in /proc/meminfo.

It indicates to the hypervisor how big the balloon can be inflated
without pushing the guest system to swap.  This metric would be very
useful in VM orchestration software to improve memory management of
different VMs under overcommit.

This patch (of 2):

Factor out calculation of the available memory counter into a separate
exportable function, in order to be able to use it in other parts of the
kernel.

In particular, it appears a relevant metric to report to the hypervisor
via virtio-balloon statistics interface (in a followup patch).

Signed-off-by: Igor Redko <[email protected]>
Signed-off-by: Denis V. Lunev <[email protected]>
Reviewed-by: Roman Kagan <[email protected]>
Cc: Michael S. Tsirkin <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
[bwh: Backported to 3.16 as dependency of commit a1078e821b60
 "xen: let alloc_xenballooned_pages() fail if not enough memory free"]
Signed-off-by: Ben Hutchings <[email protected]>

There are 75 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 fs/proc/meminfo.c  | 31 +------------------------------
 include/linux/mm.h |  1 +
 mm/page_alloc.c    | 43 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 45 insertions(+), 30 deletions(-)

diff --git a/fs/proc/meminfo.c b/fs/proc/meminfo.c
index 0da0165..a0bc660 100644
--- a/fs/proc/meminfo.c
+++ b/fs/proc/meminfo.c
@@ -27,10 +27,7 @@ static int meminfo_proc_show(struct seq_file *m, void *v)
    struct vmalloc_info vmi;
    long cached;
    long available;
-   unsigned long pagecache;
-   unsigned long wmark_low = 0;
    unsigned long pages[NR_LRU_LISTS];
-   struct zone *zone;
    int lru;

 /*
@@ -51,33 +48,7 @@ static int meminfo_proc_show(struct seq_file *m, void *v)
    for (lru = LRU_BASE; lru < NR_LRU_LISTS; lru++)
        pages[lru] = global_page_state(NR_LRU_BASE + lru);

-   for_each_zone(zone)
-       wmark_low += zone->watermark[WMARK_LOW];
-
-   /*
-    * Estimate the amount of memory available for userspace allocations,
-    * without causing swapping.
-    */
-   available = i.freeram - totalreserve_pages;
-
-   /*
-    * Not all the page cache can be freed, otherwise the system will
-    * start swapping. Assume at least half of the page cache, or the
-    * low watermark worth of cache, needs to stay.
-    */
-   pagecache = pages[LRU_ACTIVE_FILE] + pages[LRU_INACTIVE_FILE];
-   pagecache -= min(pagecache / 2, wmark_low);
-   available += pagecache;
-
-   /*
-    * Part of the reclaimable slab consists of items that are in use,
-    * and cannot be freed. Cap this estimate at the low watermark.
-    */
-   available += global_page_state(NR_SLAB_RECLAIMABLE) -
-            min(global_page_state(NR_SLAB_RECLAIMABLE) / 2, wmark_low);
-
-   if (available < 0)
-       available = 0;
+   available = si_mem_available();

    /*
     * Tagged format, for easy grepping and expansion.
diff --git a/include/linux/mm.h b/include/linux/mm.h
index a576467..e67e126 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1699,6 +1699,7 @@ extern void memmap_init_zone(unsigned long, int, unsigned long,
 extern void mem_init(void);
 extern void __init mmap_init(void);
 extern void show_mem(unsigned int flags);
+extern long si_mem_available(void);
 extern void si_meminfo(struct sysinfo * val);
 extern void si_meminfo_node(struct sysinfo *val, int nid);

diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 7a783dc..b491f75 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -3072,6 +3072,49 @@ static inline void show_node(struct zone *zone)
        printk("Node %d ", zone_to_nid(zone));
 }

+long si_mem_available(void)
+{
+   long available;
+   unsigned long pagecache;
+   unsigned long wmark_low = 0;
+   unsigned long pages[NR_LRU_LISTS];
+   struct zone *zone;
+   int lru;
+
+   for (lru = LRU_BASE; lru < NR_LRU_LISTS; lru++)
+       pages[lru] = global_page_state(NR_LRU_BASE + lru);
+
+   for_each_zone(zone)
+       wmark_low += zone->watermark[WMARK_LOW];
+
+   /*
+    * Estimate the amount of memory available for userspace allocations,
+    * without causing swapping.
+    */
+   available = global_page_state(NR_FREE_PAGES) - totalreserve_pages;
+
+   /*
+    * Not all the page cache can be freed, otherwise the system will
+    * start swapping. Assume at least half of the page cache, or the
+    * low watermark worth of cache, needs to stay.
+    */
+   pagecache = pages[LRU_ACTIVE_FILE] + pages[LRU_INACTIVE_FILE];
+   pagecache -= min(pagecache / 2, wmark_low);
+   available += pagecache;
+
+   /*
+    * Part of the reclaimable slab consists of items that are in use,
+    * and cannot be freed. Cap this estimate at the low watermark.
+    */
+   available += global_page_state(NR_SLAB_RECLAIMABLE) -
+            min(global_page_state(NR_SLAB_RECLAIMABLE) / 2, wmark_low);
+
+   if (available < 0)
+       available = 0;
+   return available;
+}
+EXPORT_SYMBOL_GPL(si_mem_available);
+
 void si_meminfo(struct sysinfo *val)
 {
    val->totalram = totalram_pages;

Leave a Reply

Your email address will not be published. Required fields are marked *