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
[email protected]
https://www.redhat.com/mailman/listinfo/crash-utility

Reply via email to