Reference: bnc#694863

A PVonHVM guest can not kexec if balloon driver gave some memory back to hypervisor.
Disable ballooning before doing kexec.

---
 kexec/crashdump-xen.c |  118 +++++++++++++++++++++++++++++++++++++++++++++++---
 kexec/crashdump.h     |    1 
 kexec/kexec.c         |    6 ++
 3 files changed, 119 insertions(+), 6 deletions(-)

Index: kexec-tools-2.0.0/kexec/crashdump-xen.c
===================================================================
--- kexec-tools-2.0.0.orig/kexec/crashdump-xen.c
+++ kexec-tools-2.0.0/kexec/crashdump-xen.c
@@ -8,6 +8,7 @@
 #include <limits.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/select.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <setjmp.h>
@@ -30,9 +31,20 @@ struct crash_note_info {
 static int xen_phys_cpus;
 static struct crash_note_info *xen_phys_notes;
 
+#define XEN_MEM0_DIR "/sys/devices/system/xen_memory/xen_memory0"
+#define XEN_MEM0_TARGET XEN_MEM0_DIR "/target_kb"
+#define XEN_MEM0_LOW XEN_MEM0_DIR "/info/low_kb"
+#define XEN_MEM0_HIGH XEN_MEM0_DIR "/info/high_kb"
+
 /* based on code from xen-detect.c */
 static int is_dom0;
 #if defined(__i386__) || defined(__x86_64__)
+enum {
+	XEN_PV = 1,
+	XEN_HVM = 2,
+	XEN_NONE = 3,
+};
+static int guest_type;
 static jmp_buf xen_sigill_jmp;
 void xen_sigill_handler(int sig)
 {
@@ -81,29 +93,118 @@ found:
 	return regs[0];
 }
 
-static int xen_detect_pv_guest(void)
+static void xen_detect_guest_type(void)
 {
 	struct sigaction act, oldact;
-	int is_pv = -1;
+
+	guest_type = XEN_NONE;
+	if (check_for_xen(0)) {
+		guest_type = XEN_HVM;
+		return;
+	}
 
 	if (setjmp(xen_sigill_jmp))
-		return is_pv;
+		return;
 
 	memset(&act, 0, sizeof(act));
 	act.sa_handler = xen_sigill_handler;
 	sigemptyset (&act.sa_mask);
 	if (sigaction(SIGILL, &act, &oldact))
-		return is_pv;
+		return;
 	if (check_for_xen(1))
-		is_pv = 1;
+		guest_type = XEN_PV;
 	sigaction(SIGILL, &oldact, NULL);
-	return is_pv;
+	return;
+}
+
+static int xen_detect_pv_guest(void)
+{
+	if (!guest_type)
+		xen_detect_guest_type();
+
+	return guest_type == XEN_PV ? 1 : -1;
 }
+
+static int do_balloon_up(void)
+{
+	char line[123];
+	FILE *f;
+	int done = 0, seen_lo, seen_hi;
+	long long lo, hi, prev_lo = 0, prev_hi = 0;
+
+	if (!guest_type)
+		xen_detect_guest_type();
+
+	if (guest_type != XEN_HVM)
+		return 0;
+
+	/* Nothing to do if no balloon driver */
+	f = fopen(XEN_MEM0_TARGET, "w");
+	if (!f)
+		return 0;
+
+	/* Balloon up to maximum, the guest can not exceed its max_memkb */
+	printf("Ballooning up in PVonHVM guest.\n");
+	snprintf(line, sizeof(line), "%llu", -1LL);
+	fwrite(line, strlen(line), 1, f);
+	fclose(f);
+
+	do {
+		struct timeval timeout = {.tv_usec = 654321, };
+		seen_lo = seen_hi = 0;
+		lo = hi = -1;
+
+		/* Wait for balloon driver to reach maximum */
+		if (select(0, NULL, NULL, NULL, &timeout) < 0) {
+			perror("select");
+			break;
+		}
+
+		/* Check ballooned low mem */
+		f = fopen(XEN_MEM0_LOW, "r");
+		if (!f)
+			break;
+		if (fscanf(f, "%lld", &lo) == 1)
+			seen_lo = 1;
+		fclose(f);
+
+		/* Check ballooned high mem */
+		f = fopen(XEN_MEM0_HIGH, "r");
+		if (!f)
+			break;
+		if (fscanf(f, "%lld", &hi) == 1)
+			seen_hi = 1;
+		fclose(f);
+
+		/* Print progress if current values changed */
+		if ((seen_lo || seen_hi) && (hi || lo) && (lo != prev_lo || hi != prev_hi)) {
+			printf("h: %lld, l: %lld\n", hi, lo);
+			if (seen_lo && lo != prev_lo)
+				prev_lo = lo;
+			if (seen_hi && hi != prev_hi)
+				prev_hi = hi;
+		}
+
+		/* Exit loop if nothing is ballooned anymore */
+		if (seen_lo && seen_hi && hi == 0 && lo == 0)
+			done = 1;
+
+	} while (!done);
+
+	printf("%s.\n", done ? "Done" : "Not done");
+	return !done;
+}
+
 #else
 static int xen_detect_pv_guest(void)
 {
 	return 1;
 }
+
+static int do_balloon_up(void)
+{
+	return 0;
+}
 #endif
 
 /*
@@ -122,6 +223,11 @@ int xen_present(void)
 	return is_dom0 > 0;
 }
 
+int xen_balloon_up(void)
+{
+	return do_balloon_up();
+}
+
 unsigned long xen_architecture(struct crash_elf_info *elf_info)
 {
 	unsigned long machine = elf_info->machine;
Index: kexec-tools-2.0.0/kexec/crashdump.h
===================================================================
--- kexec-tools-2.0.0.orig/kexec/crashdump.h
+++ kexec-tools-2.0.0/kexec/crashdump.h
@@ -47,6 +47,7 @@ int crash_create_elf64_headers(struct ke
 unsigned long crash_architecture(struct crash_elf_info *elf_info);
 
 int xen_present(void);
+int xen_balloon_up(void);
 unsigned long xen_architecture(struct crash_elf_info *elf_info);
 int xen_get_nr_phys_cpus(void);
 int xen_get_note(int cpu, uint64_t *addr, uint64_t *len);
Index: kexec-tools-2.0.0/kexec/kexec.c
===================================================================
--- kexec-tools-2.0.0.orig/kexec/kexec.c
+++ kexec-tools-2.0.0/kexec/kexec.c
@@ -898,6 +898,7 @@ int main(int argc, char *argv[])
 	int do_shutdown = 1;
 	int do_sync = 1;
 	int do_ifdown = 0;
+	int do_balloon = 0;
 	int do_unload = 0;
 	int do_reuse_initrd = 0;
 	char *type = 0;
@@ -929,6 +930,7 @@ int main(int argc, char *argv[])
 			do_shutdown = 0;
 			do_sync = 1;
 			do_ifdown = 1;
+			do_balloon = 1;
 			do_exec = 1;
 			break;
 		case OPT_LOAD:
@@ -947,6 +949,7 @@ int main(int argc, char *argv[])
 			do_shutdown = 0;
 			do_sync = 1;
 			do_ifdown = 1;
+			do_balloon = 1;
 			do_exec = 1;
 			break;
 		case OPT_TYPE:
@@ -1036,6 +1039,9 @@ int main(int argc, char *argv[])
 	if ((result == 0) && do_ifdown) {
 		ifdown();
 	}
+	if ((result == 0) && do_balloon) {
+		result = xen_balloon_up();
+	}
 	if ((result == 0) && do_exec) {
 		result = my_exec();
 	}
