From c8c1a9440afbf1e019d8dcb30c4a31fd4f37c867153c931b4e18eeef200aaa3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Tesa=C5=99=C3=ADk?= Date: Tue, 19 Jun 2012 12:31:17 +0000 Subject: [PATCH] Accepting request 125015 from home:olh:branches:Kernel:kdump Without theses changes from sles11sp2 installation in a Xen HVM guest can not work in factory because the installer uses kexec to boot into second stage.. - Fix xen cpuid() inline asm to not clobber stack's red zone See xen-unstable changeset 24344:72f4e4cb7440 - Balloon up in a Xen PVonHVM guest before kexec (bnc#694863) - Update xen_present check for xenfs in pv_ops kernel (bnc#694863) - Change xen_present hv check (bnc#658413) OBS-URL: https://build.opensuse.org/request/show/125015 OBS-URL: https://build.opensuse.org/package/show/Kernel:kdump/kexec-tools?expand=0&rev=21 --- kexec-tools-xen-balloon-up.patch | 231 +++++++++++++++++++++++++++++++ kexec-tools-xen-present.diff | 133 ++++++++++++++++++ kexec-tools.changes | 13 ++ kexec-tools.spec | 4 + 4 files changed, 381 insertions(+) create mode 100644 kexec-tools-xen-balloon-up.patch create mode 100644 kexec-tools-xen-present.diff diff --git a/kexec-tools-xen-balloon-up.patch b/kexec-tools-xen-balloon-up.patch new file mode 100644 index 0000000..91d6cae --- /dev/null +++ b/kexec-tools-xen-balloon-up.patch @@ -0,0 +1,231 @@ +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(); + } diff --git a/kexec-tools-xen-present.diff b/kexec-tools-xen-present.diff new file mode 100644 index 0000000..34440b5 --- /dev/null +++ b/kexec-tools-xen-present.diff @@ -0,0 +1,133 @@ +From: Olaf Hering +References: bnc#658413, bnc#694863 +Subject: xen_present() should be named is_xen_pv() (includes also dom0). + +A hvm guest is like physical hardware and should not need special handling. +Use code from xen-detect.c instead of stat() to distinguish hvm from pv because +xenfs in a pv_ops kernel generates /proc/xen/capabilities unconditionally. + +--- + kexec/crashdump-xen.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 95 insertions(+), 5 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 +@@ -10,6 +10,8 @@ + #include + #include + #include ++#include ++#include + #include "kexec.h" + #include "crashdump.h" + #include "kexec-syscall.h" +@@ -25,14 +27,102 @@ struct crash_note_info { + unsigned long length; + }; + +-int xen_phys_cpus = 0; +-struct crash_note_info *xen_phys_notes; ++static int xen_phys_cpus; ++static struct crash_note_info *xen_phys_notes; + +-int xen_present(void) ++/* based on code from xen-detect.c */ ++static int is_dom0; ++#if defined(__i386__) || defined(__x86_64__) ++static jmp_buf xen_sigill_jmp; ++void xen_sigill_handler(int sig) ++{ ++ longjmp(xen_sigill_jmp, 1); ++} ++ ++static void xen_cpuid(uint32_t idx, uint32_t *regs, int pv_context) ++{ ++#ifdef __i386__ ++ /* Use the stack to avoid reg constraint failures with some gcc flags */ ++ asm volatile ( ++ "push %%eax; push %%ebx; push %%ecx; push %%edx\n\t" ++ "test %1,%1 ; jz 1f ; ud2a ; .ascii \"xen\" ; 1: cpuid\n\t" ++ "mov %%eax,(%2); mov %%ebx,4(%2)\n\t" ++ "mov %%ecx,8(%2); mov %%edx,12(%2)\n\t" ++ "pop %%edx; pop %%ecx; pop %%ebx; pop %%eax\n\t" ++ : : "a" (idx), "c" (pv_context), "S" (regs) : "memory" ); ++#else ++ asm volatile ( ++ "test %5,%5 ; jz 1f ; ud2a ; .ascii \"xen\" ; 1: cpuid\n\t" ++ : "=a" (regs[0]), "=b" (regs[1]), "=c" (regs[2]), "=d" (regs[3]) ++ : "0" (idx), "1" (pv_context), "2" (0) ); ++#endif ++} ++ ++static int check_for_xen(int pv_context) + { +- struct stat buf; ++ uint32_t regs[4]; ++ char signature[13]; ++ uint32_t base; ++ ++ for (base = 0x40000000; base < 0x40010000; base += 0x100) ++ { ++ xen_cpuid(base, regs, pv_context); ++ ++ *(uint32_t *)(signature + 0) = regs[1]; ++ *(uint32_t *)(signature + 4) = regs[2]; ++ *(uint32_t *)(signature + 8) = regs[3]; ++ signature[12] = '\0'; ++ ++ if (strcmp("XenVMMXenVMM", signature) == 0 && regs[0] >= (base + 2)) ++ goto found; ++ } ++ ++ return 0; ++ ++found: ++ xen_cpuid(base + 1, regs, pv_context); ++ return regs[0]; ++} + +- return stat("/proc/xen", &buf) == 0; ++static int xen_detect_pv_guest(void) ++{ ++ struct sigaction act, oldact; ++ int is_pv = -1; ++ ++ if (setjmp(xen_sigill_jmp)) ++ return is_pv; ++ ++ memset(&act, 0, sizeof(act)); ++ act.sa_handler = xen_sigill_handler; ++ sigemptyset (&act.sa_mask); ++ if (sigaction(SIGILL, &act, &oldact)) ++ return is_pv; ++ if (check_for_xen(1)) ++ is_pv = 1; ++ sigaction(SIGILL, &oldact, NULL); ++ return is_pv; ++} ++#else ++static int xen_detect_pv_guest(void) ++{ ++ return 1; ++} ++#endif ++ ++/* ++ * Return 1 if its a PV guest. ++ * This includes dom0, which is the only PV guest where kexec/kdump works. ++ * HVM guests have to be handled as native hardware. ++ */ ++int xen_present(void) ++{ ++ if (!is_dom0) { ++ if (access("/proc/xen", F_OK) == 0) ++ is_dom0 = xen_detect_pv_guest(); ++ else ++ is_dom0 = -1; ++ } ++ return is_dom0 > 0; + } + + unsigned long xen_architecture(struct crash_elf_info *elf_info) diff --git a/kexec-tools.changes b/kexec-tools.changes index 2641c8f..09a6c43 100644 --- a/kexec-tools.changes +++ b/kexec-tools.changes @@ -1,3 +1,16 @@ +------------------------------------------------------------------- +Thu Jun 14 16:23:58 CEST 2012 - ohering@suse.de + +- Fix xen cpuid() inline asm to not clobber stack's red zone + See xen-unstable changeset 24344:72f4e4cb7440 + +------------------------------------------------------------------- +Thu Jun 14 11:26:16 CEST 2012 - ohering@suse.de + +- Balloon up in a Xen PVonHVM guest before kexec (bnc#694863) +- Update xen_present check for xenfs in pv_ops kernel (bnc#694863) +- Change xen_present hv check (bnc#658413) + ------------------------------------------------------------------- Fri Apr 20 16:19:26 UTC 2012 - rschweikert@suse.com diff --git a/kexec-tools.spec b/kexec-tools.spec index d5c6e66..b4ec55f 100644 --- a/kexec-tools.spec +++ b/kexec-tools.spec @@ -37,6 +37,8 @@ Patch0: %{name}-no-vga-output.diff Patch1: %{name}-xen-static.diff Patch2: gcc-no-undefined-flag-fix.patch Patch3: kexec-fix-strncat.patch +Patch4: kexec-tools-xen-present.diff +Patch5: kexec-tools-xen-balloon-up.patch Url: ftp://kernel.org/pub/linux/utils/kernel/kexec/%{name}-%{version}.tar.bz2 BuildRoot: %{_tmppath}/%{name}-%{version}-build #!BuildIgnore: fop @@ -74,6 +76,8 @@ Authors: %patch1 -p1 %patch2 -p1 %patch3 -p1 +%patch4 -p1 +%patch5 -p1 %build # disable as-needed