Commit 997c136f518c5debd63847e78e2a8694f56dcf90
Committed by
Linus Torvalds
1 parent
98bc93e505
Exists in
master
and in
7 other branches
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 <olaf@aepfle.de> Cc: Alexey Dobriyan <adobriyan@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Showing 2 changed files with 54 additions and 3 deletions Side-by-side Diff
fs/proc/vmcore.c
... | ... | @@ -35,6 +35,46 @@ |
35 | 35 | |
36 | 36 | static struct proc_dir_entry *proc_vmcore = NULL; |
37 | 37 | |
38 | +/* | |
39 | + * Returns > 0 for RAM pages, 0 for non-RAM pages, < 0 on error | |
40 | + * The called function has to take care of module refcounting. | |
41 | + */ | |
42 | +static int (*oldmem_pfn_is_ram)(unsigned long pfn); | |
43 | + | |
44 | +int register_oldmem_pfn_is_ram(int (*fn)(unsigned long pfn)) | |
45 | +{ | |
46 | + if (oldmem_pfn_is_ram) | |
47 | + return -EBUSY; | |
48 | + oldmem_pfn_is_ram = fn; | |
49 | + return 0; | |
50 | +} | |
51 | +EXPORT_SYMBOL_GPL(register_oldmem_pfn_is_ram); | |
52 | + | |
53 | +void unregister_oldmem_pfn_is_ram(void) | |
54 | +{ | |
55 | + oldmem_pfn_is_ram = NULL; | |
56 | + wmb(); | |
57 | +} | |
58 | +EXPORT_SYMBOL_GPL(unregister_oldmem_pfn_is_ram); | |
59 | + | |
60 | +static int pfn_is_ram(unsigned long pfn) | |
61 | +{ | |
62 | + int (*fn)(unsigned long pfn); | |
63 | + /* pfn is ram unless fn() checks pagetype */ | |
64 | + int ret = 1; | |
65 | + | |
66 | + /* | |
67 | + * Ask hypervisor if the pfn is really ram. | |
68 | + * A ballooned page contains no data and reading from such a page | |
69 | + * will cause high load in the hypervisor. | |
70 | + */ | |
71 | + fn = oldmem_pfn_is_ram; | |
72 | + if (fn) | |
73 | + ret = fn(pfn); | |
74 | + | |
75 | + return ret; | |
76 | +} | |
77 | + | |
38 | 78 | /* Reads a page from the oldmem device from given offset. */ |
39 | 79 | static ssize_t read_from_oldmem(char *buf, size_t count, |
40 | 80 | u64 *ppos, int userbuf) |
... | ... | @@ -55,9 +95,15 @@ |
55 | 95 | else |
56 | 96 | nr_bytes = count; |
57 | 97 | |
58 | - tmp = copy_oldmem_page(pfn, buf, nr_bytes, offset, userbuf); | |
59 | - if (tmp < 0) | |
60 | - return tmp; | |
98 | + /* If pfn is not ram, return zeros for sparse dump files */ | |
99 | + if (pfn_is_ram(pfn) == 0) | |
100 | + memset(buf, 0, nr_bytes); | |
101 | + else { | |
102 | + tmp = copy_oldmem_page(pfn, buf, nr_bytes, | |
103 | + offset, userbuf); | |
104 | + if (tmp < 0) | |
105 | + return tmp; | |
106 | + } | |
61 | 107 | *ppos += nr_bytes; |
62 | 108 | count -= nr_bytes; |
63 | 109 | buf += nr_bytes; |
include/linux/crash_dump.h
... | ... | @@ -66,6 +66,11 @@ |
66 | 66 | if (is_kdump_kernel()) |
67 | 67 | elfcorehdr_addr = ELFCORE_ADDR_ERR; |
68 | 68 | } |
69 | + | |
70 | +#define HAVE_OLDMEM_PFN_IS_RAM 1 | |
71 | +extern int register_oldmem_pfn_is_ram(int (*fn)(unsigned long pfn)); | |
72 | +extern void unregister_oldmem_pfn_is_ram(void); | |
73 | + | |
69 | 74 | #else /* !CONFIG_CRASH_DUMP */ |
70 | 75 | static inline int is_kdump_kernel(void) { return 0; } |
71 | 76 | #endif /* CONFIG_CRASH_DUMP */ |