* [RHEL6.8 Patch 00/19] Support mmap() on /proc/vmcore
@ 2015-07-16 8:46 Baoquan He
2015-07-16 8:46 ` [RHEL6.8 Patch 1/3] kernel: audit/fix non-modular users of module_init in core code Baoquan He
` (22 more replies)
0 siblings, 23 replies; 24+ messages in thread
From: Baoquan He @ 2015-07-16 8:46 UTC (permalink / raw)
To: linux-kernel, ncroxon, dyoung, mhuang; +Cc: Baoquan He
This patchset includes 3 parts.
-------------------------------------
1st part:
Includes 13 upstream commits. They are recommended by Nigel Croxon
since he back ported this feature to rhel7. This 13 back ports
works for all ARCHs except of s390 since it always broke s390n kdump.
c2c1b08 fs/proc/vmcore.c: put if tests in the top of the while loop to reduce duplication
0fa73b8 include/linux/mm.h: add PAGE_ALIGNED() helper
b27eb18 vmcore: clean up read_vmcore()
f2bdacd vmcore: allocate buffer for ELF headers on page-size alignment
7f614cd vmcore: treat memory chunks referenced by PT_LOAD program header entries in page-size boundary in vmcore_list
cef2ac3 vmalloc: make find_vm_area check in range
e69e9d4a vmalloc: introduce remap_vmalloc_range_partial
087350c vmcore: allocate ELF note segment in the 2nd kernel vmalloc memory
ef9e78f vmcore: allow user process to remap ELF note segment buffer
591ff71 vmcore: calculate vmcore file size from buffer size and total size of vmcore objects
8308697 vmcore: support mmap() on /proc/vmcore
5a74953 s390/kdump: Disable mmap for s390
0692ded fs/proc/vmcore.c:mmap_vmcore: skip non-ram pages reported by hypervisors
-------------------------------------
2nd part:
Includes several s390 related memory commits. Since these 13 commits
in 1st part worked on all ARCHs except of S390. Then I asked IBM
S390 kernel developers Michael Holzheu <michael.holzheu@de.ibm.com>,
Jan Willeke <WILLEKE@de.ibm.com> to help, they suggested these 3 commits.
With them it works for s390 kdump.
191a2fa s390/kdump: Allow copy_oldmem_page() copy to virtual memory"
9cb2181 vmcore: introduce remap_oldmem_pfn_range()"
23df79d s390/vmcore: implement remap_oldmem_pfn_range for s390"
-------------------------------------
3rd part:
Includes 3 commits. They are back ported because 3 commits in
2nd part will fail x86 and ppc compiling.
997c136 fs/proc/vmcore.c: add hook to read_from_oldmem() to check for non-ram pages
816422a asm-generic, mm: pgtable: consolidate zero page helpers
238ec4e [S390] zero page cache synonyms
Brew build:
I made a brew build here and tested it on s390 and x86 machine,
both works.
https://brewweb.devel.redhat.com/taskinfo?taskID=9357037
Then Nigel took patches from my rh-git and made a brew build as below.
Lisa from HP took a test and confirmed this works on HP machines
and it improved the dump as expected.
https://brewweb.devel.redhat.com/taskinfo?taskID=9380805
My rh-git for this feature is here:
git://git.engineering.redhat.com/users/bhe/rhel6/.git mmap-new
Baoquan He (19):
[S390] zero page cache synonyms
asm-generic, mm: pgtable: consolidate zero page helpers
fs/proc/vmcore.c: add hook to read_from_oldmem() to check for non-ram
pages
fs/proc/vmcore.c: put if tests in the top of the while loop to reduce
duplication
include/linux/mm.h: add PAGE_ALIGNED() helper
vmcore: clean up read_vmcore()
vmcore: allocate buffer for ELF headers on page-size alignment
vmcore: treat memory chunks referenced by PT_LOAD program header
entries in page-size boundary in vmcore_list
vmalloc: make find_vm_area check in range
vmalloc: introduce remap_vmalloc_range_partial
vmcore: allocate ELF note segment in the 2nd kernel vmalloc memory
vmcore: allow user process to remap ELF note segment buffer
vmcore: calculate vmcore file size from buffer size and total size of
vmcore objects
vmcore: support mmap() on /proc/vmcore
s390/kdump: Disable mmap for s390
s390/kdump: Allow copy_oldmem_page() copy to virtual memory
vmcore: introduce remap_oldmem_pfn_range()
s390/vmcore: implement remap_oldmem_pfn_range for s390
fs/proc/vmcore.c:mmap_vmcore: skip non-ram pages reported by
hypervisors
arch/mips/include/asm/pgtable.h | 10 +-
arch/s390/include/asm/pgtable.h | 14 +-
arch/s390/kernel/crash_dump.c | 75 +++-
arch/s390/mm/init.c | 49 ++-
fs/proc/vmcore.c | 899 ++++++++++++++++++++++++++++++----------
include/asm-generic/pgtable.h | 26 ++
include/linux/crash_dump.h | 9 +
include/linux/mm.h | 3 +
include/linux/vmalloc.h | 4 +
mm/memory.c | 14 -
mm/vmalloc.c | 70 +++-
11 files changed, 901 insertions(+), 272 deletions(-)
--
2.1.0
^ permalink raw reply [flat|nested] 24+ messages in thread
* [RHEL6.8 Patch 1/3] kernel: audit/fix non-modular users of module_init in core code
2015-07-16 8:46 [RHEL6.8 Patch 00/19] Support mmap() on /proc/vmcore Baoquan He
@ 2015-07-16 8:46 ` Baoquan He
2015-07-16 8:46 ` [RHEL6.8 Patch 01/19] [S390] zero page cache synonyms Baoquan He
` (21 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Baoquan He @ 2015-07-16 8:46 UTC (permalink / raw)
To: linux-kernel, ncroxon, dyoung, mhuang; +Cc: Baoquan He
Resolves: bz1236437
https://bugzilla.redhat.com/show_bug.cgi?id=1236437
Brew build:
https://brewweb.devel.redhat.com/taskinfo?taskID=9499237
This is back ported from upstream partionly.
The crash_notes data resides in the percpu in the first kernel.
While percpu use vmalloc to allocate by default. So if many percpu
data is needed it will cause crash_notes data crosses the page boundary.
When the second kernel tries to access this data using the physical
memory address, it sees incorrect data after crossing the page boundary.
In this patch kexec initialization from the 'device' phase to
'the 'subsys' phase. This can prevent crash_notes being allocated in
2 vmalloc pages.
commit c96d6660dc65b0a90aea9834bfd8be1d5656da18
Author: Paul Gortmaker <paul.gortmaker@windriver.com>
Date: Thu Apr 3 14:48:35 2014 -0700
kernel: audit/fix non-modular users of module_init in core code
Code that is obj-y (always built-in) or dependent on a bool Kconfig
(built-in or absent) can never be modular. So using module_init as an
alias for __initcall can be somewhat misleading.
Fix these up now, so that we can relocate module_init from init.h into
module.h in the future. If we don't do this, we'd have to add module.h
to obviously non-modular code, and that would be a worse thing.
The audit targets the following module_init users for change:
kernel/user.c obj-y
kernel/kexec.c bool KEXEC (one instance per arch)
kernel/profile.c bool PROFILING
kernel/hung_task.c bool DETECT_HUNG_TASK
kernel/sched/stats.c bool SCHEDSTATS
kernel/user_namespace.c bool USER_NS
Note that direct use of __initcall is discouraged, vs. one of the
priority categorized subgroups. As __initcall gets mapped onto
device_initcall, our use of subsys_initcall (which makes sense for these
files) will thus change this registration from level 6-device to level
4-subsys (i.e. slightly earlier). However no observable impact of that
difference has been observed during testing.
Also, two instances of missing ";" at EOL are fixed in kexec.
Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Eric Biederman <ebiederm@xmission.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Baoquan He <bhe@redhat.com>
---
kernel/kexec.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kernel/kexec.c b/kernel/kexec.c
index d977250..779f803 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -1246,7 +1246,7 @@ static int __init crash_notes_memory_init(void)
}
return 0;
}
-module_init(crash_notes_memory_init)
+subsys_initcall(crash_notes_memory_init);
/*
--
2.1.0
^ permalink raw reply [flat|nested] 24+ messages in thread
* [RHEL6.8 Patch 01/19] [S390] zero page cache synonyms
2015-07-16 8:46 [RHEL6.8 Patch 00/19] Support mmap() on /proc/vmcore Baoquan He
2015-07-16 8:46 ` [RHEL6.8 Patch 1/3] kernel: audit/fix non-modular users of module_init in core code Baoquan He
@ 2015-07-16 8:46 ` Baoquan He
2015-07-16 8:46 ` [RHEL6.8 Patch 02/19] asm-generic, mm: pgtable: consolidate zero page helpers Baoquan He
` (20 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Baoquan He @ 2015-07-16 8:46 UTC (permalink / raw)
To: linux-kernel, ncroxon, dyoung, mhuang; +Cc: Baoquan He
Resolves: bz1097904
https://bugzilla.redhat.com/show_bug.cgi?id=1097904
This is back ported from upstream.
commit 238ec4efeee4461d5cff2ed3e5a15a3ab850959b
Author: Martin Schwidefsky <schwidefsky@de.ibm.com>
Date: Mon Oct 25 16:10:07 2010 +0200
[S390] zero page cache synonyms
If the zero page is mapped to virtual user space addresses that differ
only in bit 2^12 or 2^13 we get L1 cache synonyms which can affect
performance. Follow the mips model and use multiple zero pages to avoid
the synonyms.
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Baoquan He <bhe@redhat.com>
---
arch/s390/include/asm/pgtable.h | 22 +++++++++++++++---
arch/s390/mm/init.c | 49 +++++++++++++++++++++++++++++++++++++----
2 files changed, 64 insertions(+), 7 deletions(-)
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index b3d2d66..a66fddf 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -46,11 +46,27 @@ extern void vmem_map_init(void);
#define update_mmu_cache(vma, address, pte) do { } while (0)
/*
- * ZERO_PAGE is a global shared page that is always zero: used
+ * ZERO_PAGE is a global shared page that is always zero; used
* for zero-mapped memory areas etc..
*/
-extern char empty_zero_page[PAGE_SIZE];
-#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
+
+extern unsigned long empty_zero_page;
+extern unsigned long zero_page_mask;
+
+#define ZERO_PAGE(vaddr) \
+ (virt_to_page((void *)(empty_zero_page + \
+ (((unsigned long)(vaddr)) &zero_page_mask))))
+
+#define is_zero_pfn is_zero_pfn
+static inline int is_zero_pfn(unsigned long pfn)
+{
+ extern unsigned long zero_pfn;
+ unsigned long offset_from_zero_pfn = pfn - zero_pfn;
+ return offset_from_zero_pfn <= (zero_page_mask >> PAGE_SHIFT);
+}
+
+#define my_zero_pfn(addr) page_to_pfn(ZERO_PAGE(addr))
+
#endif /* !__ASSEMBLY__ */
/*
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c
index a745dba2..d498dda 100644
--- a/arch/s390/mm/init.c
+++ b/arch/s390/mm/init.c
@@ -41,9 +41,52 @@ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE)));
-char empty_zero_page[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
+unsigned long empty_zero_page, zero_page_mask;
EXPORT_SYMBOL(empty_zero_page);
+static unsigned long setup_zero_pages(void)
+{
+ struct cpuid cpu_id;
+ unsigned int order;
+ unsigned long size;
+ struct page *page;
+ int i;
+
+ get_cpu_id(&cpu_id);
+ switch (cpu_id.machine) {
+ case 0x9672: /* g5 */
+ case 0x2064: /* z900 */
+ case 0x2066: /* z900 */
+ case 0x2084: /* z990 */
+ case 0x2086: /* z990 */
+ case 0x2094: /* z9-109 */
+ case 0x2096: /* z9-109 */
+ order = 0;
+ break;
+ case 0x2097: /* z10 */
+ case 0x2098: /* z10 */
+ default:
+ order = 2;
+ break;
+ }
+
+ empty_zero_page = __get_free_pages(GFP_KERNEL | __GFP_ZERO, order);
+ if (!empty_zero_page)
+ panic("Out of memory in setup_zero_pages");
+
+ page = virt_to_page((void *) empty_zero_page);
+ split_page(page, order);
+ for (i = 1 << order; i > 0; i--) {
+ SetPageReserved(page);
+ page++;
+ }
+
+ size = PAGE_SIZE << order;
+ zero_page_mask = (size - 1) & PAGE_MASK;
+
+ return 1UL << order;
+}
+
/*
* paging_init() sets up the page tables
*/
@@ -96,14 +139,12 @@ void __init mem_init(void)
max_mapnr = num_physpages = max_low_pfn;
high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
- /* clear the zero-page */
- memset(empty_zero_page, 0, PAGE_SIZE);
-
/* Setup guest page hinting */
cmma_init();
/* this will put all low memory onto the freelists */
totalram_pages += free_all_bootmem();
+ totalram_pages -= setup_zero_pages(); /* Setup zeroed pages. */
reservedpages = 0;
--
2.1.0
^ permalink raw reply [flat|nested] 24+ messages in thread
* [RHEL6.8 Patch 02/19] asm-generic, mm: pgtable: consolidate zero page helpers
2015-07-16 8:46 [RHEL6.8 Patch 00/19] Support mmap() on /proc/vmcore Baoquan He
2015-07-16 8:46 ` [RHEL6.8 Patch 1/3] kernel: audit/fix non-modular users of module_init in core code Baoquan He
2015-07-16 8:46 ` [RHEL6.8 Patch 01/19] [S390] zero page cache synonyms Baoquan He
@ 2015-07-16 8:46 ` Baoquan He
2015-07-16 8:46 ` [RHEL6.8 Patch 2/3] vmcore: prevent PT_NOTE p_memsz overflow during header update Baoquan He
` (19 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Baoquan He @ 2015-07-16 8:46 UTC (permalink / raw)
To: linux-kernel, ncroxon, dyoung, mhuang; +Cc: Baoquan He
Resolves: bz1097904
https://bugzilla.redhat.com/show_bug.cgi?id=1097904
This is back ported from upstream. There are conflicts in
arch/s390/include/asm/pgtable.h.
commit 816422ad76474fed8052b6f7b905a054d082e59a
Author: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Date: Wed Dec 12 13:52:36 2012 -0800
asm-generic, mm: pgtable: consolidate zero page helpers
We have two different implementation of is_zero_pfn() and my_zero_pfn()
helpers: for architectures with and without zero page coloring.
Let's consolidate them in <asm-generic/pgtable.h>.
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Baoquan He <bhe@redhat.com>
---
arch/mips/include/asm/pgtable.h | 10 +---------
arch/s390/include/asm/pgtable.h | 10 +---------
include/asm-generic/pgtable.h | 26 ++++++++++++++++++++++++++
mm/memory.c | 14 --------------
4 files changed, 28 insertions(+), 32 deletions(-)
diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h
index d6eb613..847edf2 100644
--- a/arch/mips/include/asm/pgtable.h
+++ b/arch/mips/include/asm/pgtable.h
@@ -76,15 +76,7 @@ extern unsigned long zero_page_mask;
#define ZERO_PAGE(vaddr) \
(virt_to_page((void *)(empty_zero_page + (((unsigned long)(vaddr)) & zero_page_mask))))
-#define is_zero_pfn is_zero_pfn
-static inline int is_zero_pfn(unsigned long pfn)
-{
- extern unsigned long zero_pfn;
- unsigned long offset_from_zero_pfn = pfn - zero_pfn;
- return offset_from_zero_pfn <= (zero_page_mask >> PAGE_SHIFT);
-}
-
-#define my_zero_pfn(addr) page_to_pfn(ZERO_PAGE(addr))
+#define __HAVE_COLOR_ZERO_PAGE
extern void paging_init(void);
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index a66fddf..ab7e604 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -57,15 +57,7 @@ extern unsigned long zero_page_mask;
(virt_to_page((void *)(empty_zero_page + \
(((unsigned long)(vaddr)) &zero_page_mask))))
-#define is_zero_pfn is_zero_pfn
-static inline int is_zero_pfn(unsigned long pfn)
-{
- extern unsigned long zero_pfn;
- unsigned long offset_from_zero_pfn = pfn - zero_pfn;
- return offset_from_zero_pfn <= (zero_page_mask >> PAGE_SHIFT);
-}
-
-#define my_zero_pfn(addr) page_to_pfn(ZERO_PAGE(addr))
+#define __HAVE_COLOR_ZERO_PAGE
#endif /* !__ASSEMBLY__ */
diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h
index 5122ec9..78f3f2f 100644
--- a/include/asm-generic/pgtable.h
+++ b/include/asm-generic/pgtable.h
@@ -471,6 +471,32 @@ extern void untrack_pfn_vma(struct vm_area_struct *vma, unsigned long pfn,
unsigned long size);
#endif
+#ifdef __HAVE_COLOR_ZERO_PAGE
+static inline int is_zero_pfn(unsigned long pfn)
+{
+ extern unsigned long zero_pfn;
+ unsigned long offset_from_zero_pfn = pfn - zero_pfn;
+ return offset_from_zero_pfn <= (zero_page_mask >> PAGE_SHIFT);
+}
+
+static inline unsigned long my_zero_pfn(unsigned long addr)
+{
+ return page_to_pfn(ZERO_PAGE(addr));
+}
+#else
+static inline int is_zero_pfn(unsigned long pfn)
+{
+ extern unsigned long zero_pfn;
+ return pfn == zero_pfn;
+}
+
+static inline unsigned long my_zero_pfn(unsigned long addr)
+{
+ extern unsigned long zero_pfn;
+ return zero_pfn;
+}
+#endif
+
#ifndef CONFIG_TRANSPARENT_HUGEPAGE
#define pmd_trans_huge(pmd) 0
#define pmd_trans_splitting(pmd) (0)
diff --git a/mm/memory.c b/mm/memory.c
index d94cae4..89daff0 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -468,20 +468,6 @@ static inline int is_cow_mapping(unsigned int flags)
return (flags & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE;
}
-#ifndef is_zero_pfn
-static inline int is_zero_pfn(unsigned long pfn)
-{
- return pfn == zero_pfn;
-}
-#endif
-
-#ifndef my_zero_pfn
-static inline unsigned long my_zero_pfn(unsigned long addr)
-{
- return zero_pfn;
-}
-#endif
-
/*
* vm_normal_page -- This function gets the "struct page" associated with a pte.
*
--
2.1.0
^ permalink raw reply [flat|nested] 24+ messages in thread
* [RHEL6.8 Patch 2/3] vmcore: prevent PT_NOTE p_memsz overflow during header update
2015-07-16 8:46 [RHEL6.8 Patch 00/19] Support mmap() on /proc/vmcore Baoquan He
` (2 preceding siblings ...)
2015-07-16 8:46 ` [RHEL6.8 Patch 02/19] asm-generic, mm: pgtable: consolidate zero page helpers Baoquan He
@ 2015-07-16 8:46 ` Baoquan He
2015-07-16 8:47 ` [RHEL6.8 Patch 03/19] fs/proc/vmcore.c: add hook to read_from_oldmem() to check for non-ram pages Baoquan He
` (18 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Baoquan He @ 2015-07-16 8:46 UTC (permalink / raw)
To: linux-kernel, ncroxon, dyoung, mhuang; +Cc: Baoquan He
Resolves: bz1236437
https://bugzilla.redhat.com/show_bug.cgi?id=1236437
Brew build:
https://brewweb.devel.redhat.com/taskinfo?taskID=9499237
This is back ported from upstream. Conflicts existed since there's no
update_note_header_size_elf64 yet in rhel6.
In commit 087350c9dcf1b38c597b31d7761f7366e2866e6b the notes size adding
in "for loop" is changed to "while loop". In this patch only this code
snippet is back ported since it can make later back port easier.
commit 38dfac843cb6d7be1874888839817404a15a6b3c
Author: Greg Pearson <greg.pearson@hp.com>
Date: Mon Feb 10 14:25:36 2014 -0800
vmcore: prevent PT_NOTE p_memsz overflow during header update
Currently, update_note_header_size_elf64() and
update_note_header_size_elf32() will add the size of a PT_NOTE entry to
real_sz even if that causes real_sz to exceeds max_sz. This patch
corrects the while loop logic in those routines to ensure that does not
happen and prints a warning if a PT_NOTE entry is dropped. If zero
PT_NOTE entries are found or this condition is encountered because the
only entry was dropped, a warning is printed and an error is returned.
One possible negative side effect of exceeding the max_sz limit is an
allocation failure in merge_note_headers_elf64() or
merge_note_headers_elf32() which would produce console output such as
the following while booting the crash kernel.
vmalloc: allocation failure: 14076997632 bytes
swapper/0: page allocation failure: order:0, mode:0x80d2
CPU: 0 PID: 1 Comm: swapper/0 Not tainted 3.10.0-gbp1 #7
Call Trace:
dump_stack+0x19/0x1b
warn_alloc_failed+0xf0/0x160
__vmalloc_node_range+0x19e/0x250
vmalloc_user+0x4c/0x70
merge_note_headers_elf64.constprop.9+0x116/0x24a
vmcore_init+0x2d4/0x76c
do_one_initcall+0xe2/0x190
kernel_init_freeable+0x17c/0x207
kernel_init+0xe/0x180
ret_from_fork+0x7c/0xb0
Kdump: vmcore not initialized
kdump: dump target is /dev/sda4
kdump: saving to /sysroot//var/crash/127.0.0.1-2014.01.28-13:58:52/
kdump: saving vmcore-dmesg.txt
Cannot open /proc/vmcore: No such file or directory
kdump: saving vmcore-dmesg.txt failed
kdump: saving vmcore
kdump: saving vmcore failed
This type of failure has been seen on a four socket prototype system
with certain memory configurations. Most PT_NOTE sections have a single
entry similar to:
n_namesz = 0x5
n_descsz = 0x150
n_type = 0x1
Occasionally, a second entry is encountered with very large n_namesz and
n_descsz sizes:
n_namesz = 0x80000008
n_descsz = 0x510ae163
n_type = 0x80000008
Not yet sure of the source of these extra entries, they seem bogus, but
they shouldn't cause crash dump to fail.
Signed-off-by: Greg Pearson <greg.pearson@hp.com>
Acked-by: Vivek Goyal <vgoyal@redhat.com>
Cc: HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com>
Cc: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Baoquan He <bhe@redhat.com>
---
fs/proc/vmcore.c | 29 +++++++++++++++++++++--------
1 file changed, 21 insertions(+), 8 deletions(-)
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c
index b53862a..97c950b 100644
--- a/fs/proc/vmcore.c
+++ b/fs/proc/vmcore.c
@@ -217,7 +217,6 @@ static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz,
ehdr_ptr = (Elf64_Ehdr *)elfptr;
phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr));
for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
- int j;
void *notes_section;
struct vmcore *new;
u64 offset, max_sz, sz, real_sz = 0;
@@ -235,12 +234,15 @@ static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz,
return rc;
}
nhdr_ptr = notes_section;
- for (j = 0; j < max_sz; j += sz) {
- if (nhdr_ptr->n_namesz == 0)
- break;
+ while (nhdr_ptr->n_namesz != 0) {
sz = sizeof(Elf64_Nhdr) +
((nhdr_ptr->n_namesz + 3) & ~3) +
((nhdr_ptr->n_descsz + 3) & ~3);
+ if ((real_sz + sz) > max_sz) {
+ pr_warn("Warning: Exceeded p_memsz, dropping PT_NOTE entry n_namesz=0x%x, n_descsz=0x%x\n",
+ nhdr_ptr->n_namesz, nhdr_ptr->n_descsz);
+ break;
+ }
real_sz += sz;
nhdr_ptr = (Elf64_Nhdr*)((char*)nhdr_ptr + sz);
}
@@ -256,6 +258,10 @@ static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz,
list_add_tail(&new->list, vc_list);
phdr_sz += real_sz;
kfree(notes_section);
+ if (real_sz == 0) {
+ pr_warn("Warning: Zero PT_NOTE entries found\n");
+ return -EINVAL;
+ }
}
/* Prepare merged PT_NOTE program header. */
@@ -298,7 +304,6 @@ static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz,
ehdr_ptr = (Elf32_Ehdr *)elfptr;
phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr));
for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
- int j;
void *notes_section;
struct vmcore *new;
u64 offset, max_sz, sz, real_sz = 0;
@@ -316,12 +321,15 @@ static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz,
return rc;
}
nhdr_ptr = notes_section;
- for (j = 0; j < max_sz; j += sz) {
- if (nhdr_ptr->n_namesz == 0)
- break;
+ while (nhdr_ptr->n_namesz != 0) {
sz = sizeof(Elf32_Nhdr) +
((nhdr_ptr->n_namesz + 3) & ~3) +
((nhdr_ptr->n_descsz + 3) & ~3);
+ if ((real_sz + sz) > max_sz) {
+ pr_warn("Warning: Exceeded p_memsz, dropping PT_NOTE entry n_namesz=0x%x, n_descsz=0x%x\n",
+ nhdr_ptr->n_namesz, nhdr_ptr->n_descsz);
+ break;
+ }
real_sz += sz;
nhdr_ptr = (Elf32_Nhdr*)((char*)nhdr_ptr + sz);
}
@@ -337,6 +345,11 @@ static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz,
list_add_tail(&new->list, vc_list);
phdr_sz += real_sz;
kfree(notes_section);
+ if (real_sz == 0) {
+ pr_warn("Warning: Zero PT_NOTE entries found\n");
+ return -EINVAL;
+ }
+
}
/* Prepare merged PT_NOTE program header. */
--
2.1.0
^ permalink raw reply [flat|nested] 24+ messages in thread
* [RHEL6.8 Patch 03/19] fs/proc/vmcore.c: add hook to read_from_oldmem() to check for non-ram pages
2015-07-16 8:46 [RHEL6.8 Patch 00/19] Support mmap() on /proc/vmcore Baoquan He
` (3 preceding siblings ...)
2015-07-16 8:46 ` [RHEL6.8 Patch 2/3] vmcore: prevent PT_NOTE p_memsz overflow during header update Baoquan He
@ 2015-07-16 8:47 ` Baoquan He
2015-07-16 8:47 ` [RHEL6.8 Patch 3/3] vmcore: continue vmcore initialization if PT_NOTE is found empty Baoquan He
` (17 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Baoquan He @ 2015-07-16 8:47 UTC (permalink / raw)
To: linux-kernel, ncroxon, dyoung, mhuang; +Cc: Baoquan He
Resolves: bz1097904
https://bugzilla.redhat.com/show_bug.cgi?id=1097904
This is back ported from upstream directly.
commit 997c136f518c5debd63847e78e2a8694f56dcf90
Author: Olaf Hering <olaf@aepfle.de>
Date: Thu May 26 16:25:54 2011 -0700
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>
Signed-off-by: Baoquan He <bhe@redhat.com>
---
fs/proc/vmcore.c | 52 +++++++++++++++++++++++++++++++++++++++++++---
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 b53862a..ce23082 100644
--- a/fs/proc/vmcore.c
+++ b/fs/proc/vmcore.c
@@ -34,6 +34,46 @@ static u64 vmcore_size;
static struct proc_dir_entry *proc_vmcore = NULL;
+/*
+ * Returns > 0 for RAM pages, 0 for non-RAM pages, < 0 on error
+ * The called function has to take care of module refcounting.
+ */
+static int (*oldmem_pfn_is_ram)(unsigned long pfn);
+
+int register_oldmem_pfn_is_ram(int (*fn)(unsigned long pfn))
+{
+ if (oldmem_pfn_is_ram)
+ return -EBUSY;
+ oldmem_pfn_is_ram = fn;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(register_oldmem_pfn_is_ram);
+
+void unregister_oldmem_pfn_is_ram(void)
+{
+ oldmem_pfn_is_ram = NULL;
+ wmb();
+}
+EXPORT_SYMBOL_GPL(unregister_oldmem_pfn_is_ram);
+
+static int pfn_is_ram(unsigned long pfn)
+{
+ int (*fn)(unsigned long pfn);
+ /* pfn is ram unless fn() checks pagetype */
+ int ret = 1;
+
+ /*
+ * Ask hypervisor if the pfn is really ram.
+ * A ballooned page contains no data and reading from such a page
+ * will cause high load in the hypervisor.
+ */
+ fn = oldmem_pfn_is_ram;
+ if (fn)
+ ret = fn(pfn);
+
+ return ret;
+}
+
/* Reads a page from the oldmem device from given offset. */
static ssize_t read_from_oldmem(char *buf, size_t count,
u64 *ppos, int userbuf)
@@ -54,9 +94,15 @@ static ssize_t read_from_oldmem(char *buf, size_t count,
else
nr_bytes = count;
- tmp = copy_oldmem_page(pfn, buf, nr_bytes, offset, userbuf);
- if (tmp < 0)
- return tmp;
+ /* If pfn is not ram, return zeros for sparse dump files */
+ if (pfn_is_ram(pfn) == 0)
+ memset(buf, 0, nr_bytes);
+ else {
+ tmp = copy_oldmem_page(pfn, buf, nr_bytes,
+ offset, userbuf);
+ if (tmp < 0)
+ return tmp;
+ }
*ppos += nr_bytes;
count -= nr_bytes;
buf += nr_bytes;
diff --git a/include/linux/crash_dump.h b/include/linux/crash_dump.h
index 0026f26..6719454 100644
--- a/include/linux/crash_dump.h
+++ b/include/linux/crash_dump.h
@@ -59,6 +59,11 @@ static inline void vmcore_unusable(void)
if (is_kdump_kernel())
elfcorehdr_addr = ELFCORE_ADDR_ERR;
}
+
+#define HAVE_OLDMEM_PFN_IS_RAM 1
+extern int register_oldmem_pfn_is_ram(int (*fn)(unsigned long pfn));
+extern void unregister_oldmem_pfn_is_ram(void);
+
#else /* !CONFIG_CRASH_DUMP */
static inline int is_kdump_kernel(void) { return 0; }
#endif /* CONFIG_CRASH_DUMP */
--
2.1.0
^ permalink raw reply [flat|nested] 24+ messages in thread
* [RHEL6.8 Patch 3/3] vmcore: continue vmcore initialization if PT_NOTE is found empty
2015-07-16 8:46 [RHEL6.8 Patch 00/19] Support mmap() on /proc/vmcore Baoquan He
` (4 preceding siblings ...)
2015-07-16 8:47 ` [RHEL6.8 Patch 03/19] fs/proc/vmcore.c: add hook to read_from_oldmem() to check for non-ram pages Baoquan He
@ 2015-07-16 8:47 ` Baoquan He
2015-07-16 8:47 ` [RHEL6.8 Patch 04/19] fs/proc/vmcore.c: put if tests in the top of the while loop to reduce duplication Baoquan He
` (16 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Baoquan He @ 2015-07-16 8:47 UTC (permalink / raw)
To: linux-kernel, ncroxon, dyoung, mhuang; +Cc: Baoquan He
Resolves: bz1236437
https://bugzilla.redhat.com/show_bug.cgi?id=1236437
Brew build:
https://brewweb.devel.redhat.com/taskinfo?taskID=9499237
This is back ported from upstream. This commit relies on commit
"vmcore: prevent PT_NOTE p_memsz overflow during header update".
commit c4082f36fa3eeb5d4fadc50241b6e3a388561f80
Author: WANG Chao <chaowang@redhat.com>
Date: Mon Apr 7 15:38:51 2014 -0700
vmcore: continue vmcore initialization if PT_NOTE is found empty
Currently when an empty PT_NOTE is detected, vmcore initialization
fails. It sounds too harsh. Because PT_NOTE could be empty, for
example, one offlined a cpu but never restarted kdump service, and after
crash, PT_NOTE program header is there but no data contains. It's
better to warn about the empty PT_NOTE and continue to initialise
vmcore.
And ultimately the multiple PT_NOTE are merged into a single one, all
empty PT_NOTE are discarded naturally during the merge. So empty
PT_NOTE is not visible to user space and vmcore is as good as expected.
Signed-off-by: WANG Chao <chaowang@redhat.com>
Cc: Vivek Goyal <vgoyal@redhat.com>
Cc: HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com>
Cc: Greg Pearson <greg.pearson@hp.com>
Cc: Baoquan He <bhe@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Baoquan He <bhe@redhat.com>
---
fs/proc/vmcore.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c
index 97c950b..ecc7604 100644
--- a/fs/proc/vmcore.c
+++ b/fs/proc/vmcore.c
@@ -260,7 +260,6 @@ static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz,
kfree(notes_section);
if (real_sz == 0) {
pr_warn("Warning: Zero PT_NOTE entries found\n");
- return -EINVAL;
}
}
@@ -347,7 +346,6 @@ static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz,
kfree(notes_section);
if (real_sz == 0) {
pr_warn("Warning: Zero PT_NOTE entries found\n");
- return -EINVAL;
}
}
--
2.1.0
^ permalink raw reply [flat|nested] 24+ messages in thread
* [RHEL6.8 Patch 04/19] fs/proc/vmcore.c: put if tests in the top of the while loop to reduce duplication
2015-07-16 8:46 [RHEL6.8 Patch 00/19] Support mmap() on /proc/vmcore Baoquan He
` (5 preceding siblings ...)
2015-07-16 8:47 ` [RHEL6.8 Patch 3/3] vmcore: continue vmcore initialization if PT_NOTE is found empty Baoquan He
@ 2015-07-16 8:47 ` Baoquan He
2015-07-16 8:47 ` [RHEL6.8 Patch 05/19] include/linux/mm.h: add PAGE_ALIGNED() helper Baoquan He
` (15 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Baoquan He @ 2015-07-16 8:47 UTC (permalink / raw)
To: linux-kernel, ncroxon, dyoung, mhuang; +Cc: Baoquan He
Resolves: bz1097904
https://bugzilla.redhat.com/show_bug.cgi?id=1097904
This is back ported from upstream directly.
commit c2c1b089b44b783bd50fae4bccaa6f367f92e492
Author: Zhang Yanfei <zhangyanfei@cn.fujitsu.com>
Date: Wed Feb 27 17:03:17 2013 -0800
fs/proc/vmcore.c: put if tests in the top of the while loop to reduce duplication
In read_vmcore() two `if' tests are duplicated. Change the position of
them could reduce the duplication. This change does not affect the
behaviour of the function.
[akpm@linux-foundation.org: avoid `if (foo = bar)' thing, use min_t()]
[akpm@linux-foundation.org: s/max_t/min_t/]
Signed-off-by: Zhang Yanfei <zhangyanfei@cn.fujitsu.com>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Baoquan He <bhe@redhat.com>
---
fs/proc/vmcore.c | 20 +++++++-------------
1 file changed, 7 insertions(+), 13 deletions(-)
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c
index ce23082..1def40a 100644
--- a/fs/proc/vmcore.c
+++ b/fs/proc/vmcore.c
@@ -173,15 +173,15 @@ static ssize_t read_vmcore(struct file *file, char __user *buffer,
start = map_offset_to_paddr(*fpos, &vmcore_list, &curr_m);
if (!curr_m)
return -EINVAL;
- if ((tsz = (PAGE_SIZE - (start & ~PAGE_MASK))) > buflen)
- tsz = buflen;
-
- /* Calculate left bytes in current memory segment. */
- nr_bytes = (curr_m->size - (start - curr_m->paddr));
- if (tsz > nr_bytes)
- tsz = nr_bytes;
while (buflen) {
+ tsz = min_t(size_t, buflen, PAGE_SIZE - (start & ~PAGE_MASK));
+
+ /* Calculate left bytes in current memory segment. */
+ nr_bytes = (curr_m->size - (start - curr_m->paddr));
+ if (tsz > nr_bytes)
+ tsz = nr_bytes;
+
tmp = read_from_oldmem(buffer, tsz, &start, 1);
if (tmp < 0)
return tmp;
@@ -196,12 +196,6 @@ static ssize_t read_vmcore(struct file *file, char __user *buffer,
struct vmcore, list);
start = curr_m->paddr;
}
- if ((tsz = (PAGE_SIZE - (start & ~PAGE_MASK))) > buflen)
- tsz = buflen;
- /* Calculate left bytes in current memory segment. */
- nr_bytes = (curr_m->size - (start - curr_m->paddr));
- if (tsz > nr_bytes)
- tsz = nr_bytes;
}
return acc;
}
--
2.1.0
^ permalink raw reply [flat|nested] 24+ messages in thread
* [RHEL6.8 Patch 05/19] include/linux/mm.h: add PAGE_ALIGNED() helper
2015-07-16 8:46 [RHEL6.8 Patch 00/19] Support mmap() on /proc/vmcore Baoquan He
` (6 preceding siblings ...)
2015-07-16 8:47 ` [RHEL6.8 Patch 04/19] fs/proc/vmcore.c: put if tests in the top of the while loop to reduce duplication Baoquan He
@ 2015-07-16 8:47 ` Baoquan He
2015-07-16 8:47 ` [RHEL6.8 Patch 06/19] vmcore: clean up read_vmcore() Baoquan He
` (14 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Baoquan He @ 2015-07-16 8:47 UTC (permalink / raw)
To: linux-kernel, ncroxon, dyoung, mhuang; +Cc: Baoquan He
Resolves: bz1097904
https://bugzilla.redhat.com/show_bug.cgi?id=1097904
This is back ported from upstream directly.
commit 0fa73b86ef0797ca4fde5334117ca0b330f08030
Author: Andrew Morton <akpm@linux-foundation.org>
Date: Wed Jul 3 15:02:11 2013 -0700
include/linux/mm.h: add PAGE_ALIGNED() helper
To test whether an address is aligned to PAGE_SIZE.
Cc: HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>,
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Baoquan He <bhe@redhat.com>
---
include/linux/mm.h | 3 +++
1 file changed, 3 insertions(+)
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 21c2c99..8d490e0 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -55,6 +55,9 @@ extern int overcommit_kbytes_handler(struct ctl_table *, int, void __user *,
/* to align the pointer to the (next) page boundary */
#define PAGE_ALIGN(addr) ALIGN(addr, PAGE_SIZE)
+/* test whether an address (unsigned long or pointer) is aligned to PAGE_SIZE */
+#define PAGE_ALIGNED(addr) IS_ALIGNED((unsigned long)addr, PAGE_SIZE)
+
/*
* Linux kernel virtual memory manager primitives.
* The idea being to have a "virtual" mm in the same way
--
2.1.0
^ permalink raw reply [flat|nested] 24+ messages in thread
* [RHEL6.8 Patch 06/19] vmcore: clean up read_vmcore()
2015-07-16 8:46 [RHEL6.8 Patch 00/19] Support mmap() on /proc/vmcore Baoquan He
` (7 preceding siblings ...)
2015-07-16 8:47 ` [RHEL6.8 Patch 05/19] include/linux/mm.h: add PAGE_ALIGNED() helper Baoquan He
@ 2015-07-16 8:47 ` Baoquan He
2015-07-16 8:47 ` [RHEL6.8 Patch 07/19] vmcore: allocate buffer for ELF headers on page-size alignment Baoquan He
` (13 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Baoquan He @ 2015-07-16 8:47 UTC (permalink / raw)
To: linux-kernel, ncroxon, dyoung, mhuang; +Cc: Baoquan He
Resolves: bz1097904
https://bugzilla.redhat.com/show_bug.cgi?id=1097904
This is back ported from upstream directly.
commit b27eb186608c89ef0979ae47c649859ceaa1b2e7
Author: HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com>
Date: Wed Jul 3 15:02:13 2013 -0700
vmcore: clean up read_vmcore()
Rewrite part of read_vmcore() that reads objects in vmcore_list in the
same way as part reading ELF headers, by which some duplicated and
redundant codes are removed.
Signed-off-by: HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com>
Acked-by: Vivek Goyal <vgoyal@redhat.com>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Atsushi Kumagai <kumagai-atsushi@mxc.nes.nec.co.jp>
Cc: Lisa Mitchell <lisa.mitchell@hp.com>
Cc: Zhang Yanfei <zhangyanfei@cn.fujitsu.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Baoquan He <bhe@redhat.com>
---
fs/proc/vmcore.c | 68 +++++++++++++++++---------------------------------------
1 file changed, 20 insertions(+), 48 deletions(-)
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c
index 1def40a..861956c 100644
--- a/fs/proc/vmcore.c
+++ b/fs/proc/vmcore.c
@@ -114,27 +114,6 @@ static ssize_t read_from_oldmem(char *buf, size_t count,
return read;
}
-/* Maps vmcore file offset to respective physical address in memroy. */
-static u64 map_offset_to_paddr(loff_t offset, struct list_head *vc_list,
- struct vmcore **m_ptr)
-{
- struct vmcore *m;
- u64 paddr;
-
- list_for_each_entry(m, vc_list, list) {
- u64 start, end;
- start = m->offset;
- end = m->offset + m->size - 1;
- if (offset >= start && offset <= end) {
- paddr = m->paddr + offset - start;
- *m_ptr = m;
- return paddr;
- }
- }
- *m_ptr = NULL;
- return 0;
-}
-
/* Read from the ELF header and then the crash dump. On error, negative value is
* returned otherwise number of bytes read are returned.
*/
@@ -143,8 +122,8 @@ static ssize_t read_vmcore(struct file *file, char __user *buffer,
{
ssize_t acc = 0, tmp;
size_t tsz;
- u64 start, nr_bytes;
- struct vmcore *curr_m = NULL;
+ u64 start;
+ struct vmcore *m = NULL;
if (buflen == 0 || *fpos >= vmcore_size)
return 0;
@@ -170,33 +149,26 @@ static ssize_t read_vmcore(struct file *file, char __user *buffer,
return acc;
}
- start = map_offset_to_paddr(*fpos, &vmcore_list, &curr_m);
- if (!curr_m)
- return -EINVAL;
-
- while (buflen) {
- tsz = min_t(size_t, buflen, PAGE_SIZE - (start & ~PAGE_MASK));
-
- /* Calculate left bytes in current memory segment. */
- nr_bytes = (curr_m->size - (start - curr_m->paddr));
- if (tsz > nr_bytes)
- tsz = nr_bytes;
-
- tmp = read_from_oldmem(buffer, tsz, &start, 1);
- if (tmp < 0)
- return tmp;
- buflen -= tsz;
- *fpos += tsz;
- buffer += tsz;
- acc += tsz;
- if (start >= (curr_m->paddr + curr_m->size)) {
- if (curr_m->list.next == &vmcore_list)
- return acc; /*EOF*/
- curr_m = list_entry(curr_m->list.next,
- struct vmcore, list);
- start = curr_m->paddr;
+ list_for_each_entry(m, &vmcore_list, list) {
+ if (*fpos < m->offset + m->size) {
+ tsz = m->offset + m->size - *fpos;
+ if (buflen < tsz)
+ tsz = buflen;
+ start = m->paddr + *fpos - m->offset;
+ tmp = read_from_oldmem(buffer, tsz, &start, 1);
+ if (tmp < 0)
+ return tmp;
+ buflen -= tsz;
+ *fpos += tsz;
+ buffer += tsz;
+ acc += tsz;
+
+ /* leave now if filled buffer already */
+ if (buflen == 0)
+ return acc;
}
}
+
return acc;
}
--
2.1.0
^ permalink raw reply [flat|nested] 24+ messages in thread
* [RHEL6.8 Patch 07/19] vmcore: allocate buffer for ELF headers on page-size alignment
2015-07-16 8:46 [RHEL6.8 Patch 00/19] Support mmap() on /proc/vmcore Baoquan He
` (8 preceding siblings ...)
2015-07-16 8:47 ` [RHEL6.8 Patch 06/19] vmcore: clean up read_vmcore() Baoquan He
@ 2015-07-16 8:47 ` Baoquan He
2015-07-16 8:47 ` [RHEL6.8 Patch 08/19] vmcore: treat memory chunks referenced by PT_LOAD program header entries in page-size boundary in vmcore_list Baoquan He
` (12 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Baoquan He @ 2015-07-16 8:47 UTC (permalink / raw)
To: linux-kernel, ncroxon, dyoung, mhuang; +Cc: Baoquan He
Resolves: bz1097904
https://bugzilla.redhat.com/show_bug.cgi?id=1097904
This is back ported from upstream. There are small format conflicts.
commit f2bdacdd597d8d05c3d5f5d36273084f7ef7e6f5
Author: HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com>
Date: Wed Jul 3 15:02:14 2013 -0700
vmcore: allocate buffer for ELF headers on page-size alignment
Allocate ELF headers on page-size boundary using __get_free_pages()
instead of kmalloc().
Later patch will merge PT_NOTE entries into a single unique one and
decrease the buffer size actually used. Keep original buffer size in
variable elfcorebuf_sz_orig to kfree the buffer later and actually used
buffer size with rounded up to page-size boundary in variable
elfcorebuf_sz separately.
The size of part of the ELF buffer exported from /proc/vmcore is
elfcorebuf_sz.
The merged, removed PT_NOTE entries, i.e. the range [elfcorebuf_sz,
elfcorebuf_sz_orig], is filled with 0.
Use size of the ELF headers as an initial offset value in
set_vmcore_list_offsets_elf{64,32} and
process_ptload_program_headers_elf{64,32} in order to indicate that the
offset includes the holes towards the page boundary.
As a result, both set_vmcore_list_offsets_elf{64,32} have the same
definition. Merge them as set_vmcore_list_offsets.
[akpm@linux-foundation.org: add free_elfcorebuf(), cleanups]
Signed-off-by: HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com>
Acked-by: Vivek Goyal <vgoyal@redhat.com>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Atsushi Kumagai <kumagai-atsushi@mxc.nes.nec.co.jp>
Cc: Lisa Mitchell <lisa.mitchell@hp.com>
Cc: Zhang Yanfei <zhangyanfei@cn.fujitsu.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Baoquan He <bhe@redhat.com>
---
fs/proc/vmcore.c | 119 ++++++++++++++++++++++++-------------------------------
1 file changed, 51 insertions(+), 68 deletions(-)
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c
index 861956c..f7b9aa1 100644
--- a/fs/proc/vmcore.c
+++ b/fs/proc/vmcore.c
@@ -28,6 +28,7 @@ static LIST_HEAD(vmcore_list);
/* Stores the pointer to the buffer containing kernel elf core headers. */
static char *elfcorebuf;
static size_t elfcorebuf_sz;
+static size_t elfcorebuf_sz_orig;
/* Total size of vmcore file. */
static u64 vmcore_size;
@@ -181,7 +182,7 @@ static struct vmcore* __init get_new_element(void)
return kzalloc(sizeof(struct vmcore), GFP_KERNEL);
}
-static u64 __init get_vmcore_size_elf64(char *elfptr)
+static u64 __init get_vmcore_size_elf64(char *elfptr, size_t elfsz)
{
int i;
u64 size;
@@ -190,7 +191,7 @@ static u64 __init get_vmcore_size_elf64(char *elfptr)
ehdr_ptr = (Elf64_Ehdr *)elfptr;
phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr));
- size = sizeof(Elf64_Ehdr) + ((ehdr_ptr->e_phnum) * sizeof(Elf64_Phdr));
+ size = elfsz;
for (i = 0; i < ehdr_ptr->e_phnum; i++) {
size += phdr_ptr->p_memsz;
phdr_ptr++;
@@ -198,7 +199,7 @@ static u64 __init get_vmcore_size_elf64(char *elfptr)
return size;
}
-static u64 __init get_vmcore_size_elf32(char *elfptr)
+static u64 __init get_vmcore_size_elf32(char *elfptr, size_t elfsz)
{
int i;
u64 size;
@@ -207,7 +208,7 @@ static u64 __init get_vmcore_size_elf32(char *elfptr)
ehdr_ptr = (Elf32_Ehdr *)elfptr;
phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr));
- size = sizeof(Elf32_Ehdr) + ((ehdr_ptr->e_phnum) * sizeof(Elf32_Phdr));
+ size = elfsz;
for (i = 0; i < ehdr_ptr->e_phnum; i++) {
size += phdr_ptr->p_memsz;
phdr_ptr++;
@@ -289,6 +290,8 @@ static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz,
i = (nr_ptnote - 1) * sizeof(Elf64_Phdr);
*elfsz = *elfsz - i;
memmove(tmp, tmp+i, ((*elfsz)-sizeof(Elf64_Ehdr)-sizeof(Elf64_Phdr)));
+ memset(elfptr + *elfsz, 0, i);
+ *elfsz = roundup(*elfsz, PAGE_SIZE);
/* Modify e_phnum to reflect merged headers. */
ehdr_ptr->e_phnum = ehdr_ptr->e_phnum - nr_ptnote + 1;
@@ -370,6 +373,8 @@ static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz,
i = (nr_ptnote - 1) * sizeof(Elf32_Phdr);
*elfsz = *elfsz - i;
memmove(tmp, tmp+i, ((*elfsz)-sizeof(Elf32_Ehdr)-sizeof(Elf32_Phdr)));
+ memset(elfptr + *elfsz, 0, i);
+ *elfsz = roundup(*elfsz, PAGE_SIZE);
/* Modify e_phnum to reflect merged headers. */
ehdr_ptr->e_phnum = ehdr_ptr->e_phnum - nr_ptnote + 1;
@@ -393,8 +398,7 @@ static int __init process_ptload_program_headers_elf64(char *elfptr,
phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr)); /* PT_NOTE hdr */
/* First program header is PT_NOTE header. */
- vmcore_off = sizeof(Elf64_Ehdr) +
- (ehdr_ptr->e_phnum) * sizeof(Elf64_Phdr) +
+ vmcore_off = elfsz +
phdr_ptr->p_memsz; /* Note sections */
for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
@@ -430,8 +434,7 @@ static int __init process_ptload_program_headers_elf32(char *elfptr,
phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr)); /* PT_NOTE hdr */
/* First program header is PT_NOTE header. */
- vmcore_off = sizeof(Elf32_Ehdr) +
- (ehdr_ptr->e_phnum) * sizeof(Elf32_Phdr) +
+ vmcore_off = elfsz +
phdr_ptr->p_memsz; /* Note sections */
for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
@@ -454,18 +457,14 @@ static int __init process_ptload_program_headers_elf32(char *elfptr,
}
/* Sets offset fields of vmcore elements. */
-static void __init set_vmcore_list_offsets_elf64(char *elfptr,
- struct list_head *vc_list)
+static void __init set_vmcore_list_offsets(size_t elfsz,
+ struct list_head *vc_list)
{
loff_t vmcore_off;
- Elf64_Ehdr *ehdr_ptr;
struct vmcore *m;
- ehdr_ptr = (Elf64_Ehdr *)elfptr;
-
/* Skip Elf header and program headers. */
- vmcore_off = sizeof(Elf64_Ehdr) +
- (ehdr_ptr->e_phnum) * sizeof(Elf64_Phdr);
+ vmcore_off = elfsz;
list_for_each_entry(m, vc_list, list) {
m->offset = vmcore_off;
@@ -473,24 +472,10 @@ static void __init set_vmcore_list_offsets_elf64(char *elfptr,
}
}
-/* Sets offset fields of vmcore elements. */
-static void __init set_vmcore_list_offsets_elf32(char *elfptr,
- struct list_head *vc_list)
+static void free_elfcorebuf(void)
{
- loff_t vmcore_off;
- Elf32_Ehdr *ehdr_ptr;
- struct vmcore *m;
-
- ehdr_ptr = (Elf32_Ehdr *)elfptr;
-
- /* Skip Elf header and program headers. */
- vmcore_off = sizeof(Elf32_Ehdr) +
- (ehdr_ptr->e_phnum) * sizeof(Elf32_Phdr);
-
- list_for_each_entry(m, vc_list, list) {
- m->offset = vmcore_off;
- vmcore_off += m->size;
- }
+ free_pages((unsigned long)elfcorebuf, get_order(elfcorebuf_sz_orig));
+ elfcorebuf = NULL;
}
static int __init parse_crash_elf64_headers(void)
@@ -522,31 +507,31 @@ static int __init parse_crash_elf64_headers(void)
}
/* Read in all elf headers. */
- elfcorebuf_sz = sizeof(Elf64_Ehdr) + ehdr.e_phnum * sizeof(Elf64_Phdr);
- elfcorebuf = kmalloc(elfcorebuf_sz, GFP_KERNEL);
+ elfcorebuf_sz_orig = sizeof(Elf64_Ehdr) +
+ ehdr.e_phnum * sizeof(Elf64_Phdr);
+ elfcorebuf_sz = elfcorebuf_sz_orig;
+ elfcorebuf = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
+ get_order(elfcorebuf_sz_orig));
if (!elfcorebuf)
return -ENOMEM;
addr = elfcorehdr_addr;
- rc = read_from_oldmem(elfcorebuf, elfcorebuf_sz, &addr, 0);
- if (rc < 0) {
- kfree(elfcorebuf);
- return rc;
- }
+ rc = read_from_oldmem(elfcorebuf, elfcorebuf_sz_orig, &addr, 0);
+ if (rc < 0)
+ goto fail;
/* Merge all PT_NOTE headers into one. */
rc = merge_note_headers_elf64(elfcorebuf, &elfcorebuf_sz, &vmcore_list);
- if (rc) {
- kfree(elfcorebuf);
- return rc;
- }
+ if (rc)
+ goto fail;
rc = process_ptload_program_headers_elf64(elfcorebuf, elfcorebuf_sz,
&vmcore_list);
- if (rc) {
- kfree(elfcorebuf);
- return rc;
- }
- set_vmcore_list_offsets_elf64(elfcorebuf, &vmcore_list);
+ if (rc)
+ goto fail;
+ set_vmcore_list_offsets(elfcorebuf_sz, &vmcore_list);
return 0;
+fail:
+ free_elfcorebuf();
+ return rc;
}
static int __init parse_crash_elf32_headers(void)
@@ -578,31 +563,30 @@ static int __init parse_crash_elf32_headers(void)
}
/* Read in all elf headers. */
- elfcorebuf_sz = sizeof(Elf32_Ehdr) + ehdr.e_phnum * sizeof(Elf32_Phdr);
- elfcorebuf = kmalloc(elfcorebuf_sz, GFP_KERNEL);
+ elfcorebuf_sz_orig = sizeof(Elf32_Ehdr) + ehdr.e_phnum * sizeof(Elf32_Phdr);
+ elfcorebuf_sz = elfcorebuf_sz_orig;
+ elfcorebuf = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO,
+ get_order(elfcorebuf_sz_orig));
if (!elfcorebuf)
return -ENOMEM;
addr = elfcorehdr_addr;
- rc = read_from_oldmem(elfcorebuf, elfcorebuf_sz, &addr, 0);
- if (rc < 0) {
- kfree(elfcorebuf);
- return rc;
- }
+ rc = read_from_oldmem(elfcorebuf, elfcorebuf_sz_orig, &addr, 0);
+ if (rc < 0)
+ goto fail;
/* Merge all PT_NOTE headers into one. */
rc = merge_note_headers_elf32(elfcorebuf, &elfcorebuf_sz, &vmcore_list);
- if (rc) {
- kfree(elfcorebuf);
- return rc;
- }
+ if (rc)
+ goto fail;
rc = process_ptload_program_headers_elf32(elfcorebuf, elfcorebuf_sz,
&vmcore_list);
- if (rc) {
- kfree(elfcorebuf);
- return rc;
- }
- set_vmcore_list_offsets_elf32(elfcorebuf, &vmcore_list);
+ if (rc)
+ goto fail;
+ set_vmcore_list_offsets(elfcorebuf_sz, &vmcore_list);
return 0;
+fail:
+ free_elfcorebuf();
+ return rc;
}
static int __init parse_crash_elf_headers(void)
@@ -627,14 +611,14 @@ static int __init parse_crash_elf_headers(void)
return rc;
/* Determine vmcore size. */
- vmcore_size = get_vmcore_size_elf64(elfcorebuf);
+ vmcore_size = get_vmcore_size_elf64(elfcorebuf, elfcorebuf_sz);
} else if (e_ident[EI_CLASS] == ELFCLASS32) {
rc = parse_crash_elf32_headers();
if (rc)
return rc;
/* Determine vmcore size. */
- vmcore_size = get_vmcore_size_elf32(elfcorebuf);
+ vmcore_size = get_vmcore_size_elf32(elfcorebuf, elfcorebuf_sz);
} else {
printk(KERN_WARNING "Warning: Core image elf header is not"
" sane\n");
@@ -682,7 +666,6 @@ void vmcore_cleanup(void)
list_del(&m->list);
kfree(m);
}
- kfree(elfcorebuf);
- elfcorebuf = NULL;
+ free_elfcorebuf();
}
EXPORT_SYMBOL_GPL(vmcore_cleanup);
--
2.1.0
^ permalink raw reply [flat|nested] 24+ messages in thread
* [RHEL6.8 Patch 08/19] vmcore: treat memory chunks referenced by PT_LOAD program header entries in page-size boundary in vmcore_list
2015-07-16 8:46 [RHEL6.8 Patch 00/19] Support mmap() on /proc/vmcore Baoquan He
` (9 preceding siblings ...)
2015-07-16 8:47 ` [RHEL6.8 Patch 07/19] vmcore: allocate buffer for ELF headers on page-size alignment Baoquan He
@ 2015-07-16 8:47 ` Baoquan He
2015-07-16 8:47 ` [RHEL6.8 Patch 09/19] vmalloc: make find_vm_area check in range Baoquan He
` (11 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Baoquan He @ 2015-07-16 8:47 UTC (permalink / raw)
To: linux-kernel, ncroxon, dyoung, mhuang; +Cc: Baoquan He
Resolves: bz1097904
https://bugzilla.redhat.com/show_bug.cgi?id=1097904
This is back port from upstream directly.
commit 7f614cd1e052ebbddee7ea49c725dc75fee74a5a
Author: HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com>
Date: Wed Jul 3 15:02:15 2013 -0700
vmcore: treat memory chunks referenced by PT_LOAD program header entries in page-size boundary in vmcore_list
Treat memory chunks referenced by PT_LOAD program header entries in
page-size boundary in vmcore_list. Formally, for each range [start,
end], we set up the corresponding vmcore object in vmcore_list to
[rounddown(start, PAGE_SIZE), roundup(end, PAGE_SIZE)].
This change affects layout of /proc/vmcore. The gaps generated by the
rearrangement are newly made visible to applications as holes.
Concretely, they are two ranges [rounddown(start, PAGE_SIZE), start] and
[end, roundup(end, PAGE_SIZE)].
Suppose variable m points at a vmcore object in vmcore_list, and
variable phdr points at the program header of PT_LOAD type the variable
m corresponds to. Then, pictorially:
m->offset +---------------+
| hole |
phdr->p_offset = +---------------+
m->offset + (paddr - start) | |\
| kernel memory | phdr->p_memsz
| |/
+---------------+
| hole |
m->offset + m->size +---------------+
where m->offset and m->offset + m->size are always page-size aligned.
Signed-off-by: HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com>
Acked-by: Vivek Goyal <vgoyal@redhat.com>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Atsushi Kumagai <kumagai-atsushi@mxc.nes.nec.co.jp>
Cc: Lisa Mitchell <lisa.mitchell@hp.com>
Cc: Zhang Yanfei <zhangyanfei@cn.fujitsu.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Baoquan He <bhe@redhat.com>
---
fs/proc/vmcore.c | 30 ++++++++++++++++++++++--------
1 file changed, 22 insertions(+), 8 deletions(-)
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c
index f7b9aa1..2850906 100644
--- a/fs/proc/vmcore.c
+++ b/fs/proc/vmcore.c
@@ -402,20 +402,27 @@ static int __init process_ptload_program_headers_elf64(char *elfptr,
phdr_ptr->p_memsz; /* Note sections */
for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
+ u64 paddr, start, end, size;
+
if (phdr_ptr->p_type != PT_LOAD)
continue;
+ paddr = phdr_ptr->p_offset;
+ start = rounddown(paddr, PAGE_SIZE);
+ end = roundup(paddr + phdr_ptr->p_memsz, PAGE_SIZE);
+ size = end - start;
+
/* Add this contiguous chunk of memory to vmcore list.*/
new = get_new_element();
if (!new)
return -ENOMEM;
- new->paddr = phdr_ptr->p_offset;
- new->size = phdr_ptr->p_memsz;
+ new->paddr = start;
+ new->size = size;
list_add_tail(&new->list, vc_list);
/* Update the program header offset. */
- phdr_ptr->p_offset = vmcore_off;
- vmcore_off = vmcore_off + phdr_ptr->p_memsz;
+ phdr_ptr->p_offset = vmcore_off + (paddr - start);
+ vmcore_off = vmcore_off + size;
}
return 0;
}
@@ -438,20 +445,27 @@ static int __init process_ptload_program_headers_elf32(char *elfptr,
phdr_ptr->p_memsz; /* Note sections */
for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
+ u64 paddr, start, end, size;
+
if (phdr_ptr->p_type != PT_LOAD)
continue;
+ paddr = phdr_ptr->p_offset;
+ start = rounddown(paddr, PAGE_SIZE);
+ end = roundup(paddr + phdr_ptr->p_memsz, PAGE_SIZE);
+ size = end - start;
+
/* Add this contiguous chunk of memory to vmcore list.*/
new = get_new_element();
if (!new)
return -ENOMEM;
- new->paddr = phdr_ptr->p_offset;
- new->size = phdr_ptr->p_memsz;
+ new->paddr = start;
+ new->size = size;
list_add_tail(&new->list, vc_list);
/* Update the program header offset */
- phdr_ptr->p_offset = vmcore_off;
- vmcore_off = vmcore_off + phdr_ptr->p_memsz;
+ phdr_ptr->p_offset = vmcore_off + (paddr - start);
+ vmcore_off = vmcore_off + size;
}
return 0;
}
--
2.1.0
^ permalink raw reply [flat|nested] 24+ messages in thread
* [RHEL6.8 Patch 09/19] vmalloc: make find_vm_area check in range
2015-07-16 8:46 [RHEL6.8 Patch 00/19] Support mmap() on /proc/vmcore Baoquan He
` (10 preceding siblings ...)
2015-07-16 8:47 ` [RHEL6.8 Patch 08/19] vmcore: treat memory chunks referenced by PT_LOAD program header entries in page-size boundary in vmcore_list Baoquan He
@ 2015-07-16 8:47 ` Baoquan He
2015-07-16 8:47 ` [RHEL6.8 Patch 10/19] vmalloc: introduce remap_vmalloc_range_partial Baoquan He
` (10 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Baoquan He @ 2015-07-16 8:47 UTC (permalink / raw)
To: linux-kernel, ncroxon, dyoung, mhuang; +Cc: Baoquan He
Resolves: bz1097904
https://bugzilla.redhat.com/show_bug.cgi?id=1097904
This is back ported from upstream directly.
commit cef2ac3f6c8ab532e49cf69d05f540931ad8ee64
Author: HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com>
Date: Wed Jul 3 15:02:17 2013 -0700
vmalloc: make find_vm_area check in range
Currently, __find_vmap_area searches for the kernel VM area starting at
a given address. This patch changes this behavior so that it searches
for the kernel VM area to which the address belongs. This change is
needed by remap_vmalloc_range_partial to be introduced in later patch
that receives any position of kernel VM area as target address.
This patch changes the condition (addr > va->va_start) to the equivalent
(addr >= va->va_end) by taking advantage of the fact that each kernel VM
area is non-overlapping.
Signed-off-by: HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com>
Acked-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Vivek Goyal <vgoyal@redhat.com>
Cc: Atsushi Kumagai <kumagai-atsushi@mxc.nes.nec.co.jp>
Cc: Lisa Mitchell <lisa.mitchell@hp.com>
Cc: Zhang Yanfei <zhangyanfei@cn.fujitsu.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Baoquan He <bhe@redhat.com>
---
mm/vmalloc.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index a8b83c7..2ae8618 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -302,7 +302,7 @@ static struct vmap_area *__find_vmap_area(unsigned long addr)
va = rb_entry(n, struct vmap_area, rb_node);
if (addr < va->va_start)
n = n->rb_left;
- else if (addr > va->va_start)
+ else if (addr >= va->va_end)
n = n->rb_right;
else
return va;
--
2.1.0
^ permalink raw reply [flat|nested] 24+ messages in thread
* [RHEL6.8 Patch 10/19] vmalloc: introduce remap_vmalloc_range_partial
2015-07-16 8:46 [RHEL6.8 Patch 00/19] Support mmap() on /proc/vmcore Baoquan He
` (11 preceding siblings ...)
2015-07-16 8:47 ` [RHEL6.8 Patch 09/19] vmalloc: make find_vm_area check in range Baoquan He
@ 2015-07-16 8:47 ` Baoquan He
2015-07-16 8:47 ` [RHEL6.8 Patch 11/19] vmcore: allocate ELF note segment in the 2nd kernel vmalloc memory Baoquan He
` (9 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Baoquan He @ 2015-07-16 8:47 UTC (permalink / raw)
To: linux-kernel, ncroxon, dyoung, mhuang; +Cc: Baoquan He
Resolves: bz1097904
https://bugzilla.redhat.com/show_bug.cgi?id=1097904
This is back ported from upstream. There's a small conflict in
remap_vmalloc_range.
commit e69e9d4aee712a22665f008ae0550bb3d7c7f7c1
Author: HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com>
Date: Wed Jul 3 15:02:18 2013 -0700
vmalloc: introduce remap_vmalloc_range_partial
We want to allocate ELF note segment buffer on the 2nd kernel in vmalloc
space and remap it to user-space in order to reduce the risk that memory
allocation fails on system with huge number of CPUs and so with huge ELF
note segment that exceeds 11-order block size.
Although there's already remap_vmalloc_range for the purpose of
remapping vmalloc memory to user-space, we need to specify user-space
range via vma.
Mmap on /proc/vmcore needs to remap range across multiple objects, so
the interface that requires vma to cover full range is problematic.
This patch introduces remap_vmalloc_range_partial that receives user-space
range as a pair of base address and size and can be used for mmap on
/proc/vmcore case.
remap_vmalloc_range is rewritten using remap_vmalloc_range_partial.
[akpm@linux-foundation.org: use PAGE_ALIGNED()]
Signed-off-by: HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Vivek Goyal <vgoyal@redhat.com>
Cc: Atsushi Kumagai <kumagai-atsushi@mxc.nes.nec.co.jp>
Cc: Lisa Mitchell <lisa.mitchell@hp.com>
Cc: Zhang Yanfei <zhangyanfei@cn.fujitsu.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Baoquan He <bhe@redhat.com>
---
include/linux/vmalloc.h | 4 +++
mm/vmalloc.c | 68 +++++++++++++++++++++++++++++++++----------------
2 files changed, 50 insertions(+), 22 deletions(-)
diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index 56e82f6..1ecf5c7 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -68,6 +68,10 @@ extern void *vmap(struct page **pages, unsigned int count,
unsigned long flags, pgprot_t prot);
extern void vunmap(const void *addr);
+extern int remap_vmalloc_range_partial(struct vm_area_struct *vma,
+ unsigned long uaddr, void *kaddr,
+ unsigned long size);
+
extern int remap_vmalloc_range(struct vm_area_struct *vma, void *addr,
unsigned long pgoff);
void vmalloc_sync_all(void);
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 2ae8618..ff148e0 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -1477,10 +1477,9 @@ static void __vunmap(const void *addr, int deallocate_pages)
if (!addr)
return;
- if ((PAGE_SIZE-1) & (unsigned long)addr) {
- WARN(1, KERN_ERR "Trying to vfree() bad address (%p)\n", addr);
+ if (WARN(!PAGE_ALIGNED(addr), "Trying to vfree() bad address (%p)\n",
+ addr));
return;
- }
area = remove_vm_area(addr);
if (unlikely(!area)) {
@@ -2117,42 +2116,43 @@ finished:
}
/**
- * remap_vmalloc_range - map vmalloc pages to userspace
- * @vma: vma to cover (map full range of vma)
- * @addr: vmalloc memory
- * @pgoff: number of pages into addr before first page to map
+ * remap_vmalloc_range_partial - map vmalloc pages to userspace
+ * @vma: vma to cover
+ * @uaddr: target user address to start at
+ * @kaddr: virtual address of vmalloc kernel memory
+ * @size: size of map area
*
* Returns: 0 for success, -Exxx on failure
*
- * This function checks that addr is a valid vmalloc'ed area, and
- * that it is big enough to cover the vma. Will return failure if
- * that criteria isn't met.
+ * This function checks that @kaddr is a valid vmalloc'ed area,
+ * and that it is big enough to cover the range starting at
+ * @uaddr in @vma. Will return failure if that criteria isn't
+ * met.
*
* Similar to remap_pfn_range() (see mm/memory.c)
*/
-int remap_vmalloc_range(struct vm_area_struct *vma, void *addr,
- unsigned long pgoff)
+int remap_vmalloc_range_partial(struct vm_area_struct *vma, unsigned long uaddr,
+ void *kaddr, unsigned long size)
{
struct vm_struct *area;
- unsigned long uaddr = vma->vm_start;
- unsigned long usize = vma->vm_end - vma->vm_start;
- if ((PAGE_SIZE-1) & (unsigned long)addr)
+ size = PAGE_ALIGN(size);
+
+ if (!PAGE_ALIGNED(uaddr) || !PAGE_ALIGNED(kaddr))
return -EINVAL;
- area = find_vm_area(addr);
+ area = find_vm_area(kaddr);
if (!area)
return -EINVAL;
if (!(area->flags & VM_USERMAP))
return -EINVAL;
- if (usize + (pgoff << PAGE_SHIFT) > area->size - PAGE_SIZE)
+ if (kaddr + size > area->addr + area->size)
return -EINVAL;
- addr += pgoff << PAGE_SHIFT;
do {
- struct page *page = vmalloc_to_page(addr);
+ struct page *page = vmalloc_to_page(kaddr);
int ret;
ret = vm_insert_page(vma, uaddr, page);
@@ -2160,15 +2160,39 @@ int remap_vmalloc_range(struct vm_area_struct *vma, void *addr,
return ret;
uaddr += PAGE_SIZE;
- addr += PAGE_SIZE;
- usize -= PAGE_SIZE;
- } while (usize > 0);
+ kaddr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ } while (size > 0);
/* Prevent "things" like memory migration? VM_flags need a cleanup... */
vma->vm_flags |= VM_RESERVED;
return 0;
}
+EXPORT_SYMBOL(remap_vmalloc_range_partial);
+
+/**
+ * remap_vmalloc_range - map vmalloc pages to userspace
+ * @vma: vma to cover (map full range of vma)
+ * @addr: vmalloc memory
+ * @pgoff: number of pages into addr before first page to map
+ *
+ * Returns: 0 for success, -Exxx on failure
+ *
+ * This function checks that addr is a valid vmalloc'ed area, and
+ * that it is big enough to cover the vma. Will return failure if
+ * that criteria isn't met.
+ *
+ * Similar to remap_pfn_range() (see mm/memory.c)
+ */
+int remap_vmalloc_range(struct vm_area_struct *vma, void *addr,
+ unsigned long pgoff)
+{
+ return remap_vmalloc_range_partial(vma, vma->vm_start,
+ addr + (pgoff << PAGE_SHIFT),
+ vma->vm_end - vma->vm_start);
+}
+
EXPORT_SYMBOL(remap_vmalloc_range);
/*
--
2.1.0
^ permalink raw reply [flat|nested] 24+ messages in thread
* [RHEL6.8 Patch 11/19] vmcore: allocate ELF note segment in the 2nd kernel vmalloc memory
2015-07-16 8:46 [RHEL6.8 Patch 00/19] Support mmap() on /proc/vmcore Baoquan He
` (12 preceding siblings ...)
2015-07-16 8:47 ` [RHEL6.8 Patch 10/19] vmalloc: introduce remap_vmalloc_range_partial Baoquan He
@ 2015-07-16 8:47 ` Baoquan He
2015-07-16 8:47 ` [RHEL6.8 Patch 12/19] vmcore: allow user process to remap ELF note segment buffer Baoquan He
` (8 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Baoquan He @ 2015-07-16 8:47 UTC (permalink / raw)
To: linux-kernel, ncroxon, dyoung, mhuang; +Cc: Baoquan He
Resolves: bz1097904
https://bugzilla.redhat.com/show_bug.cgi?id=1097904
This is back ported from upstream.
commit 087350c9dcf1b38c597b31d7761f7366e2866e6b
Author: HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com>
Date: Wed Jul 3 15:02:19 2013 -0700
vmcore: allocate ELF note segment in the 2nd kernel vmalloc memory
The reasons why we don't allocate ELF note segment in the 1st kernel
(old memory) on page boundary is to keep backward compatibility for old
kernels, and that if doing so, we waste not a little memory due to
round-up operation to fit the memory to page boundary since most of the
buffers are in per-cpu area.
ELF notes are per-cpu, so total size of ELF note segments depends on
number of CPUs. The current maximum number of CPUs on x86_64 is 5192,
and there's already system with 4192 CPUs in SGI, where total size
amounts to 1MB. This can be larger in the near future or possibly even
now on another architecture that has larger size of note per a single
cpu. Thus, to avoid the case where memory allocation for large block
fails, we allocate vmcore objects on vmalloc memory.
This patch adds elfnotes_buf and elfnotes_sz variables to keep pointer
to the ELF note segment buffer and its size. There's no longer the
vmcore object that corresponds to the ELF note segment in vmcore_list.
Accordingly, read_vmcore() has new case for ELF note segment and
set_vmcore_list_offsets_elf{64,32}() and other helper functions starts
calculating offset from sum of size of ELF headers and size of ELF note
segment.
[akpm@linux-foundation.org: use min(), fix error-path vzalloc() leaks]
Signed-off-by: HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com>
Acked-by: Vivek Goyal <vgoyal@redhat.com>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Atsushi Kumagai <kumagai-atsushi@mxc.nes.nec.co.jp>
Cc: Lisa Mitchell <lisa.mitchell@hp.com>
Cc: Zhang Yanfei <zhangyanfei@cn.fujitsu.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Baoquan He <bhe@redhat.com>
---
fs/proc/vmcore.c | 359 ++++++++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 286 insertions(+), 73 deletions(-)
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c
index 2850906..7b1d5f8 100644
--- a/fs/proc/vmcore.c
+++ b/fs/proc/vmcore.c
@@ -30,6 +30,9 @@ static char *elfcorebuf;
static size_t elfcorebuf_sz;
static size_t elfcorebuf_sz_orig;
+static char *elfnotes_buf;
+static size_t elfnotes_sz;
+
/* Total size of vmcore file. */
static u64 vmcore_size;
@@ -135,9 +138,7 @@ static ssize_t read_vmcore(struct file *file, char __user *buffer,
/* Read ELF core header */
if (*fpos < elfcorebuf_sz) {
- tsz = elfcorebuf_sz - *fpos;
- if (buflen < tsz)
- tsz = buflen;
+ tsz = min(elfcorebuf_sz - (size_t)*fpos, buflen);
if (copy_to_user(buffer, elfcorebuf + *fpos, tsz))
return -EFAULT;
buflen -= tsz;
@@ -150,11 +151,27 @@ static ssize_t read_vmcore(struct file *file, char __user *buffer,
return acc;
}
+ /* Read Elf note segment */
+ if (*fpos < elfcorebuf_sz + elfnotes_sz) {
+ void *kaddr;
+
+ tsz = min(elfcorebuf_sz + elfnotes_sz - (size_t)*fpos, buflen);
+ kaddr = elfnotes_buf + *fpos - elfcorebuf_sz;
+ if (copy_to_user(buffer, kaddr, tsz))
+ return -EFAULT;
+ buflen -= tsz;
+ *fpos += tsz;
+ buffer += tsz;
+ acc += tsz;
+
+ /* leave now if filled buffer already */
+ if (buflen == 0)
+ return acc;
+ }
+
list_for_each_entry(m, &vmcore_list, list) {
if (*fpos < m->offset + m->size) {
- tsz = m->offset + m->size - *fpos;
- if (buflen < tsz)
- tsz = buflen;
+ tsz = min_t(size_t, m->offset + m->size - *fpos, buflen);
start = m->paddr + *fpos - m->offset;
tmp = read_from_oldmem(buffer, tsz, &start, 1);
if (tmp < 0)
@@ -216,27 +233,27 @@ static u64 __init get_vmcore_size_elf32(char *elfptr, size_t elfsz)
return size;
}
-/* Merges all the PT_NOTE headers into one. */
-static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz,
- struct list_head *vc_list)
+/**
+ * update_note_header_size_elf64 - update p_memsz member of each PT_NOTE entry
+ *
+ * @ehdr_ptr: ELF header
+ *
+ * This function updates p_memsz member of each PT_NOTE entry in the
+ * program header table pointed to by @ehdr_ptr to real size of ELF
+ * note segment.
+ */
+static int __init update_note_header_size_elf64(const Elf64_Ehdr *ehdr_ptr)
{
- int i, nr_ptnote=0, rc=0;
- char *tmp;
- Elf64_Ehdr *ehdr_ptr;
- Elf64_Phdr phdr, *phdr_ptr;
+ int i, rc=0;
+ Elf64_Phdr *phdr_ptr;
Elf64_Nhdr *nhdr_ptr;
- u64 phdr_sz = 0, note_off;
- ehdr_ptr = (Elf64_Ehdr *)elfptr;
- phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr));
+ phdr_ptr = (Elf64_Phdr *)(ehdr_ptr + 1);
for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
- int j;
void *notes_section;
- struct vmcore *new;
u64 offset, max_sz, sz, real_sz = 0;
if (phdr_ptr->p_type != PT_NOTE)
continue;
- nr_ptnote++;
max_sz = phdr_ptr->p_memsz;
offset = phdr_ptr->p_offset;
notes_section = kmalloc(max_sz, GFP_KERNEL);
@@ -248,7 +265,7 @@ static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz,
return rc;
}
nhdr_ptr = notes_section;
- for (j = 0; j < max_sz; j += sz) {
+ while (real_sz < max_sz) {
if (nhdr_ptr->n_namesz == 0)
break;
sz = sizeof(Elf64_Nhdr) +
@@ -257,26 +274,122 @@ static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz,
real_sz += sz;
nhdr_ptr = (Elf64_Nhdr*)((char*)nhdr_ptr + sz);
}
-
- /* Add this contiguous chunk of notes section to vmcore list.*/
- new = get_new_element();
- if (!new) {
- kfree(notes_section);
- return -ENOMEM;
- }
- new->paddr = phdr_ptr->p_offset;
- new->size = real_sz;
- list_add_tail(&new->list, vc_list);
- phdr_sz += real_sz;
kfree(notes_section);
+ phdr_ptr->p_memsz = real_sz;
}
+ return 0;
+}
+
+/**
+ * get_note_number_and_size_elf64 - get the number of PT_NOTE program
+ * headers and sum of real size of their ELF note segment headers and
+ * data.
+ *
+ * @ehdr_ptr: ELF header
+ * @nr_ptnote: buffer for the number of PT_NOTE program headers
+ * @sz_ptnote: buffer for size of unique PT_NOTE program header
+ *
+ * This function is used to merge multiple PT_NOTE program headers
+ * into a unique single one. The resulting unique entry will have
+ * @sz_ptnote in its phdr->p_mem.
+ *
+ * It is assumed that program headers with PT_NOTE type pointed to by
+ * @ehdr_ptr has already been updated by update_note_header_size_elf64
+ * and each of PT_NOTE program headers has actual ELF note segment
+ * size in its p_memsz member.
+ */
+static int __init get_note_number_and_size_elf64(const Elf64_Ehdr *ehdr_ptr,
+ int *nr_ptnote, u64 *sz_ptnote)
+{
+ int i;
+ Elf64_Phdr *phdr_ptr;
+
+ *nr_ptnote = *sz_ptnote = 0;
+
+ phdr_ptr = (Elf64_Phdr *)(ehdr_ptr + 1);
+ for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
+ if (phdr_ptr->p_type != PT_NOTE)
+ continue;
+ *nr_ptnote += 1;
+ *sz_ptnote += phdr_ptr->p_memsz;
+ }
+
+ return 0;
+}
+
+/**
+ * copy_notes_elf64 - copy ELF note segments in a given buffer
+ *
+ * @ehdr_ptr: ELF header
+ * @notes_buf: buffer into which ELF note segments are copied
+ *
+ * This function is used to copy ELF note segment in the 1st kernel
+ * into the buffer @notes_buf in the 2nd kernel. It is assumed that
+ * size of the buffer @notes_buf is equal to or larger than sum of the
+ * real ELF note segment headers and data.
+ *
+ * It is assumed that program headers with PT_NOTE type pointed to by
+ * @ehdr_ptr has already been updated by update_note_header_size_elf64
+ * and each of PT_NOTE program headers has actual ELF note segment
+ * size in its p_memsz member.
+ */
+static int __init copy_notes_elf64(const Elf64_Ehdr *ehdr_ptr, char *notes_buf)
+{
+ int i, rc=0;
+ Elf64_Phdr *phdr_ptr;
+
+ phdr_ptr = (Elf64_Phdr*)(ehdr_ptr + 1);
+
+ for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
+ u64 offset;
+ if (phdr_ptr->p_type != PT_NOTE)
+ continue;
+ offset = phdr_ptr->p_offset;
+ rc = read_from_oldmem(notes_buf, phdr_ptr->p_memsz, &offset, 0);
+ if (rc < 0)
+ return rc;
+ notes_buf += phdr_ptr->p_memsz;
+ }
+
+ return 0;
+}
+
+/* Merges all the PT_NOTE headers into one. */
+static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz,
+ char **notes_buf, size_t *notes_sz)
+{
+ int i, nr_ptnote=0, rc=0;
+ char *tmp;
+ Elf64_Ehdr *ehdr_ptr;
+ Elf64_Phdr phdr;
+ u64 phdr_sz = 0, note_off;
+
+ ehdr_ptr = (Elf64_Ehdr *)elfptr;
+
+ rc = update_note_header_size_elf64(ehdr_ptr);
+ if (rc < 0)
+ return rc;
+
+ rc = get_note_number_and_size_elf64(ehdr_ptr, &nr_ptnote, &phdr_sz);
+ if (rc < 0)
+ return rc;
+
+ *notes_sz = roundup(phdr_sz, PAGE_SIZE);
+ *notes_buf = vzalloc(*notes_sz);
+ if (!*notes_buf)
+ return -ENOMEM;
+
+ rc = copy_notes_elf64(ehdr_ptr, *notes_buf);
+ if (rc < 0)
+ return rc;
+
/* Prepare merged PT_NOTE program header. */
phdr.p_type = PT_NOTE;
phdr.p_flags = 0;
note_off = sizeof(Elf64_Ehdr) +
(ehdr_ptr->e_phnum - nr_ptnote +1) * sizeof(Elf64_Phdr);
- phdr.p_offset = note_off;
+ phdr.p_offset = roundup(note_off, PAGE_SIZE);
phdr.p_vaddr = phdr.p_paddr = 0;
phdr.p_filesz = phdr.p_memsz = phdr_sz;
phdr.p_align = 0;
@@ -299,27 +412,27 @@ static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz,
return 0;
}
-/* Merges all the PT_NOTE headers into one. */
-static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz,
- struct list_head *vc_list)
+/**
+ * update_note_header_size_elf32 - update p_memsz member of each PT_NOTE entry
+ *
+ * @ehdr_ptr: ELF header
+ *
+ * This function updates p_memsz member of each PT_NOTE entry in the
+ * program header table pointed to by @ehdr_ptr to real size of ELF
+ * note segment.
+ */
+static int __init update_note_header_size_elf32(const Elf32_Ehdr *ehdr_ptr)
{
- int i, nr_ptnote=0, rc=0;
- char *tmp;
- Elf32_Ehdr *ehdr_ptr;
- Elf32_Phdr phdr, *phdr_ptr;
+ int i, rc=0;
+ Elf32_Phdr *phdr_ptr;
Elf32_Nhdr *nhdr_ptr;
- u64 phdr_sz = 0, note_off;
- ehdr_ptr = (Elf32_Ehdr *)elfptr;
- phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr));
+ phdr_ptr = (Elf32_Phdr *)(ehdr_ptr + 1);
for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
- int j;
void *notes_section;
- struct vmcore *new;
u64 offset, max_sz, sz, real_sz = 0;
if (phdr_ptr->p_type != PT_NOTE)
continue;
- nr_ptnote++;
max_sz = phdr_ptr->p_memsz;
offset = phdr_ptr->p_offset;
notes_section = kmalloc(max_sz, GFP_KERNEL);
@@ -331,7 +444,7 @@ static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz,
return rc;
}
nhdr_ptr = notes_section;
- for (j = 0; j < max_sz; j += sz) {
+ while (real_sz < max_sz) {
if (nhdr_ptr->n_namesz == 0)
break;
sz = sizeof(Elf32_Nhdr) +
@@ -340,26 +453,122 @@ static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz,
real_sz += sz;
nhdr_ptr = (Elf32_Nhdr*)((char*)nhdr_ptr + sz);
}
-
- /* Add this contiguous chunk of notes section to vmcore list.*/
- new = get_new_element();
- if (!new) {
- kfree(notes_section);
- return -ENOMEM;
- }
- new->paddr = phdr_ptr->p_offset;
- new->size = real_sz;
- list_add_tail(&new->list, vc_list);
- phdr_sz += real_sz;
kfree(notes_section);
+ phdr_ptr->p_memsz = real_sz;
+ }
+
+ return 0;
+}
+
+/**
+ * get_note_number_and_size_elf32 - get the number of PT_NOTE program
+ * headers and sum of real size of their ELF note segment headers and
+ * data.
+ *
+ * @ehdr_ptr: ELF header
+ * @nr_ptnote: buffer for the number of PT_NOTE program headers
+ * @sz_ptnote: buffer for size of unique PT_NOTE program header
+ *
+ * This function is used to merge multiple PT_NOTE program headers
+ * into a unique single one. The resulting unique entry will have
+ * @sz_ptnote in its phdr->p_mem.
+ *
+ * It is assumed that program headers with PT_NOTE type pointed to by
+ * @ehdr_ptr has already been updated by update_note_header_size_elf32
+ * and each of PT_NOTE program headers has actual ELF note segment
+ * size in its p_memsz member.
+ */
+static int __init get_note_number_and_size_elf32(const Elf32_Ehdr *ehdr_ptr,
+ int *nr_ptnote, u64 *sz_ptnote)
+{
+ int i;
+ Elf32_Phdr *phdr_ptr;
+
+ *nr_ptnote = *sz_ptnote = 0;
+
+ phdr_ptr = (Elf32_Phdr *)(ehdr_ptr + 1);
+ for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
+ if (phdr_ptr->p_type != PT_NOTE)
+ continue;
+ *nr_ptnote += 1;
+ *sz_ptnote += phdr_ptr->p_memsz;
}
+ return 0;
+}
+
+/**
+ * copy_notes_elf32 - copy ELF note segments in a given buffer
+ *
+ * @ehdr_ptr: ELF header
+ * @notes_buf: buffer into which ELF note segments are copied
+ *
+ * This function is used to copy ELF note segment in the 1st kernel
+ * into the buffer @notes_buf in the 2nd kernel. It is assumed that
+ * size of the buffer @notes_buf is equal to or larger than sum of the
+ * real ELF note segment headers and data.
+ *
+ * It is assumed that program headers with PT_NOTE type pointed to by
+ * @ehdr_ptr has already been updated by update_note_header_size_elf32
+ * and each of PT_NOTE program headers has actual ELF note segment
+ * size in its p_memsz member.
+ */
+static int __init copy_notes_elf32(const Elf32_Ehdr *ehdr_ptr, char *notes_buf)
+{
+ int i, rc=0;
+ Elf32_Phdr *phdr_ptr;
+
+ phdr_ptr = (Elf32_Phdr*)(ehdr_ptr + 1);
+
+ for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
+ u64 offset;
+ if (phdr_ptr->p_type != PT_NOTE)
+ continue;
+ offset = phdr_ptr->p_offset;
+ rc = read_from_oldmem(notes_buf, phdr_ptr->p_memsz, &offset, 0);
+ if (rc < 0)
+ return rc;
+ notes_buf += phdr_ptr->p_memsz;
+ }
+
+ return 0;
+}
+
+/* Merges all the PT_NOTE headers into one. */
+static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz,
+ char **notes_buf, size_t *notes_sz)
+{
+ int i, nr_ptnote=0, rc=0;
+ char *tmp;
+ Elf32_Ehdr *ehdr_ptr;
+ Elf32_Phdr phdr;
+ u64 phdr_sz = 0, note_off;
+
+ ehdr_ptr = (Elf32_Ehdr *)elfptr;
+
+ rc = update_note_header_size_elf32(ehdr_ptr);
+ if (rc < 0)
+ return rc;
+
+ rc = get_note_number_and_size_elf32(ehdr_ptr, &nr_ptnote, &phdr_sz);
+ if (rc < 0)
+ return rc;
+
+ *notes_sz = roundup(phdr_sz, PAGE_SIZE);
+ *notes_buf = vzalloc(*notes_sz);
+ if (!*notes_buf)
+ return -ENOMEM;
+
+ rc = copy_notes_elf32(ehdr_ptr, *notes_buf);
+ if (rc < 0)
+ return rc;
+
/* Prepare merged PT_NOTE program header. */
phdr.p_type = PT_NOTE;
phdr.p_flags = 0;
note_off = sizeof(Elf32_Ehdr) +
(ehdr_ptr->e_phnum - nr_ptnote +1) * sizeof(Elf32_Phdr);
- phdr.p_offset = note_off;
+ phdr.p_offset = roundup(note_off, PAGE_SIZE);
phdr.p_vaddr = phdr.p_paddr = 0;
phdr.p_filesz = phdr.p_memsz = phdr_sz;
phdr.p_align = 0;
@@ -386,6 +595,7 @@ static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz,
* the new offset fields of exported program headers. */
static int __init process_ptload_program_headers_elf64(char *elfptr,
size_t elfsz,
+ size_t elfnotes_sz,
struct list_head *vc_list)
{
int i;
@@ -397,9 +607,8 @@ static int __init process_ptload_program_headers_elf64(char *elfptr,
ehdr_ptr = (Elf64_Ehdr *)elfptr;
phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr)); /* PT_NOTE hdr */
- /* First program header is PT_NOTE header. */
- vmcore_off = elfsz +
- phdr_ptr->p_memsz; /* Note sections */
+ /* Skip Elf header, program headers and Elf note segment. */
+ vmcore_off = elfsz + elfnotes_sz;
for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
u64 paddr, start, end, size;
@@ -429,6 +638,7 @@ static int __init process_ptload_program_headers_elf64(char *elfptr,
static int __init process_ptload_program_headers_elf32(char *elfptr,
size_t elfsz,
+ size_t elfnotes_sz,
struct list_head *vc_list)
{
int i;
@@ -440,9 +650,8 @@ static int __init process_ptload_program_headers_elf32(char *elfptr,
ehdr_ptr = (Elf32_Ehdr *)elfptr;
phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr)); /* PT_NOTE hdr */
- /* First program header is PT_NOTE header. */
- vmcore_off = elfsz +
- phdr_ptr->p_memsz; /* Note sections */
+ /* Skip Elf header, program headers and Elf note segment. */
+ vmcore_off = elfsz + elfnotes_sz;
for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
u64 paddr, start, end, size;
@@ -471,14 +680,14 @@ static int __init process_ptload_program_headers_elf32(char *elfptr,
}
/* Sets offset fields of vmcore elements. */
-static void __init set_vmcore_list_offsets(size_t elfsz,
+static void __init set_vmcore_list_offsets(size_t elfsz, size_t elfnotes_sz,
struct list_head *vc_list)
{
loff_t vmcore_off;
struct vmcore *m;
- /* Skip Elf header and program headers. */
- vmcore_off = elfsz;
+ /* Skip Elf header, program headers and Elf note segment. */
+ vmcore_off = elfsz + elfnotes_sz;
list_for_each_entry(m, vc_list, list) {
m->offset = vmcore_off;
@@ -490,6 +699,8 @@ static void free_elfcorebuf(void)
{
free_pages((unsigned long)elfcorebuf, get_order(elfcorebuf_sz_orig));
elfcorebuf = NULL;
+ vfree(elfnotes_buf);
+ elfnotes_buf = NULL;
}
static int __init parse_crash_elf64_headers(void)
@@ -534,14 +745,15 @@ static int __init parse_crash_elf64_headers(void)
goto fail;
/* Merge all PT_NOTE headers into one. */
- rc = merge_note_headers_elf64(elfcorebuf, &elfcorebuf_sz, &vmcore_list);
+ rc = merge_note_headers_elf64(elfcorebuf, &elfcorebuf_sz,
+ &elfnotes_buf, &elfnotes_sz);
if (rc)
goto fail;
rc = process_ptload_program_headers_elf64(elfcorebuf, elfcorebuf_sz,
- &vmcore_list);
+ elfnotes_sz, &vmcore_list);
if (rc)
goto fail;
- set_vmcore_list_offsets(elfcorebuf_sz, &vmcore_list);
+ set_vmcore_list_offsets(elfcorebuf_sz, elfnotes_sz, &vmcore_list);
return 0;
fail:
free_elfcorebuf();
@@ -589,14 +801,15 @@ static int __init parse_crash_elf32_headers(void)
goto fail;
/* Merge all PT_NOTE headers into one. */
- rc = merge_note_headers_elf32(elfcorebuf, &elfcorebuf_sz, &vmcore_list);
+ rc = merge_note_headers_elf32(elfcorebuf, &elfcorebuf_sz,
+ &elfnotes_buf, &elfnotes_sz);
if (rc)
goto fail;
rc = process_ptload_program_headers_elf32(elfcorebuf, elfcorebuf_sz,
- &vmcore_list);
+ elfnotes_sz, &vmcore_list);
if (rc)
goto fail;
- set_vmcore_list_offsets(elfcorebuf_sz, &vmcore_list);
+ set_vmcore_list_offsets(elfcorebuf_sz, elfnotes_sz, &vmcore_list);
return 0;
fail:
free_elfcorebuf();
--
2.1.0
^ permalink raw reply [flat|nested] 24+ messages in thread
* [RHEL6.8 Patch 12/19] vmcore: allow user process to remap ELF note segment buffer
2015-07-16 8:46 [RHEL6.8 Patch 00/19] Support mmap() on /proc/vmcore Baoquan He
` (13 preceding siblings ...)
2015-07-16 8:47 ` [RHEL6.8 Patch 11/19] vmcore: allocate ELF note segment in the 2nd kernel vmalloc memory Baoquan He
@ 2015-07-16 8:47 ` Baoquan He
2015-07-16 8:47 ` [RHEL6.8 Patch 13/19] vmcore: calculate vmcore file size from buffer size and total size of vmcore objects Baoquan He
` (7 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Baoquan He @ 2015-07-16 8:47 UTC (permalink / raw)
To: linux-kernel, ncroxon, dyoung, mhuang; +Cc: Baoquan He
Resolves: bz1097904
https://bugzilla.redhat.com/show_bug.cgi?id=1097904
This is back ported from upstream.
commit ef9e78fd2753213ea01d77f7a76a9cb6ad0f50a7
Author: HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com>
Date: Wed Jul 3 15:02:21 2013 -0700
vmcore: allow user process to remap ELF note segment buffer
Now ELF note segment has been copied in the buffer on vmalloc memory.
To allow user process to remap the ELF note segment buffer with
remap_vmalloc_page, the corresponding VM area object has to have
VM_USERMAP flag set.
[akpm@linux-foundation.org: use the conventional comment layout]
Signed-off-by: HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com>
Acked-by: Vivek Goyal <vgoyal@redhat.com>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Atsushi Kumagai <kumagai-atsushi@mxc.nes.nec.co.jp>
Cc: Lisa Mitchell <lisa.mitchell@hp.com>
Cc: Zhang Yanfei <zhangyanfei@cn.fujitsu.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Baoquan He <bhe@redhat.com>
---
fs/proc/vmcore.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c
index 7b1d5f8..6849c3f 100644
--- a/fs/proc/vmcore.c
+++ b/fs/proc/vmcore.c
@@ -364,6 +364,7 @@ static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz,
Elf64_Ehdr *ehdr_ptr;
Elf64_Phdr phdr;
u64 phdr_sz = 0, note_off;
+ struct vm_struct *vm;
ehdr_ptr = (Elf64_Ehdr *)elfptr;
@@ -380,6 +381,14 @@ static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz,
if (!*notes_buf)
return -ENOMEM;
+ /*
+ * Allow users to remap ELF note segment buffer on vmalloc memory using
+ * remap_vmalloc_range.()
+ */
+ vm = find_vm_area(*notes_buf);
+ BUG_ON(!vm);
+ vm->flags |= VM_USERMAP;
+
rc = copy_notes_elf64(ehdr_ptr, *notes_buf);
if (rc < 0)
return rc;
@@ -543,6 +552,7 @@ static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz,
Elf32_Ehdr *ehdr_ptr;
Elf32_Phdr phdr;
u64 phdr_sz = 0, note_off;
+ struct vm_struct *vm;
ehdr_ptr = (Elf32_Ehdr *)elfptr;
@@ -559,6 +569,14 @@ static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz,
if (!*notes_buf)
return -ENOMEM;
+ /*
+ * Allow users to remap ELF note segment buffer on vmalloc memory using
+ * remap_vmalloc_range()
+ */
+ vm = find_vm_area(*notes_buf);
+ BUG_ON(!vm);
+ vm->flags |= VM_USERMAP;
+
rc = copy_notes_elf32(ehdr_ptr, *notes_buf);
if (rc < 0)
return rc;
--
2.1.0
^ permalink raw reply [flat|nested] 24+ messages in thread
* [RHEL6.8 Patch 13/19] vmcore: calculate vmcore file size from buffer size and total size of vmcore objects
2015-07-16 8:46 [RHEL6.8 Patch 00/19] Support mmap() on /proc/vmcore Baoquan He
` (14 preceding siblings ...)
2015-07-16 8:47 ` [RHEL6.8 Patch 12/19] vmcore: allow user process to remap ELF note segment buffer Baoquan He
@ 2015-07-16 8:47 ` Baoquan He
2015-07-16 8:47 ` [RHEL6.8 Patch 14/19] vmcore: support mmap() on /proc/vmcore Baoquan He
` (6 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Baoquan He @ 2015-07-16 8:47 UTC (permalink / raw)
To: linux-kernel, ncroxon, dyoung, mhuang; +Cc: Baoquan He
Resolves: bz1097904
https://bugzilla.redhat.com/show_bug.cgi?id=1097904
This is back ported from upstream.
commit 591ff71664e764a3806e341370f3c758cb2e7e3c
Author: HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com>
Date: Wed Jul 3 15:02:22 2013 -0700
vmcore: calculate vmcore file size from buffer size and total size of vmcore objects
The previous patches newly added holes before each chunk of memory and
the holes need to be count in vmcore file size. There are two ways to
count file size in such a way:
1) suppose m is a poitner to the last vmcore object in vmcore_list.
Then file size is (m->offset + m->size), or
2) calculate sum of size of buffers for ELF header, program headers,
ELF note segments and objects in vmcore_list.
Although 1) is more direct and simpler than 2), 2) seems better in that
it reflects internal object structure of /proc/vmcore. Thus, this patch
changes get_vmcore_size_elf{64, 32} so that it calculates size in the
way of 2).
As a result, both get_vmcore_size_elf{64, 32} have the same definition.
Merge them as get_vmcore_size.
Signed-off-by: HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com>
Acked-by: Vivek Goyal <vgoyal@redhat.com>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Atsushi Kumagai <kumagai-atsushi@mxc.nes.nec.co.jp>
Cc: Lisa Mitchell <lisa.mitchell@hp.com>
Cc: Zhang Yanfei <zhangyanfei@cn.fujitsu.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Baoquan He <bhe@redhat.com>
---
fs/proc/vmcore.c | 44 +++++++++++---------------------------------
1 file changed, 11 insertions(+), 33 deletions(-)
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c
index 6849c3f..88af2af 100644
--- a/fs/proc/vmcore.c
+++ b/fs/proc/vmcore.c
@@ -199,36 +199,15 @@ static struct vmcore* __init get_new_element(void)
return kzalloc(sizeof(struct vmcore), GFP_KERNEL);
}
-static u64 __init get_vmcore_size_elf64(char *elfptr, size_t elfsz)
+static u64 __init get_vmcore_size(size_t elfsz, size_t elfnotesegsz,
+ struct list_head *vc_list)
{
- int i;
u64 size;
- Elf64_Ehdr *ehdr_ptr;
- Elf64_Phdr *phdr_ptr;
-
- ehdr_ptr = (Elf64_Ehdr *)elfptr;
- phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr));
- size = elfsz;
- for (i = 0; i < ehdr_ptr->e_phnum; i++) {
- size += phdr_ptr->p_memsz;
- phdr_ptr++;
- }
- return size;
-}
-
-static u64 __init get_vmcore_size_elf32(char *elfptr, size_t elfsz)
-{
- int i;
- u64 size;
- Elf32_Ehdr *ehdr_ptr;
- Elf32_Phdr *phdr_ptr;
+ struct vmcore *m;
- ehdr_ptr = (Elf32_Ehdr *)elfptr;
- phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr));
- size = elfsz;
- for (i = 0; i < ehdr_ptr->e_phnum; i++) {
- size += phdr_ptr->p_memsz;
- phdr_ptr++;
+ size = elfsz + elfnotesegsz;
+ list_for_each_entry(m, vc_list, list) {
+ size += m->size;
}
return size;
}
@@ -854,21 +833,20 @@ static int __init parse_crash_elf_headers(void)
rc = parse_crash_elf64_headers();
if (rc)
return rc;
-
- /* Determine vmcore size. */
- vmcore_size = get_vmcore_size_elf64(elfcorebuf, elfcorebuf_sz);
} else if (e_ident[EI_CLASS] == ELFCLASS32) {
rc = parse_crash_elf32_headers();
if (rc)
return rc;
-
- /* Determine vmcore size. */
- vmcore_size = get_vmcore_size_elf32(elfcorebuf, elfcorebuf_sz);
} else {
printk(KERN_WARNING "Warning: Core image elf header is not"
" sane\n");
return -EINVAL;
}
+
+ /* Determine vmcore size. */
+ vmcore_size = get_vmcore_size(elfcorebuf_sz, elfnotes_sz,
+ &vmcore_list);
+
return 0;
}
--
2.1.0
^ permalink raw reply [flat|nested] 24+ messages in thread
* [RHEL6.8 Patch 14/19] vmcore: support mmap() on /proc/vmcore
2015-07-16 8:46 [RHEL6.8 Patch 00/19] Support mmap() on /proc/vmcore Baoquan He
` (15 preceding siblings ...)
2015-07-16 8:47 ` [RHEL6.8 Patch 13/19] vmcore: calculate vmcore file size from buffer size and total size of vmcore objects Baoquan He
@ 2015-07-16 8:47 ` Baoquan He
2015-07-16 8:47 ` [RHEL6.8 Patch 15/19] s390/kdump: Disable mmap for s390 Baoquan He
` (5 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Baoquan He @ 2015-07-16 8:47 UTC (permalink / raw)
To: linux-kernel, ncroxon, dyoung, mhuang; +Cc: Baoquan He
Resolves: bz1097904
https://bugzilla.redhat.com/show_bug.cgi?id=1097904
This is back ported from upstream. Conflict exists since
commit 73296bc611cee009f3be6b451e827d1425b9c10f is not back ported.
commit 83086978c63afd7c73e1c173c84aeab184c1e916
Author: HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com>
Date: Wed Jul 3 15:02:23 2013 -0700
vmcore: support mmap() on /proc/vmcore
This patch introduces mmap_vmcore().
Don't permit writable nor executable mapping even with mprotect()
because this mmap() is aimed at reading crash dump memory. Non-writable
mapping is also requirement of remap_pfn_range() when mapping linear
pages on non-consecutive physical pages; see is_cow_mapping().
Set VM_MIXEDMAP flag to remap memory by remap_pfn_range and by
remap_vmalloc_range_pertial at the same time for a single vma.
do_munmap() can correctly clean partially remapped vma with two
functions in abnormal case. See zap_pte_range(), vm_normal_page() and
their comments for details.
On x86-32 PAE kernels, mmap() supports at most 16TB memory only. This
limitation comes from the fact that the third argument of
remap_pfn_range(), pfn, is of 32-bit length on x86-32: unsigned long.
[akpm@linux-foundation.org: use min(), switch to conventional error-unwinding approach]
Signed-off-by: HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com>
Acked-by: Vivek Goyal <vgoyal@redhat.com>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Atsushi Kumagai <kumagai-atsushi@mxc.nes.nec.co.jp>
Cc: Lisa Mitchell <lisa.mitchell@hp.com>
Cc: Zhang Yanfei <zhangyanfei@cn.fujitsu.com>
Tested-by: Maxim Uvarov <muvarov@gmail.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Baoquan He <bhe@redhat.com>
---
fs/proc/vmcore.c | 138 +++++++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 118 insertions(+), 20 deletions(-)
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c
index 88af2af..f083c15 100644
--- a/fs/proc/vmcore.c
+++ b/fs/proc/vmcore.c
@@ -16,6 +16,7 @@
#include <linux/bootmem.h>
#include <linux/init.h>
#include <linux/crash_dump.h>
+#include <linux/vmalloc.h>
#include <linux/list.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -190,8 +191,123 @@ static ssize_t read_vmcore(struct file *file, char __user *buffer,
return acc;
}
+/**
+ * alloc_elfnotes_buf - allocate buffer for ELF note segment in
+ * vmalloc memory
+ *
+ * @notes_sz: size of buffer
+ *
+ * If CONFIG_MMU is defined, use vmalloc_user() to allow users to mmap
+ * the buffer to user-space by means of remap_vmalloc_range().
+ *
+ * If CONFIG_MMU is not defined, use vzalloc() since mmap_vmcore() is
+ * disabled and there's no need to allow users to mmap the buffer.
+ */
+static inline char *alloc_elfnotes_buf(size_t notes_sz)
+{
+#ifdef CONFIG_MMU
+ return vmalloc_user(notes_sz);
+#else
+ return vzalloc(notes_sz);
+#endif
+}
+
+/*
+ * Disable mmap_vmcore() if CONFIG_MMU is not defined. MMU is
+ * essential for mmap_vmcore() in order to map physically
+ * non-contiguous objects (ELF header, ELF note segment and memory
+ * regions in the 1st kernel pointed to by PT_LOAD entries) into
+ * virtually contiguous user-space in ELF layout.
+ */
+#ifdef CONFIG_MMU
+static int mmap_vmcore(struct file *file, struct vm_area_struct *vma)
+{
+ size_t size = vma->vm_end - vma->vm_start;
+ u64 start, end, len, tsz;
+ struct vmcore *m;
+
+ start = (u64)vma->vm_pgoff << PAGE_SHIFT;
+ end = start + size;
+
+ if (size > vmcore_size || end > vmcore_size)
+ return -EINVAL;
+
+ if (vma->vm_flags & (VM_WRITE | VM_EXEC))
+ return -EPERM;
+
+ vma->vm_flags &= ~(VM_MAYWRITE | VM_MAYEXEC);
+ vma->vm_flags |= VM_MIXEDMAP;
+
+ len = 0;
+
+ if (start < elfcorebuf_sz) {
+ u64 pfn;
+
+ tsz = min(elfcorebuf_sz - (size_t)start, size);
+ pfn = __pa(elfcorebuf + start) >> PAGE_SHIFT;
+ if (remap_pfn_range(vma, vma->vm_start, pfn, tsz,
+ vma->vm_page_prot))
+ return -EAGAIN;
+ size -= tsz;
+ start += tsz;
+ len += tsz;
+
+ if (size == 0)
+ return 0;
+ }
+
+ if (start < elfcorebuf_sz + elfnotes_sz) {
+ void *kaddr;
+
+ tsz = min(elfcorebuf_sz + elfnotes_sz - (size_t)start, size);
+ kaddr = elfnotes_buf + start - elfcorebuf_sz;
+ if (remap_vmalloc_range_partial(vma, vma->vm_start + len,
+ kaddr, tsz))
+ goto fail;
+ size -= tsz;
+ start += tsz;
+ len += tsz;
+
+ if (size == 0)
+ return 0;
+ }
+
+ list_for_each_entry(m, &vmcore_list, list) {
+ if (start < m->offset + m->size) {
+ u64 paddr = 0;
+
+ tsz = min_t(size_t, m->offset + m->size - start, size);
+ paddr = m->paddr + start - m->offset;
+ if (remap_pfn_range(vma, vma->vm_start + len,
+ paddr >> PAGE_SHIFT, tsz,
+ vma->vm_page_prot))
+ goto fail;
+ size -= tsz;
+ start += tsz;
+ len += tsz;
+
+ if (size == 0)
+ return 0;
+ }
+ }
+
+ return 0;
+fail:
+ do_munmap(vma->vm_mm, vma->vm_start, len);
+ return -EAGAIN;
+}
+#else
+static int mmap_vmcore(struct file *file, struct vm_area_struct *vma)
+{
+ return -ENOSYS;
+}
+#endif
+
+
+
static const struct file_operations proc_vmcore_operations = {
.read = read_vmcore,
+ .mmap = mmap_vmcore,
};
static struct vmcore* __init get_new_element(void)
@@ -343,7 +459,6 @@ static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz,
Elf64_Ehdr *ehdr_ptr;
Elf64_Phdr phdr;
u64 phdr_sz = 0, note_off;
- struct vm_struct *vm;
ehdr_ptr = (Elf64_Ehdr *)elfptr;
@@ -356,18 +471,10 @@ static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz,
return rc;
*notes_sz = roundup(phdr_sz, PAGE_SIZE);
- *notes_buf = vzalloc(*notes_sz);
+ *notes_buf = alloc_elfnotes_buf(*notes_sz);
if (!*notes_buf)
return -ENOMEM;
- /*
- * Allow users to remap ELF note segment buffer on vmalloc memory using
- * remap_vmalloc_range.()
- */
- vm = find_vm_area(*notes_buf);
- BUG_ON(!vm);
- vm->flags |= VM_USERMAP;
-
rc = copy_notes_elf64(ehdr_ptr, *notes_buf);
if (rc < 0)
return rc;
@@ -531,7 +638,6 @@ static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz,
Elf32_Ehdr *ehdr_ptr;
Elf32_Phdr phdr;
u64 phdr_sz = 0, note_off;
- struct vm_struct *vm;
ehdr_ptr = (Elf32_Ehdr *)elfptr;
@@ -544,18 +650,10 @@ static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz,
return rc;
*notes_sz = roundup(phdr_sz, PAGE_SIZE);
- *notes_buf = vzalloc(*notes_sz);
+ *notes_buf = alloc_elfnotes_buf(*notes_sz);
if (!*notes_buf)
return -ENOMEM;
- /*
- * Allow users to remap ELF note segment buffer on vmalloc memory using
- * remap_vmalloc_range()
- */
- vm = find_vm_area(*notes_buf);
- BUG_ON(!vm);
- vm->flags |= VM_USERMAP;
-
rc = copy_notes_elf32(ehdr_ptr, *notes_buf);
if (rc < 0)
return rc;
--
2.1.0
^ permalink raw reply [flat|nested] 24+ messages in thread
* [RHEL6.8 Patch 15/19] s390/kdump: Disable mmap for s390
2015-07-16 8:46 [RHEL6.8 Patch 00/19] Support mmap() on /proc/vmcore Baoquan He
` (16 preceding siblings ...)
2015-07-16 8:47 ` [RHEL6.8 Patch 14/19] vmcore: support mmap() on /proc/vmcore Baoquan He
@ 2015-07-16 8:47 ` Baoquan He
2015-07-16 8:47 ` [RHEL6.8 Patch 16/19] s390/kdump: Allow copy_oldmem_page() copy to virtual memory Baoquan He
` (4 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Baoquan He @ 2015-07-16 8:47 UTC (permalink / raw)
To: linux-kernel, ncroxon, dyoung, mhuang; +Cc: Baoquan He
Resolves: bz1097904
https://bugzilla.redhat.com/show_bug.cgi?id=1097904
This is back ported from upstream.
commit 5a74953ff56aa870d6913ef4d81934f5c620c59d
Author: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Date: Thu Jul 18 12:17:57 2013 +0200
s390/kdump: Disable mmap for s390
The kdump mmap patch series (git commit 83086978c63afd7c73e1c) directly
map the PT_LOADs to memory. On s390 this does not work because the
copy_from_oldmem() function swaps [0,crashkernel size] with
[crashkernel base, crashkernel base+crashkernel size]. The swap
int copy_from_oldmem() was done in order correctly implement /dev/oldmem.
See: http://marc.info/?l=kexec&m=136940802511603&w=2
Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Baoquan He <bhe@redhat.com>
---
fs/proc/vmcore.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c
index f083c15..e93bcf9 100644
--- a/fs/proc/vmcore.c
+++ b/fs/proc/vmcore.c
@@ -219,7 +219,7 @@ static inline char *alloc_elfnotes_buf(size_t notes_sz)
* regions in the 1st kernel pointed to by PT_LOAD entries) into
* virtually contiguous user-space in ELF layout.
*/
-#ifdef CONFIG_MMU
+#if defined(CONFIG_MMU) && !defined(CONFIG_S390)
static int mmap_vmcore(struct file *file, struct vm_area_struct *vma)
{
size_t size = vma->vm_end - vma->vm_start;
--
2.1.0
^ permalink raw reply [flat|nested] 24+ messages in thread
* [RHEL6.8 Patch 16/19] s390/kdump: Allow copy_oldmem_page() copy to virtual memory
2015-07-16 8:46 [RHEL6.8 Patch 00/19] Support mmap() on /proc/vmcore Baoquan He
` (17 preceding siblings ...)
2015-07-16 8:47 ` [RHEL6.8 Patch 15/19] s390/kdump: Disable mmap for s390 Baoquan He
@ 2015-07-16 8:47 ` Baoquan He
2015-07-16 8:47 ` [RHEL6.8 Patch 17/19] vmcore: introduce remap_oldmem_pfn_range() Baoquan He
` (3 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Baoquan He @ 2015-07-16 8:47 UTC (permalink / raw)
To: linux-kernel, ncroxon, dyoung, mhuang; +Cc: Baoquan He
Resolves: bz1097904
https://bugzilla.redhat.com/show_bug.cgi?id=1097904
This is back ported from upstream. It need be edited manually since
several irrelevant commits are not back ported.
commit 191a2fa0a8d2bbb64c98f9b1976fcb37ee5eae6b
Author: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Date: Thu Jul 18 12:18:27 2013 +0200
s390/kdump: Allow copy_oldmem_page() copy to virtual memory
The kdump mmap patch series (git commit 83086978c63afd7c73e1c) changed the
requirements for copy_oldmem_page(). Now this function is used for copying
to virtual memory.
So implement vmalloc support for the s390 version of copy_oldmem_page().
Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Baoquan He <bhe@redhat.com>
---
arch/s390/kernel/crash_dump.c | 49 ++++++++++++++++++++++++++++++++++++++++---
1 file changed, 46 insertions(+), 3 deletions(-)
diff --git a/arch/s390/kernel/crash_dump.c b/arch/s390/kernel/crash_dump.c
index b66edb9..0f70217 100644
--- a/arch/s390/kernel/crash_dump.c
+++ b/arch/s390/kernel/crash_dump.c
@@ -56,6 +56,47 @@ static int __init setup_elfcorehdr(char *arg)
early_param("elfcorehdr", setup_elfcorehdr);
/*
+ * Return physical address for virtual address
+ */
+static inline void *load_real_addr(void *addr)
+{
+ unsigned long real_addr;
+
+ asm volatile(
+ " lra %0,0(%1)\n"
+ " jz 0f\n"
+ " la %0,0\n"
+ "0:"
+ : "=a" (real_addr) : "a" (addr) : "cc");
+ return (void *)real_addr;
+}
+
+/*
+ * Copy up to one page to vmalloc or real memory
+ */
+static ssize_t copy_page_real(void *buf, void *src, size_t csize)
+{
+ size_t size;
+
+ if (is_vmalloc_addr(buf)) {
+ BUG_ON(csize >= PAGE_SIZE);
+ /* If buf is not page aligned, copy first part */
+ size = min(roundup(__pa(buf), PAGE_SIZE) - __pa(buf), csize);
+ if (size) {
+ if (memcpy_real(load_real_addr(buf), src, size))
+ return -EFAULT;
+ buf += size;
+ src += size;
+ }
+ /* Copy second part */
+ size = csize - size;
+ return (size) ? memcpy_real(load_real_addr(buf), src, size) : 0;
+ } else {
+ return memcpy_real(buf, src, csize);
+ }
+}
+
+/*
* Copy one page from "oldmem"
*
* For the kdump reserved memory this functions performs a swap operation:
@@ -66,6 +107,7 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
size_t csize, unsigned long offset, int userbuf)
{
unsigned long src;
+ int rc;
if (!csize)
return 0;
@@ -77,10 +119,11 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
src < OLDMEM_BASE + OLDMEM_SIZE)
src -= OLDMEM_BASE;
if (userbuf)
- copy_to_user_real((void __user *) buf, (void *) src, csize);
+ rc = copy_to_user_real((void __force __user *) buf,
+ (void *) src, csize);
else
- memcpy_real(buf, (void *) src, csize);
- return csize;
+ rc = copy_page_real(buf, (void *) src, csize);
+ return (rc == 0) ? csize : rc;
}
/*
--
2.1.0
^ permalink raw reply [flat|nested] 24+ messages in thread
* [RHEL6.8 Patch 17/19] vmcore: introduce remap_oldmem_pfn_range()
2015-07-16 8:46 [RHEL6.8 Patch 00/19] Support mmap() on /proc/vmcore Baoquan He
` (18 preceding siblings ...)
2015-07-16 8:47 ` [RHEL6.8 Patch 16/19] s390/kdump: Allow copy_oldmem_page() copy to virtual memory Baoquan He
@ 2015-07-16 8:47 ` Baoquan He
2015-07-16 8:47 ` [RHEL6.8 Patch 18/19] s390/vmcore: implement remap_oldmem_pfn_range for s390 Baoquan He
` (2 subsequent siblings)
22 siblings, 0 replies; 24+ messages in thread
From: Baoquan He @ 2015-07-16 8:47 UTC (permalink / raw)
To: linux-kernel, ncroxon, dyoung, mhuang; +Cc: Baoquan He
Resolves: bz1097904
https://bugzilla.redhat.com/show_bug.cgi?id=1097904
This is back ported from upstream.
commit 9cb218131de1c59dca9063b2efe876f053f316af
Author: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Date: Wed Sep 11 14:24:51 2013 -0700
vmcore: introduce remap_oldmem_pfn_range()
For zfcpdump we can't map the HSA storage because it is only available via
a read interface. Therefore, for the new vmcore mmap feature we have
introduce a new mechanism to create mappings on demand.
This patch introduces a new architecture function remap_oldmem_pfn_range()
that should be used to create mappings with remap_pfn_range() for oldmem
areas that can be directly mapped. For zfcpdump this is everything
besides of the HSA memory. For the areas that are not mapped by
remap_oldmem_pfn_range() a generic vmcore a new generic vmcore fault
handler mmap_vmcore_fault() is called.
This handler works as follows:
* Get already available or new page from page cache (find_or_create_page)
* Check if /proc/vmcore page is filled with data (PageUptodate)
* If yes:
Return that page
* If no:
Fill page using __vmcore_read(), set PageUptodate, and return page
Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Acked-by: Vivek Goyal <vgoyal@redhat.com>
Cc: HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com>
Cc: Jan Willeke <willeke@de.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Baoquan He <bhe@redhat.com>
---
fs/proc/vmcore.c | 91 ++++++++++++++++++++++++++++++++++++++++++----
include/linux/crash_dump.h | 4 ++
2 files changed, 87 insertions(+), 8 deletions(-)
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c
index e93bcf9..6d7d646 100644
--- a/fs/proc/vmcore.c
+++ b/fs/proc/vmcore.c
@@ -17,6 +17,7 @@
#include <linux/init.h>
#include <linux/crash_dump.h>
#include <linux/vmalloc.h>
+#include <linux/pagemap.h>
#include <linux/list.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -119,11 +120,35 @@ static ssize_t read_from_oldmem(char *buf, size_t count,
return read;
}
+/*
+ * Architectures may override this function to map oldmem
+ */
+int __weak remap_oldmem_pfn_range(struct vm_area_struct *vma,
+ unsigned long from, unsigned long pfn,
+ unsigned long size, pgprot_t prot)
+{
+ return remap_pfn_range(vma, from, pfn, size, prot);
+}
+
+/*
+ * Copy to either kernel or user space
+ */
+static int copy_to(void *target, void *src, size_t size, int userbuf)
+{
+ if (userbuf) {
+ if (copy_to_user((char __user *) target, src, size))
+ return -EFAULT;
+ } else {
+ memcpy(target, src, size);
+ }
+ return 0;
+}
+
/* Read from the ELF header and then the crash dump. On error, negative value is
* returned otherwise number of bytes read are returned.
*/
-static ssize_t read_vmcore(struct file *file, char __user *buffer,
- size_t buflen, loff_t *fpos)
+static ssize_t __read_vmcore(char *buffer, size_t buflen, loff_t *fpos,
+ int userbuf)
{
ssize_t acc = 0, tmp;
size_t tsz;
@@ -140,7 +165,7 @@ static ssize_t read_vmcore(struct file *file, char __user *buffer,
/* Read ELF core header */
if (*fpos < elfcorebuf_sz) {
tsz = min(elfcorebuf_sz - (size_t)*fpos, buflen);
- if (copy_to_user(buffer, elfcorebuf + *fpos, tsz))
+ if (copy_to(buffer, elfcorebuf + *fpos, tsz, userbuf))
return -EFAULT;
buflen -= tsz;
*fpos += tsz;
@@ -158,7 +183,7 @@ static ssize_t read_vmcore(struct file *file, char __user *buffer,
tsz = min(elfcorebuf_sz + elfnotes_sz - (size_t)*fpos, buflen);
kaddr = elfnotes_buf + *fpos - elfcorebuf_sz;
- if (copy_to_user(buffer, kaddr, tsz))
+ if (copy_to(buffer, kaddr, tsz, userbuf))
return -EFAULT;
buflen -= tsz;
*fpos += tsz;
@@ -174,7 +199,7 @@ static ssize_t read_vmcore(struct file *file, char __user *buffer,
if (*fpos < m->offset + m->size) {
tsz = min_t(size_t, m->offset + m->size - *fpos, buflen);
start = m->paddr + *fpos - m->offset;
- tmp = read_from_oldmem(buffer, tsz, &start, 1);
+ tmp = read_from_oldmem(buffer, tsz, &start, userbuf);
if (tmp < 0)
return tmp;
buflen -= tsz;
@@ -191,6 +216,55 @@ static ssize_t read_vmcore(struct file *file, char __user *buffer,
return acc;
}
+static ssize_t read_vmcore(struct file *file, char __user *buffer,
+ size_t buflen, loff_t *fpos)
+{
+ return __read_vmcore((__force char *) buffer, buflen, fpos, 1);
+}
+
+/*
+ * The vmcore fault handler uses the page cache and fills data using the
+ * standard __vmcore_read() function.
+ *
+ * On s390 the fault handler is used for memory regions that can't be mapped
+ * directly with remap_pfn_range().
+ */
+static int mmap_vmcore_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+#ifdef CONFIG_S390
+ struct address_space *mapping = vma->vm_file->f_mapping;
+ pgoff_t index = vmf->pgoff;
+ struct page *page;
+ loff_t offset;
+ char *buf;
+ int rc;
+
+ page = find_or_create_page(mapping, index, GFP_KERNEL);
+ if (!page)
+ return VM_FAULT_OOM;
+ if (!PageUptodate(page)) {
+ offset = (loff_t) index << PAGE_CACHE_SHIFT;
+ buf = __va((page_to_pfn(page) << PAGE_SHIFT));
+ rc = __read_vmcore(buf, PAGE_SIZE, &offset, 0);
+ if (rc < 0) {
+ unlock_page(page);
+ page_cache_release(page);
+ return (rc == -ENOMEM) ? VM_FAULT_OOM : VM_FAULT_SIGBUS;
+ }
+ SetPageUptodate(page);
+ }
+ unlock_page(page);
+ vmf->page = page;
+ return 0;
+#else
+ return VM_FAULT_SIGBUS;
+#endif
+}
+
+static const struct vm_operations_struct vmcore_mmap_ops = {
+ .fault = mmap_vmcore_fault,
+};
+
/**
* alloc_elfnotes_buf - allocate buffer for ELF note segment in
* vmalloc memory
@@ -237,6 +311,7 @@ static int mmap_vmcore(struct file *file, struct vm_area_struct *vma)
vma->vm_flags &= ~(VM_MAYWRITE | VM_MAYEXEC);
vma->vm_flags |= VM_MIXEDMAP;
+ vma->vm_ops = &vmcore_mmap_ops;
len = 0;
@@ -278,9 +353,9 @@ static int mmap_vmcore(struct file *file, struct vm_area_struct *vma)
tsz = min_t(size_t, m->offset + m->size - start, size);
paddr = m->paddr + start - m->offset;
- if (remap_pfn_range(vma, vma->vm_start + len,
- paddr >> PAGE_SHIFT, tsz,
- vma->vm_page_prot))
+ if (remap_oldmem_pfn_range(vma, vma->vm_start + len,
+ paddr >> PAGE_SHIFT, tsz,
+ vma->vm_page_prot))
goto fail;
size -= tsz;
start += tsz;
diff --git a/include/linux/crash_dump.h b/include/linux/crash_dump.h
index 6719454..a0c54ec 100644
--- a/include/linux/crash_dump.h
+++ b/include/linux/crash_dump.h
@@ -11,6 +11,10 @@
extern unsigned long long elfcorehdr_addr;
+extern int remap_oldmem_pfn_range(struct vm_area_struct *vma,
+ unsigned long from, unsigned long pfn,
+ unsigned long size, pgprot_t prot);
+
extern ssize_t copy_oldmem_page(unsigned long, char *, size_t,
unsigned long, int);
--
2.1.0
^ permalink raw reply [flat|nested] 24+ messages in thread
* [RHEL6.8 Patch 18/19] s390/vmcore: implement remap_oldmem_pfn_range for s390
2015-07-16 8:46 [RHEL6.8 Patch 00/19] Support mmap() on /proc/vmcore Baoquan He
` (19 preceding siblings ...)
2015-07-16 8:47 ` [RHEL6.8 Patch 17/19] vmcore: introduce remap_oldmem_pfn_range() Baoquan He
@ 2015-07-16 8:47 ` Baoquan He
2015-07-16 8:47 ` [RHEL6.8 Patch 19/19] fs/proc/vmcore.c:mmap_vmcore: skip non-ram pages reported by hypervisors Baoquan He
2015-07-16 11:01 ` [RHEL6.8 Patch 00/19] Support mmap() on /proc/vmcore Baoquan He
22 siblings, 0 replies; 24+ messages in thread
From: Baoquan He @ 2015-07-16 8:47 UTC (permalink / raw)
To: linux-kernel, ncroxon, dyoung, mhuang; +Cc: Baoquan He
Resolves: bz1097904
https://bugzilla.redhat.com/show_bug.cgi?id=1097904
This is back ported from upstream.
commit 23df79da8eb97757e39af7625665c1c5cecc610b
Author: Jan Willeke <willeke@de.ibm.com>
Date: Wed Sep 11 14:24:52 2013 -0700
s390/vmcore: implement remap_oldmem_pfn_range for s390
Introduce the s390 specific way to map pages from oldmem. The memory area
below OLDMEM_SIZE is mapped with offset OLDMEM_BASE. The other old memory
is mapped directly.
Signed-off-by: Jan Willeke <willeke@de.ibm.com>
Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Cc: HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com>
Cc: Vivek Goyal <vgoyal@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Baoquan He <bhe@redhat.com>
---
arch/s390/kernel/crash_dump.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/arch/s390/kernel/crash_dump.c b/arch/s390/kernel/crash_dump.c
index 0f70217..1f38051 100644
--- a/arch/s390/kernel/crash_dump.c
+++ b/arch/s390/kernel/crash_dump.c
@@ -127,6 +127,32 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
}
/*
+ * Remap "oldmem"
+ *
+ * For the kdump reserved memory this functions performs a swap operation:
+ * [0 - OLDMEM_SIZE] is mapped to [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE]
+ */
+int remap_oldmem_pfn_range(struct vm_area_struct *vma, unsigned long from,
+ unsigned long pfn, unsigned long size, pgprot_t prot)
+{
+ unsigned long size_old;
+ int rc;
+
+ if (pfn < OLDMEM_SIZE >> PAGE_SHIFT) {
+ size_old = min(size, OLDMEM_SIZE - (pfn << PAGE_SHIFT));
+ rc = remap_pfn_range(vma, from,
+ pfn + (OLDMEM_BASE >> PAGE_SHIFT),
+ size_old, prot);
+ if (rc || size == size_old)
+ return rc;
+ size -= size_old;
+ from += size_old;
+ pfn += size_old >> PAGE_SHIFT;
+ }
+ return remap_pfn_range(vma, from, pfn, size, prot);
+}
+
+/*
* Copy memory from old kernel
*/
static int copy_from_oldmem(void *dest, void *src, size_t count)
--
2.1.0
^ permalink raw reply [flat|nested] 24+ messages in thread
* [RHEL6.8 Patch 19/19] fs/proc/vmcore.c:mmap_vmcore: skip non-ram pages reported by hypervisors
2015-07-16 8:46 [RHEL6.8 Patch 00/19] Support mmap() on /proc/vmcore Baoquan He
` (20 preceding siblings ...)
2015-07-16 8:47 ` [RHEL6.8 Patch 18/19] s390/vmcore: implement remap_oldmem_pfn_range for s390 Baoquan He
@ 2015-07-16 8:47 ` Baoquan He
2015-07-16 11:01 ` [RHEL6.8 Patch 00/19] Support mmap() on /proc/vmcore Baoquan He
22 siblings, 0 replies; 24+ messages in thread
From: Baoquan He @ 2015-07-16 8:47 UTC (permalink / raw)
To: linux-kernel, ncroxon, dyoung, mhuang; +Cc: Baoquan He
Resolves: bz1097904
https://bugzilla.redhat.com/show_bug.cgi?id=1097904
This is back ported from upstream.
commit 0692dedcf64bf3cdcfb9f6a51c70d49c8db351d2
Author: Vitaly Kuznetsov <vkuznets@redhat.com>
Date: Fri Aug 8 14:22:05 2014 -0700
fs/proc/vmcore.c:mmap_vmcore: skip non-ram pages reported by hypervisors
We have a special check in read_vmcore() handler to check if the page was
reported as ram or not by the hypervisor (pfn_is_ram()). However, when
vmcore is read with mmap() no such check is performed. That can lead to
unpredictable results, e.g. when running Xen PVHVM guest memcpy() after
mmap() on /proc/vmcore will hang processing HVMMEM_mmio_dm pages creating
enormous load in both DomU and Dom0.
Fix the issue by mapping each non-ram page to the zero page. Keep direct
path with remap_oldmem_pfn_range() to avoid looping through all pages on
bare metal.
The issue can also be solved by overriding remap_oldmem_pfn_range() in
xen-specific code, as remap_oldmem_pfn_range() was been designed for.
That, however, would involve non-obvious xen code path for all x86 builds
with CONFIG_XEN_PVHVM=y and would prevent all other hypervisor-specific
code on x86 arch from doing the same override.
[fengguang.wu@intel.com: remap_oldmem_pfn_checked() can be static]
[akpm@linux-foundation.org: clean up layout]
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
Reviewed-by: Andrew Jones <drjones@redhat.com>
Cc: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Acked-by: Vivek Goyal <vgoyal@redhat.com>
Cc: David Vrabel <david.vrabel@citrix.com>
Signed-off-by: Fengguang Wu <fengguang.wu@intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Baoquan He <bhe@redhat.com>
---
fs/proc/vmcore.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 79 insertions(+), 3 deletions(-)
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c
index 6d7d646..0d962bc 100644
--- a/fs/proc/vmcore.c
+++ b/fs/proc/vmcore.c
@@ -294,6 +294,82 @@ static inline char *alloc_elfnotes_buf(size_t notes_sz)
* virtually contiguous user-space in ELF layout.
*/
#if defined(CONFIG_MMU) && !defined(CONFIG_S390)
+/*
+ * remap_oldmem_pfn_checked - do remap_oldmem_pfn_range replacing all pages
+ * reported as not being ram with the zero page.
+ *
+ * @vma: vm_area_struct describing requested mapping
+ * @from: start remapping from
+ * @pfn: page frame number to start remapping to
+ * @size: remapping size
+ * @prot: protection bits
+ *
+ * Returns zero on success, -EAGAIN on failure.
+ */
+static int remap_oldmem_pfn_checked(struct vm_area_struct *vma,
+ unsigned long from, unsigned long pfn,
+ unsigned long size, pgprot_t prot)
+{
+ unsigned long map_size;
+ unsigned long pos_start, pos_end, pos;
+ unsigned long zeropage_pfn = my_zero_pfn(0);
+ size_t len = 0;
+
+ pos_start = pfn;
+ pos_end = pfn + (size >> PAGE_SHIFT);
+
+ for (pos = pos_start; pos < pos_end; ++pos) {
+ if (!pfn_is_ram(pos)) {
+ /*
+ * We hit a page which is not ram. Remap the continuous
+ * region between pos_start and pos-1 and replace
+ * the non-ram page at pos with the zero page.
+ */
+ if (pos > pos_start) {
+ /* Remap continuous region */
+ map_size = (pos - pos_start) << PAGE_SHIFT;
+ if (remap_oldmem_pfn_range(vma, from + len,
+ pos_start, map_size,
+ prot))
+ goto fail;
+ len += map_size;
+ }
+ /* Remap the zero page */
+ if (remap_oldmem_pfn_range(vma, from + len,
+ zeropage_pfn,
+ PAGE_SIZE, prot))
+ goto fail;
+ len += PAGE_SIZE;
+ pos_start = pos + 1;
+ }
+ }
+ if (pos > pos_start) {
+ /* Remap the rest */
+ map_size = (pos - pos_start) << PAGE_SHIFT;
+ if (remap_oldmem_pfn_range(vma, from + len, pos_start,
+ map_size, prot))
+ goto fail;
+ }
+ return 0;
+fail:
+ do_munmap(vma->vm_mm, from, len);
+ return -EAGAIN;
+}
+
+static int vmcore_remap_oldmem_pfn(struct vm_area_struct *vma,
+ unsigned long from, unsigned long pfn,
+ unsigned long size, pgprot_t prot)
+{
+ /*
+ * Check if oldmem_pfn_is_ram was registered to avoid
+ * looping over all pages without a reason.
+ */
+ if (oldmem_pfn_is_ram)
+ return remap_oldmem_pfn_checked(vma, from, pfn, size, prot);
+ else
+ return remap_oldmem_pfn_range(vma, from, pfn, size, prot);
+}
+
static int mmap_vmcore(struct file *file, struct vm_area_struct *vma)
{
size_t size = vma->vm_end - vma->vm_start;
@@ -353,9 +429,9 @@ static int mmap_vmcore(struct file *file, struct vm_area_struct *vma)
tsz = min_t(size_t, m->offset + m->size - start, size);
paddr = m->paddr + start - m->offset;
- if (remap_oldmem_pfn_range(vma, vma->vm_start + len,
- paddr >> PAGE_SHIFT, tsz,
- vma->vm_page_prot))
+ if (vmcore_remap_oldmem_pfn(vma, vma->vm_start + len,
+ paddr >> PAGE_SHIFT, tsz,
+ vma->vm_page_prot))
goto fail;
size -= tsz;
start += tsz;
--
2.1.0
^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [RHEL6.8 Patch 00/19] Support mmap() on /proc/vmcore
2015-07-16 8:46 [RHEL6.8 Patch 00/19] Support mmap() on /proc/vmcore Baoquan He
` (21 preceding siblings ...)
2015-07-16 8:47 ` [RHEL6.8 Patch 19/19] fs/proc/vmcore.c:mmap_vmcore: skip non-ram pages reported by hypervisors Baoquan He
@ 2015-07-16 11:01 ` Baoquan He
22 siblings, 0 replies; 24+ messages in thread
From: Baoquan He @ 2015-07-16 11:01 UTC (permalink / raw)
To: linux-kernel, ncroxon, dyoung, mhuang
Sorry to bother you. I just sent to the wrong mailing list. Please
ignore this thread.
On 07/16/15 at 04:46pm, Baoquan He wrote:
> This patchset includes 3 parts.
>
> -------------------------------------
> 1st part:
> Includes 13 upstream commits. They are recommended by Nigel Croxon
> since he back ported this feature to rhel7. This 13 back ports
> works for all ARCHs except of s390 since it always broke s390n kdump.
>
> c2c1b08 fs/proc/vmcore.c: put if tests in the top of the while loop to reduce duplication
> 0fa73b8 include/linux/mm.h: add PAGE_ALIGNED() helper
> b27eb18 vmcore: clean up read_vmcore()
> f2bdacd vmcore: allocate buffer for ELF headers on page-size alignment
> 7f614cd vmcore: treat memory chunks referenced by PT_LOAD program header entries in page-size boundary in vmcore_list
> cef2ac3 vmalloc: make find_vm_area check in range
> e69e9d4a vmalloc: introduce remap_vmalloc_range_partial
> 087350c vmcore: allocate ELF note segment in the 2nd kernel vmalloc memory
> ef9e78f vmcore: allow user process to remap ELF note segment buffer
> 591ff71 vmcore: calculate vmcore file size from buffer size and total size of vmcore objects
> 8308697 vmcore: support mmap() on /proc/vmcore
> 5a74953 s390/kdump: Disable mmap for s390
> 0692ded fs/proc/vmcore.c:mmap_vmcore: skip non-ram pages reported by hypervisors
>
> -------------------------------------
> 2nd part:
> Includes several s390 related memory commits. Since these 13 commits
> in 1st part worked on all ARCHs except of S390. Then I asked IBM
> S390 kernel developers Michael Holzheu <michael.holzheu@de.ibm.com>,
> Jan Willeke <WILLEKE@de.ibm.com> to help, they suggested these 3 commits.
> With them it works for s390 kdump.
>
> 191a2fa s390/kdump: Allow copy_oldmem_page() copy to virtual memory"
> 9cb2181 vmcore: introduce remap_oldmem_pfn_range()"
> 23df79d s390/vmcore: implement remap_oldmem_pfn_range for s390"
>
> -------------------------------------
> 3rd part:
> Includes 3 commits. They are back ported because 3 commits in
> 2nd part will fail x86 and ppc compiling.
>
> 997c136 fs/proc/vmcore.c: add hook to read_from_oldmem() to check for non-ram pages
> 816422a asm-generic, mm: pgtable: consolidate zero page helpers
> 238ec4e [S390] zero page cache synonyms
>
>
> Brew build:
>
> I made a brew build here and tested it on s390 and x86 machine,
> both works.
> https://brewweb.devel.redhat.com/taskinfo?taskID=9357037
>
> Then Nigel took patches from my rh-git and made a brew build as below.
> Lisa from HP took a test and confirmed this works on HP machines
> and it improved the dump as expected.
> https://brewweb.devel.redhat.com/taskinfo?taskID=9380805
>
> My rh-git for this feature is here:
> git://git.engineering.redhat.com/users/bhe/rhel6/.git mmap-new
>
> Baoquan He (19):
> [S390] zero page cache synonyms
> asm-generic, mm: pgtable: consolidate zero page helpers
> fs/proc/vmcore.c: add hook to read_from_oldmem() to check for non-ram
> pages
> fs/proc/vmcore.c: put if tests in the top of the while loop to reduce
> duplication
> include/linux/mm.h: add PAGE_ALIGNED() helper
> vmcore: clean up read_vmcore()
> vmcore: allocate buffer for ELF headers on page-size alignment
> vmcore: treat memory chunks referenced by PT_LOAD program header
> entries in page-size boundary in vmcore_list
> vmalloc: make find_vm_area check in range
> vmalloc: introduce remap_vmalloc_range_partial
> vmcore: allocate ELF note segment in the 2nd kernel vmalloc memory
> vmcore: allow user process to remap ELF note segment buffer
> vmcore: calculate vmcore file size from buffer size and total size of
> vmcore objects
> vmcore: support mmap() on /proc/vmcore
> s390/kdump: Disable mmap for s390
> s390/kdump: Allow copy_oldmem_page() copy to virtual memory
> vmcore: introduce remap_oldmem_pfn_range()
> s390/vmcore: implement remap_oldmem_pfn_range for s390
> fs/proc/vmcore.c:mmap_vmcore: skip non-ram pages reported by
> hypervisors
>
> arch/mips/include/asm/pgtable.h | 10 +-
> arch/s390/include/asm/pgtable.h | 14 +-
> arch/s390/kernel/crash_dump.c | 75 +++-
> arch/s390/mm/init.c | 49 ++-
> fs/proc/vmcore.c | 899 ++++++++++++++++++++++++++++++----------
> include/asm-generic/pgtable.h | 26 ++
> include/linux/crash_dump.h | 9 +
> include/linux/mm.h | 3 +
> include/linux/vmalloc.h | 4 +
> mm/memory.c | 14 -
> mm/vmalloc.c | 70 +++-
> 11 files changed, 901 insertions(+), 272 deletions(-)
>
> --
> 2.1.0
>
^ permalink raw reply [flat|nested] 24+ messages in thread
end of thread, other threads:[~2015-07-16 11:01 UTC | newest]
Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-07-16 8:46 [RHEL6.8 Patch 00/19] Support mmap() on /proc/vmcore Baoquan He
2015-07-16 8:46 ` [RHEL6.8 Patch 1/3] kernel: audit/fix non-modular users of module_init in core code Baoquan He
2015-07-16 8:46 ` [RHEL6.8 Patch 01/19] [S390] zero page cache synonyms Baoquan He
2015-07-16 8:46 ` [RHEL6.8 Patch 02/19] asm-generic, mm: pgtable: consolidate zero page helpers Baoquan He
2015-07-16 8:46 ` [RHEL6.8 Patch 2/3] vmcore: prevent PT_NOTE p_memsz overflow during header update Baoquan He
2015-07-16 8:47 ` [RHEL6.8 Patch 03/19] fs/proc/vmcore.c: add hook to read_from_oldmem() to check for non-ram pages Baoquan He
2015-07-16 8:47 ` [RHEL6.8 Patch 3/3] vmcore: continue vmcore initialization if PT_NOTE is found empty Baoquan He
2015-07-16 8:47 ` [RHEL6.8 Patch 04/19] fs/proc/vmcore.c: put if tests in the top of the while loop to reduce duplication Baoquan He
2015-07-16 8:47 ` [RHEL6.8 Patch 05/19] include/linux/mm.h: add PAGE_ALIGNED() helper Baoquan He
2015-07-16 8:47 ` [RHEL6.8 Patch 06/19] vmcore: clean up read_vmcore() Baoquan He
2015-07-16 8:47 ` [RHEL6.8 Patch 07/19] vmcore: allocate buffer for ELF headers on page-size alignment Baoquan He
2015-07-16 8:47 ` [RHEL6.8 Patch 08/19] vmcore: treat memory chunks referenced by PT_LOAD program header entries in page-size boundary in vmcore_list Baoquan He
2015-07-16 8:47 ` [RHEL6.8 Patch 09/19] vmalloc: make find_vm_area check in range Baoquan He
2015-07-16 8:47 ` [RHEL6.8 Patch 10/19] vmalloc: introduce remap_vmalloc_range_partial Baoquan He
2015-07-16 8:47 ` [RHEL6.8 Patch 11/19] vmcore: allocate ELF note segment in the 2nd kernel vmalloc memory Baoquan He
2015-07-16 8:47 ` [RHEL6.8 Patch 12/19] vmcore: allow user process to remap ELF note segment buffer Baoquan He
2015-07-16 8:47 ` [RHEL6.8 Patch 13/19] vmcore: calculate vmcore file size from buffer size and total size of vmcore objects Baoquan He
2015-07-16 8:47 ` [RHEL6.8 Patch 14/19] vmcore: support mmap() on /proc/vmcore Baoquan He
2015-07-16 8:47 ` [RHEL6.8 Patch 15/19] s390/kdump: Disable mmap for s390 Baoquan He
2015-07-16 8:47 ` [RHEL6.8 Patch 16/19] s390/kdump: Allow copy_oldmem_page() copy to virtual memory Baoquan He
2015-07-16 8:47 ` [RHEL6.8 Patch 17/19] vmcore: introduce remap_oldmem_pfn_range() Baoquan He
2015-07-16 8:47 ` [RHEL6.8 Patch 18/19] s390/vmcore: implement remap_oldmem_pfn_range for s390 Baoquan He
2015-07-16 8:47 ` [RHEL6.8 Patch 19/19] fs/proc/vmcore.c:mmap_vmcore: skip non-ram pages reported by hypervisors Baoquan He
2015-07-16 11:01 ` [RHEL6.8 Patch 00/19] Support mmap() on /proc/vmcore Baoquan He
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®