]> Pileus Git - ~andy/linux/blobdiff - fs/proc/vmcore.c
Merge branch 'for-linus' of git://oss.sgi.com/xfs/xfs
[~andy/linux] / fs / proc / vmcore.c
index 74802bc5ded95e09d510bcadfba94167e1390bc2..cd99bf557650c4c727cdd9ac060ec28800a0ffe5 100644 (file)
@@ -35,6 +35,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)
@@ -55,9 +95,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;