2012-06-19 14:31:17 +02:00
|
|
|
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/kexec.c | 6 ++
|
2014-02-06 00:15:44 +01:00
|
|
|
kexec/kexec.h | 1
|
2012-06-19 14:31:17 +02:00
|
|
|
3 files changed, 119 insertions(+), 6 deletions(-)
|
|
|
|
|
2014-01-11 14:04:44 +01:00
|
|
|
--- a/kexec/crashdump-xen.c
|
|
|
|
+++ b/kexec/crashdump-xen.c
|
2012-06-19 14:31:17 +02:00
|
|
|
@@ -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)
|
|
|
|
{
|
2014-01-11 14:04:44 +01:00
|
|
|
@@ -84,29 +96,118 @@ found:
|
2012-06-19 14:31:17 +02:00
|
|
|
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
|
|
|
|
|
|
|
|
/*
|
2014-01-11 14:04:44 +01:00
|
|
|
@@ -125,6 +226,11 @@ int xen_present(void)
|
2012-06-19 14:31:17 +02:00
|
|
|
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;
|
2014-01-11 14:04:44 +01:00
|
|
|
--- a/kexec/kexec.c
|
|
|
|
+++ b/kexec/kexec.c
|
2017-05-31 22:00:34 +02:00
|
|
|
@@ -1240,6 +1240,7 @@ int main(int argc, char *argv[])
|
2012-06-19 14:31:17 +02:00
|
|
|
int do_shutdown = 1;
|
2015-06-26 16:31:02 +02:00
|
|
|
int do_sync = 1, skip_sync = 0;
|
|
|
|
int do_ifdown = 0, skip_ifdown = 0;
|
2012-06-19 14:31:17 +02:00
|
|
|
+ int do_balloon = 0;
|
|
|
|
int do_unload = 0;
|
|
|
|
int do_reuse_initrd = 0;
|
2014-10-09 19:32:13 +02:00
|
|
|
int do_kexec_file_syscall = 0;
|
2017-05-31 22:00:34 +02:00
|
|
|
@@ -1298,6 +1299,7 @@ int main(int argc, char *argv[])
|
2012-06-19 14:31:17 +02:00
|
|
|
do_shutdown = 0;
|
|
|
|
do_sync = 1;
|
|
|
|
do_ifdown = 1;
|
|
|
|
+ do_balloon = 1;
|
|
|
|
do_exec = 1;
|
|
|
|
break;
|
|
|
|
case OPT_LOAD:
|
2017-05-31 22:00:34 +02:00
|
|
|
@@ -1318,6 +1320,7 @@ int main(int argc, char *argv[])
|
2012-06-19 14:31:17 +02:00
|
|
|
do_shutdown = 0;
|
|
|
|
do_sync = 1;
|
|
|
|
do_ifdown = 1;
|
|
|
|
+ do_balloon = 1;
|
|
|
|
do_exec = 1;
|
|
|
|
break;
|
|
|
|
case OPT_LOAD_JUMP_BACK_HELPER:
|
2017-05-31 22:00:34 +02:00
|
|
|
@@ -1482,6 +1485,9 @@ int main(int argc, char *argv[])
|
2012-06-19 14:31:17 +02:00
|
|
|
if ((result == 0) && do_ifdown) {
|
|
|
|
ifdown();
|
|
|
|
}
|
|
|
|
+ if ((result == 0) && do_balloon) {
|
|
|
|
+ result = xen_balloon_up();
|
|
|
|
+ }
|
|
|
|
if ((result == 0) && do_exec) {
|
|
|
|
result = my_exec();
|
|
|
|
}
|
2014-02-06 00:15:44 +01:00
|
|
|
--- a/kexec/kexec.h
|
|
|
|
+++ b/kexec/kexec.h
|
2017-05-31 22:00:34 +02:00
|
|
|
@@ -316,6 +316,7 @@ int xen_kexec_load(struct kexec_info *in
|
2014-02-06 00:15:44 +01:00
|
|
|
int xen_kexec_unload(uint64_t kexec_flags);
|
|
|
|
void xen_kexec_exec(void);
|
2017-05-31 22:00:34 +02:00
|
|
|
int xen_kexec_status(uint64_t kexec_flags);
|
2014-02-06 00:15:44 +01:00
|
|
|
+int xen_balloon_up(void);
|
|
|
|
|
2017-05-31 22:00:34 +02:00
|
|
|
extern unsigned long long get_kernel_sym(const char *text);
|
|
|
|
|