Display compound page order when running command kmem with -p. Also verifies compound pages based on: for head page, compound order can't be zero; for tail page, its head page must exist. When verification fails, display the compound order as -1. --- help.c | 8 ++++- memory.c | 114 +++++++++++++++++++++++++++++++++++++++++++++------------------ 2 files changed, 88 insertions(+), 34 deletions(-) diff --git a/help.c b/help.c index 716de33..ffc8aeb 100644 --- a/help.c +++ b/help.c @@ -5541,7 +5541,7 @@ NULL char *help_kmem[] = { "kmem", "kernel memory", -"[-f|-F|-p|-c|-C|-i|-s|-S|-v|-V|-n|-z|-o|-h] [slab] [[-P] address]\n" +"[-f|-F|-p|-c|-C|-i|-s|-S|-v|-V|-n|-z|-o|-h|-k] [slab] [[-P] address]\n" " [-g [flags]] [-I slab[,slab]]", " This command displays information about the use of kernel memory.\n", " -f displays the contents of the system free memory headers.", @@ -5570,6 +5570,12 @@ char *help_kmem[] = { " \"flags\" field.", " -h display the address of hugepage hstate array entries, along with", " their hugepage size, total and free counts, and name.", +" -k verify compound page: if a page is head, check its compound order", +" which should not be zero; if a page is tail, check its head page", +" which should exist. The option is useful when debugging problems", +" caused by misuse of compound pages (e.g. free with wrong order).", +" When an error is found, the compound order will be shown as -1.", +" Only works when -p is used without an address.", " flags when used with -g, translates all bits in this hexadecimal page", " structure flags value into its enumerator values.", " slab when used with -s or -S, limits the command to only the slab cache", diff --git a/memory.c b/memory.c index db7dddb..43ceff7 100644 --- a/memory.c +++ b/memory.c @@ -40,6 +40,7 @@ struct meminfo { /* general purpose memory information structure */ ulong objects; ulonglong spec_addr; ulong flags; + ulong extra_flags; ulong size; ulong objsize; int memtype; @@ -288,6 +289,7 @@ static int __is_page_tail(const char *); static int is_page_tail(ulong); static int __compound_order(const char *); static int compound_order(ulong); +static int __check_compound_order(const char *, int); static ulong __compound_head(const char *); static ulong compound_head(ulong); static long count_partial(ulong, struct meminfo *); @@ -4422,6 +4424,8 @@ get_task_mem_usage(ulong task, struct task_mem_usage *tm) #define SLAB_OVERLOAD_PAGE_PTR (ADDRESS_SPECIFIED << 24) #define SLAB_BITFIELD (ADDRESS_SPECIFIED << 25) +#define VERIFY_COMPOUND_PAGES (1 << 0) + #define GET_ALL \ (GET_SHARED_PAGES|GET_TOTALRAM_PAGES|GET_BUFFERS_PAGES|GET_SLAB_PAGES) @@ -4432,6 +4436,7 @@ cmd_kmem(void) int c; int sflag, Sflag, pflag, fflag, Fflag, vflag, zflag, oflag, gflag; int nflag, cflag, Cflag, iflag, lflag, Lflag, Pflag, Vflag, hflag; + int kflag; struct meminfo meminfo; ulonglong value[MAXARGS]; char buf[BUFSIZE]; @@ -4441,12 +4446,12 @@ cmd_kmem(void) spec_addr = 0; sflag = Sflag = pflag = fflag = Fflag = Pflag = zflag = oflag = 0; vflag = Cflag = cflag = iflag = nflag = lflag = Lflag = Vflag = 0; - gflag = hflag = 0; + gflag = hflag = kflag = 0; escape = FALSE; BZERO(&meminfo, sizeof(struct meminfo)); BZERO(&value[0], sizeof(ulonglong)*MAXARGS); - while ((c = getopt(argcnt, args, "gI:sSFfpvczCinl:L:PVoh")) != EOF) { + while ((c = getopt(argcnt, args, "gI:sSFfpkvczCinl:L:PVoh")) != EOF) { switch(c) { case 'V': @@ -4551,6 +4556,10 @@ cmd_kmem(void) gflag = 1; break; + case 'k': + kflag = 1; + break; + default: argerrs++; break; @@ -4718,8 +4727,11 @@ cmd_kmem(void) if (iflag == 1) dump_kmeminfo(); - if (pflag == 1) + if (pflag == 1) { + if (kflag) + meminfo.extra_flags |= VERIFY_COMPOUND_PAGES; dump_mem_map(&meminfo); + } if (fflag == 1) vt->dump_free_pages(&meminfo); @@ -4984,12 +4996,14 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi) char buf2[BUFSIZE]; char buf3[BUFSIZE]; char buf4[BUFSIZE]; + char buf5[BUFSIZE]; char *pcache; ulong section, section_nr, nr_mem_sections, section_size; long buffersize; char *outputbuffer; int bufferindex; struct mem_map_cache mmc; + int order; buffersize = 1024 * 1024; outputbuffer = GETBUF(buffersize + 512); @@ -5006,7 +5020,7 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi) VADDR_PRLEN, space(MINSPACE), space(MINSPACE)); - sprintf((char *)&style2, "%%-%dlx%s%%%dllx%s%s%s%s %2s ", + sprintf((char *)&style2, "%%-%dlx%s%%%dllx%s%s%s%s%%8d %2s ", VADDR_PRLEN, space(MINSPACE), (int)MAX(PADDR_PRLEN, strlen("PHYSICAL")), @@ -5015,7 +5029,7 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi) space(MINSPACE), mkstring(buf4, 8, CENTER|RJUST, " "), " "); - sprintf((char *)&style3, "%%-%dlx%s%%%dllx%s%s%s%s %%2d ", + sprintf((char *)&style3, "%%-%dlx%s%%%dllx%s%s%s%s%%8d %%2d ", VADDR_PRLEN, space(MINSPACE), (int)MAX(PADDR_PRLEN, strlen("PHYSICAL")), @@ -5023,7 +5037,7 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi) mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, "-------"), space(MINSPACE), mkstring(buf4, 8, CENTER|RJUST, "-----")); - sprintf((char *)&style4, "%%-%dlx%s%%%dllx%s%%%dlx%s%%8lx %%2d ", + sprintf((char *)&style4, "%%-%dlx%s%%%dllx%s%%8d %%%dlx%s%%8lx %%2d ", VADDR_PRLEN, space(MINSPACE), (int)MAX(PADDR_PRLEN, strlen("PHYSICAL")), @@ -5045,15 +5059,17 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi) mkstring(buf4, 8, CENTER|LJUST, "OFFSET"), space(MINSPACE-1)); } else { - sprintf(hdr, "%s%s%s%s%s%s%sCNT FLAGS\n", - mkstring(buf1, VADDR_PRLEN, CENTER, "PAGE"), - space(MINSPACE), - mkstring(buf2, MAX(PADDR_PRLEN, strlen("PHYSICAL")), - RJUST, "PHYSICAL"), - space(MINSPACE), - mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, "MAPPING"), - space(MINSPACE), - mkstring(buf4, 8, CENTER|RJUST, "INDEX")); + sprintf(hdr, "%s%s%s%s%s%s%s%s%sCNT FLAGS\n", + mkstring(buf1, VADDR_PRLEN, CENTER, "PAGE"), + space(MINSPACE), + mkstring(buf2, MAX(PADDR_PRLEN, strlen("PHYSICAL")), + RJUST, "PHYSICAL"), + space(MINSPACE), + mkstring(buf3, 8, CENTER | RJUST, "ORDER"), + space(MINSPACE), + mkstring(buf4, VADDR_PRLEN, CENTER | RJUST, "MAPPING"), + space(MINSPACE), + mkstring(buf5, 8, CENTER | RJUST, "INDEX")); } mapping = index = 0; @@ -5281,6 +5297,12 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi) page_not_mapped = phys_not_mapped = FALSE; + order = (i + 1) % PGMM_CACHED ? + __compound_order(pcache) : compound_order(pp); + + if (mi->extra_flags & VERIFY_COMPOUND_PAGES) + order = __check_compound_order(pcache, order); + if (v22) { bufferindex += sprintf(outputbuffer+bufferindex, (char *)&style1, pp, phys, inode, @@ -5294,13 +5316,14 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi) } if (page_not_mapped) bufferindex += sprintf(outputbuffer+bufferindex, - (char *)&style2, pp, phys); + (char *)&style2, pp, phys, order); else if (!page_mapping) bufferindex += sprintf(outputbuffer+bufferindex, - (char *)&style3, pp, phys, count); + (char *)&style3, pp, phys, order, + count); else bufferindex += sprintf(outputbuffer+bufferindex, - (char *)&style4, pp, phys, + (char *)&style4, pp, phys, order, mapping, index, count); } @@ -5456,11 +5479,13 @@ dump_mem_map(struct meminfo *mi) char buf2[BUFSIZE]; char buf3[BUFSIZE]; char buf4[BUFSIZE]; + char buf5[BUFSIZE]; char *pcache; long buffersize; char *outputbuffer; int bufferindex; struct mem_map_cache mmc; + int order; buffersize = 1024 * 1024; outputbuffer = GETBUF(buffersize + 512); @@ -5482,7 +5507,7 @@ dump_mem_map(struct meminfo *mi) VADDR_PRLEN, space(MINSPACE), space(MINSPACE)); - sprintf((char *)&style2, "%%-%dlx%s%%%dllx%s%s%s%s %2s ", + sprintf((char *)&style2, "%%-%dlx%s%%%dllx%s%s%s%s%%8d %2s ", VADDR_PRLEN, space(MINSPACE), (int)MAX(PADDR_PRLEN, strlen("PHYSICAL")), @@ -5491,7 +5516,7 @@ dump_mem_map(struct meminfo *mi) space(MINSPACE), mkstring(buf4, 8, CENTER|RJUST, " "), " "); - sprintf((char *)&style3, "%%-%dlx%s%%%dllx%s%s%s%s %%2d ", + sprintf((char *)&style3, "%%-%dlx%s%%%dllx%s%s%s%s%%8d %%2d ", VADDR_PRLEN, space(MINSPACE), (int)MAX(PADDR_PRLEN, strlen("PHYSICAL")), @@ -5499,7 +5524,7 @@ dump_mem_map(struct meminfo *mi) mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, "-------"), space(MINSPACE), mkstring(buf4, 8, CENTER|RJUST, "-----")); - sprintf((char *)&style4, "%%-%dlx%s%%%dllx%s%%%dlx%s%%8lx %%2d ", + sprintf((char *)&style4, "%%-%dlx%s%%%dllx%s%%8d %%%dlx%s%%8lx %%2d ", VADDR_PRLEN, space(MINSPACE), (int)MAX(PADDR_PRLEN, strlen("PHYSICAL")), @@ -5521,15 +5546,17 @@ dump_mem_map(struct meminfo *mi) mkstring(buf4, 8, CENTER|LJUST, "OFFSET"), space(MINSPACE-1)); } else { - sprintf(hdr, "%s%s%s%s%s%s%sCNT FLAGS\n", - mkstring(buf1, VADDR_PRLEN, CENTER, "PAGE"), - space(MINSPACE), - mkstring(buf2, MAX(PADDR_PRLEN, strlen("PHYSICAL")), - RJUST, "PHYSICAL"), - space(MINSPACE), - mkstring(buf3, VADDR_PRLEN, CENTER|RJUST, "MAPPING"), - space(MINSPACE), - mkstring(buf4, 8, CENTER|RJUST, "INDEX")); + sprintf(hdr, "%s%s%s%s%s%s%s%s%sCNT FLAGS\n", + mkstring(buf1, VADDR_PRLEN, CENTER, "PAGE"), + space(MINSPACE), + mkstring(buf2, MAX(PADDR_PRLEN, strlen("PHYSICAL")), + RJUST, "PHYSICAL"), + space(MINSPACE), + mkstring(buf3, 8, CENTER | RJUST, "ORDER"), + space(MINSPACE), + mkstring(buf4, VADDR_PRLEN, CENTER | RJUST, "MAPPING"), + space(MINSPACE), + mkstring(buf5, 8, CENTER | RJUST, "INDEX")); } mapping = index = 0; @@ -5720,6 +5747,12 @@ dump_mem_map(struct meminfo *mi) page_not_mapped = phys_not_mapped = FALSE; + order = (i + 1) % PGMM_CACHED ? + __compound_order(pcache) : compound_order(pp); + + if (mi->extra_flags & VERIFY_COMPOUND_PAGES) + order = __check_compound_order(pcache, order); + if (v22) { bufferindex += sprintf(outputbuffer+bufferindex, (char *)&style1, pp, phys, inode, @@ -5733,13 +5766,14 @@ dump_mem_map(struct meminfo *mi) } if (page_not_mapped) bufferindex += sprintf(outputbuffer+bufferindex, - (char *)&style2, pp, phys); + (char *)&style2, pp, phys, order); else if (!page_mapping) bufferindex += sprintf(outputbuffer+bufferindex, - (char *)&style3, pp, phys, count); + (char *)&style3, pp, phys, order, + count); else bufferindex += sprintf(outputbuffer+bufferindex, - (char *)&style4, pp, phys, + (char *)&style4, pp, phys, order, mapping, index, count); } @@ -18340,6 +18374,20 @@ compound_order(ulong page) return order; } +static int +__check_compound_order(const char *p, int order) +{ + /* head page must have non-zero order */ + if (__is_page_head(p) && !order) + return -1; + + /* tail page must have a non-zero order head */ + if (__is_page_tail(p) && !compound_order(__compound_head(p))) + return -1; + + return order; +} + /* * In contrast to compound_head(), this function only can be used on a tail page. */ -- 2.2.0.rc0.207.ga3a616c -- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility