Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S261617AbVASHfD (ORCPT ); Wed, 19 Jan 2005 02:35:03 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S261646AbVASHfD (ORCPT ); Wed, 19 Jan 2005 02:35:03 -0500 Received: from ebiederm.dsl.xmission.com ([166.70.28.69]:49343 "EHLO ebiederm.dsl.xmission.com") by vger.kernel.org with ESMTP id S261617AbVASHdL (ORCPT ); Wed, 19 Jan 2005 02:33:11 -0500 From: "Eric W. Biederman" To: Andrew Morton Cc: , Subject: [PATCH 28/29] crashdump-elf-format-dump-file-access Date: Wed, 19 Jan 2005 0:31:37 -0700 Message-ID: X-Mailer: patch-bomb.pl@ebiederm.dsl.xmission.com In-Reply-To: References: Sender: linux-kernel-owner@vger.kernel.org X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 11797 Lines: 381 This patch has been refactored to more closely match the prevailing style in the affected files. And to clearly indicate the dependency between /proc/kcore and proc/vmcore.c From: Hariprasad Nellitheertha This patch contains the code that provides an ELF format interface to the previous kernel's memory post kexec reboot. Signed off by Hariprasad Nellitheertha Signed-off-by: Eric Biederman --- fs/proc/Makefile | 3 fs/proc/kcore.c | 10 - fs/proc/proc_misc.c | 8 + fs/proc/vmcore.c | 239 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/crash_dump.h | 13 ++ 5 files changed, 267 insertions(+), 6 deletions(-) diff -uNr linux-2.6.11-rc1-mm1-nokexec-crashdump-routines-for-copying-dump-pages/fs/proc/Makefile linux-2.6.11-rc1-mm1-nokexec-crashdump-elf-format-dump-file-access/fs/proc/Makefile --- linux-2.6.11-rc1-mm1-nokexec-crashdump-routines-for-copying-dump-pages/fs/proc/Makefile Fri Jan 14 04:28:46 2005 +++ linux-2.6.11-rc1-mm1-nokexec-crashdump-elf-format-dump-file-access/fs/proc/Makefile Tue Jan 18 23:16:57 2005 @@ -10,5 +10,6 @@ proc-y += inode.o root.o base.o generic.o array.o \ kmsg.o proc_tty.o proc_misc.o -proc-$(CONFIG_PROC_KCORE) += kcore.o +kcore-$(CONFIG_CRASH_DUMP) += vmcore.o +proc-$(CONFIG_PROC_KCORE) += kcore.o $(kcore-y) proc-$(CONFIG_PROC_DEVICETREE) += proc_devtree.o diff -uNr linux-2.6.11-rc1-mm1-nokexec-crashdump-routines-for-copying-dump-pages/fs/proc/kcore.c linux-2.6.11-rc1-mm1-nokexec-crashdump-elf-format-dump-file-access/fs/proc/kcore.c --- linux-2.6.11-rc1-mm1-nokexec-crashdump-routines-for-copying-dump-pages/fs/proc/kcore.c Fri Jan 14 04:32:26 2005 +++ linux-2.6.11-rc1-mm1-nokexec-crashdump-elf-format-dump-file-access/fs/proc/kcore.c Tue Jan 18 23:16:57 2005 @@ -97,7 +97,7 @@ /* * determine size of ELF note */ -static int notesize(struct memelfnote *en) +int notesize(struct memelfnote *en) { int sz; @@ -112,7 +112,7 @@ /* * store a note in the header buffer */ -static char *storenote(struct memelfnote *men, char *bufp) +char *storenote(struct memelfnote *men, char *bufp) { struct elf_note en; @@ -139,7 +139,7 @@ * store an ELF coredump header in the supplied buffer * nphdr is the number of elf_phdr to insert */ -static void elf_kcore_store_hdr(char *bufp, int nphdr, int dataoff) +void elf_kcore_store_hdr(char *bufp, int nphdr, int dataoff, struct kcore_list *clist) { struct elf_prstatus prstatus; /* NT_PRSTATUS */ struct elf_prpsinfo prpsinfo; /* NT_PRPSINFO */ @@ -191,7 +191,7 @@ nhdr->p_align = 0; /* setup ELF PT_LOAD program header for every area */ - for (m=kclist; m; m=m->next) { + for (m=clist; m; m=m->next) { phdr = (struct elf_phdr *) bufp; bufp += sizeof(struct elf_phdr); offset += sizeof(struct elf_phdr); @@ -287,7 +287,7 @@ return -ENOMEM; } memset(elf_buf, 0, elf_buflen); - elf_kcore_store_hdr(elf_buf, nphdr, elf_buflen); + elf_kcore_store_hdr(elf_buf, nphdr, elf_buflen, kclist); read_unlock(&kclist_lock); if (copy_to_user(buffer, elf_buf + *fpos, tsz)) { kfree(elf_buf); diff -uNr linux-2.6.11-rc1-mm1-nokexec-crashdump-routines-for-copying-dump-pages/fs/proc/proc_misc.c linux-2.6.11-rc1-mm1-nokexec-crashdump-elf-format-dump-file-access/fs/proc/proc_misc.c --- linux-2.6.11-rc1-mm1-nokexec-crashdump-routines-for-copying-dump-pages/fs/proc/proc_misc.c Fri Jan 14 04:28:46 2005 +++ linux-2.6.11-rc1-mm1-nokexec-crashdump-elf-format-dump-file-access/fs/proc/proc_misc.c Tue Jan 18 23:16:57 2005 @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -598,6 +599,13 @@ proc_root_kcore->size = (size_t)high_memory - PAGE_OFFSET + PAGE_SIZE; } +# ifdef CONFIG_CRASH_DUMP + entry = create_proc_entry("vmcore", S_IRUSR, NULL); + if (entry) { + entry->proc_fops = &proc_vmcore_operations; + entry->size = (size_t)(saved_max_pfn << PAGE_SHIFT); + } +# endif #endif #ifdef CONFIG_MAGIC_SYSRQ entry = create_proc_entry("sysrq-trigger", S_IWUSR, NULL); diff -uNr linux-2.6.11-rc1-mm1-nokexec-crashdump-routines-for-copying-dump-pages/fs/proc/vmcore.c linux-2.6.11-rc1-mm1-nokexec-crashdump-elf-format-dump-file-access/fs/proc/vmcore.c --- linux-2.6.11-rc1-mm1-nokexec-crashdump-routines-for-copying-dump-pages/fs/proc/vmcore.c Wed Dec 31 17:00:00 1969 +++ linux-2.6.11-rc1-mm1-nokexec-crashdump-elf-format-dump-file-access/fs/proc/vmcore.c Tue Jan 18 23:16:57 2005 @@ -0,0 +1,239 @@ +/* + * fs/proc/vmcore.c Interface for accessing the crash + * dump from the system's previous life. + * Heavily borrowed from fs/proc/kcore.c + * Created by: Hariprasad Nellitheertha (hari@in.ibm.com) + * Copyright (C) IBM Corporation, 2004. All rights reserved + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* This is to re-use the kcore header creation code */ +static struct kcore_list vmcore_mem; + +static int open_vmcore(struct inode * inode, struct file * filp) +{ + return 0; +} + +static ssize_t read_vmcore(struct file *,char __user *,size_t, loff_t *); + +#define BACKUP_START CRASH_BACKUP_BASE +#define BACKUP_END CRASH_BACKUP_BASE + CRASH_BACKUP_SIZE +#define REG_SIZE sizeof(elf_gregset_t) + +struct file_operations proc_vmcore_operations = { + .read = read_vmcore, + .open = open_vmcore, +}; + +struct proc_dir_entry *proc_vmcore; + +struct memelfnote +{ + const char *name; + int type; + unsigned int datasz; + void *data; +}; + +static size_t get_vmcore_size(int *nphdr, size_t *elf_buflen) +{ + size_t size; + + /* We need 1 PT_LOAD segment headers + * In addition, we need one PT_NOTE header + */ + *nphdr = 2; + size = (size_t)(saved_max_pfn << PAGE_SHIFT); + + *elf_buflen = sizeof(struct elfhdr) + + (*nphdr + 2)*sizeof(struct elf_phdr) + + 3 * sizeof(struct memelfnote) + + sizeof(struct elf_prstatus) + + sizeof(struct elf_prpsinfo) + + sizeof(struct task_struct); + *elf_buflen = PAGE_ALIGN(*elf_buflen); + return size + *elf_buflen; +} + +/* + * Reads a page from the oldmem device from given offset. + */ +static ssize_t read_from_oldmem(char *buf, size_t count, + loff_t *ppos, int userbuf) +{ + unsigned long pfn; + size_t read = 0; + + pfn = (unsigned long)(*ppos / PAGE_SIZE); + + if (pfn > saved_max_pfn) { + read = -EINVAL; + goto done; + } + + count = (count > PAGE_SIZE) ? PAGE_SIZE : count; + + if (copy_oldmem_page(pfn, buf, count, userbuf)) { + read = -EFAULT; + goto done; + } + + *ppos += count; +done: + return read; +} + +/* + * store an ELF crash dump header in the supplied buffer + * nphdr is the number of elf_phdr to insert + */ +static void elf_vmcore_store_hdr(char *bufp, int nphdr, int dataoff) +{ + struct elf_prstatus prstatus; /* NT_PRSTATUS */ + struct memelfnote notes[1]; + char reg_buf[REG_SIZE]; + loff_t reg_ppos; + char *buf = bufp; + + vmcore_mem.addr = (unsigned long)__va(0); + vmcore_mem.size = saved_max_pfn << PAGE_SHIFT; + vmcore_mem.next = NULL; + + /* Re-use the kcore code */ + elf_kcore_store_hdr(bufp, nphdr, dataoff, &vmcore_mem); + buf += sizeof(struct elfhdr) + 2*sizeof(struct elf_phdr); + + /* set up the process status */ + notes[0].name = "CORE"; + notes[0].type = NT_PRSTATUS; + notes[0].datasz = sizeof(struct elf_prstatus); + notes[0].data = &prstatus; + + memset(&prstatus, 0, sizeof(struct elf_prstatus)); + + /* 1 - Get the registers from the reserved memory area */ + reg_ppos = BACKUP_END + CRASH_RELOCATE_SIZE; + read_from_oldmem(reg_buf, REG_SIZE, ®_ppos, 0); + elf_core_copy_regs(&prstatus.pr_reg, (struct pt_regs *)reg_buf); + buf = storenote(¬es[0], buf); +} + +/* + * read from the ELF header and then the crash dump + */ +static ssize_t read_vmcore( +struct file *file, char __user *buffer, size_t buflen, loff_t *fpos) +{ + ssize_t acc = 0; + size_t size, tsz; + size_t elf_buflen; + int nphdr; + unsigned long start; + + tsz = get_vmcore_size(&nphdr, &elf_buflen); + proc_vmcore->size = size = tsz + elf_buflen; + if (buflen == 0 || *fpos >= size) { + goto done; + } + + /* trim buflen to not go beyond EOF */ + if (buflen > size - *fpos) + buflen = size - *fpos; + + /* construct an ELF core header if we'll need some of it */ + if (*fpos < elf_buflen) { + char * elf_buf; + + tsz = elf_buflen - *fpos; + if (buflen < tsz) + tsz = buflen; + elf_buf = kmalloc(elf_buflen, GFP_ATOMIC); + if (!elf_buf) { + acc = -ENOMEM; + goto done; + } + memset(elf_buf, 0, elf_buflen); + elf_vmcore_store_hdr(elf_buf, nphdr, elf_buflen); + if (copy_to_user(buffer, elf_buf + *fpos, tsz)) { + kfree(elf_buf); + acc = -EFAULT; + goto done; + } + kfree(elf_buf); + buflen -= tsz; + *fpos += tsz; + buffer += tsz; + acc += tsz; + + /* leave now if filled buffer already */ + if (buflen == 0) { + goto done; + } + } + + start = *fpos - elf_buflen; + if ((tsz = (PAGE_SIZE - (start & ~PAGE_MASK))) > buflen) + tsz = buflen; + + while (buflen) { + unsigned long p; + loff_t pdup; + + if ((start < 0) || (start >= size)) + if (clear_user(buffer, tsz)) { + acc = -EFAULT; + goto done; + } + + /* tsz contains actual len of dump to be read. + * buflen is the total len that was requested. + * This may contain part of ELF header. start + * is the fpos for the oldmem region + * If the file position corresponds to the second + * kernel's memory, we just return zeroes + */ + p = start; + if ((p >= BACKUP_START) && (p < BACKUP_END)) { + if (clear_user(buffer, tsz)) { + acc = -EFAULT; + goto done; + } + + goto read_done; + } else if (p < CRASH_RELOCATE_SIZE) + p += BACKUP_END; + + pdup = p; + if (read_from_oldmem(buffer, tsz, &pdup, 1)) { + acc = -EINVAL; + goto done; + } + +read_done: + buflen -= tsz; + *fpos += tsz; + buffer += tsz; + acc += tsz; + start += tsz; + tsz = (buflen > PAGE_SIZE ? PAGE_SIZE : buflen); + } + +done: + return acc; +} diff -uNr linux-2.6.11-rc1-mm1-nokexec-crashdump-routines-for-copying-dump-pages/include/linux/crash_dump.h linux-2.6.11-rc1-mm1-nokexec-crashdump-elf-format-dump-file-access/include/linux/crash_dump.h --- linux-2.6.11-rc1-mm1-nokexec-crashdump-routines-for-copying-dump-pages/include/linux/crash_dump.h Tue Jan 18 23:16:24 2005 +++ linux-2.6.11-rc1-mm1-nokexec-crashdump-elf-format-dump-file-access/include/linux/crash_dump.h Tue Jan 18 23:16:57 2005 @@ -1,10 +1,23 @@ #include #include #include +#include #ifdef CONFIG_CRASH_DUMP #include #endif +extern unsigned long saved_max_pfn; +extern struct memelfnote memelfnote; +extern int notesize(struct memelfnote *); +extern char *storenote(struct memelfnote *, char *); +extern void elf_kcore_store_hdr(char *, int, int, struct kcore_list *); + #ifdef CONFIG_CRASH_DUMP +extern struct file_operations proc_vmcore_operations; +extern struct proc_dir_entry *proc_vmcore; + +extern ssize_t copy_oldmem_page(unsigned long, char *, size_t, int); +extern void crash_create_proc_entry(void); #else +#define crash_create_proc_entry() do { } while(0) #endif - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/