[Crash-utility] [PATCH] fix vmstat handling

vinayak menon vinayakm.list at gmail.com
Thu Nov 2 12:57:15 UTC 2017


From: Vinayak Menon <vinayakm.list at gmail.com>

With kernels where LRUs are moved to node and thus vm_stat is
split into zone and node, crash utility fails to show the vmstat with "kmem
-V", and the "CACHED" of kmem -i is shown as zero.

Signed-off-by: Vinayak Menon <vinayakm.list at gmail.com>
---
 memory.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 76 insertions(+), 21 deletions(-)

diff --git a/memory.c b/memory.c
index ebd671a..3097558 100644
--- a/memory.c
+++ b/memory.c
@@ -17340,30 +17340,43 @@ vm_stat_init(void)
        int c ATTRIBUTE_UNUSED;
         struct gnu_request *req;
        char *start;
-       long enum_value;
+       long enum_value, zc = -1;
+       int split_vmstat = 0, ni = 0;

        if (vt->flags & VM_STAT)
                return TRUE;

-       if ((vt->nr_vm_stat_items == -1) || !symbol_exists("vm_stat"))
+       if ((vt->nr_vm_stat_items == -1) ||
+               (!symbol_exists("vm_stat") && !symbol_exists("vm_zone_stat")))
                goto bailout;

         /*
          *  look for type: type = atomic_long_t []
          */
        if (LKCD_KERNTYPES()) {
-               if (!symbol_exists("vm_stat"))
+               if ((!symbol_exists("vm_stat") &&
+                               !symbol_exists("vm_zone_stat")))
                        goto bailout;
                /*
                 *  Just assume that vm_stat is an array; there is
                 *  no symbol info in a kerntypes file.
                 */
        } else {
-               if (!symbol_exists("vm_stat") ||
-                   get_symbol_type("vm_stat", NULL, NULL) != TYPE_CODE_ARRAY)
+               if (symbol_exists("vm_stat") &&
+                   get_symbol_type("vm_stat", NULL, NULL) == TYPE_CODE_ARRAY) {
+                       vt->nr_vm_stat_items =
+                               get_array_length("vm_stat", NULL, 0);
+               } else if (symbol_exists("vm_zone_stat") &&
+                       get_symbol_type("vm_zone_stat",
+                       NULL, NULL) == TYPE_CODE_ARRAY) {
+                       vt->nr_vm_stat_items =
+                               get_array_length("vm_zone_stat", NULL, 0)
+                               + get_array_length("vm_node_stat", NULL, 0);
+                       split_vmstat = 1;
+                       enumerator_value("NR_VM_ZONE_STAT_ITEMS", &zc);
+               } else {
                        goto bailout;
-
-               vt->nr_vm_stat_items = get_array_length("vm_stat", NULL, 0);
+               }
        }

         open_tmpfile();
@@ -17372,6 +17385,14 @@ vm_stat_init(void)
         req->name = "zone_stat_item";
         req->flags = GNU_PRINT_ENUMERATORS;
         gdb_interface(req);
+
+       if (split_vmstat) {
+               req->command = GNU_GET_DATATYPE;
+               req->name = "node_stat_item";
+               req->flags = GNU_PRINT_ENUMERATORS;
+               gdb_interface(req);
+       }
+
         FREEBUF(req);

        stringlen = 1;
@@ -17383,11 +17404,17 @@ vm_stat_init(void)
                        continue;
                clean_line(buf);
                c = parse_line(buf, arglist);
