[PATCH 2/3] makedumpfile: Mark unstored ELF pages as filtered

Petr Tesarik ptesarik at suse.cz
Tue Feb 9 23:49:41 PST 2016


Pages that were filtered in the original dump file should also be filtered
in the destination file, i.e. pages between p_filesz and p_memsz must have
their corresponding bit cleared in the 2nd bitmap. Note that in theory,
such ELF segments might not refer to filtered pages, because the crash
kernel copies the program headers verbatim from elfcorehdr=. However, all
common sources of /proc/vmcore program headers use the same value for each
p_memsz and p_filesz:

a. kexec(8)
   Program headers are created in two places, but in both cases the value
   of p_memsz is equal to p_filesz.
   Reference: kexec/crashdump-elf.c in kexec-tools

b. kexec_file_load(2)
   Conceptually the same code as kexec(8): two places, both set p_filesz
   and p_memsz to the same value.
   Reference: kexec/crashdump-elf.c in Linux kernel

c. created in the crash kernel (s390)
   On s390, program headers are created in the crash kernel, but both
   p_filesz and p_memsz are set to "end - start", i.e. the same value.
   Reference: arch/s390/kernel/crash_dump.c in Linux kernel

The above means that p_memsz > p_filesz only in ELF files that were
processed by makedumpfile, hence it can be safely assumed that pages
between p_filesz and p_memsz were filtered out.

Signed-off-by: Petr Tesarik <ptesarik at suse.com>

---
 elf_info.c     |   26 ++++++++++++++++++++++++++
 elf_info.h     |    5 +++++
 makedumpfile.c |   32 ++++++++++++++++++++++++++++++++
 3 files changed, 63 insertions(+)

--- a/elf_info.c
+++ b/elf_info.c
@@ -1096,6 +1096,32 @@ get_pt_load(int idx,
 	return TRUE;
 }
 
+int
+get_pt_load_extents(int idx,
+	unsigned long long *phys_start,
+	unsigned long long *phys_end,
+	off_t *file_offset,
+	off_t *file_size)
+{
+	struct pt_load_segment *pls;
+
+	if (num_pt_loads <= idx)
+		return FALSE;
+
+	pls = &pt_loads[idx];
+
+	if (phys_start)
+		*phys_start  = pls->phys_start;
+	if (phys_end)
+		*phys_end    = pls->phys_end;
+	if (file_offset)
+		*file_offset = pls->file_offset;
+	if (file_size)
+		*file_size   = pls->file_size;
+
+	return TRUE;
+}
+
 unsigned int
 get_num_pt_loads(void)
 {
--- a/elf_info.h
+++ b/elf_info.h
@@ -61,6 +61,11 @@ int get_pt_load(int idx,
 	unsigned long long *phys_end,
 	unsigned long long *virt_start,
 	unsigned long long *virt_end);
+int get_pt_load_extents(int idx,
+	unsigned long long *phys_start,
+	unsigned long long *phys_end,
+	off_t *file_offset,
+	off_t *file_size);
 unsigned int get_num_pt_loads(void);
 
 void set_nr_cpus(int num);
--- a/makedumpfile.c
+++ b/makedumpfile.c
@@ -4395,6 +4395,32 @@ read_start_flat_header(void)
 	return TRUE;
 }
 
+static void
+exclude_nodata_pages(struct cycle *cycle)
+{
+	int i;
+	unsigned long long phys_start, phys_end;
+	off_t file_size;
+
+	i = 0;
+	while (get_pt_load_extents(i, &phys_start, &phys_end,
+				   NULL, &file_size)) {
+		unsigned long long pfn, pfn_end;
+
+		pfn = paddr_to_pfn(phys_start + file_size);
+		pfn_end = paddr_to_pfn(phys_end);
+		if (pfn < cycle->start_pfn)
+			pfn = cycle->start_pfn;
+		if (pfn_end >= cycle->end_pfn)
+			pfn_end = cycle->end_pfn - 1;
+		while (pfn <= pfn_end) {
+			clear_bit_on_2nd_bitmap(pfn, cycle);
+			++pfn;
+		}
+		++i;
+	}
+}
+
 int
 read_flat_data_header(struct makedumpfile_data_header *fdh)
 {
@@ -6087,6 +6113,12 @@ create_2nd_bitmap(struct cycle *cycle)
 	}
 
 	/*
+	 * If re-filtering ELF dump, exclude pages that were already
+	 * excluded in the original file.
+	 */
+	exclude_nodata_pages(cycle);
+
+	/*
 	 * Exclude cache pages, cache private pages, user data pages,
 	 * and hwpoison pages.
 	 */



More information about the kexec mailing list