Support Linux's advanced crashkernel= syntax
authorKeir Fraser <keir.fraser@citrix.com>
Mon, 26 Apr 2010 11:12:12 +0000 (12:12 +0100)
committerKeir Fraser <keir.fraser@citrix.com>
Mon, 26 Apr 2010 11:12:12 +0000 (12:12 +0100)
Quoting the original Linux patch's description:

"This patch adds a extended crashkernel syntax that makes the value of
 reserved system RAM dependent on the system RAM itself:

    crashkernel=3D<range1>:<size1>[,<range2>:<size2>,...][@offset]
    range=3Dstart-[end]

 For example:

    crashkernel=3D512M-2G:64M,2G-:128M

 The motivation comes from distributors that configure their
 crashkernel command line automatically with some configuration tool
 (YaST, you know ;)). Of course that tool knows the value of System
 RAM, but if the user removes RAM, then the system becomes unbootable
 or at least unusable and error handling is very difficult."

For x86, other than Linux we pass the actual amount of RAM rather than
the highest page's address (to cope with sparse physical address
maps).

This still needs to be hooked up for ia64.

Signed-off-by: Jan Beulich <jbeulich@novell.com>
xen/arch/x86/setup.c
xen/common/kexec.c
xen/include/xen/kexec.h

index 4ff9dab413ffd831bb40462e722a15f1a7f329bf..4eabbbf6e4c62864dd19971e693680f4950ad827 100644 (file)
@@ -643,6 +643,11 @@ void __init __start_xen(unsigned long mbi_p)
     memcpy(&boot_e820, &e820, sizeof(e820));
 
     /* Early kexec reservation (explicit static start address). */
+    nr_pages = 0;
+    for ( i = 0; i < e820.nr_map; i++ )
+        if ( e820.map[i].type == E820_RAM )
+            nr_pages += e820.map[i].size >> PAGE_SHIFT;
+    set_kexec_crash_area_size((u64)nr_pages << PAGE_SHIFT);
     kexec_reserve_area(&boot_e820);
 
     /*
index 56196167b8a60a2f606b0046fc663c730041fd8f..e4dc1f039058e4014a0323120437f0079c0a6b6d 100644 (file)
@@ -47,15 +47,109 @@ static unsigned char vmcoreinfo_data[VMCOREINFO_BYTES];
 static size_t vmcoreinfo_size = 0;
 
 xen_kexec_reserve_t kexec_crash_area;
+static struct {
+    u64 start, end;
+    unsigned long size;
+} ranges[16] __initdata;
 
+/*
+ * Parse command lines in the format
+ *
+ *   crashkernel=<ramsize-range>:<size>[,...][@<offset>]
+ *
+ * with <ramsize-range> being of form
+ *
+ *   <start>-[<end>]
+ *
+ * as well as the legacy ones in the format
+ *
+ *   crashkernel=<size>[@<offset>]
+ */
 static void __init parse_crashkernel(const char *str)
 {
-    kexec_crash_area.size = parse_size_and_unit(str, &str);
-    if ( *str == '@' )
-        kexec_crash_area.start = parse_size_and_unit(str+1, NULL);
+    const char *cur;
+
+    if ( strchr(str, ':' ) )
+    {
+        unsigned int idx = 0;
+
+        do {
+            if ( idx >= ARRAY_SIZE(ranges) )
+            {
+                printk(XENLOG_WARNING "crashkernel: too many ranges\n");
+                cur = NULL;
+                str = strchr(str, '@');
+                break;
+            }
+
+            ranges[idx].start = parse_size_and_unit(cur = str + !!idx, &str);
+            if ( cur == str )
+                break;
+
+            if ( *str != '-' )
+            {
+                printk(XENLOG_WARNING "crashkernel: '-' expected\n");
+                break;
+            }
+
+            if ( *++str != ':' )
+            {
+                ranges[idx].end = parse_size_and_unit(cur = str, &str);
+                if ( cur == str )
+                    break;
+                if ( ranges[idx].end <= ranges[idx].start )
+                {
+                    printk(XENLOG_WARNING "crashkernel: end <= start\n");
+                    break;
+                }
+            }
+            else
+                ranges[idx].end = -1;
+
+            if ( *str != ':' )
+            {
+                printk(XENLOG_WARNING "crashkernel: ':' expected\n");
+                break;
+            }
+
+            ranges[idx].size = parse_size_and_unit(cur = str + 1, &str);
+            if ( cur == str )
+                break;
+
+            ++idx;
+        } while ( *str == ',' );
+        if ( idx < ARRAY_SIZE(ranges) )
+            ranges[idx].size = 0;
+    }
+    else
+        kexec_crash_area.size = parse_size_and_unit(cur = str, &str);
+    if ( cur != str && *str == '@' )
+        kexec_crash_area.start = parse_size_and_unit(cur = str + 1, &str);
+    if ( cur == str )
+        printk(XENLOG_WARNING "crashkernel: memory value expected\n");
 }
 custom_param("crashkernel", parse_crashkernel);
 
+void __init set_kexec_crash_area_size(u64 system_ram)
+{
+    unsigned int idx;
+
+    for ( idx = 0; idx < ARRAY_SIZE(ranges) && !kexec_crash_area.size; ++idx )
+    {
+        if ( !ranges[idx].size )
+            break;
+
+        if ( ranges[idx].size >= system_ram )
+        {
+            printk(XENLOG_WARNING "crashkernel: invalid size\n");
+            continue;
+        }
+
+        if ( ranges[idx].start <= system_ram && ranges[idx].end > system_ram )
+            kexec_crash_area.size = ranges[idx].size;
+    }
+}
+
 static void one_cpu_only(void)
 {
     /* Only allow the first cpu to continue - force other cpus to spin */
index d78510e639e61d9f940cf98b18ff852519f788e7..fb1e6b59b1a492f94f516f0fc28a222d62ebee6b 100644 (file)
@@ -12,6 +12,8 @@ typedef struct xen_kexec_reserve {
 
 extern xen_kexec_reserve_t kexec_crash_area;
 
+void set_kexec_crash_area_size(u64 system_ram);
+
 /* We have space for 4 images to support atomic update
  * of images. This is important for CRASH images since
  * a panic can happen at any time...