Resolves: bz1097904
https://bugzilla.redhat.com/show_bug.cgi?id=1097904

This is back ported from upstream directly.

commit 997c136f518c5debd63847e78e2a8694f56dcf90
Author: Olaf Hering <[email protected]>
Date:   Thu May 26 16:25:54 2011 -0700

    fs/proc/vmcore.c: add hook to read_from_oldmem() to check for non-ram pages

    The balloon driver in a Xen guest frees guest pages and marks them as
    mmio.  When the kernel crashes and the crash kernel attempts to read the
    oldmem via /proc/vmcore a read from ballooned pages will generate 100%
    load in dom0 because Xen asks qemu-dm for the page content.  Since the
    reads come in as 8byte requests each ballooned page is tried 512 times.

    With this change a hook can be registered which checks wether the given
    pfn is really ram.  The hook has to return a value > 0 for ram pages, a
    value < 0 on error (because the hypercall is not known) and 0 for non-ram
    pages.

    This will reduce the time to read /proc/vmcore.  Without this change a
    512M guest with 128M crashkernel region needs 200 seconds to read it, with
    this change it takes just 2 seconds.

    Signed-off-by: Olaf Hering <[email protected]>
    Cc: Alexey Dobriyan <[email protected]>
    Signed-off-by: Andrew Morton <[email protected]>
    Signed-off-by: Linus Torvalds <[email protected]>

Signed-off-by: Baoquan He <[email protected]>
---
 fs/proc/vmcore.c           | 52 +++++++++++++++++++++++++++++++++++++++++++---
 include/linux/crash_dump.h |  5 +++++
 2 files changed, 54 insertions(+), 3 deletions(-)

diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c
index b53862a..ce23082 100644
--- a/fs/proc/vmcore.c
+++ b/fs/proc/vmcore.c
@@ -34,6 +34,46 @@ static u64 vmcore_size;
 
 static struct proc_dir_entry *proc_vmcore = NULL;
 
+/*
+ * Returns > 0 for RAM pages, 0 for non-RAM pages, < 0 on error
+ * The called function has to take care of module refcounting.
+ */
+static int (*oldmem_pfn_is_ram)(unsigned long pfn);
+
+int register_oldmem_pfn_is_ram(int (*fn)(unsigned long pfn))
+{
+       if (oldmem_pfn_is_ram)
+               return -EBUSY;
+       oldmem_pfn_is_ram = fn;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(register_oldmem_pfn_is_ram);
+
+void unregister_oldmem_pfn_is_ram(void)
+{
+       oldmem_pfn_is_ram = NULL;
+       wmb();
+}
+EXPORT_SYMBOL_GPL(unregister_oldmem_pfn_is_ram);
+
+static int pfn_is_ram(unsigned long pfn)
+{
+       int (*fn)(unsigned long pfn);
+       /* pfn is ram unless fn() checks pagetype */
+       int ret = 1;
+
+       /*
+        * Ask hypervisor if the pfn is really ram.
+        * A ballooned page contains no data and reading from such a page
+        * will cause high load in the hypervisor.
+        */
+       fn = oldmem_pfn_is_ram;
+       if (fn)
+               ret = fn(pfn);
+
+       return ret;
+}
+
 /* Reads a page from the oldmem device from given offset. */
 static ssize_t read_from_oldmem(char *buf, size_t count,
                                u64 *ppos, int userbuf)
@@ -54,9 +94,15 @@ static ssize_t read_from_oldmem(char *buf, size_t count,
                else
                        nr_bytes = count;
 
-               tmp = copy_oldmem_page(pfn, buf, nr_bytes, offset, userbuf);
-               if (tmp < 0)
-                       return tmp;
+               /* If pfn is not ram, return zeros for sparse dump files */
+               if (pfn_is_ram(pfn) == 0)
+                       memset(buf, 0, nr_bytes);
+               else {
+                       tmp = copy_oldmem_page(pfn, buf, nr_bytes,
+                                               offset, userbuf);
+                       if (tmp < 0)
+                               return tmp;
+               }
                *ppos += nr_bytes;
                count -= nr_bytes;
                buf += nr_bytes;
diff --git a/include/linux/crash_dump.h b/include/linux/crash_dump.h
index 0026f26..6719454 100644
--- a/include/linux/crash_dump.h
+++ b/include/linux/crash_dump.h
@@ -59,6 +59,11 @@ static inline void vmcore_unusable(void)
        if (is_kdump_kernel())
                elfcorehdr_addr = ELFCORE_ADDR_ERR;
 }
+
+#define HAVE_OLDMEM_PFN_IS_RAM 1
+extern int register_oldmem_pfn_is_ram(int (*fn)(unsigned long pfn));
+extern void unregister_oldmem_pfn_is_ram(void);
+
 #else /* !CONFIG_CRASH_DUMP */
 static inline int is_kdump_kernel(void) { return 0; }
 #endif /* CONFIG_CRASH_DUMP */
-- 
2.1.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to