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