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.2/kexec/crashdump-xen.c =================================================================== --- kexec-tools-2.0.2.orig/kexec/crashdump-xen.c +++ kexec-tools-2.0.2/kexec/crashdump-xen.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -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.2/kexec/crashdump.h =================================================================== --- kexec-tools-2.0.2.orig/kexec/crashdump.h +++ kexec-tools-2.0.2/kexec/crashdump.h @@ -50,6 +50,7 @@ unsigned long phys_to_virt(struct crash_ unsigned long paddr); 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.2/kexec/kexec.c =================================================================== --- kexec-tools-2.0.2.orig/kexec/kexec.c +++ kexec-tools-2.0.2/kexec/kexec.c @@ -1048,6 +1048,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; void *entry = 0; @@ -1082,6 +1083,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: @@ -1100,6 +1102,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_JUMP_BACK_HELPER: @@ -1222,6 +1225,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(); }