Blame SOURCES/kexec-tools-2.0.4-makedumpfile-Support-to-filter-dump-for-kernels-that-use.patch

765b01
From bcdba922182def3dac288ca201e77e7738a1e4ab Mon Sep 17 00:00:00 2001
765b01
From: Hari Bathini <hbathini@linux.vnet.ibm.com>
765b01
Date: Mon, 25 Nov 2013 17:20:55 +0900
765b01
Subject: [PATCH] [PATCH v5] Support to filter dump for kernels that use
765b01
 CONFIG_SPARSEMEM_VMEMMAP.
765b01
765b01
Makedumpfile tool fails to filter dump for kernels that are build with
765b01
CONFIG_SPARSEMEM_VMEMMAP set, as it fails to do address translations
765b01
for vmemmap regions that are mapped out of zone normal. This patch
765b01
provides support in makedumpfile to do vmemmap to physical address
765b01
translations when they are mapped outside zone normal. Some kernel
765b01
symbols are needed in vmcoreinfo for this changes to be effective.
765b01
The kernel patch that adds the necessary symbols to vmcoreinfo has
765b01
been posted to linuxppc devel mailing list. This patch is influenced
765b01
by vmemmap to physical address translation support code in crash tool.
765b01
This patch has been tested successfully at all dump filtering levels
765b01
on kernels with CONFIG_SPARSEMEM_VMEMMAP set/unset. Also, tested dump
765b01
filtering on already filtered vmcores (re-filtering).
765b01
765b01
Changes from v4 to v5:
765b01
Trimmed patch description to be compact and readable.
765b01
765b01
Changes from v3 to v4:
765b01
Rebased to devel branch.
765b01
765b01
Signed-off-by: Onkar N Mahajan <onmahaja@in.ibm.com>
765b01
Signed-off-by: Hari Bathini <hbathini@linux.vnet.ibm.com>
765b01
---
765b01
 arch/ppc64.c   | 175 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--
765b01
 makedumpfile.c |  39 +++++++++++++
765b01
 makedumpfile.h |  37 ++++++++++++
765b01
 3 files changed, 247 insertions(+), 4 deletions(-)
765b01
765b01
diff --git a/makedumpfile-1.5.4/arch/ppc64.c b/makedumpfile-1.5.4/arch/ppc64.c
765b01
index 85144f6..09c0eb3 100644
765b01
--- a/makedumpfile-1.5.4/arch/ppc64.c
765b01
+++ b/makedumpfile-1.5.4/arch/ppc64.c
765b01
@@ -24,6 +24,154 @@
765b01
 #include "../elf_info.h"
765b01
 #include "../makedumpfile.h"
765b01
 