-               if (STREQ(arglist[0], "NR_VM_ZONE_STAT_ITEMS")) {
+               if ((!split_vmstat &&
+                       STREQ(arglist[0], "NR_VM_ZONE_STAT_ITEMS")) ||
+                       (split_vmstat &&
+                       STREQ(arglist[0], "NR_VM_NODE_STAT_ITEMS"))) {
                        if (LKCD_KERNTYPES())
                                vt->nr_vm_stat_items =
                                        MAX(atoi(arglist[2]), count);
                        break;
+               } else if (split_vmstat &&
+                       STREQ(arglist[0], "NR_VM_ZONE_STAT_ITEMS")) {
+                       continue;
                } else {
                        stringlen += strlen(arglist[0]);
                        count++;
@@ -17409,18 +17436,24 @@ vm_stat_init(void)
                 if (strstr(buf, "{") || strstr(buf, "}"))
                         continue;
                c = parse_line(buf, arglist);
-               if (enumerator_value(arglist[0], &enum_value))
-                       i = enum_value;
-               else {
+               if (!enumerator_value(arglist[0], &enum_value)) {
                        close_tmpfile();
                        goto bailout;
                }
+
+               i = ni + enum_value;
+               if (!ni && (enum_value == zc)) {
+                       ni = zc;
+                       continue;
+               }
+
                if (i < vt->nr_vm_stat_items) {
                        vt->vm_stat_items[i] = start;
                        strcpy(start, arglist[0]);
                        start += strlen(arglist[0]) + 1;
                }
         }
+
        close_tmpfile();

        vt->flags |= VM_STAT;
@@ -17443,39 +17476,61 @@ dump_vm_stat(char *item, long *retval, ulong zone)
        ulong *vp;
        ulong location;
        int i, maxlen, len;
+       long tc, zc = 0, nc = 0;
+       int split_vmstat = 0;

        if (!vm_stat_init()) {
                if (!item)
                        if (CRASHDEBUG(1))
-                               error(INFO,
+                               error(INFO,
                                    "vm_stat not available in this kernel\n");
                return FALSE;
        }

        buf = GETBUF(sizeof(ulong) * vt->nr_vm_stat_items);

-       location = zone ? zone : symbol_value("vm_stat");
-
-       readmem(location, KVADDR, buf,
-           sizeof(ulong) * vt->nr_vm_stat_items,
-           "vm_stat", FAULT_ON_ERROR);
+       if (symbol_exists("vm_node_stat") && symbol_exists("vm_zone_stat"))
+               split_vmstat = 1;
+       else
+               location = zone ? zone : symbol_value("vm_stat");
+
+       if (split_vmstat) {
+               enumerator_value("NR_VM_ZONE_STAT_ITEMS", &zc);
+               location = zone ? zone : symbol_value("vm_zone_stat");
+               readmem(location, KVADDR, buf,
+                       sizeof(ulong) * zc,
+                       "vm_zone_stat", FAULT_ON_ERROR);
+               if (!zone) {
+                       location = symbol_value("vm_node_stat");
+                       enumerator_value("NR_VM_NODE_STAT_ITEMS", &nc);
+                       readmem(location, KVADDR, buf + (sizeof(ulong) * zc),
+                               sizeof(ulong) * nc,
+                               "vm_node_stat", FAULT_ON_ERROR);
+               }
+               tc = zc + nc;
+       } else {
+               readmem(location, KVADDR, buf,
+                       sizeof(ulong) * vt->nr_vm_stat_items,
+                       "vm_stat", FAULT_ON_ERROR);
+               tc = vt->nr_vm_stat_items;
+       }

        if (!item) {
                if (!zone)
                        fprintf(fp, "  VM_STAT:\n");
-               for (i = maxlen = 0; i < vt->nr_vm_stat_items; i++)
+               for (i = maxlen = 0; i < tc; i++)
                        if ((len = strlen(vt->vm_stat_items[i])) > maxlen)
                                maxlen = len;
                vp = (ulong *)buf;
-               for (i = 0; i < vt->nr_vm_stat_items; i++)
-                       fprintf(fp, "%s%s: %ld\n",
+               for (i = 0; i < tc; i++)
+                       fprintf(fp, "%s%s: %ld\n",
                                space(maxlen - strlen(vt->vm_stat_items[i])),
                                 vt->vm_stat_items[i], vp[i]);
                return TRUE;
        }

        vp = (ulong *)buf;
-       for (i = 0; i < vt->nr_vm_stat_items; i++) {
+       for (i = 0; i < tc; i++) {
                if (STREQ(vt->vm_stat_items[i], item)) {
                        *retval = vp[i];
                        return TRUE;




More information about the Crash-utility mailing list