[Crash-utility] [PATCH 4/5] memory: display and verify compound page order

Yu Zhao yuzhao at google.com
Thu Feb 5 21:06:47 UTC 2015


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




More information about the Crash-utility mailing list