765b01
+/*
765b01
+ * This function traverses vmemmap list to get the count of vmemmap regions
765b01
+ * and populates the regions' info in info->vmemmap_list[]
765b01
+ */
765b01
+static int
765b01
+get_vmemmap_list_info(ulong head)
765b01
+{
765b01
+	int   i, cnt;
765b01
+	long  backing_size, virt_addr_offset, phys_offset, list_offset;
765b01
+	ulong curr, next;
765b01
+	char  *vmemmap_buf = NULL;
765b01
+
765b01
+	backing_size		= SIZE(vmemmap_backing);
765b01
+	virt_addr_offset	= OFFSET(vmemmap_backing.virt_addr);
765b01
+	phys_offset		= OFFSET(vmemmap_backing.phys);
765b01
+	list_offset		= OFFSET(vmemmap_backing.list);
765b01
+	info->vmemmap_list = NULL;
765b01
+
765b01
+	/*
765b01
+	 * Get list count by traversing the vmemmap list
765b01
+	 */
765b01
+	cnt = 0;
765b01
+	curr = head;
765b01
+	next = 0;
765b01
+	do {
765b01
+		if (!readmem(VADDR, (curr + list_offset), &next,
765b01
+			     sizeof(next))) {
765b01
+			ERRMSG("Can't get vmemmap region addresses\n");
765b01
+			goto err;
765b01
+		}
765b01
+		curr = next;
765b01
+		cnt++;
765b01
+	} while ((next != 0) && (next != head));
765b01
+
765b01
+	/*
765b01
+	 * Using temporary buffer to save vmemmap region information
765b01
+	 */
765b01
+	vmemmap_buf = calloc(1, backing_size);
765b01
+	if (vmemmap_buf == NULL) {
765b01
+		ERRMSG("Can't allocate memory for vmemmap_buf. %s\n",
765b01
+		       strerror(errno));
765b01
+		goto err;
765b01
+	}
765b01
+
765b01
+	info->vmemmap_list = calloc(1, cnt * sizeof(struct ppc64_vmemmap));
765b01
+	if (info->vmemmap_list == NULL) {
765b01
+		ERRMSG("Can't allocate memory for vmemmap_list. %s\n",
765b01
+		       strerror(errno));
765b01
+		goto err;
765b01
+	}
765b01
+
765b01
+	curr = head;
765b01
+	for (i = 0; i < cnt; i++) {
765b01
+		if (!readmem(VADDR, curr, vmemmap_buf, backing_size)) {
765b01
+			ERRMSG("Can't get vmemmap region info\n");
765b01
+			goto err;
765b01
+		}
765b01
+
765b01
+		info->vmemmap_list[i].phys = ULONG(vmemmap_buf + phys_offset);
765b01
+		info->vmemmap_list[i].virt = ULONG(vmemmap_buf +
765b01
+						   virt_addr_offset);
765b01
+		curr = ULONG(vmemmap_buf + list_offset);
765b01
+
765b01
+		if (info->vmemmap_list[i].virt < info->vmemmap_start)
765b01
+			info->vmemmap_start = info->vmemmap_list[i].virt;
765b01
+
765b01
+		if ((info->vmemmap_list[i].virt + info->vmemmap_psize) >
765b01
+		    info->vmemmap_end)
765b01
+			info->vmemmap_end = (info->vmemmap_list[i].virt +
765b01
+					     info->vmemmap_psize);
765b01
+	}
765b01
+
765b01
+	free(vmemmap_buf);
765b01
+	return cnt;
765b01
+err:
765b01
+	free(vmemmap_buf);
765b01
+	free(info->vmemmap_list);
765b01
+	return 0;
765b01
+}
765b01
+
765b01
+/*
765b01
+ *  Verify that the kernel has made the vmemmap list available,
765b01
+ *  and if so, stash the relevant data required to make vtop
765b01
+ *  translations.
765b01
+ */
765b01
+static int
765b01
+ppc64_vmemmap_init(void)
765b01
+{
765b01
+	int psize, shift;
765b01
+	ulong head;
765b01
+
765b01
+	if ((SYMBOL(vmemmap_list) == NOT_FOUND_SYMBOL)
765b01
+	    || (SYMBOL(mmu_psize_defs) == NOT_FOUND_SYMBOL)
765b01
+	    || (SYMBOL(mmu_vmemmap_psize) == NOT_FOUND_SYMBOL)
765b01
+	    || (SIZE(vmemmap_backing) == NOT_FOUND_STRUCTURE)
765b01
+	    || (SIZE(mmu_psize_def) == NOT_FOUND_STRUCTURE)
765b01
+	    || (OFFSET(mmu_psize_def.shift) == NOT_FOUND_STRUCTURE)
765b01
+	    || (OFFSET(vmemmap_backing.phys) == NOT_FOUND_STRUCTURE)
765b01
+	    || (OFFSET(vmemmap_backing.virt_addr) == NOT_FOUND_STRUCTURE)
765b01
+	    || (OFFSET(vmemmap_backing.list) == NOT_FOUND_STRUCTURE))
765b01
+		return FALSE;
765b01
+
765b01
+	if (!readmem(VADDR, SYMBOL(mmu_vmemmap_psize), &psize, sizeof(int)))
765b01
+		return FALSE;
765b01
+
765b01
+	if (!readmem(VADDR, SYMBOL(mmu_psize_defs) +
765b01
+		     (SIZE(mmu_psize_def) * psize) +
765b01
+		     OFFSET(mmu_psize_def.shift), &shift, sizeof(int)))
765b01
+		return FALSE;
765b01
+	info->vmemmap_psize = 1 << shift;
765b01
+
765b01
+	if (!readmem(VADDR, SYMBOL(vmemmap_list), &head, sizeof(unsigned long)))
765b01
+		return FALSE;
765b01
+
765b01
+	/*
765b01
+	 * Get vmemmap list count and populate vmemmap regions info
765b01
+	 */
765b01
+	info->vmemmap_cnt = get_vmemmap_list_info(head);
765b01
+	if (info->vmemmap_cnt == 0)
765b01
+		return FALSE;
765b01
+
765b01
+	info->flag_vmemmap = TRUE;
765b01
+	return TRUE;
765b01
+}
765b01
+
765b01
+/*
765b01
+ *  If the vmemmap address translation information is stored in the kernel,
765b01
+ *  make the translation.
765b01
+ */
765b01
+static unsigned long long
765b01
+ppc64_vmemmap_to_phys(unsigned long vaddr)
765b01
+{
765b01
+	int	i;
765b01
+	ulong	offset;
765b01
+	unsigned long long paddr = NOT_PADDR;
765b01
+
765b01
+	for (i = 0; i < info->vmemmap_cnt; i++) {
765b01
+		if ((vaddr >= info->vmemmap_list[i].virt) && (vaddr <
765b01
+		    (info->vmemmap_list[i].virt + info->vmemmap_psize))) {
765b01
+			offset = vaddr - info->vmemmap_list[i].virt;
765b01
+			paddr = info->vmemmap_list[i].phys + offset;
765b01
+			break;
765b01
+		}
765b01
+	}
765b01
+
765b01
+	return paddr;
765b01
+}
765b01
+
765b01
 int
