diff mbox

[1/2,Xenial,SRU] mm/page_alloc.c: calculate 'available' memory in a separate function

Message ID 1465405088-595-1-git-send-email-tim.gardner@canonical.com
State New
Headers show

Commit Message

Tim Gardner June 8, 2016, 4:58 p.m. UTC
From: Igor Redko <redkoi@virtuozzo.com>

BugLink: http://bugs.launchpad.net/bugs/1587091

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 <redkoi@virtuozzo.com>
Signed-off-by: Denis V. Lunev <den@openvz.org>
Reviewed-by: Roman Kagan <rkagan@virtuozzo.com>
Cc: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
(back ported from commit d02bd27bd33dd7e8d22594cd568b81be0cb584cd)
Signed-off-by: Tim Gardner <tim.gardner@canonical.com>

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

Comments

Chris J Arges June 8, 2016, 6:19 p.m. UTC | #1
Ack for both patches. Backport looks correct and cherry-pick seems reasonable.
I think this feature addition is minimal enough in just reporting additional
information which can be very useful when trying to allocate vms on a system.

--chris

On Wed, Jun 08, 2016 at 10:58:07AM -0600, Tim Gardner wrote:
> From: Igor Redko <redkoi@virtuozzo.com>
> 
> BugLink: http://bugs.launchpad.net/bugs/1587091
> 
> 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 <redkoi@virtuozzo.com>
> Signed-off-by: Denis V. Lunev <den@openvz.org>
> Reviewed-by: Roman Kagan <rkagan@virtuozzo.com>
> Cc: Michael S. Tsirkin <mst@redhat.com>
> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
> (back ported from commit d02bd27bd33dd7e8d22594cd568b81be0cb584cd)
> Signed-off-by: Tim Gardner <tim.gardner@canonical.com>
> 
> Conflicts:
> 	fs/proc/meminfo.c
> ---
>  fs/proc/meminfo.c  | 34 +---------------------------------
>  include/linux/mm.h |  1 +
>  mm/page_alloc.c    | 43 +++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 45 insertions(+), 33 deletions(-)
> 
> diff --git a/fs/proc/meminfo.c b/fs/proc/meminfo.c
> index 9155a5a..8372046 100644
> --- a/fs/proc/meminfo.c
> +++ b/fs/proc/meminfo.c
> @@ -29,10 +29,7 @@ static int meminfo_proc_show(struct seq_file *m, void *v)
>  	unsigned long committed;
>  	long cached;
>  	long available;
> -	unsigned long pagecache;
> -	unsigned long wmark_low = 0;
>  	unsigned long pages[NR_LRU_LISTS];
> -	struct zone *zone;
>  	int lru;
>  
>  /*
> @@ -51,36 +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.
> -	 *
> -	 * Free memory cannot be taken below the low watermark, before the
> -	 * system starts swapping.
> -	 */
> -	available = i.freeram - wmark_low;
> -
> -	/*
> -	 * 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 70cbf8c..3b13fd3 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -1829,6 +1829,7 @@ extern int __meminit init_per_zone_wmark_min(void);
>  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 6cf5cad..2f4e66a 100644
> --- a/mm/page_alloc.c
> +++ b/mm/page_alloc.c
> @@ -3604,6 +3604,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;
> -- 
> 1.9.1
> 
> 
> -- 
> kernel-team mailing list
> kernel-team@lists.ubuntu.com
> https://lists.ubuntu.com/mailman/listinfo/kernel-team
Kamal Mostafa June 8, 2016, 10:06 p.m. UTC | #2
Applied to X.

 -Kamal
diff mbox

Patch

diff --git a/fs/proc/meminfo.c b/fs/proc/meminfo.c
index 9155a5a..8372046 100644
--- a/fs/proc/meminfo.c
+++ b/fs/proc/meminfo.c
@@ -29,10 +29,7 @@  static int meminfo_proc_show(struct seq_file *m, void *v)
 	unsigned long committed;
 	long cached;
 	long available;
-	unsigned long pagecache;
-	unsigned long wmark_low = 0;
 	unsigned long pages[NR_LRU_LISTS];
-	struct zone *zone;
 	int lru;
 
 /*
@@ -51,36 +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.
-	 *
-	 * Free memory cannot be taken below the low watermark, before the
-	 * system starts swapping.
-	 */
-	available = i.freeram - wmark_low;
-
-	/*
-	 * 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 70cbf8c..3b13fd3 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1829,6 +1829,7 @@  extern int __meminit init_per_zone_wmark_min(void);
 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 6cf5cad..2f4e66a 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -3604,6 +3604,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;