From 49041c2d57d603e5b990b4aafe5c266835b9be7b Mon Sep 17 00:00:00 2001 From: Vinayak Menon Date: Thu, 2 Nov 2017 15:58:39 +0530 Subject: [PATCH] fix vmstat handling 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 --- 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; --