765b01
 set_ppc64_max_physmem_bits(void)
765b01
 {
765b01
@@ -103,6 +251,16 @@ get_machdep_info_ppc64(void)
765b01
 	info->vmalloc_start = vmalloc_start;
765b01
 	DEBUG_MSG("vmalloc_start: %lx\n", vmalloc_start);
765b01
 
765b01
+	if (SYMBOL(vmemmap_list) != NOT_FOUND_SYMBOL) {
765b01
+		info->vmemmap_start = VMEMMAP_REGION_ID << REGION_SHIFT;
765b01
+		info->vmemmap_end = info->vmemmap_start;
765b01
+		if (ppc64_vmemmap_init() == FALSE) {
765b01
+			ERRMSG("Can't get vmemmap list info.\n");
765b01
+			return FALSE;
765b01
+		}
765b01
+		DEBUG_MSG("vmemmap_start: %lx\n", info->vmemmap_start);
765b01
+	}
765b01
+
765b01
 	return TRUE;
765b01
 }
765b01
 
765b01
@@ -121,14 +279,23 @@ vaddr_to_paddr_ppc64(unsigned long vaddr)
765b01
 	if (paddr != NOT_PADDR)
765b01
 		return paddr;
765b01
 
765b01
-	if ((SYMBOL(vmlist) == NOT_FOUND_SYMBOL)
765b01
-	    || (OFFSET(vm_struct.addr) == NOT_FOUND_STRUCTURE)) {
765b01
-		ERRMSG("Can't get necessary information for vmalloc translation.\n");
765b01
-		return NOT_PADDR;
765b01
+	if ((SYMBOL(vmap_area_list) == NOT_FOUND_SYMBOL)
765b01
+	    || (OFFSET(vmap_area.va_start) == NOT_FOUND_STRUCTURE)
765b01
+	    || (OFFSET(vmap_area.list) == NOT_FOUND_STRUCTURE)) {
765b01
+		if ((SYMBOL(vmlist) == NOT_FOUND_SYMBOL)
765b01
+		    || (OFFSET(vm_struct.addr) == NOT_FOUND_STRUCTURE)) {
765b01
+			ERRMSG("Can't get info for vmalloc translation.\n");
765b01
+			return NOT_PADDR;
765b01
+		}
765b01
 	}
765b01
 	if (!is_vmalloc_addr_ppc64(vaddr))
765b01
 		return (vaddr - info->kernel_start);
765b01
 
765b01
+	if ((info->flag_vmemmap)
765b01
+	    && (vaddr >= info->vmemmap_start)) {
765b01
+		return ppc64_vmemmap_to_phys(vaddr);
765b01
+	}
765b01
+
765b01
 	/*
765b01
 	 * TODO: Support vmalloc translation.
765b01
 	 */
765b01
diff --git a/makedumpfile-1.5.4/makedumpfile.c b/makedumpfile-1.5.4/makedumpfile.c
765b01
index 3746cf6..0c68f32 100644
765b01
--- a/makedumpfile-1.5.4/makedumpfile.c
765b01
+++ b/makedumpfile-1.5.4/makedumpfile.c
765b01
@@ -1107,6 +1107,10 @@ get_symbol_info(void)
765b01
 		SYMBOL_ARRAY_LENGTH_INIT(node_remap_start_pfn,
765b01
 					"node_remap_start_pfn");
765b01
 
765b01
+	SYMBOL_INIT(vmemmap_list, "vmemmap_list");
765b01
+	SYMBOL_INIT(mmu_psize_defs, "mmu_psize_defs");
765b01
+	SYMBOL_INIT(mmu_vmemmap_psize, "mmu_vmemmap_psize");
765b01
+
765b01
 	return TRUE;
765b01
 }
