xen: let alloc_xenballooned_pages() fail if not enough memory free [Linux 3.16.72]

This Linux kernel change "xen: let alloc_xenballooned_pages() fail if not enough memory free" is included in the Linux 3.16.72 release. This change is authored by Juergen Gross <jgross [at] suse.com> on Wed Jun 19 11:00:56 2019 +0200. The commit for this change in Linux stable tree is 2ed58e5 (patch) which is from upstream commit a1078e8. 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 a1078e8.

xen: let alloc_xenballooned_pages() fail if not enough memory free

commit a1078e821b605813b63bf6bca414a85f804d5c66 upstream.

Instead of trying to allocate pages with GFP_USER in
add_ballooned_pages() check the available free memory via
si_mem_available(). GFP_USER is far less limiting memory exhaustion
than the test via si_mem_available().

This will avoid dom0 running out of memory due to excessive foreign
page mappings especially on ARM and on x86 in PVH mode, as those don't
have a pre-ballooned area which can be used for foreign mappings.

As the normal ballooning suffers from the same problem don't balloon
down more than si_mem_available() pages in one iteration. At the same
time limit the default maximum number of retries.

This is part of XSA-300.

Signed-off-by: Juergen Gross <[email protected]>
[bwh: Backported to 3.16: adjust context, indentation]
Signed-off-by: Ben Hutchings <[email protected]>

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

 drivers/xen/balloon.c | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c
index 8db7abb..cdb0552 100644
--- a/drivers/xen/balloon.c
+++ b/drivers/xen/balloon.c
@@ -502,8 +502,15 @@ static void balloon_process(struct work_struct *work)
                state = reserve_additional_memory(credit);
        }

-       if (credit < 0)
-           state = decrease_reservation(-credit, GFP_BALLOON);
+       if (credit < 0) {
+           long n_pages;
+
+           n_pages = min(-credit, si_mem_available());
+           state = decrease_reservation(n_pages, GFP_BALLOON);
+           if (state == BP_DONE && n_pages != -credit &&
+               n_pages < totalreserve_pages)
+               state = BP_EAGAIN;
+       }

        state = update_schedule(state);

@@ -561,6 +568,9 @@ int alloc_xenballooned_pages(int nr_pages, struct page **pages, bool highmem)
            enum bp_state st;
            if (page)
                balloon_append(page);
+           if (si_mem_available() < nr_pages)
+               return -ENOMEM;
+
            st = decrease_reservation(nr_pages - pgno,
                    highmem ? GFP_HIGHUSER : GFP_USER);
            if (st != BP_DONE)
@@ -692,7 +702,7 @@ static int __init balloon_init(void)
    balloon_stats.schedule_delay = 1;
    balloon_stats.max_schedule_delay = 32;
    balloon_stats.retry_count = 1;
-   balloon_stats.max_retry_count = RETRY_UNLIMITED;
+   balloon_stats.max_retry_count = 4;

 #ifdef CONFIG_XEN_BALLOON_MEMORY_HOTPLUG
    balloon_stats.hotplug_pages = 0;

Leave a Reply

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