From: Masayoshi Mizuma <[email protected]>

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.

Signed-off-by: Masayoshi Mizuma <[email protected]>
---
 defs.h   |   8 ++
 memory.c | 412 +++++++++++++++++++++++++++++++++++++++++++++++++------
 2 files changed, 379 insertions(+), 41 deletions(-)

diff --git a/defs.h b/defs.h
index 5b64bb7..f707c64 100644
--- a/defs.h
+++ b/defs.h
@@ -2049,6 +2049,14 @@ 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 mem_section_pageblock_flags;
+       long memory_block_state;
+       long memory_block_nid;
+       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..c7a4787 100644
--- a/memory.c
+++ b/memory.c
@@ -254,14 +254,16 @@ static void PG_reserved_flag_init(void);
 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_mem_block_and_sections(int);
+void _dump_mem_block_and_sections(void);
+void dump_mem_sections(void);
 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 +5530,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 +13391,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));
 
@@ -16355,7 +16357,7 @@ dump_memory_nodes(int initialize)
        }
 
        if (IS_SPARSEMEM())
-               dump_mem_sections(initialize);
+               dump_mem_block_and_sections(initialize);
 }
 
 /*
@@ -17140,7 +17142,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 +17150,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 +17182,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 +17191,365 @@ pfn_to_map(ulong pfn)
        return 0;
 }
 
-void 
-dump_mem_sections(int initialize)
+struct memory_block_info {
+       ulong memory_block;
+       ulong start_sec;
+       ulong start_pfn;
+       ulong nid;
+       char state[24];
+       char name[32];
+};
+
+#define MIN_MEMORY_BLOCK_SIZE     (1UL << _SECTION_SIZE_BITS)
+
+#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 nr, max, addr;
-       ulong nr_mem_sections;
+       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 void
+fill_mem_section_state(ulong state, char *buf)
+{
+       int bufidx = 0, others = 0;
+
+       memset(buf, 0, sizeof(*buf) * BUFSIZE);
+
+#define printflag(X) sprintf(buf + bufidx, X, others++ ? "|" : "")
+
+       if (state & SECTION_MARKED_PRESENT)
+               bufidx += printflag("%sPRESENT");
+       if (state & SECTION_HAS_MEM_MAP)
+               bufidx += printflag("%sHAS_MEMMAP");
+       if (state & SECTION_IS_ONLINE)
+               bufidx += printflag("%sONLINE");
+}
+
+static ulong
+pfn_to_phys(ulong pfn)
+{
+       return pfn << PAGE_SHIFT;
+}
+
+static ulong
+get_memory_block_size(void)
+{
+       static ulong blksz;
+
+       if (blksz)
+               return blksz;
+
+       if (symbol_exists("memory_block_size_probed"))
+               get_symbol_data("memory_block_size_probed", sizeof(ulong),
+                               &blksz);
+       else
+               blksz = MIN_MEMORY_BLOCK_SIZE;
+
+       return blksz;
+}
+
+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_info(ulong mb, struct memory_block_info *mbi)
+{
+       ulong start, start_pfn, nid;
+       char statebuf[BUFSIZE];
+       char name[BUFSIZE];
+
+       readmem(mb + OFFSET(memory_block_start_section_nr), KVADDR,
+               &start, sizeof(void *), "memory_block start_section_nr",
+               FAULT_ON_ERROR);
+
+       start_pfn = section_nr_to_pfn(start);
+       fill_memory_block_state(mb, statebuf);
+       fill_memory_block_name(mb, name);
+
+       mbi->memory_block = mb;
+       mbi->start_sec = start;
+       mbi->start_pfn = start_pfn;
+       strncpy(mbi->state, statebuf, sizeof(mbi->state));
+       strncpy(mbi->name, name, sizeof(mbi->name));
+       if (MEMBER_EXISTS("memory_block", "nid")) {
+               readmem(mb + OFFSET(memory_block_nid), KVADDR, &nid,
+                       sizeof(void *), "memory_block nid", FAULT_ON_ERROR);
+               mbi->nid = nid;
+       }
+}
+
+static void
+init_memory_block(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_state, "memory_block", "state");
+       if (MEMBER_EXISTS("memory_block", "nid"))
+               MEMBER_OFFSET_INIT(memory_block_nid, "memory_block", "nid");
+}
+
+static struct memory_block_info*
+parse_memory_block(void)
+{
+       ulong memory_subsys = symbol_value("memory_subsys");
+       ulong private, klist, memory_block, device;
+       ulong *klistbuf;
+       int klistcnt, i;
+       struct list_data list_data, *ld;
+       struct memory_block_info *memory_block_info;
+
+       init_memory_block();
+
+       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);
+       ld = &list_data;
+       BZERO(ld, sizeof(struct list_data));
+
+       ld->start = klist;
+       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();
+
+       memory_block_info = calloc(klistcnt + 1,
+                                       sizeof(struct memory_block_info));
+       if (!memory_block_info)
+               error(FATAL, "cannot allocate memory for memory_block_info\n");
+
+       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);
+               fill_memory_block_info(memory_block, &memory_block_info[i]);
+       }
+       FREEBUF(klistbuf);
+
+       return memory_block_info;
+}
+
+static struct memory_block_info*
+get_memory_block_info(ulong pfn, struct memory_block_info *mbi_tbl)
+{
+       int i;
+
+       for (i = 0; mbi_tbl[i].memory_block != 0; i++)
+               if (pfn == mbi_tbl[i].start_pfn)
+                       return &mbi_tbl[i];
+
+       return NULL;
+}
+
+
+static int
+is_memory_block_head(ulong pfn)
+{
+       ulong nr_pages = get_memory_block_size() / PAGE_SIZE;
+
+       return (pfn % nr_pages) == 0;
+}
+
+static void
+print_memory_block(ulong pfn, ulong nr_mb_pages, struct memory_block_info *mbi)
+{
+       char buf1[BUFSIZE];
+       char buf2[BUFSIZE];
+       char buf3[BUFSIZE];
+       char buf4[BUFSIZE];
+       char buf5[BUFSIZE];
+       char buf6[BUFSIZE];
+
+       if (MEMBER_EXISTS("memory_block", "nid"))
+               fprintf(fp, " %s %s %s - %s %s %s\n",
+                       mkstring(buf1, VADDR_PRLEN, LJUST|LONG_HEX,
+                       MKSTR(mbi->memory_block)),
+                       mkstring(buf2, 12, CENTER, mbi->name),
+                       mkstring(buf3, PADDR_PRLEN, RJUST|LONG_HEX,
+                       MKSTR(pfn_to_phys(pfn))),
+                       mkstring(buf4, PADDR_PRLEN, LJUST|LONG_HEX,
+                       MKSTR(pfn_to_phys(pfn + nr_mb_pages) - 1)),
+                       mkstring(buf5, strlen("NODE"), CENTER|LONG_DEC,
+                       MKSTR(mbi->nid)),
+                       mkstring(buf6, strlen("CANCEL_OFFLINE"), LJUST,
+                       mbi->state));
+       else
+               fprintf(fp, " %s %s %s - %s %s\n",
+                       mkstring(buf1, VADDR_PRLEN, LJUST|LONG_HEX,
+                       MKSTR(mbi->memory_block)),
+                       mkstring(buf2, 10, CENTER, mbi->name),
+                       mkstring(buf3, PADDR_PRLEN, RJUST|LONG_HEX,
+                       MKSTR(pfn_to_phys(pfn))),
+                       mkstring(buf4, PADDR_PRLEN, LJUST|LONG_HEX,
+                       MKSTR(pfn_to_phys(pfn + nr_mb_pages) - 1)),
+                       mkstring(buf5, strlen("CANCEL_OFFLINE"), LJUST,
+                       mbi->state));
+}
+
+static void
+do_mem_block_and_sections(int print_memblk, struct memory_block_info *mbi_tbl)
+{
+       ulong nr, addr;
+       ulong nr_mem_sections, nr_mb_pages;
        ulong coded_mem_map, mem_map, pfn;
+       struct memory_block_info *mbi;
+       char mb_hdr[BUFSIZE];
+       char ms_hdr[BUFSIZE];
+       char statebuf[BUFSIZE];
        char buf1[BUFSIZE];
        char buf2[BUFSIZE];
        char buf3[BUFSIZE];
        char buf4[BUFSIZE];
+       char buf5[BUFSIZE];
+
+       nr_mb_pages = PAGES_PER_SECTION() *
+                       get_memory_block_size() / MIN_MEMORY_BLOCK_SIZE;
+
+       if (MEMBER_EXISTS("memory_block", "nid"))
+               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 + 2, CENTER, "PHYSICAL 
RANGE"),
+                       mkstring(buf4, strlen("NODE"), CENTER, "NODE"),
+                       mkstring(buf5, strlen("CANCEL_OFFLINE"), LJUST, 
"STATE"));
+       else
+               sprintf(mb_hdr, "\n%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"));
+
+       sprintf(ms_hdr, "NR     %s  %s  %s  %s %s\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(buf4, 12, CENTER, "PFN"),
+               mkstring(buf5, 12, LJUST, "STATE"));
+
+       if (!print_memblk)
+               fprintf(fp, "%s", ms_hdr);
+
+       nr_mem_sections = NR_MEM_SECTIONS();
+       for (nr = 0; nr < nr_mem_sections ; nr++) {
+               addr = valid_section_nr(nr);
+               if (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);
+
+                       if ((print_memblk) && (is_memory_block_head(pfn))) {
+                               mbi = get_memory_block_info(pfn, mbi_tbl);
+                               fprintf(fp, "%s", mb_hdr);
+                               print_memory_block(pfn, nr_mb_pages, mbi);
+                               fprintf(fp, "%s", ms_hdr);
+                       }
+
+                       fprintf(fp, "%5ld  %s  %s  %s  %s %s\n",
+                               nr,
+                               mkstring(buf1, VADDR_PRLEN,
+                               CENTER|LONG_HEX, MKSTR(addr)),
+                               mkstring(buf2, MAX(VADDR_PRLEN,
+                               strlen("CODED_MEM_MAP")),
+                               CENTER|LONG_HEX|RJUST, MKSTR(coded_mem_map)),
+                               mkstring(buf3, VADDR_PRLEN,
+                               CENTER|LONG_HEX|RJUST, MKSTR(mem_map)),
+                               pc->output_radix == 10 ?
+                               mkstring(buf4, 12,
+                               LONG_DEC|LJUST, MKSTR(pfn)) :
+                               mkstring(buf4, 12,
+                               LONG_HEX|LJUST, MKSTR(pfn)),
+                               mkstring(buf5, 12, LJUST, statebuf));
+               }
+       }
+}
+
+
+void
+dump_mem_sections(void)
+{
+       do_mem_block_and_sections(0, NULL);
+}
+
+void
+_dump_mem_block_and_sections(void)
+{
+       struct memory_block_info *mbi_tbl;
+
+       mbi_tbl = parse_memory_block();
+       do_mem_block_and_sections(1, mbi_tbl);
+       free(mbi_tbl);
+}
+
+void
+dump_mem_block_and_sections(int initialize)
+{
+       ulong nr, max;
+       ulong nr_mem_sections;
 
        nr_mem_sections = NR_MEM_SECTIONS();
 
@@ -17212,34 +17564,12 @@ dump_mem_sections(int initialize)
 
        fprintf(fp, "\n");
        pad_line(fp, BITS32() ? 59 : 67, '-');
-        fprintf(fp, "\n\nNR  %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"));
-
-       for (nr = 0; nr < nr_mem_sections ; nr++) {
-               if ((addr = valid_section_nr(nr))) {
-                       coded_mem_map = section_mem_map_addr(addr);
-                       mem_map = sparse_decode_mem_map(coded_mem_map,nr);
-                       pfn = section_nr_to_pfn(nr);
-
-                       fprintf(fp, "%2ld  %s  %s  %s  %s\n",
-                               nr,
-                               mkstring(buf1, VADDR_PRLEN,
-                               CENTER|LONG_HEX, MKSTR(addr)),
-                               mkstring(buf2, MAX(VADDR_PRLEN,
-                               strlen("CODED_MEM_MAP")),
-                               CENTER|LONG_HEX|RJUST, MKSTR(coded_mem_map)),
-                               mkstring(buf3, VADDR_PRLEN,
-                               CENTER|LONG_HEX|RJUST, MKSTR(mem_map)),
-                               pc->output_radix == 10 ?
-                               mkstring(buf4, VADDR_PRLEN,
-                               LONG_DEC|LJUST, MKSTR(pfn)) :
-                               mkstring(buf4, VADDR_PRLEN,
-                               LONG_HEX|LJUST, MKSTR(pfn)));
-               }
-       }
+       fprintf(fp, "\n\n");
+       if ((!STRUCT_EXISTS("memory_block")) ||
+                               (!symbol_exists("memory_subsys")))
+               dump_mem_sections();
+       else
+               _dump_mem_block_and_sections();
 }
 
 void 
@@ -17251,7 +17581,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,
-- 
2.19.0

--
Crash-utility mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/crash-utility

Reply via email to