765b01
 
765b01
@@ -1417,6 +1421,20 @@ get_structure_info(void)
765b01
 		OFFSET_INIT(printk_log.text_len, "log", "text_len");
765b01
 	}
765b01
 
765b01
+	/*
765b01
+	 * Get offsets of the vmemmap_backing's members.
765b01
+	 */
765b01
+	SIZE_INIT(vmemmap_backing, "vmemmap_backing");
765b01
+	OFFSET_INIT(vmemmap_backing.phys, "vmemmap_backing", "phys");
765b01
+	OFFSET_INIT(vmemmap_backing.virt_addr, "vmemmap_backing", "virt_addr");
765b01
+	OFFSET_INIT(vmemmap_backing.list, "vmemmap_backing", "list");
765b01
+
765b01
+	/*
765b01
+	 * Get offsets of the mmu_psize_def's members.
765b01
+	 */
765b01
+	SIZE_INIT(mmu_psize_def, "mmu_psize_def");
765b01
+	OFFSET_INIT(mmu_psize_def.shift, "mmu_psize_def", "shift");
765b01
+
765b01
 	return TRUE;
765b01
 }
765b01
 
765b01
@@ -1603,6 +1621,9 @@ write_vmcoreinfo_data(void)
765b01
 	WRITE_SYMBOL("node_remap_start_vaddr", node_remap_start_vaddr);
765b01
 	WRITE_SYMBOL("node_remap_end_vaddr", node_remap_end_vaddr);
765b01
 	WRITE_SYMBOL("node_remap_start_pfn", node_remap_start_pfn);
765b01
+	WRITE_SYMBOL("vmemmap_list", vmemmap_list);
765b01
+	WRITE_SYMBOL("mmu_psize_defs", mmu_psize_defs);
765b01
+	WRITE_SYMBOL("mmu_vmemmap_psize", mmu_vmemmap_psize);
765b01
 
