From: Rachita Kothiyal This patch allocates a page to copy the previous kernel's memory before we copy it onto a user buffer using copy_to_user(), thereby taking care of the scenario of a possible page fault in an atomic context. Signed-off-by: Rachita Kothiyal Signed-off-by: Andrew Morton --- arch/i386/kernel/crash_dump.c | 39 +++++++++++++++++++++++++++++++++------ 1 files changed, 33 insertions(+), 6 deletions(-) diff -puN arch/i386/kernel/crash_dump.c~kdump-read-previous-kernels-memory-fix arch/i386/kernel/crash_dump.c --- devel/arch/i386/kernel/crash_dump.c~kdump-read-previous-kernels-memory-fix 2005-11-26 18:28:14.000000000 -0800 +++ devel-akpm/arch/i386/kernel/crash_dump.c 2005-11-26 18:28:14.000000000 -0800 @@ -11,6 +11,8 @@ #include +static void *kdump_buf_page; + /** * copy_oldmem_page - copy one page from "oldmem" * @pfn: page frame number to be copied @@ -23,6 +25,10 @@ * * Copy a page from "oldmem". For this page, there is no pte mapped * in the current kernel. We stitch up a pte, similar to kmap_atomic. + * + * Calling copy_to_user() in atomic context is not desirable. Hence first + * copying the data to a pre-allocated kernel page and then copying to user + * space in non-atomic context. */ ssize_t copy_oldmem_page(unsigned long pfn, char *buf, size_t csize, unsigned long offset, int userbuf) @@ -34,14 +40,35 @@ ssize_t copy_oldmem_page(unsigned long p vaddr = kmap_atomic_pfn(pfn, KM_PTE0); - if (userbuf) { - if (copy_to_user(buf, (vaddr + offset), csize)) { - kunmap_atomic(vaddr, KM_PTE0); + if (!userbuf) { + memcpy(buf, (vaddr + offset), csize); + kunmap_atomic(vaddr, KM_PTE0); + } else { + if (!kdump_buf_page) { + printk(KERN_WARNING "Kdump: Kdump buffer page not" + " allocated\n"); return -EFAULT; } - } else - memcpy(buf, (vaddr + offset), csize); + copy_page(kdump_buf_page, vaddr); + kunmap_atomic(vaddr, KM_PTE0); + if (copy_to_user(buf, (kdump_buf_page + offset), csize)) + return -EFAULT; + } - kunmap_atomic(vaddr, KM_PTE0); return csize; } + +static int __init kdump_buf_page_init(void) +{ + int ret = 0; + + kdump_buf_page = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!kdump_buf_page) { + printk(KERN_WARNING "Kdump: Failed to allocate kdump buffer" + " page\n"); + ret = -ENOMEM; + } + + return ret; +} +arch_initcall(kdump_buf_page_init); _