diff options
author | Vivek Goyal <vgoyal@in.ibm.com> | 2005-06-25 17:58:23 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-06-25 19:24:54 -0400 |
commit | 50b1fdbd81edcc8bd343ca44aca2b87a29e2f15c (patch) | |
tree | fc5da6014f015171574c337be1c3abce5573ec99 /drivers/char/mem.c | |
parent | 72658e9d5004fc0dd807bea9eda49e6a52e40103 (diff) |
[PATCH] kdump: Accessing dump file in linear raw format (/dev/oldmem)
Hariprasad Nellitheertha <hari@in.ibm.com>
This patch contains the code that enables us to access the previous kernel's
memory as /dev/oldmem.
Signed-off-by: Eric Biederman <ebiederm@xmission.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/char/mem.c')
-rw-r--r-- | drivers/char/mem.c | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/drivers/char/mem.c b/drivers/char/mem.c index e3085b22a365..01b3c17ca851 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c | |||
@@ -23,6 +23,8 @@ | |||
23 | #include <linux/devfs_fs_kernel.h> | 23 | #include <linux/devfs_fs_kernel.h> |
24 | #include <linux/ptrace.h> | 24 | #include <linux/ptrace.h> |
25 | #include <linux/device.h> | 25 | #include <linux/device.h> |
26 | #include <linux/highmem.h> | ||
27 | #include <linux/crash_dump.h> | ||
26 | #include <linux/backing-dev.h> | 28 | #include <linux/backing-dev.h> |
27 | 29 | ||
28 | #include <asm/uaccess.h> | 30 | #include <asm/uaccess.h> |
@@ -273,6 +275,62 @@ static int mmap_kmem(struct file * file, struct vm_area_struct * vma) | |||
273 | return mmap_mem(file, vma); | 275 | return mmap_mem(file, vma); |
274 | } | 276 | } |
275 | 277 | ||
278 | #ifdef CONFIG_CRASH_DUMP | ||
279 | /* | ||
280 | * Read memory corresponding to the old kernel. | ||
281 | * If we are reading from the reserved section, which is | ||
282 | * actually used by the current kernel, we just return zeroes. | ||
283 | * Or if we are reading from the first 640k, we return from the | ||
284 | * backed up area. | ||
285 | */ | ||
286 | static ssize_t read_oldmem(struct file * file, char * buf, | ||
287 | size_t count, loff_t *ppos) | ||
288 | { | ||
289 | unsigned long pfn; | ||
290 | unsigned backup_start, backup_end, relocate_start; | ||
291 | size_t read=0, csize; | ||
292 | |||
293 | backup_start = CRASH_BACKUP_BASE / PAGE_SIZE; | ||
294 | backup_end = backup_start + (CRASH_BACKUP_SIZE / PAGE_SIZE); | ||
295 | relocate_start = (CRASH_BACKUP_BASE + CRASH_BACKUP_SIZE) / PAGE_SIZE; | ||
296 | |||
297 | while(count) { | ||
298 | pfn = *ppos / PAGE_SIZE; | ||
299 | |||
300 | csize = (count > PAGE_SIZE) ? PAGE_SIZE : count; | ||
301 | |||
302 | /* Perform translation (see comment above) */ | ||
303 | if ((pfn >= backup_start) && (pfn < backup_end)) { | ||
304 | if (clear_user(buf, csize)) { | ||
305 | read = -EFAULT; | ||
306 | goto done; | ||
307 | } | ||
308 | |||
309 | goto copy_done; | ||
310 | } else if (pfn < (CRASH_RELOCATE_SIZE / PAGE_SIZE)) | ||
311 | pfn += relocate_start; | ||
312 | |||
313 | if (pfn > saved_max_pfn) { | ||
314 | read = 0; | ||
315 | goto done; | ||
316 | } | ||
317 | |||
318 | if (copy_oldmem_page(pfn, buf, csize, 1)) { | ||
319 | read = -EFAULT; | ||
320 | goto done; | ||
321 | } | ||
322 | |||
323 | copy_done: | ||
324 | buf += csize; | ||
325 | *ppos += csize; | ||
326 | read += csize; | ||
327 | count -= csize; | ||
328 | } | ||
329 | done: | ||
330 | return read; | ||
331 | } | ||
332 | #endif | ||
333 | |||
276 | extern long vread(char *buf, char *addr, unsigned long count); | 334 | extern long vread(char *buf, char *addr, unsigned long count); |
277 | extern long vwrite(char *buf, char *addr, unsigned long count); | 335 | extern long vwrite(char *buf, char *addr, unsigned long count); |
278 | 336 | ||
@@ -721,6 +779,7 @@ static int open_port(struct inode * inode, struct file * filp) | |||
721 | #define read_full read_zero | 779 | #define read_full read_zero |
722 | #define open_mem open_port | 780 | #define open_mem open_port |
723 | #define open_kmem open_mem | 781 | #define open_kmem open_mem |
782 | #define open_oldmem open_mem | ||
724 | 783 | ||
725 | static struct file_operations mem_fops = { | 784 | static struct file_operations mem_fops = { |
726 | .llseek = memory_lseek, | 785 | .llseek = memory_lseek, |
@@ -770,6 +829,13 @@ static struct file_operations full_fops = { | |||
770 | .write = write_full, | 829 | .write = write_full, |
771 | }; | 830 | }; |
772 | 831 | ||
832 | #ifdef CONFIG_CRASH_DUMP | ||
833 | static struct file_operations oldmem_fops = { | ||
834 | .read = read_oldmem, | ||
835 | .open = open_oldmem, | ||
836 | }; | ||
837 | #endif | ||
838 | |||
773 | static ssize_t kmsg_write(struct file * file, const char __user * buf, | 839 | static ssize_t kmsg_write(struct file * file, const char __user * buf, |
774 | size_t count, loff_t *ppos) | 840 | size_t count, loff_t *ppos) |
775 | { | 841 | { |
@@ -825,6 +891,11 @@ static int memory_open(struct inode * inode, struct file * filp) | |||
825 | case 11: | 891 | case 11: |
826 | filp->f_op = &kmsg_fops; | 892 | filp->f_op = &kmsg_fops; |
827 | break; | 893 | break; |
894 | #ifdef CONFIG_CRASH_DUMP | ||
895 | case 12: | ||
896 | filp->f_op = &oldmem_fops; | ||
897 | break; | ||
898 | #endif | ||
828 | default: | 899 | default: |
829 | return -ENXIO; | 900 | return -ENXIO; |
830 | } | 901 | } |
@@ -854,6 +925,9 @@ static const struct { | |||
854 | {8, "random", S_IRUGO | S_IWUSR, &random_fops}, | 925 | {8, "random", S_IRUGO | S_IWUSR, &random_fops}, |
855 | {9, "urandom", S_IRUGO | S_IWUSR, &urandom_fops}, | 926 | {9, "urandom", S_IRUGO | S_IWUSR, &urandom_fops}, |
856 | {11,"kmsg", S_IRUGO | S_IWUSR, &kmsg_fops}, | 927 | {11,"kmsg", S_IRUGO | S_IWUSR, &kmsg_fops}, |
928 | #ifdef CONFIG_CRASH_DUMP | ||
929 | {12,"oldmem", S_IRUSR | S_IWUSR | S_IRGRP, &oldmem_fops}, | ||
930 | #endif | ||
857 | }; | 931 | }; |
858 | 932 | ||
859 | static struct class *mem_class; | 933 | static struct class *mem_class; |