765b01
 	/*
765b01
 	 * write the structure size of 1st kernel
765b01
@@ -1620,6 +1641,8 @@ write_vmcoreinfo_data(void)
765b01
 		WRITE_STRUCTURE_SIZE("printk_log", printk_log);
765b01
 	else
765b01
 		WRITE_STRUCTURE_SIZE("log", printk_log);
765b01
+	WRITE_STRUCTURE_SIZE("vmemmap_backing", vmemmap_backing);
765b01
+	WRITE_STRUCTURE_SIZE("mmu_psize_def", mmu_psize_def);
765b01
 
765b01
 	/*
765b01
 	 * write the member offset of 1st kernel
765b01
@@ -1664,6 +1687,11 @@ write_vmcoreinfo_data(void)
765b01
 		WRITE_MEMBER_OFFSET("log.len", printk_log.len);
765b01
 		WRITE_MEMBER_OFFSET("log.text_len", printk_log.text_len);
765b01
 	}
765b01
+	WRITE_MEMBER_OFFSET("vmemmap_backing.phys", vmemmap_backing.phys);
765b01
+	WRITE_MEMBER_OFFSET("vmemmap_backing.virt_addr",
765b01
+	    vmemmap_backing.virt_addr);
765b01
+	WRITE_MEMBER_OFFSET("vmemmap_backing.list", vmemmap_backing.list);
765b01
+	WRITE_MEMBER_OFFSET("mmu_psize_def.shift", mmu_psize_def.shift);
765b01
 
765b01
 	if (SYMBOL(node_data) != NOT_FOUND_SYMBOL)
765b01
 		WRITE_ARRAY_LENGTH("node_data", node_data);
765b01
@@ -1932,6 +1960,9 @@ read_vmcoreinfo(void)
765b01
 	READ_SYMBOL("node_remap_start_vaddr", node_remap_start_vaddr);
765b01
 	READ_SYMBOL("node_remap_end_vaddr", node_remap_end_vaddr);
765b01
 	READ_SYMBOL("node_remap_start_pfn", node_remap_start_pfn);
765b01
+	READ_SYMBOL("vmemmap_list", vmemmap_list);
765b01
+	READ_SYMBOL("mmu_psize_defs", mmu_psize_defs);
765b01
+	READ_SYMBOL("mmu_vmemmap_psize", mmu_vmemmap_psize);
765b01
 
765b01
 	READ_STRUCTURE_SIZE("page", page);
765b01
 	READ_STRUCTURE_SIZE("mem_section", mem_section);
765b01
@@ -1942,6 +1973,9 @@ read_vmcoreinfo(void)
765b01
 	READ_STRUCTURE_SIZE("node_memblk_s", node_memblk_s);
765b01
 	READ_STRUCTURE_SIZE("nodemask_t", nodemask_t);
765b01
 	READ_STRUCTURE_SIZE("pageflags", pageflags);
765b01
+	READ_STRUCTURE_SIZE("vmemmap_backing", vmemmap_backing);
765b01
+	READ_STRUCTURE_SIZE("mmu_psize_def", mmu_psize_def);
765b01
+
765b01
 
765b01
 	READ_MEMBER_OFFSET("page.flags", page.flags);
765b01
 	READ_MEMBER_OFFSET("page._count", page._count);
765b01
@@ -1972,6 +2006,11 @@ read_vmcoreinfo(void)
765b01
 	READ_MEMBER_OFFSET("vm_struct.addr", vm_struct.addr);
765b01
 	READ_MEMBER_OFFSET("vmap_area.va_start", vmap_area.va_start);
765b01
 	READ_MEMBER_OFFSET("vmap_area.list", vmap_area.list);
765b01
+	READ_MEMBER_OFFSET("vmemmap_backing.phys", vmemmap_backing.phys);
765b01
+	READ_MEMBER_OFFSET("vmemmap_backing.virt_addr",
765b01
+	    vmemmap_backing.virt_addr);
765b01
+	READ_MEMBER_OFFSET("vmemmap_backing.list", vmemmap_backing.list);
765b01
+	READ_MEMBER_OFFSET("mmu_psize_def.shift", mmu_psize_def.shift);
765b01
 
765b01
 	READ_STRUCTURE_SIZE("printk_log", printk_log);
765b01
 	if (SIZE(printk_log) != NOT_FOUND_STRUCTURE) {
765b01
diff --git a/makedumpfile-1.5.4/makedumpfile.h b/makedumpfile-1.5.4/makedumpfile.h
765b01
index 3a7e61a..517e16e 100644
765b01
--- a/makedumpfile-1.5.4/makedumpfile.h
765b01
+++ b/makedumpfile-1.5.4/makedumpfile.h
765b01
@@ -576,6 +576,8 @@ do { \
765b01
 #define _SECTION_SIZE_BITS	(24)
765b01
 #define _MAX_PHYSMEM_BITS_ORIG  (44)
765b01
 #define _MAX_PHYSMEM_BITS_3_7   (46)
765b01
+#define REGION_SHIFT            (60UL)
765b01
+#define VMEMMAP_REGION_ID       (0xfUL)
765b01
 #endif
765b01
 
765b01
 #ifdef __powerpc32__
765b01
@@ -862,6 +864,11 @@ struct splitting_info {
765b01
 	unsigned long		size_eraseinfo;
765b01
 } splitting_info_t;
765b01
 
765b01
+struct ppc64_vmemmap {
765b01
+	unsigned long		phys;
765b01
+	unsigned long		virt;
765b01
+};
765b01
+
765b01
 struct DumpInfo {
765b01
 	int32_t		kernel_version;      /* version of first kernel*/
