[Crash-utility] [PATCH v2] kmem: update n option to dump memory block

Dave Anderson anderson at redhat.com
Thu Oct 4 20:54:45 UTC 2018



----- Original Message -----
> From: Masayoshi Mizuma <m.mizuma at jp.fujitsu.com>
> 
> Update for the "kmem -n" option to also dump memory block.
> Currently, "kmem -n" shows the memory section only. This
> patch gets available the memory block as well if 'memory_block'
> structure and 'memory_subsys' symbol exist.
> The memory block information is useful to investigate memory
> hot-plug issue.

Masa,

I added some information to the help page for "kmem -n", and queued
the patch for crash-7.2.5:

  https://github.com/crash-utility/crash/commit/e342618cb4fde8cd1fcf2ed39e23addac3540aea

Thanks,
  Dave

> 
> Signed-off-by: Masayoshi Mizuma <m.mizuma at jp.fujitsu.com>
> ---
>  defs.h    |   9 ++
>  memory.c  | 286 +++++++++++++++++++++++++++++++++++++++++++++++++++---
>  symbols.c |  18 ++++
>  3 files changed, 299 insertions(+), 14 deletions(-)
> 
> diff --git a/defs.h b/defs.h
> index 5b64bb7..20dd6a7 100644
> --- a/defs.h
> +++ b/defs.h
> @@ -2049,6 +2049,15 @@ struct offset_table {                    /* stash of
> commonly-used offsets */
>          long pci_bus_self;
>  	long device_kobj;
>  	long kobject_name;
> +	long memory_block_dev;
> +	long memory_block_start_section_nr;
> +	long memory_block_end_section_nr;
> +	long memory_block_state;
> +	long memory_block_nid;
> +	long mem_section_pageblock_flags;
> +	long bus_type_p;
> +	long device_private_device;
> +	long device_private_knode_bus;
>  };
>  
>  struct size_table {         /* stash of commonly-used sizes */
> diff --git a/memory.c b/memory.c
> index ea25047..9657c28 100644
> --- a/memory.c
> +++ b/memory.c
> @@ -255,13 +255,14 @@ static void PG_slab_flag_init(void);
>  static ulong nr_blockdev_pages(void);
>  void sparse_mem_init(void);
>  void dump_mem_sections(int);
> +void dump_memory_blocks(int);
>  void list_mem_sections(void);
>  ulong sparse_decode_mem_map(ulong, ulong);
>  char *read_mem_section(ulong);
>  ulong nr_to_section(ulong);
>  int valid_section(ulong);
>  int section_has_mem_map(ulong);
> -ulong section_mem_map_addr(ulong);
> +ulong section_mem_map_addr(ulong, int);
>  ulong valid_section_nr(ulong);
>  ulong pfn_to_map(ulong);
>  static int get_nodes_online(void);
> @@ -5528,7 +5529,7 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi)
>  			pc->curcmd_flags |= HEADER_PRINTED;
>  		}
>  
> -		pp = section_mem_map_addr(section);
> +		pp = section_mem_map_addr(section, 0);
>  		pp = sparse_decode_mem_map(pp, section_nr);
>  		phys = (physaddr_t) section_nr * PAGES_PER_SECTION() * PAGESIZE();
>  		section_size = PAGES_PER_SECTION();
> @@ -13389,7 +13390,7 @@ is_page_ptr(ulong addr, physaddr_t *phys)
>  		nr_mem_sections = vt->max_mem_section_nr+1;
>  	        for (nr = 0; nr < nr_mem_sections ; nr++) {
>  	                if ((sec_addr = valid_section_nr(nr))) {
> -	                        coded_mem_map = section_mem_map_addr(sec_addr);
> +	                        coded_mem_map = section_mem_map_addr(sec_addr, 0);
>  	                        mem_map = sparse_decode_mem_map(coded_mem_map, nr);
>  				end_mem_map = mem_map + (PAGES_PER_SECTION() * SIZE(page));
>  
> @@ -16354,8 +16355,10 @@ dump_memory_nodes(int initialize)
>  		vt->numnodes = n;
>  	}
>  
> -	if (IS_SPARSEMEM())
> +	if (IS_SPARSEMEM()) {
>  		dump_mem_sections(initialize);
> +		dump_memory_blocks(initialize);
> +	}
>  }
>  
>  /*
> @@ -17140,7 +17143,7 @@ section_has_mem_map(ulong addr)
>  }
>  
>  ulong
> -section_mem_map_addr(ulong addr)
> +section_mem_map_addr(ulong addr, int raw)
>  {
>  	char *mem_section;
>  	ulong map;
> @@ -17148,7 +17151,8 @@ section_mem_map_addr(ulong addr)
>  	if ((mem_section = read_mem_section(addr))) {
>  		map = ULONG(mem_section +
>  			OFFSET(mem_section_section_mem_map));
> -		map &= SECTION_MAP_MASK;
> +		if (!raw)
> +			map &= SECTION_MAP_MASK;
>  		return map;
>  	}
>  	return 0;
> @@ -17179,7 +17183,7 @@ pfn_to_map(ulong pfn)
>  
>  	if (section_has_mem_map(section)) {
>  		page_offset = pfn - section_nr_to_pfn(section_nr);
> -		coded_mem_map = section_mem_map_addr(section);
> +		coded_mem_map = section_mem_map_addr(section, 0);
>  		mem_map = sparse_decode_mem_map(coded_mem_map, section_nr) +
>  			(page_offset * SIZE(page));
>  		return mem_map;
> @@ -17188,16 +17192,33 @@ pfn_to_map(ulong pfn)
>  	return 0;
>  }
>  
> +static void
> +fill_mem_section_state(ulong state, char *buf)
> +{
> +	int bufidx = 0;
> +
> +	memset(buf, 0, sizeof(*buf) * BUFSIZE);
> +
> +	if (state & SECTION_MARKED_PRESENT)
> +		bufidx += sprintf(buf + bufidx, "%s", "P");
> +	if (state & SECTION_HAS_MEM_MAP)
> +		bufidx += sprintf(buf + bufidx, "%s", "M");
> +	if (state & SECTION_IS_ONLINE)
> +		bufidx += sprintf(buf + bufidx, "%s", "O");
> +}
> +
>  void
>  dump_mem_sections(int initialize)
>  {
>  	ulong nr, max, addr;
>  	ulong nr_mem_sections;
>  	ulong coded_mem_map, mem_map, pfn;
> +	char statebuf[BUFSIZE];
>  	char buf1[BUFSIZE];
>  	char buf2[BUFSIZE];
>  	char buf3[BUFSIZE];
>  	char buf4[BUFSIZE];
> +	char buf5[BUFSIZE];
>  
>  	nr_mem_sections = NR_MEM_SECTIONS();
>  
> @@ -17212,19 +17233,23 @@ dump_mem_sections(int initialize)
>  
>  	fprintf(fp, "\n");
>  	pad_line(fp, BITS32() ? 59 : 67, '-');
> -        fprintf(fp, "\n\nNR  %s  %s  %s  PFN\n",
> +	fprintf(fp, "\n\nNR  %s  %s  %s  %s PFN\n",
>                  mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "SECTION"),
>                  mkstring(buf2, MAX(VADDR_PRLEN,strlen("CODED_MEM_MAP")),
>  		CENTER|LJUST, "CODED_MEM_MAP"),
> -                mkstring(buf3, VADDR_PRLEN, CENTER|LJUST, "MEM_MAP"));
> +		mkstring(buf3, VADDR_PRLEN, CENTER|LJUST, "MEM_MAP"),
> +		mkstring(buf4, strlen("STATE"), CENTER, "STATE"));
>  
>  	for (nr = 0; nr < nr_mem_sections ; nr++) {
>  		if ((addr = valid_section_nr(nr))) {
> -			coded_mem_map = section_mem_map_addr(addr);
> +			coded_mem_map = section_mem_map_addr(addr, 0);
>  			mem_map = sparse_decode_mem_map(coded_mem_map,nr);
>  			pfn = section_nr_to_pfn(nr);
> +			fill_mem_section_state(section_mem_map_addr(addr, 1),
> +						statebuf);
>  
> -        		fprintf(fp, "%2ld  %s  %s  %s  %s\n",
> +
> +			fprintf(fp, "%2ld  %s  %s  %s  %s %s\n",
>                  		nr,
>                  		mkstring(buf1, VADDR_PRLEN,
>                          	CENTER|LONG_HEX, MKSTR(addr)),
> @@ -17233,15 +17258,248 @@ dump_mem_sections(int initialize)
>                          	CENTER|LONG_HEX|RJUST, MKSTR(coded_mem_map)),
>                  		mkstring(buf3, VADDR_PRLEN,
>                          	CENTER|LONG_HEX|RJUST, MKSTR(mem_map)),
> +				mkstring(buf4, strlen("STATE"), CENTER, statebuf),
>  				pc->output_radix == 10 ?
> -                		mkstring(buf4, VADDR_PRLEN,
> +				mkstring(buf5, VADDR_PRLEN,
>                          	LONG_DEC|LJUST, MKSTR(pfn)) :
> -                		mkstring(buf4, VADDR_PRLEN,
> +				mkstring(buf5, VADDR_PRLEN,
>                          	LONG_HEX|LJUST, MKSTR(pfn)));
>  		}
>  	}
>  }
>  
> +#define MEM_ONLINE		(1<<0)
> +#define MEM_GOING_OFFLINE	(1<<1)
> +#define MEM_OFFLINE		(1<<2)
> +#define MEM_GOING_ONLINE	(1<<3)
> +#define MEM_CANCEL_ONLINE	(1<<4)
> +#define MEM_CANCEL_OFFLINE	(1<<5)
> +
> +static void
> +fill_memory_block_state(ulong memblock, char *buf)
> +{
> +	ulong state;
> +
> +	memset(buf, 0, sizeof(*buf) * BUFSIZE);
> +
> +	readmem(memblock + OFFSET(memory_block_state), KVADDR, &state,
> +		sizeof(void *), "memory_block state", FAULT_ON_ERROR);
> +
> +	switch (state) {
> +	case MEM_ONLINE:
> +		sprintf(buf, "%s", "ONLINE");
> +		break;
> +	case MEM_GOING_OFFLINE:
> +		sprintf(buf, "%s", "GOING_OFFLINE");
> +		break;
> +	case MEM_OFFLINE:
> +		sprintf(buf, "%s", "OFFLINE");
> +		break;
> +	case MEM_GOING_ONLINE:
> +		sprintf(buf, "%s", "GOING_ONLINE");
> +		break;
> +	case MEM_CANCEL_ONLINE:
> +		sprintf(buf, "%s", "CANCEL_ONLINE");
> +		break;
> +	case MEM_CANCEL_OFFLINE:
> +		sprintf(buf, "%s",  "CANCEL_OFFLINE");
> +		break;
> +	default:
> +		sprintf(buf, "%s", "UNKNOWN");
> +	}
> +}
> +
> +static ulong
> +pfn_to_phys(ulong pfn)
> +{
> +	return pfn << PAGE_SHIFT;
> +}
> +
> +static void
> +fill_memory_block_name(ulong memblock, char *name)
> +{
> +	ulong kobj, value;
> +
> +	memset(name, 0, sizeof(*name) * BUFSIZE);
> +
> +	kobj = memblock + OFFSET(memory_block_dev) + OFFSET(device_kobj);
> +
> +	readmem(kobj + OFFSET(kobject_name),
> +		KVADDR, &value, sizeof(void *), "kobject name",
> +		FAULT_ON_ERROR);
> +
> +	read_string(value, name, BUFSIZE-1);
> +}
> +
> +static void
> +fill_memory_block_srange(ulong start_sec, ulong end_sec, char *srange)
> +{
> +	memset(srange, 0, sizeof(*srange) * BUFSIZE);
> +
> +	if (start_sec == end_sec)
> +		sprintf(srange, "%lu", start_sec);
> +	else
> +		sprintf(srange, "%lu-%lu", start_sec, end_sec);
> +}
> +
> +static void
> +print_memory_block(ulong memory_block)
> +{
> +	ulong start_sec, end_sec, start_pfn, end_pfn, nid;
> +	char statebuf[BUFSIZE];
> +	char srangebuf[BUFSIZE];
> +	char name[BUFSIZE];
> +	char buf1[BUFSIZE];
> +	char buf2[BUFSIZE];
> +	char buf3[BUFSIZE];
> +	char buf4[BUFSIZE];
> +	char buf5[BUFSIZE];
> +	char buf6[BUFSIZE];
> +	char buf7[BUFSIZE];
> +
> +	readmem(memory_block + OFFSET(memory_block_start_section_nr), KVADDR,
> +		&start_sec, sizeof(void *), "memory_block start_section_nr",
> +		FAULT_ON_ERROR);
> +	readmem(memory_block + OFFSET(memory_block_end_section_nr), KVADDR,
> +		&end_sec, sizeof(void *), "memory_block end_section_nr",
> +		FAULT_ON_ERROR);
> +
> +	start_pfn = section_nr_to_pfn(start_sec);
> +	end_pfn = section_nr_to_pfn(end_sec + 1);
> +	fill_memory_block_state(memory_block, statebuf);
> +	fill_memory_block_name(memory_block, name);
> +	fill_memory_block_srange(start_sec, end_sec, srangebuf);
> +
> +	if (MEMBER_EXISTS("memory_block", "nid")) {
> +		readmem(memory_block + OFFSET(memory_block_nid), KVADDR, &nid,
> +			sizeof(void *), "memory_block nid", FAULT_ON_ERROR);
> +		fprintf(fp, " %s %s %s - %s %s %s %s\n",
> +			mkstring(buf1, VADDR_PRLEN, LJUST|LONG_HEX,
> +			MKSTR(memory_block)),
> +			mkstring(buf2, 12, CENTER, name),
> +			mkstring(buf3, PADDR_PRLEN, RJUST|LONG_HEX,
> +			MKSTR(pfn_to_phys(start_pfn))),
> +			mkstring(buf4, PADDR_PRLEN, LJUST|LONG_HEX,
> +			MKSTR(pfn_to_phys(end_pfn) - 1)),
> +			mkstring(buf5, strlen("NODE"), CENTER|LONG_DEC,
> +			MKSTR(nid)),
> +			mkstring(buf6, strlen("CANCEL_OFFLINE"), LJUST,
> +			statebuf),
> +			mkstring(buf7, 12, LJUST, srangebuf));
> +	} else
> +		fprintf(fp, " %s %s %s - %s %s %s\n",
> +			mkstring(buf1, VADDR_PRLEN, LJUST|LONG_HEX,
> +			MKSTR(memory_block)),
> +			mkstring(buf2, 10, CENTER, name),
> +			mkstring(buf3, PADDR_PRLEN, RJUST|LONG_HEX,
> +			MKSTR(pfn_to_phys(start_pfn))),
> +			mkstring(buf4, PADDR_PRLEN, LJUST|LONG_HEX,
> +			MKSTR(pfn_to_phys(end_pfn) - 1)),
> +			mkstring(buf5, strlen("CANCEL_OFFLINE"), LJUST,
> +			statebuf),
> +			mkstring(buf6, 12, LJUST, srangebuf));
> +}
> +
> +static void
> +init_memory_block_offset(void)
> +{
> +	MEMBER_OFFSET_INIT(bus_type_p, "bus_type", "p");
> +	MEMBER_OFFSET_INIT(subsys_private_klist_devices,
> +				"subsys_private", "klist_devices");
> +	MEMBER_OFFSET_INIT(klist_k_list, "klist", "k_list");
> +	MEMBER_OFFSET_INIT(klist_node_n_node, "klist_node", "n_node");
> +	MEMBER_OFFSET_INIT(device_private_knode_bus,
> +				"device_private", "knode_bus");
> +	MEMBER_OFFSET_INIT(device_private_device, "device_private", "device");
> +	MEMBER_OFFSET_INIT(memory_block_dev, "memory_block", "dev");
> +	MEMBER_OFFSET_INIT(memory_block_start_section_nr,
> +				"memory_block", "start_section_nr");
> +	MEMBER_OFFSET_INIT(memory_block_end_section_nr,
> +				"memory_block", "end_section_nr");
> +	MEMBER_OFFSET_INIT(memory_block_state, "memory_block", "state");
> +	if (MEMBER_EXISTS("memory_block", "nid"))
> +		MEMBER_OFFSET_INIT(memory_block_nid, "memory_block", "nid");
> +}
> +
> +static void
> +init_memory_block(struct list_data *ld, int *klistcnt, ulong **klistbuf)
> +{
> +	ulong memory_subsys = symbol_value("memory_subsys");
> +	ulong private, klist, start;
> +
> +	init_memory_block_offset();
> +
> +	readmem(memory_subsys + OFFSET(bus_type_p), KVADDR, &private,
> +		sizeof(void *), "memory_subsys.private", FAULT_ON_ERROR);
> +	klist = private + OFFSET(subsys_private_klist_devices) +
> +					OFFSET(klist_k_list);
> +	BZERO(ld, sizeof(struct list_data));
> +
> +	readmem(klist, KVADDR, &start,
> +		sizeof(void *), "klist klist", FAULT_ON_ERROR);
> +
> +	ld->start = start;
> +	ld->end = klist;
> +	ld->list_head_offset = OFFSET(klist_node_n_node) +
> +					OFFSET(device_private_knode_bus);
> +	hq_open();
> +	*klistcnt = do_list(ld);
> +	*klistbuf = (ulong *)GETBUF(*klistcnt * sizeof(ulong));
> +	*klistcnt = retrieve_list(*klistbuf, *klistcnt);
> +	hq_close();
> +}
> +
> +void
> +dump_memory_blocks(int initialize)
> +{
> +	ulong memory_block, device;
> +	ulong *klistbuf;
> +	int klistcnt, i;
> +	struct list_data list_data;
> +	char mb_hdr[BUFSIZE];
> +	char buf1[BUFSIZE];
> +	char buf2[BUFSIZE];
> +	char buf3[BUFSIZE];
> +	char buf4[BUFSIZE];
> +	char buf5[BUFSIZE];
> +	char buf6[BUFSIZE];
> +
> +	if ((!STRUCT_EXISTS("memory_block")) ||
> +				(!symbol_exists("memory_subsys")))
> +		return;
> +
> +	if (initialize)
> +		return;
> +
> +	init_memory_block(&list_data, &klistcnt, &klistbuf);
> +
> +	if (MEMBER_EXISTS("memory_block", "nid"))
> +		sprintf(mb_hdr, "\n%s %s %s     %s %s %s\n",
> +			mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "MEM_BLOCK"),
> +			mkstring(buf2, 10, CENTER, "NAME"),
> +			mkstring(buf3, PADDR_PRLEN*2 + 2, CENTER, "PHYSICAL RANGE"),
> +			mkstring(buf4, strlen("NODE"), CENTER, "NODE"),
> +			mkstring(buf5, strlen("CANCEL_OFFLINE"), LJUST, "STATE"),
> +			mkstring(buf6, 12, LJUST, "SECTIONS"));
> +	else
> +		sprintf(mb_hdr, "\n%s %s %s     %s %s\n",
> +			mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "MEM_BLOCK"),
> +			mkstring(buf2, 10, CENTER, "NAME"),
> +			mkstring(buf3, PADDR_PRLEN*2, CENTER, "PHYSICAL RANGE"),
> +			mkstring(buf4, strlen("CANCEL_OFFLINE"), LJUST, "STATE"),
> +			mkstring(buf5, 12, LJUST, "SECTIONS"));
> +	fprintf(fp, "%s", mb_hdr);
> +
> +	for (i = 0; i < klistcnt; i++) {
> +		readmem(klistbuf[i] + OFFSET(device_private_device), KVADDR,
> +			&device, sizeof(void *), "device_private device",
> +			FAULT_ON_ERROR);
> +		memory_block = device - OFFSET(memory_block_dev);
> +		print_memory_block(memory_block);
> +	}
> +	FREEBUF(klistbuf);
> +}
> +
>  void
>  list_mem_sections(void)
>  {
> @@ -17251,7 +17509,7 @@ list_mem_sections(void)
>  
>  	for (nr = 0; nr <= nr_mem_sections ; nr++) {
>  		if ((addr = valid_section_nr(nr))) {
> -			coded_mem_map = section_mem_map_addr(addr);
> +			coded_mem_map = section_mem_map_addr(addr, 0);
>  			fprintf(fp,
>  			    "nr=%ld section = %lx coded_mem_map=%lx pfn=%ld mem_map=%lx\n",
>  				nr,
> diff --git a/symbols.c b/symbols.c
> index cb2174b..c5aab14 100644
> --- a/symbols.c
> +++ b/symbols.c
> @@ -9938,6 +9938,18 @@ dump_offset_table(char *spec, ulong makestruct)
>  		OFFSET(tss_struct_ist));
>  	fprintf(fp, "   mem_section_section_mem_map: %ld\n",
>  		OFFSET(mem_section_section_mem_map));
> +	fprintf(fp, "   mem_section_pageblock_flags: %ld\n",
> +		OFFSET(mem_section_pageblock_flags));
> +	fprintf(fp, "              memory_block_dev: %ld\n",
> +		OFFSET(memory_block_dev));
> +	fprintf(fp, "              memory_block_nid: %ld\n",
> +		OFFSET(memory_block_nid));
> +	fprintf(fp, " memory_block_start_section_nr: %ld\n",
> +		OFFSET(memory_block_start_section_nr));
> +	fprintf(fp, "   memory_block_end_section_nr: %ld\n",
> +		OFFSET(memory_block_end_section_nr));
> +	fprintf(fp, "            memory_block_state: %ld\n",
> +		OFFSET(memory_block_state));
>  
>  	fprintf(fp, "  vcpu_guest_context_user_regs: %ld\n",
>  		OFFSET(vcpu_guest_context_user_regs));
> @@ -10031,6 +10043,8 @@ dump_offset_table(char *spec, ulong makestruct)
>  		OFFSET(unwind_idx_addr));
>  	fprintf(fp, "               unwind_idx_insn: %ld\n",
>  		OFFSET(unwind_idx_insn));
> +	fprintf(fp, "                    bus_type_p: %ld\n",
> +		OFFSET(bus_type_p));
>  	fprintf(fp, "                 class_devices: %ld\n",
>  		OFFSET(class_devices));
>  	fprintf(fp, "                       class_p: %ld\n",
> @@ -10041,6 +10055,10 @@ dump_offset_table(char *spec, ulong makestruct)
>  		OFFSET(device_knode_class));
>  	fprintf(fp, "                   device_node: %ld\n",
>  		OFFSET(device_node));
> +	fprintf(fp, "         device_private_device: %ld\n",
> +		OFFSET(device_private_device));
> +	fprintf(fp, "      device_private_knode_bus: %ld\n",
> +		OFFSET(device_private_knode_bus));
>  	fprintf(fp, "                   gendisk_dev: %ld\n",
>  		OFFSET(gendisk_dev));
>  	fprintf(fp, "                  gendisk_kobj: %ld\n",
> --
> 2.19.0
> 
> --
> Crash-utility mailing list
> Crash-utility at redhat.com
> https://www.redhat.com/mailman/listinfo/crash-utility
> 




More information about the Crash-utility mailing list