From 947818c731094a952d4955e99a23ef336daf7ab9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20Marczykowski-G=C3=B3recki?= Date: Thu, 21 Oct 2021 01:10:21 +0200 Subject: [PATCH] WIP: xen/balloon: wait for initial balloon down before starting userspace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Organization: Invisible Things Lab Cc: Marek Marczykowski-Górecki When HVM/PVH guest with maxmem > memory, a populate on demand feature is used. This allows the guest to see up to 'maxmem' memory, but when it tries to use more than 'memory', it is crashed. Balloon driver should prevent that by ballooning down the guest before it tries to use too much memory. Unfortunately, this was done asynchronously and it wasn't really guaranteed to be quick enough. And indeed, with recent kernel versions, the initial balloon down process is slower and guests with small initial 'memory' are crashed frequently by Xen. Fix this by adding late init call that waits for the initial balloon down to complete, before allowing any userspace to run. If that initial balloon down fails, it is very likely that guest will be killed (as soon as it will really use all the memory that something has allocated) - print a message about that to aid diagnosing issues. Signed-off-by: Marek Marczykowski-Górecki (cherry picked from commit 9a226e669c918c98ee603ee30a1798da6434a423) --- drivers/xen/balloon.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index b57b2067ecbf..c2a4e25a14dc 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -56,6 +56,7 @@ #include #include #include +#include #include #include @@ -136,6 +137,8 @@ static DEFINE_MUTEX(balloon_mutex); struct balloon_stats balloon_stats; EXPORT_SYMBOL_GPL(balloon_stats); +static DECLARE_COMPLETION(initial_balloon); + /* We increase/decrease in batches which fit in a page */ static xen_pfn_t frame_list[PAGE_SIZE / sizeof(xen_pfn_t)]; @@ -501,7 +504,6 @@ static void balloon_process(struct work_struct *work) enum bp_state state = BP_DONE; long credit; - do { mutex_lock(&balloon_mutex); @@ -526,6 +528,15 @@ static void balloon_process(struct work_struct *work) state = update_schedule(state); + if (credit >= 0) + complete(&initial_balloon); + else if (state == BP_ECANCELED) { + if (!completion_done(&initial_balloon) && !xen_pv_domain()) + pr_err("Initial balloon down failed, expect the domain to be killed with \"out of PoD memory\" error by Xen.\n"); + complete(&initial_balloon); + } + + mutex_unlock(&balloon_mutex); cond_resched(); @@ -677,6 +688,20 @@ static void __init balloon_add_region(unsigned long start_pfn, } #endif +static int __init wait_for_initial_balloon_down(void) +{ + mutex_lock(&balloon_mutex); + /* optionally re-init completion after retrieving balloon target */ + if (current_credit() < 0) + reinit_completion(&initial_balloon); + mutex_unlock(&balloon_mutex); + printk(KERN_INFO "waiting for initial balloon down %ld\n", current_credit()); + wait_for_completion(&initial_balloon); + printk(KERN_INFO "done waiting for initial balloon down %ld\n", current_credit()); + return 0; +} +late_initcall(wait_for_initial_balloon_down); + static int __init balloon_init(void) { if (!xen_domain()) -- 2.31.1