kexec: allow relaxed placement specification via command line
authorJan Beulich <jbeulich@suse.com>
Wed, 8 Jun 2016 12:12:45 +0000 (14:12 +0200)
committerJan Beulich <jbeulich@suse.com>
Wed, 8 Jun 2016 12:12:45 +0000 (14:12 +0200)
Rather than just allowing a fixed address or fully automatic placement,
also allow for specifying an upper bound. Especially on EFI systems,
where firmware memory use is commonly less predictable than on legacy
BIOS ones, this makes success of the reservation more likely when
automatic placement is not an option (e.g. because of special DMA
restrictions of devices involved in actually carrying out the dump).

Also take the opportunity to actually add text to the "crashkernel"
entry in the command line option doc.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: David Vrabel <david.vrabel@citrix.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
docs/misc/xen-command-line.markdown
xen/arch/x86/setup.c
xen/common/kexec.c
xen/include/xen/kexec.h

index b4bae118f4ecc74e6fc89c9d6ab7c3b8610b78bc..fed732c2d07db93135c61e9f0a0e299f1372f751 100644 (file)
@@ -458,7 +458,18 @@ Specify the maximum address to allocate certain structures, if used in
 combination with the `low_crashinfo` command line option.
 
 ### crashkernel
-> `= <ramsize-range>:<size>[,...][@<offset>]`
+> `= <ramsize-range>:<size>[,...][{@,<}<offset>]`
+> `= <size>[{@,<}<offset>]`
+
+Specify sizes and optionally placement of the crash kernel reservation
+area.  The `<ramsize-range>:<size>` pairs indicate how much memory to
+set aside for a crash kernel (`<size>`) for a given range of installed
+RAM (`<ramsize-range>`).  Each `<ramsize-range>` is of the form
+`<start>-[<end>]`.
+
+A trailing `@<offset>` specifies the exact address this area should be
+placed at, whereas `<` in place of `@` just specifies an upper bound of
+the address range the area should fall into.
 
 ### credit2\_balance\_over
 > `= <integer>`
index de682e7c26881b6e66d7140e17e29cfae19367b8..6f6a6a78d9b3072dbf2a73fb2be5de70fa096ea9 100644 (file)
@@ -1044,13 +1044,23 @@ void __init noreturn __start_xen(unsigned long mbi_p)
         }
 
 #ifdef CONFIG_KEXEC
-        /* Don't overlap with modules. */
-        e = consider_modules(s, e, PAGE_ALIGN(kexec_crash_area.size),
-                             mod, mbi->mods_count, -1);
-        if ( !kexec_crash_area.start && (s < e) )
+        /*
+         * Looking backwards from the crash area limit, find a large
+         * enough range that does not overlap with modules.
+         */
+        while ( !kexec_crash_area.start )
         {
-            e = (e - kexec_crash_area.size) & PAGE_MASK;
-            kexec_crash_area.start = e;
+            /* Don't overlap with modules. */
+            e = consider_modules(s, e, PAGE_ALIGN(kexec_crash_area.size),
+                                 mod, mbi->mods_count, -1);
+            if ( s >= e )
+                break;
+            if ( e > kexec_crash_area_limit )
+            {
+                e = kexec_crash_area_limit & PAGE_MASK;
+                continue;
+            }
+            kexec_crash_area.start = (e - kexec_crash_area.size) & PAGE_MASK;
         }
 #endif
     }
index 2fc2957a38b742b09f6af2d697c1d72539274ab7..c83d48fc79db6745bbf99ffafcbef4536f1be46c 100644 (file)
@@ -60,6 +60,7 @@ static unsigned char vmcoreinfo_data[VMCOREINFO_BYTES];
 static size_t vmcoreinfo_size = 0;
 
 xen_kexec_reserve_t kexec_crash_area;
+paddr_t __initdata kexec_crash_area_limit = ~(paddr_t)0;
 static struct {
     u64 start, end;
     unsigned long size;
@@ -86,7 +87,7 @@ static void *crash_heap_current = NULL, *crash_heap_end = NULL;
 /*
  * Parse command lines in the format
  *
- *   crashkernel=<ramsize-range>:<size>[,...][@<offset>]
+ *   crashkernel=<ramsize-range>:<size>[,...][{@,<}<address>]
  *
  * with <ramsize-range> being of form
  *
@@ -94,7 +95,7 @@ static void *crash_heap_current = NULL, *crash_heap_end = NULL;
  *
  * as well as the legacy ones in the format
  *
- *   crashkernel=<size>[@<offset>]
+ *   crashkernel=<size>[{@,<}<address>]
  */
 static void __init parse_crashkernel(const char *str)
 {
@@ -109,7 +110,7 @@ static void __init parse_crashkernel(const char *str)
             {
                 printk(XENLOG_WARNING "crashkernel: too many ranges\n");
                 cur = NULL;
-                str = strchr(str, '@');
+                str = strpbrk(str, "@<");
                 break;
             }
 
@@ -154,9 +155,16 @@ static void __init parse_crashkernel(const char *str)
     }
     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 )
+    if ( cur != str )
+    {
+        if ( *str == '@' )
+            kexec_crash_area.start = parse_size_and_unit(cur = str + 1, &str);
+        else if ( *str == '<' )
+            kexec_crash_area_limit = parse_size_and_unit(cur = str + 1, &str);
+        else
+            printk(XENLOG_WARNING "crashkernel: '%s' ignored\n", str);
+    }
+    if ( cur && cur == str )
         printk(XENLOG_WARNING "crashkernel: memory value expected\n");
 }
 custom_param("crashkernel", parse_crashkernel);
index baaeb88ac0db270515f2c5f6c371d98e80874143..f5b9d165aee98341f9400f701d6c9cdccbbe1ed8 100644 (file)
@@ -14,6 +14,7 @@ typedef struct xen_kexec_reserve {
 } xen_kexec_reserve_t;
 
 extern xen_kexec_reserve_t kexec_crash_area;
+extern paddr_t kexec_crash_area_limit;
 
 extern bool_t kexecing;