765b01
 	struct timeval	timestamp;
765b01
@@ -895,6 +902,7 @@ struct DumpInfo {
765b01
 	int             flag_dmesg;          /* dump the dmesg log out of the vmcore file */
765b01
 	int		flag_use_printk_log; /* did we read printk_log symbol name? */
765b01
 	int		flag_nospace;	     /* the flag of "No space on device" error */
765b01
+	int		flag_vmemmap;        /* kernel supports vmemmap address space */
765b01
 	unsigned long	vaddr_for_vtop;      /* virtual address for debugging */
765b01
 	long		page_size;           /* size of page */
765b01
 	long		page_shift;
765b01
@@ -909,6 +917,9 @@ struct DumpInfo {
765b01
 	unsigned long   vmalloc_end;
765b01
 	unsigned long	vmemmap_start;
765b01
 	unsigned long	vmemmap_end;
765b01
+	int		vmemmap_psize;
765b01
+	int		vmemmap_cnt;
765b01
+	struct ppc64_vmemmap	*vmemmap_list;
765b01
 
765b01
 	/*
765b01
 	 * Filter config file containing filter commands to filter out kernel
765b01
@@ -1166,6 +1177,13 @@ struct symbol_table {
765b01
 	unsigned long long	__per_cpu_load;
765b01
 	unsigned long long	cpu_online_mask;
765b01
 	unsigned long long	kexec_crash_image;
765b01
+
765b01
+	/*
765b01
+	 * vmemmap symbols on ppc64 arch
765b01
+	 */
765b01
+	unsigned long long		vmemmap_list;
765b01
+	unsigned long long		mmu_vmemmap_psize;
765b01
+	unsigned long long		mmu_psize_defs;
765b01
 };
765b01
 
765b01
 struct size_table {
765b01
@@ -1201,6 +1219,12 @@ struct size_table {
765b01
 	long	kexec_segment;
765b01
 	long	elf64_hdr;
765b01
 
765b01
+	/*
765b01
+	 * vmemmap symbols on ppc64 arch
765b01
+	 */
765b01
+	long	vmemmap_backing;
765b01
+	long	mmu_psize_def;
765b01
+
765b01
 	long	pageflags;
765b01
 };
765b01
 
765b01
@@ -1344,6 +1368,19 @@ struct offset_table {
765b01
 		long text_len;
765b01
 	} printk_log;
765b01
 
765b01
+	/*
765b01
+	 * vmemmap symbols on ppc64 arch
765b01
+	 */
765b01
+	struct mmu_psize_def {
765b01
+		long	shift;
765b01
+	} mmu_psize_def;
765b01
+
765b01
+	struct vmemmap_backing {
765b01
+		long	phys;
765b01
+		long	virt_addr;
765b01
+		long	list;
765b01
+	} vmemmap_backing;
765b01
+
765b01
 };
765b01
 
765b01
 /*
765b01
-- 
765b01
1.8.3.1
765b01