Linux Headquarters
[ Register ]
[ About us ] [ Home Page ]

Advertisement
[ Kernel ] [ Documentation ] [ Links ] [ Books ]

Advertisement

Kernel v2.6.24-rc8 /kernel/kexec.c

Filename:/kernel/kexec.c
Lines Added:282
Lines Deleted:4
Also changed in: (Previous) 2.6.24-rc7-git8  2.6.24-rc7-git7  2.6.24-rc7-git6  2.6.24-rc7-git5  2.6.24-rc7-git4  2.6.24-rc7-git3 
(Following) 2.6.24  2.6.24-git17  2.6.24-git18  2.6.24-git19  2.6.24-git20  2.6.24-git21 

Location
[  2.6.24-rc8
  [  kernel
     o  kexec.c

Patch

diff --git a/kernel/kexec.c b/kernel/kexec.c
index 25db14b..9a26eec 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -17,21 +17,30 @@
 #include <linux/highmem.h>
 #include <linux/syscalls.h>
 #include <linux/reboot.h>
-#include <linux/syscalls.h>
 #include <linux/ioport.h>
 #include <linux/hardirq.h>
 #include <linux/elf.h>
 #include <linux/elfcore.h>
+#include <linux/utsrelease.h>
+#include <linux/utsname.h>
+#include <linux/numa.h>
 
 #include <asm/page.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/semaphore.h>
+#include <asm/sections.h>
 
 /* Per cpu memory for storing cpu states in case of system crash. */
 note_buf_t* crash_notes;
 
+/* vmcoreinfo stuff */
+unsigned char vmcoreinfo_data[VMCOREINFO_BYTES];
+u32 vmcoreinfo_note[VMCOREINFO_NOTE_SIZE/4];
+size_t vmcoreinfo_size;
+size_t vmcoreinfo_max_size = sizeof(vmcoreinfo_data);
+
 /* Location of the reserved area for the crash kernel */
 struct resource crashk_res = {
    .name  = "Crash kernel",
@@ -42,7 +51,7 @@ struct resource crashk_res = {
 
 int kexec_should_crash(struct task_struct *p)
 {
-   if (in_interrupt() || !p->pid || is_init(p) || panic_on_oops)
+   if (in_interrupt() || !p->pid || is_global_init(p) || panic_on_oops)
       return 1;
    return 0;
 }
@@ -776,7 +785,7 @@ static int kimage_load_normal_segment(struct kimage *image,
       size_t uchunk, mchunk;
 
       page = kimage_alloc_page(image, GFP_HIGHUSER, maddr);
-      if (page == 0) {
+      if (!page) {
          result  = -ENOMEM;
          goto out;
       }
@@ -835,7 +844,7 @@ static int kimage_load_crash_segment(struct kimage *image,
       size_t uchunk, mchunk;
 
       page = pfn_to_page(maddr >> PAGE_SHIFT);
-      if (page == 0) {
+      if (!page) {
          result  = -ENOMEM;
          goto out;
       }
@@ -1061,6 +1070,7 @@ void crash_kexec(struct pt_regs *regs)
       if (kexec_crash_image) {
          struct pt_regs fixed_regs;
          crash_setup_regs(&fixed_regs, regs);
+         crash_save_vmcoreinfo();
          machine_crash_shutdown(&fixed_regs);
          machine_kexec(kexec_crash_image);
       }
@@ -1135,3 +1145,271 @@ static int __init crash_notes_memory_init(void)
    return 0;
 }
 module_init(crash_notes_memory_init)
+
+
+/*
+ * parsing the "crashkernel" commandline
+ *
+ * this code is intended to be called from architecture specific code
+ */
+
+
+/*
+ * This function parses command lines in the format
+ *
+ *   crashkernel=ramsize-range:size[,...][@offset]
+ *
+ * The function returns 0 on success and -EINVAL on failure.
+ */
+static int __init parse_crashkernel_mem(char          *cmdline,
+               unsigned long long   system_ram,
+               unsigned long long   *crash_size,
+               unsigned long long   *crash_base)
+{
+   char *cur = cmdline, *tmp;
+
+   /* for each entry of the comma-separated list */
+   do {
+      unsigned long long start, end = ULLONG_MAX, size;
+
+      /* get the start of the range */
+      start = memparse(cur, &tmp);
+      if (cur == tmp) {
+         pr_warning("crashkernel: Memory value expected\n");
+         return -EINVAL;
+      }
+      cur = tmp;
+      if (*cur != '-') {
+         pr_warning("crashkernel: '-' expected\n");
+         return -EINVAL;
+      }
+      cur++;
+
+      /* if no ':' is here, than we read the end */
+      if (*cur != ':') {
+         end = memparse(cur, &tmp);
+         if (cur == tmp) {
+            pr_warning("crashkernel: Memory "
+                  "value expected\n");
+            return -EINVAL;
+         }
+         cur = tmp;
+         if (end <= start) {
+            pr_warning("crashkernel: end <= start\n");
+            return -EINVAL;
+         }
+      }
+
+      if (*cur != ':') {
+         pr_warning("crashkernel: ':' expected\n");
+         return -EINVAL;
+      }
+      cur++;
+
+      size = memparse(cur, &tmp);
+      if (cur == tmp) {
+         pr_warning("Memory value expected\n");
+         return -EINVAL;
+      }
+      cur = tmp;
+      if (size >= system_ram) {
+         pr_warning("crashkernel: invalid size\n");
+         return -EINVAL;
+      }
+
+      /* match ? */
+      if (system_ram >= start && system_ram <= end) {
+         *crash_size = size;
+         break;
+      }
+   } while (*cur++ == ',');
+
+   if (*crash_size > 0) {
+      while (*cur != ' ' && *cur != '@')
+         cur++;
+      if (*cur == '@') {
+         cur++;
+         *crash_base = memparse(cur, &tmp);
+         if (cur == tmp) {
+            pr_warning("Memory value expected "
+                  "after '@'\n");
+            return -EINVAL;
+         }
+      }
+   }
+
+   return 0;
+}
+
+/*
+ * That function parses "simple" (old) crashkernel command lines like
+ *
+ *    crashkernel=size[@offset]
+ *
+ * It returns 0 on success and -EINVAL on failure.
+ */
+static int __init parse_crashkernel_simple(char       *cmdline,
+                  unsigned long long    *crash_size,
+                  unsigned long long    *crash_base)
+{
+   char *cur = cmdline;
+
+   *crash_size = memparse(cmdline, &cur);
+   if (cmdline == cur) {
+      pr_warning("crashkernel: memory value expected\n");
+      return -EINVAL;
+   }
+
+   if (*cur == '@')
+      *crash_base = memparse(cur+1, &cur);
+
+   return 0;
+}
+
+/*
+ * That function is the entry point for command line parsing and should be
+ * called from the arch-specific code.
+ */
+int __init parse_crashkernel(char        *cmdline,
+              unsigned long long system_ram,
+              unsigned long long *crash_size,
+              unsigned long long *crash_base)
+{
+   char    *p = cmdline, *ck_cmdline = NULL;
+   char   *first_colon, *first_space;
+
+   BUG_ON(!crash_size || !crash_base);
+   *crash_size = 0;
+   *crash_base = 0;
+
+   /* find crashkernel and use the last one if there are more */
+   p = strstr(p, "crashkernel=");
+   while (p) {
+      ck_cmdline = p;
+      p = strstr(p+1, "crashkernel=");
+   }
+
+   if (!ck_cmdline)
+      return -EINVAL;
+
+   ck_cmdline += 12; /* strlen("crashkernel=") */
+
+   /*
+    * if the commandline contains a ':', then that's the extended
+    * syntax -- if not, it must be the classic syntax
+    */
+   first_colon = strchr(ck_cmdline, ':');
+   first_space = strchr(ck_cmdline, ' ');
+   if (first_colon && (!first_space || first_colon < first_space))
+      return parse_crashkernel_mem(ck_cmdline, system_ram,
+            crash_size, crash_base);
+   else
+      return parse_crashkernel_simple(ck_cmdline, crash_size,
+            crash_base);
+
+   return 0;
+}
+
+
+
+void crash_save_vmcoreinfo(void)
+{
+   u32 *buf;
+
+   if (!vmcoreinfo_size)
+      return;
+
+   vmcoreinfo_append_str("CRASHTIME=%ld", get_seconds());
+
+   buf = (u32 *)vmcoreinfo_note;
+
+   buf = append_elf_note(buf, VMCOREINFO_NOTE_NAME, 0, vmcoreinfo_data,
+               vmcoreinfo_size);
+
+   final_note(buf);
+}
+
+void vmcoreinfo_append_str(const char *fmt, ...)
+{
+   va_list args;
+   char buf[0x50];
+   int r;
+
+   va_start(args, fmt);
+   r = vsnprintf(buf, sizeof(buf), fmt, args);
+   va_end(args);
+
+   if (r + vmcoreinfo_size > vmcoreinfo_max_size)
+      r = vmcoreinfo_max_size - vmcoreinfo_size;
+
+   memcpy(&vmcoreinfo_data[vmcoreinfo_size], buf, r);
+
+   vmcoreinfo_size += r;
+}
+
+/*
+ * provide an empty default implementation here -- architecture
+ * code may override this
+ */
+void __attribute__ ((weak)) arch_crash_save_vmcoreinfo(void)
+{}
+
+unsigned long __attribute__ ((weak)) paddr_vmcoreinfo_note(void)
+{
+   return __pa((unsigned long)(char *)&vmcoreinfo_note);
+}
+
+static int __init crash_save_vmcoreinfo_init(void)
+{
+   vmcoreinfo_append_str("OSRELEASE=%s\n", init_uts_ns.name.release);
+   vmcoreinfo_append_str("PAGESIZE=%ld\n", PAGE_SIZE);
+
+   VMCOREINFO_SYMBOL(init_uts_ns);
+   VMCOREINFO_SYMBOL(node_online_map);
+   VMCOREINFO_SYMBOL(swapper_pg_dir);
+   VMCOREINFO_SYMBOL(_stext);
+
+#ifndef CONFIG_NEED_MULTIPLE_NODES
+   VMCOREINFO_SYMBOL(mem_map);
+   VMCOREINFO_SYMBOL(contig_page_data);
+#endif
+#ifdef CONFIG_SPARSEMEM
+   VMCOREINFO_SYMBOL(mem_section);
+   VMCOREINFO_LENGTH(mem_section, NR_SECTION_ROOTS);
+   VMCOREINFO_SIZE(mem_section);
+   VMCOREINFO_OFFSET(mem_section, section_mem_map);
+#endif
+   VMCOREINFO_SIZE(page);
+   VMCOREINFO_SIZE(pglist_data);
+   VMCOREINFO_SIZE(zone);
+   VMCOREINFO_SIZE(free_area);
+   VMCOREINFO_SIZE(list_head);
+   VMCOREINFO_TYPEDEF_SIZE(nodemask_t);
+   VMCOREINFO_OFFSET(page, flags);
+   VMCOREINFO_OFFSET(page, _count);
+   VMCOREINFO_OFFSET(page, mapping);
+   VMCOREINFO_OFFSET(page, lru);
+   VMCOREINFO_OFFSET(pglist_data, node_zones);
+   VMCOREINFO_OFFSET(pglist_data, nr_zones);
+#ifdef CONFIG_FLAT_NODE_MEM_MAP
+   VMCOREINFO_OFFSET(pglist_data, node_mem_map);
+#endif
+   VMCOREINFO_OFFSET(pglist_data, node_start_pfn);
+   VMCOREINFO_OFFSET(pglist_data, node_spanned_pages);
+   VMCOREINFO_OFFSET(pglist_data, node_id);
+   VMCOREINFO_OFFSET(zone, free_area);
+   VMCOREINFO_OFFSET(zone, vm_stat);
+   VMCOREINFO_OFFSET(zone, spanned_pages);
+   VMCOREINFO_OFFSET(free_area, free_list);
+   VMCOREINFO_OFFSET(list_head, next);
+   VMCOREINFO_OFFSET(list_head, prev);
+   VMCOREINFO_LENGTH(zone.free_area, MAX_ORDER);
+   VMCOREINFO_LENGTH(free_area.free_list, MIGRATE_TYPES);
+   VMCOREINFO_NUMBER(NR_FREE_PAGES);
+
+   arch_crash_save_vmcoreinfo();
+
+   return 0;
+}
+
+module_init(crash_save_vmcoreinfo_init)


Comments: webmaster (at) linuxhq.com.
Advertising: banners (at) linuxhq.com.
Compilation ©1998-2008 Linux Headquarters, Inc.