mirror of
https://github.com/crash-utility/crash
synced 2025-01-20 15:50:42 +00:00
Implemented a new "kmem -m" option that is similar to "kmem -p",
but it allows the user to specify the page struct members to be displayed. The option takes a comma-separated list of one or more page struct members, which will be displayed following the page structure address. The "flags" member will always be expressed in hexadecimal format, and the "_count" and "_mapcount" members will always be expressed in decimal format. Otherwise, all other members will be displayed in hexadecimal format unless the current output radix is 10 and the member is a signed/unsigned integer. Members that are data structures may be specified by the data structure's member name, or expanded to specify a member of that data structure. For example, "-m lru" refers to a list_head data structure, in which case both the list_head.next and list_head.prev pointer values will be displayed; if "-m lru.next" is specified, just the list_head.next value will be displayed. (atomlin@redhat.com, anderson@redhat.com)
This commit is contained in:
parent
c50fad9be1
commit
a8e7fc1e58
1
defs.h
1
defs.h
@ -4201,6 +4201,7 @@ enum type_code {
|
||||
/*
|
||||
* NOTE: the remainder of the type codes are not list or used here...
|
||||
*/
|
||||
TYPE_CODE_BOOL = 20,
|
||||
#endif
|
||||
};
|
||||
|
||||
|
105
help.c
105
help.c
@ -5532,23 +5532,15 @@ 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"
|
||||
" [-g [flags]] [-I slab[,slab]]",
|
||||
"[-f|-F|-c|-C|-i|-v|-V|-n|-z|-o|-h] [-p | -m member[,member]]\n"
|
||||
" [[-s|-S] [slab] [-I slab[,slab]]] [-g [flags]] [[-P] address]]",
|
||||
" This command displays information about the use of kernel memory.\n",
|
||||
" -f displays the contents of the system free memory headers.",
|
||||
" also verifies that the page count equals nr_free_pages.",
|
||||
" -F same as -f, but also dumps all pages linked to that header.",
|
||||
" -p displays basic information about each page in the system ",
|
||||
" mem_map[] array.",
|
||||
" -c walks through the page_hash_table and verifies page_cache_size.",
|
||||
" -C same as -c, but also dumps all pages in the page_hash_table.",
|
||||
" -i displays general memory usage information",
|
||||
" -s displays basic kmalloc() slab data.",
|
||||
" -S displays all kmalloc() slab data, including all slab objects,",
|
||||
" and whether each object is in use or is free. If CONFIG_SLUB,",
|
||||
" slab data for each per-cpu slab is displayed, along with the",
|
||||
" address of each kmem_cache_node, its count of full and partial",
|
||||
" slabs, and a list of all tracked slabs.",
|
||||
" -v displays the mapped virtual memory regions allocated by vmalloc().",
|
||||
" -V displays the kernel vm_stat table if it exists, the cumulative",
|
||||
" page_states counter values if they exist, and/or the cumulative",
|
||||
@ -5557,17 +5549,41 @@ char *help_kmem[] = {
|
||||
" -z displays per-zone memory statistics.",
|
||||
" -o displays each cpu's offset value that is added to per-cpu symbol",
|
||||
" values to translate them into kernel virtual addresses.",
|
||||
" -g displays the enumerator value of all bits in the page structure's",
|
||||
" \"flags\" field.",
|
||||
" -h display the address of hugepage hstate array entries, along with",
|
||||
" their hugepage size, total and free counts, and name.",
|
||||
" flags when used with -g, translates all bits in this hexadecimal page",
|
||||
" structure flags value into its enumerator values.",
|
||||
" -p displays basic information about each page structure in the system",
|
||||
" mem_map[] array, made up of the page struct address, its associated",
|
||||
" physical address, the page.mapping, page.index, page._count and",
|
||||
" page.flags fields.",
|
||||
" -m member similar to -p, but displays page structure contents specified by",
|
||||
" a comma-separated list of one or more struct page members. The",
|
||||
" \"flags\" member will always be expressed in hexadecimal format, and",
|
||||
" the \"_count\" and \"_mapcount\" members will always be expressed",
|
||||
" in decimal format. Otherwise, all other members will be displayed",
|
||||
" in hexadecimal format unless the output radix is 10 and the member",
|
||||
" is a signed/unsigned integer. Members that are data structures may",
|
||||
" be specified either by the data structure's member name, or expanded",
|
||||
" to specify a member of the data structure. For example, \"-m lru\"",
|
||||
" refers to a list_head data structure, and both the list_head.next",
|
||||
" and list_head.prev pointer values will be displayed, whereas if",
|
||||
" \"-m lru.next\" is specified, just the list_head.next value will",
|
||||
" be displayed.",
|
||||
" -s displays basic kmalloc() slab data.",
|
||||
" -S displays all kmalloc() slab data, including all slab objects,",
|
||||
" and whether each object is in use or is free. If CONFIG_SLUB,",
|
||||
" slab data for each per-cpu slab is displayed, along with the",
|
||||
" address of each kmem_cache_node, its count of full and partial",
|
||||
" slabs, and a list of all tracked slabs.",
|
||||
" slab when used with -s or -S, limits the command to only the slab cache",
|
||||
" of name \"slab\". If the slab argument is \"list\", then",
|
||||
" all slab cache names and addresses are listed.",
|
||||
" -I slab when used with -s or -S, one or more slab cache names in a",
|
||||
" comma-separated list may be specified as slab caches to ignore.",
|
||||
" their hugepage size, total and free counts, and name.",
|
||||
" -g displays the enumerator value of all bits in the page structure's",
|
||||
" \"flags\" field.",
|
||||
" flags when used with -g, translates all bits in this hexadecimal page",
|
||||
" structure flags value into its enumerator values.",
|
||||
" -P declares that the following address argument is a physical address.",
|
||||
" address when used without any flag, the address can be a kernel virtual,",
|
||||
" or physical address; a search is made through the symbol table,",
|
||||
@ -5587,6 +5603,9 @@ char *help_kmem[] = {
|
||||
" address when used with -p, the address can be either a page pointer, a",
|
||||
" physical address, or a kernel virtual address; its basic mem_map",
|
||||
" page information is displayed.",
|
||||
" address when used with -m, the address can be either a page pointer, a",
|
||||
" physical address, or a kernel virtual address; the specified",
|
||||
" members of the associated page struct are displayed.",
|
||||
" address when used with -c, the address must be a page pointer address;",
|
||||
" the page_hash_table entry containing the page is displayed.",
|
||||
" address when used with -l, the address must be a page pointer address;",
|
||||
@ -5720,6 +5739,64 @@ char *help_kmem[] = {
|
||||
" f5c51440 22000 0 0 1 80 slab",
|
||||
" ...",
|
||||
" ",
|
||||
" Display the \"page.lru\" list_head structure member in each page:\n",
|
||||
" %s> kmem -m lru",
|
||||
" PAGE lru ",
|
||||
" ffffea0000000000 0000000000000000,0000000000000000 ",
|
||||
" ffffea0000000040 ffffea0000000060,ffffea0000000060 ",
|
||||
" ffffea0000000080 ffffea00000000a0,ffffea00000000a0 ",
|
||||
" ffffea00000000c0 ffffea00000000e0,ffffea00000000e0 ",
|
||||
" ffffea0000000100 ffffea0000000120,ffffea0000000120 ",
|
||||
" ffffea0000000140 ffffea0000000160,ffffea0000000160 ",
|
||||
" ffffea0000000180 ffffea00000001a0,ffffea00000001a0 ",
|
||||
" ffffea00000001c0 ffffea00000001e0,ffffea00000001e0 ",
|
||||
" ffffea0000000200 ffffea0000000220,ffffea0000000220 ",
|
||||
" ffffea0000000240 ffffea0000000260,ffffea0000000260 ",
|
||||
" ffffea0000000280 ffffea00000002a0,ffffea00000002a0 ",
|
||||
" ffffea00000002c0 ffffea00000002e0,ffffea00000002e0 ",
|
||||
" ffffea0000000300 ffffea0000000320,ffffea0000000320 ",
|
||||
" ffffea0000000340 ffffea0000000360,ffffea0000000360 ",
|
||||
" ffffea0000000380 ffffea00000003a0,ffffea00000003a0 ",
|
||||
" ffffea00000003c0 ffffea00000003e0,ffffea00000003e0 ",
|
||||
" ffffea0000000400 ffff88021e5e41e8,ffffea0000002020 ",
|
||||
" ffffea0000000440 dead000000100100,dead000000200200 ",
|
||||
" ffffea0000000480 dead000000100100,dead000000200200 ",
|
||||
" ffffea00000004c0 dead000000100100,dead000000200200 ",
|
||||
" ...",
|
||||
" ",
|
||||
" Find the two pages that link to the page at ffffea0001dafb20 ",
|
||||
" via their page.lru list_head's next and prev pointers:\n",
|
||||
" %s> kmem -m lru | grep ffffea0001dafb20",
|
||||
" ffffea000006b500 ffffea0001dafb20,ffffea0001eb4520 ",
|
||||
" ffffea0000127d80 ffffea000152b620,ffffea0001dafb20 ",
|
||||
" ",
|
||||
" Find all of the combined slab/page structures that are used by",
|
||||
" the kmalloc-8192 slab cache:\n",
|
||||
" %s> kmem -s kmalloc-8192",
|
||||
" CACHE NAME OBJSIZE ALLOCATED TOTAL SLABS SSIZE",
|
||||
" ffff880215802e00 kmalloc-8192 8192 65 80 20 32k",
|
||||
" %s> kmem -m slab_cache | grep ffff880215802e00",
|
||||
" ffffea0004117800 ffff880215802e00 ",
|
||||
" ffffea00041ca600 ffff880215802e00 ",
|
||||
" ffffea00044ab200 ffff880215802e00 ",
|
||||
" ffffea0004524000 ffff880215802e00 ",
|
||||
" ffffea0004591600 ffff880215802e00 ",
|
||||
" ffffea00047eac00 ffff880215802e00 ",
|
||||
" ffffea0004875800 ffff880215802e00 ",
|
||||
" ffffea0008357a00 ffff880215802e00 ",
|
||||
" ffffea0008362a00 ffff880215802e00 ",
|
||||
" ffffea00083b9400 ffff880215802e00 ",
|
||||
" ffffea00083c1000 ffff880215802e00 ",
|
||||
" ffffea00083c1e00 ffff880215802e00 ",
|
||||
" ffffea00083c2000 ffff880215802e00 ",
|
||||
" ffffea00083c2a00 ffff880215802e00 ",
|
||||
" ffffea00083d2000 ffff880215802e00 ",
|
||||
" ffffea00083d3e00 ffff880215802e00 ",
|
||||
" ffffea0008407c00 ffff880215802e00 ",
|
||||
" ffffea000848ce00 ffff880215802e00 ",
|
||||
" ffffea0008491800 ffff880215802e00 ",
|
||||
" ffffea00084bf800 ffff880215802e00 ",
|
||||
" ",
|
||||
" Use the commands above with a page pointer or a physical address argument:\n",
|
||||
" %s> kmem -f c40425b0",
|
||||
" NODE ",
|
||||
|
311
memory.c
311
memory.c
@ -54,6 +54,8 @@ struct meminfo { /* general purpose memory information structure */
|
||||
int current_cache_index;
|
||||
ulong found;
|
||||
ulong retval;
|
||||
struct struct_member_data *page_member_cache;
|
||||
ulong nr_members;
|
||||
char *ignore;
|
||||
int errors;
|
||||
int calls;
|
||||
@ -134,6 +136,14 @@ struct searchinfo {
|
||||
|
||||
static char *memtype_string(int, int);
|
||||
static char *error_handle_string(ulong);
|
||||
static void collect_page_member_data(char *, struct meminfo *);
|
||||
struct integer_data {
|
||||
ulong value;
|
||||
ulong bitfield_value;
|
||||
struct struct_member_data *pmd;
|
||||
};
|
||||
static int get_bitfield_data(struct integer_data *);
|
||||
static int show_page_member_data(char *, ulong, struct meminfo *, char *);
|
||||
static void dump_mem_map(struct meminfo *);
|
||||
static void dump_mem_map_SPARSEMEM(struct meminfo *);
|
||||
static void fill_mem_map_cache(ulong, ulong, char *);
|
||||
@ -4214,6 +4224,268 @@ tgid_quick_search(ulong tgid)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
collect_page_member_data(char *optlist, struct meminfo *mi)
|
||||
{
|
||||
int i;
|
||||
int members;
|
||||
char buf[BUFSIZE];
|
||||
char *memberlist[MAXARGS];
|
||||
struct struct_member_data *page_member_cache, *pmd;
|
||||
|
||||
if ((count_chars(optlist, ',')+1) > MAXARGS)
|
||||
error(FATAL, "too many members in comma-separated list\n");
|
||||
|
||||
if ((LASTCHAR(optlist) == ',') || (LASTCHAR(optlist) == '.'))
|
||||
error(FATAL, "invalid format: %s\n", optlist);
|
||||
|
||||
strcpy(buf, optlist);
|
||||
replace_string(optlist, ",", ' ');
|
||||
|
||||
if (!(members = parse_line(optlist, memberlist)))
|
||||
error(FATAL, "invalid page struct member list format: %s\n", buf);
|
||||
|
||||
page_member_cache = (struct struct_member_data *)
|
||||
GETBUF(sizeof(struct struct_member_data) * members);
|
||||
|
||||
for (i = 0, pmd = page_member_cache; i < members; i++, pmd++) {
|
||||
pmd->structure = "page";
|
||||
pmd->member = memberlist[i];
|
||||
|
||||
if (!fill_struct_member_data(pmd))
|
||||
error(FATAL, "invalid %s struct member: %s\n",
|
||||
pmd->structure, pmd->member);
|
||||
|
||||
if (CRASHDEBUG(1)) {
|
||||
fprintf(fp, " structure: %s\n", pmd->structure);
|
||||
fprintf(fp, " member: %s\n", pmd->member);
|
||||
fprintf(fp, " type: %ld\n", pmd->type);
|
||||
fprintf(fp, " unsigned_type: %ld\n", pmd->unsigned_type);
|
||||
fprintf(fp, " length: %ld\n", pmd->length);
|
||||
fprintf(fp, " offset: %ld\n", pmd->offset);
|
||||
fprintf(fp, " bitpos: %ld\n", pmd->bitpos);
|
||||
fprintf(fp, " bitsize: %ld%s", pmd->bitsize,
|
||||
members > 1 ? "\n\n" : "\n");
|
||||
}
|
||||
}
|
||||
|
||||
mi->nr_members = members;
|
||||
mi->page_member_cache = page_member_cache;
|
||||
}
|
||||
|
||||
static int
|
||||
get_bitfield_data(struct integer_data *bd)
|
||||
{
|
||||
int pos, size;
|
||||
uint32_t tmpvalue32;
|
||||
uint64_t tmpvalue64;
|
||||
uint32_t mask32;
|
||||
uint64_t mask64;
|
||||
struct struct_member_data *pmd;
|
||||
|
||||
pmd = bd->pmd;
|
||||
pos = bd->pmd->bitpos;
|
||||
size = bd->pmd->bitsize;
|
||||
|
||||
if (pos == 0 && size == 0) {
|
||||
bd->bitfield_value = bd->value;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
switch (__BYTE_ORDER)
|
||||
{
|
||||
case __LITTLE_ENDIAN:
|
||||
switch (pmd->length)
|
||||
{
|
||||
case 4:
|
||||
tmpvalue32 = (uint32_t)bd->value;
|
||||
tmpvalue32 >>= pos;
|
||||
mask32 = (1 << size) - 1;
|
||||
tmpvalue32 &= mask32;
|
||||
bd->bitfield_value = (ulong)tmpvalue32;
|
||||
break;
|
||||
case 8:
|
||||
tmpvalue64 = (uint64_t)bd->value;
|
||||
tmpvalue64 >>= pos;
|
||||
mask64 = (1UL << size) - 1;
|
||||
tmpvalue64 &= mask64;
|
||||
bd->bitfield_value = tmpvalue64;
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
|
||||
case __BIG_ENDIAN:
|
||||
switch (pmd->length)
|
||||
{
|
||||
case 4:
|
||||
tmpvalue32 = (uint32_t)bd->value;
|
||||
tmpvalue32 <<= pos;
|
||||
tmpvalue32 >>= (32-size);
|
||||
mask32 = (1 << size) - 1;
|
||||
tmpvalue32 &= mask32;
|
||||
bd->bitfield_value = (ulong)tmpvalue32;
|
||||
break;
|
||||
case 8:
|
||||
tmpvalue64 = (uint64_t)bd->value;
|
||||
tmpvalue64 <<= pos;
|
||||
tmpvalue64 >>= (64-size);
|
||||
mask64 = (1UL << size) - 1;
|
||||
tmpvalue64 &= mask64;
|
||||
bd->bitfield_value = tmpvalue64;
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
show_page_member_data(char *pcache, ulong pp, struct meminfo *mi, char *outputbuffer)
|
||||
{
|
||||
int bufferindex, i, c, cnt, radix, struct_intbuf[10];
|
||||
ulong longbuf, struct_longbuf[10];
|
||||
unsigned char boolbuf;
|
||||
void *voidptr;
|
||||
ushort shortbuf;
|
||||
struct struct_member_data *pmd;
|
||||
struct integer_data integer_data;
|
||||
|
||||
bufferindex = 0;
|
||||
pmd = mi->page_member_cache;
|
||||
|
||||
bufferindex += sprintf(outputbuffer + bufferindex, "%lx ", pp);
|
||||
|
||||
for (i = 0; i < mi->nr_members; pmd++, i++) {
|
||||
|
||||
switch (pmd->type)
|
||||
{
|
||||
case TYPE_CODE_PTR:
|
||||
voidptr = VOID_PTR(pcache + pmd->offset);
|
||||
bufferindex += sprintf(outputbuffer + bufferindex,
|
||||
VADDR_PRLEN == 8 ? "%08lx " : "%016lx ", (ulong)voidptr);
|
||||
break;
|
||||
|
||||
case TYPE_CODE_INT:
|
||||
switch (pmd->length)
|
||||
{
|
||||
case 1:
|
||||
integer_data.value = UCHAR(pcache + pmd->offset);
|
||||
break;
|
||||
case 2:
|
||||
integer_data.value = USHORT(pcache + pmd->offset);
|
||||
break;
|
||||
case 4:
|
||||
integer_data.value = UINT(pcache + pmd->offset);
|
||||
break;
|
||||
case 8:
|
||||
if (BITS32())
|
||||
goto unsupported;
|
||||
integer_data.value = ULONG(pcache + pmd->offset);
|
||||
break;
|
||||
default:
|
||||
goto unsupported;
|
||||
}
|
||||
|
||||
integer_data.pmd = pmd;
|
||||
if (get_bitfield_data(&integer_data))
|
||||
longbuf = integer_data.bitfield_value;
|
||||
else
|
||||
goto unsupported;
|
||||
|
||||
if (STREQ(pmd->member, "flags"))
|
||||
radix = 16;
|
||||
else if (STRNEQ(pmd->member, "_count") || STRNEQ(pmd->member, "_mapcount"))
|
||||
radix = 10;
|
||||
else
|
||||
radix = *gdb_output_radix;
|
||||
|
||||
if (pmd->unsigned_type) {
|
||||
if (pmd->length == sizeof(ulonglong))
|
||||
bufferindex += sprintf(outputbuffer + bufferindex,
|
||||
radix == 10 ? "%lu " : "%016lx ", longbuf);
|
||||
else if (pmd->length == sizeof(int))
|
||||
bufferindex += sprintf(outputbuffer + bufferindex,
|
||||
radix == 10 ? "%u " : "%08x ", (uint)longbuf);
|
||||
else if (pmd->length == sizeof(short)) {
|
||||
bufferindex += sprintf(outputbuffer + bufferindex,
|
||||
radix == 10 ? "%u " : "%04x ", (ushort)longbuf);
|
||||
}
|
||||
else if (pmd->length == sizeof(char))
|
||||
bufferindex += sprintf(outputbuffer + bufferindex,
|
||||
radix == 10 ? "%u " : "%02x ", (unsigned char)longbuf);
|
||||
} else {
|
||||
if (pmd->length == sizeof(ulonglong))
|
||||
bufferindex += sprintf(outputbuffer + bufferindex,
|
||||
radix == 10 ? "%ld " : "%016lx", longbuf);
|
||||
else if (pmd->length == sizeof(int))
|
||||
bufferindex += sprintf(outputbuffer + bufferindex,
|
||||
radix == 10 ? "%d " : "%08x ", (int)longbuf);
|
||||
else if (pmd->length == sizeof(short))
|
||||
bufferindex += sprintf(outputbuffer + bufferindex,
|
||||
radix == 10 ? "%d " : "%04x ", (short)longbuf);
|
||||
else if (pmd->length == sizeof(char))
|
||||
bufferindex += sprintf(outputbuffer + bufferindex,
|
||||
radix == 10 ? "%d " : "%02x ", (char)longbuf);
|
||||
}
|
||||
break;
|
||||
|
||||
case TYPE_CODE_STRUCT:
|
||||
if (STRNEQ(pmd->member, "_count") || STRNEQ(pmd->member, "_mapcount")) {
|
||||
BCOPY(pcache+pmd->offset, (char *)&struct_intbuf[0], pmd->length);
|
||||
bufferindex += sprintf(outputbuffer + bufferindex,
|
||||
"%d ", struct_intbuf[0]);
|
||||
} else if ((pmd->length % sizeof(long)) == 0) {
|
||||
BCOPY(pcache+pmd->offset, (char *)&struct_longbuf[0], pmd->length);
|
||||
cnt = pmd->length / sizeof(long);
|
||||
for (c = 0; c < cnt; c++) {
|
||||
bufferindex += sprintf(outputbuffer + bufferindex,
|
||||
BITS32() ? "%08lx%s" : "%016lx%s",
|
||||
struct_longbuf[c], (c+1) < cnt ? "," : "");
|
||||
}
|
||||
bufferindex += sprintf(outputbuffer + bufferindex, " ");
|
||||
} else if ((pmd->length % sizeof(int)) == 0) {
|
||||
BCOPY(pcache+pmd->offset, (char *)&struct_intbuf[0], pmd->length);
|
||||
cnt = pmd->length / sizeof(int);
|
||||
for (c = 0; c < cnt; c++) {
|
||||
bufferindex += sprintf(outputbuffer + bufferindex,
|
||||
"%08x%s", struct_intbuf[c],
|
||||
(c+1) < cnt ? "," : "");
|
||||
}
|
||||
} else if (pmd->length == sizeof(short)) {
|
||||
BCOPY(pcache+pmd->offset, (char *)&shortbuf, pmd->length);
|
||||
bufferindex += sprintf(outputbuffer + bufferindex,
|
||||
"%04x ", shortbuf);
|
||||
} else
|
||||
goto unsupported;
|
||||
break;
|
||||
|
||||
case TYPE_CODE_BOOL:
|
||||
radix = *gdb_output_radix;
|
||||
boolbuf = UCHAR(pcache + pmd->offset);
|
||||
if (boolbuf <= 1)
|
||||
bufferindex += sprintf(outputbuffer + bufferindex, "%s ",
|
||||
boolbuf ? "true" : "false");
|
||||
else
|
||||
bufferindex += sprintf(outputbuffer + bufferindex,
|
||||
radix == 10 ? "%d" : "%x ", boolbuf);
|
||||
break;
|
||||
|
||||
default:
|
||||
unsupported:
|
||||
error(FATAL, "unsupported page member reference: %s.%s\n",
|
||||
pmd->structure, pmd->member);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return bufferindex += sprintf(outputbuffer+bufferindex, "\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill in the task_mem_usage structure with the RSS, virtual memory size,
|
||||
* percent of physical memory being used, and the mm_struct address.
|
||||
@ -4426,7 +4698,7 @@ cmd_kmem(void)
|
||||
BZERO(&value[0], sizeof(ulonglong)*MAXARGS);
|
||||
pc->curcmd_flags &= ~HEADER_PRINTED;
|
||||
|
||||
while ((c = getopt(argcnt, args, "gI:sSFfpvczCinl:L:PVoh")) != EOF) {
|
||||
while ((c = getopt(argcnt, args, "gI:sSFfm:pvczCinl:L:PVoh")) != EOF) {
|
||||
switch(c)
|
||||
{
|
||||
case 'V':
|
||||
@ -4481,6 +4753,11 @@ cmd_kmem(void)
|
||||
pflag = 1;
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
pflag = 1;
|
||||
collect_page_member_data(optarg, &meminfo);
|
||||
break;
|
||||
|
||||
case 'I':
|
||||
meminfo.ignore = optarg;
|
||||
break;
|
||||
@ -5026,7 +5303,13 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi)
|
||||
space(MINSPACE),
|
||||
mkstring(buf4, 8, CENTER|LJUST, "OFFSET"),
|
||||
space(MINSPACE-1));
|
||||
} else {
|
||||
} else if (mi->nr_members) {
|
||||
sprintf(hdr, "%s", mkstring(buf1, VADDR_PRLEN, CENTER, "PAGE"));
|
||||
for (i = 0; i < mi->nr_members; i++)
|
||||
sprintf(&hdr[strlen(hdr)], " %s",
|
||||
mi->page_member_cache[i].member);
|
||||
strcat(hdr, "\n");
|
||||
} else {
|
||||
sprintf(hdr, "%s%s%s%s%s%s%sCNT FLAGS\n",
|
||||
mkstring(buf1, VADDR_PRLEN, CENTER, "PAGE"),
|
||||
space(MINSPACE),
|
||||
@ -5189,6 +5472,11 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi)
|
||||
|
||||
if (!done && (pg_spec || phys_spec))
|
||||
continue;
|
||||
|
||||
if (mi->nr_members) {
|
||||
bufferindex += show_page_member_data(pcache, pp, mi, outputbuffer+bufferindex);
|
||||
goto display_members;
|
||||
}
|
||||
|
||||
flags = ULONG(pcache + OFFSET(page_flags));
|
||||
if (SIZE(page_flags) == 4)
|
||||
@ -5365,6 +5653,7 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi)
|
||||
bufferindex += sprintf(outputbuffer+bufferindex, "\n");
|
||||
}
|
||||
|
||||
display_members:
|
||||
if (bufferindex > buffersize) {
|
||||
fprintf(fp, "%s", outputbuffer);
|
||||
bufferindex = 0;
|
||||
@ -5412,6 +5701,8 @@ dump_mem_map_SPARSEMEM(struct meminfo *mi)
|
||||
break;
|
||||
}
|
||||
|
||||
if (mi->nr_members)
|
||||
FREEBUF(mi->page_member_cache);
|
||||
FREEBUF(outputbuffer);
|
||||
FREEBUF(page_cache);
|
||||
}
|
||||
@ -5502,7 +5793,13 @@ dump_mem_map(struct meminfo *mi)
|
||||
space(MINSPACE),
|
||||
mkstring(buf4, 8, CENTER|LJUST, "OFFSET"),
|
||||
space(MINSPACE-1));
|
||||
} else {
|
||||
} else if (mi->nr_members) {
|
||||
sprintf(hdr, "%s", mkstring(buf1, VADDR_PRLEN, CENTER, "PAGE"));
|
||||
for (i = 0; i < mi->nr_members; i++)
|
||||
sprintf(&hdr[strlen(hdr)], " %s",
|
||||
mi->page_member_cache[i].member);
|
||||
strcat(hdr, "\n");
|
||||
} else {
|
||||
sprintf(hdr, "%s%s%s%s%s%s%sCNT FLAGS\n",
|
||||
mkstring(buf1, VADDR_PRLEN, CENTER, "PAGE"),
|
||||
space(MINSPACE),
|
||||
@ -5627,6 +5924,11 @@ dump_mem_map(struct meminfo *mi)
|
||||
if (!done && (pg_spec || phys_spec))
|
||||
continue;
|
||||
|
||||
if (mi->nr_members) {
|
||||
bufferindex += show_page_member_data(pcache, pp, mi, outputbuffer+bufferindex);
|
||||
goto display_members;
|
||||
}
|
||||
|
||||
flags = ULONG(pcache + OFFSET(page_flags));
|
||||
if (SIZE(page_flags) == 4)
|
||||
flags &= 0xffffffff;
|
||||
@ -5803,6 +6105,7 @@ dump_mem_map(struct meminfo *mi)
|
||||
bufferindex += sprintf(outputbuffer+bufferindex, "\n");
|
||||
}
|
||||
|
||||
display_members:
|
||||
if (bufferindex > buffersize) {
|
||||
fprintf(fp, "%s", outputbuffer);
|
||||
bufferindex = 0;
|
||||
@ -5850,6 +6153,8 @@ dump_mem_map(struct meminfo *mi)
|
||||
break;
|
||||
}
|
||||
|
||||
if (mi->nr_members)
|
||||
FREEBUF(mi->page_member_cache);
|
||||
FREEBUF(outputbuffer);
|
||||
FREEBUF(page_cache);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user