diff options
-rw-r--r-- | fs/proc/vmcore.c | 52 | ||||
-rw-r--r-- | 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 74802bc5ded9..cd99bf557650 100644 --- a/fs/proc/vmcore.c +++ b/fs/proc/vmcore.c | |||
@@ -35,6 +35,46 @@ static u64 vmcore_size; | |||
35 | 35 | ||
36 | static struct proc_dir_entry *proc_vmcore = NULL; | 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 | /* Reads a page from the oldmem device from given offset. */ | 78 | /* Reads a page from the oldmem device from given offset. */ |
39 | static ssize_t read_from_oldmem(char *buf, size_t count, | 79 | static ssize_t read_from_oldmem(char *buf, size_t count, |
40 | u64 *ppos, int userbuf) | 80 | u64 *ppos, int userbuf) |
@@ -55,9 +95,15 @@ static ssize_t read_from_oldmem(char *buf, size_t count, | |||
55 | else | 95 | else |
56 | nr_bytes = count; | 96 | nr_bytes = count; |
57 | 97 | ||
58 | tmp = copy_oldmem_page(pfn, buf, nr_bytes, offset, userbuf); | 98 | /* If pfn is not ram, return zeros for sparse dump files */ |
59 | if (tmp < 0) | 99 | if (pfn_is_ram(pfn) == 0) |
60 | return tmp; | 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 | *ppos += nr_bytes; | 107 | *ppos += nr_bytes; |
62 | count -= nr_bytes; | 108 | count -= nr_bytes; |
63 | buf += nr_bytes; | 109 | buf += nr_bytes; |
diff --git a/include/linux/crash_dump.h b/include/linux/crash_dump.h index 088cd4ace4ef..74054074e876 100644 --- a/include/linux/crash_dump.h +++ b/include/linux/crash_dump.h | |||
@@ -66,6 +66,11 @@ static inline void vmcore_unusable(void) | |||
66 | if (is_kdump_kernel()) | 66 | if (is_kdump_kernel()) |
67 | elfcorehdr_addr = ELFCORE_ADDR_ERR; | 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 | #else /* !CONFIG_CRASH_DUMP */ | 74 | #else /* !CONFIG_CRASH_DUMP */ |
70 | static inline int is_kdump_kernel(void) { return 0; } | 75 | static inline int is_kdump_kernel(void) { return 0; } |
71 | #endif /* CONFIG_CRASH_DUMP */ | 76 | #endif /* CONFIG_CRASH_DUMP */ |