----- Original Message -----
> >
> > So in the interest of expediency, what I will do is this:
> >
> > (1) change "files -m" to "files -c"
> > (2) drop the MAPPING column from "files -p"
> > (3) reword the description of the two options in the help page to emphasize
> > that the NRPAGES count and page dumps are page cache counts/page-dumps
> > (4) either figure out a way to compress the help page example outputs into
> > 80 columns, or drop the files -p example completely
> >
> > I'll post the patch this afternoon and you can verify it tonight.
>
> Sure, I will. Thanks for your helps and comments.
> I hope I can do better for my next patch. :-)
>
>
Hi Oliver,
I've attached the patch for your review. In addition to the items listed
above, I also made a few other minor changes to better handle some error
conditions I ran into while testing the patch, I renamed a few functions and
macros to be more related to their actual purpose, globally exposed just the
single-page dump callback function, and made it return a legitimate return
value.
(And there may be other minor changes that I can't remember.)
Let me know what you think about the changes, and if we're in agreement,
I'll check it in tomorrow.
Thanks,
Dave
--- crash-7.1.1/help.c.orig
+++ crash-7.1.1/help.c
@@ -6488,7 +6488,7 @@ NULL
char *help_files[] = {
"files",
"open files",
-"[-d dentry] | [-R reference] [pid | taskp] ... ",
+"[-d dentry] | [-p inode] | [-c] [-R reference] [pid | taskp] ... ",
" This command displays information about open files of a context.",
" It prints the context's current root directory and current working",
" directory, and then for each open file descriptor it prints a pointer",
@@ -6501,8 +6501,15 @@ char *help_files[] = {
" specific, and only shows the data requested.\n",
" -d dentry given a hexadecimal dentry address, display its inode,",
" super block, file type, and full pathname.",
+" -p inode given a hexadecimal inode address, dump all of its pages",
+" that are in the page cache.",
+" -c for each open file descriptor, prints a pointer to its",
+" inode, a pointer to the inode's i_mapping address_space",
+" structure, the number of pages of the inode that are in",
+" the page cache, the file type, and the pathname.",
" -R reference search for references to this file descriptor number,",
-" filename, or dentry, inode, or file structure address.",
+" filename, dentry, inode, address_space, or file structure",
+" address.",
" pid a process PID.",
" taskp a hexadecimal task_struct pointer.",
"\nEXAMPLES",
@@ -6578,6 +6585,34 @@ char *help_files[] = {
" %s> files -d f745fd60",
" DENTRY INODE SUPERBLK TYPE PATH",
" f745fd60 f7284640 f73a3e00 REG /var/spool/lpd/lpd.lock",
+" ",
+" For each open file, display the number of pages that are in the page cache:\n",
+" %s> files -c 1954",
+" PID: 1954 TASK: f7a28000 CPU: 1 COMMAND: \"syslogd\"",
+" ROOT: / CWD: /",
+" FD INODE I_MAPPING NRPAGES TYPE PATH",
+" 0 cb3ae868 cb3ae910 0 SOCK socket:/[4690]",
+" 2 f2721c5c f2721d04 461 REG /var/log/messages",
+" 3 cbda4884 cbda492c 47 REG /var/log/secure",
+" 4 e48092c0 e4809368 58 REG /var/log/maillog",
+" 5 f65192c0 f6519368 48 REG /var/log/cron",
+" 6 e4809e48 e4809ef0 0 REG /var/log/spooler",
+" 7 d9c43884 d9c4392c 0 REG /var/log/boot.log",
+" ",
+" For the inode at address f59b90fc, display all of its pages that are in",
+" the page cache:\n",
+" %s> files -p f59b90fc",
+" INODE NRPAGES",
+" f59b90fc 6",
+" ",
+" PAGE PHYSICAL MAPPING INDEX CNT FLAGS",
+" ca3353e0 39a9f000 f59b91ac 0 2 82c referenced,uptodate,lru,private",
+" ca22cb20 31659000 f59b91ac 1 2 82c referenced,uptodate,lru,private",
+" ca220160 3100b000 f59b91ac 2 2 82c referenced,uptodate,lru,private",
+" ca1ddde0 2eeef000 f59b91ac 3 2 82c referenced,uptodate,lru,private",
+" ca36b300 3b598000 f59b91ac 4 2 82c referenced,uptodate,lru,private",
+" ca202680 30134000 f59b91ac 5 2 82c referenced,uptodate,lru,private",
+" ",
NULL
};
--- crash-7.1.1/defs.h.orig
+++ crash-7.1.1/defs.h
@@ -1940,6 +1940,7 @@ struct offset_table {
long task_struct_thread_reg31;
long pt_regs_regs;
long pt_regs_cp0_badvaddr;
+ long address_space_page_tree;
};
struct size_table { /* stash of commonly-used sizes */
@@ -2598,6 +2599,7 @@ struct load_module {
#define PRINT_SINGLE_VMA (0x80)
#define PRINT_RADIX_10 (0x100)
#define PRINT_RADIX_16 (0x200)
+#define PRINT_NRPAGES (0x400)
#define MIN_PAGE_SIZE (4096)
@@ -4707,6 +4709,8 @@ void alter_stackbuf(struct bt_info *);
int vaddr_type(ulong, struct task_context *);
char *format_stack_entry(struct bt_info *bt, char *, ulong, ulong);
int in_user_stack(ulong, ulong);
+int dump_inode_page(ulong);
+
/*
* filesys.c
@@ -4743,6 +4747,7 @@ int is_readable(char *);
#define RADIX_TREE_SEARCH (2)
#define RADIX_TREE_DUMP (3)
#define RADIX_TREE_GATHER (4)
+#define RADIX_TREE_DUMP_CB (5)
struct radix_tree_pair {
ulong index;
void *value;
@@ -4753,6 +4758,7 @@ int file_dump(ulong, ulong, ulong, int,
#define DUMP_INODE_ONLY 2
#define DUMP_DENTRY_ONLY 4
#define DUMP_EMPTY_FILE 8
+#define DUMP_FILE_NRPAGES 16
#endif /* !GDB_COMMON */
int same_file(char *, char *);
#ifndef GDB_COMMON
--- crash-7.1.1/symbols.c.orig
+++ crash-7.1.1/symbols.c
@@ -8634,6 +8634,8 @@ dump_offset_table(char *spec, ulong make
OFFSET(block_device_bd_disk));
fprintf(fp, " address_space_nrpages: %ld\n",
OFFSET(address_space_nrpages));
+ fprintf(fp, " address_space_page_tree: %ld\n",
+ OFFSET(address_space_page_tree));
fprintf(fp, " gendisk_major: %ld\n",
OFFSET(gendisk_major));
fprintf(fp, " gendisk_fops: %ld\n",
--- crash-7.1.1/memory.c.orig
+++ crash-7.1.1/memory.c
@@ -476,6 +476,7 @@ vm_init(void)
MEMBER_OFFSET_INIT(block_device_bd_list, "block_device", "bd_list");
MEMBER_OFFSET_INIT(block_device_bd_disk, "block_device", "bd_disk");
MEMBER_OFFSET_INIT(inode_i_mapping, "inode", "i_mapping");
+ MEMBER_OFFSET_INIT(address_space_page_tree, "address_space", "page_tree");
MEMBER_OFFSET_INIT(address_space_nrpages, "address_space", "nrpages");
if (INVALID_MEMBER(address_space_nrpages))
MEMBER_OFFSET_INIT(address_space_nrpages, "address_space", "__nrpages");
@@ -6465,6 +6466,23 @@ translate_page_flags(char *buffer, ulong
}
/*
+ * Display the mem_map data for a single page.
+ */
+int
+dump_inode_page(ulong page)
+{
+ struct meminfo meminfo;
+
+ BZERO(&meminfo, sizeof(struct meminfo));
+ meminfo.spec_addr = page;
+ meminfo.memtype = KVADDR;
+ meminfo.flags = ADDRESS_SPECIFIED;
+ dump_mem_map(&meminfo);
+
+ return meminfo.retval;
+}
+
+/*
* dump_page_hash_table() displays the entries in each page_hash_table.
*/
--- crash-7.1.1/task.c.orig
+++ crash-7.1.1/task.c
@@ -6234,6 +6234,12 @@ foreach(struct foreach_data *fd)
print_header = FALSE;
break;
+ case FOREACH_FILES:
+ if (fd->flags & FOREACH_p_FLAG)
+ error(FATAL,
+ "files command does not support -p option\n");
+ break;
+
case FOREACH_TEST:
break;
}
@@ -6460,9 +6466,15 @@ foreach(struct foreach_data *fd)
case FOREACH_FILES:
pc->curcmd = "files";
- open_files_dump(tc->task,
- fd->flags & FOREACH_i_FLAG ?
- PRINT_INODES : 0,
+ cmdflags = 0;
+
+ if (fd->flags & FOREACH_i_FLAG)
+ cmdflags |= PRINT_INODES;
+ if (fd->flags & FOREACH_c_FLAG)
+ cmdflags |= PRINT_NRPAGES;
+
+ open_files_dump(tc->task,
+ cmdflags,
fd->reference ? ref : NULL);
break;
--- crash-7.1.1/filesys.c.orig
+++ crash-7.1.1/filesys.c
@@ -49,7 +49,8 @@ static void *radix_tree_lookup(ulong, ul
static int match_file_string(char *, char *, char *);
static ulong get_root_vfsmount(char *);
static void check_live_arch_mismatch(void);
-
+static long get_inode_nrpages(ulong);
+static void dump_inode_page_cache_info(ulong);
#define DENTRY_CACHE (20)
#define INODE_CACHE (20)
@@ -2168,6 +2169,70 @@ show_hit_rates:
}
/*
+ * Get the page count for the specific mapping
+ */
+static long
+get_inode_nrpages(ulong i_mapping)
+{
+ char *address_space_buf;
+ ulong nrpages;
+
+ address_space_buf = GETBUF(SIZE(address_space));
+
+ readmem(i_mapping, KVADDR, address_space_buf,
+ SIZE(address_space), "address_space buffer",
+ FAULT_ON_ERROR);
+ nrpages = ULONG(address_space_buf + OFFSET(address_space_nrpages));
+
+ FREEBUF(address_space_buf);
+
+ return nrpages;
+}
+
+static void
+dump_inode_page_cache_info(ulong inode)
+{
+ char *inode_buf;
+ ulong i_mapping, nrpages, root_rnode, count;
+ struct radix_tree_pair rtp;
+ char header[BUFSIZE];
+ char buf1[BUFSIZE];
+ char buf2[BUFSIZE];
+
+ inode_buf = GETBUF(SIZE(inode));
+ readmem(inode, KVADDR, inode_buf, SIZE(inode), "inode buffer",
+ FAULT_ON_ERROR);
+
+ i_mapping = ULONG(inode_buf + OFFSET(inode_i_mapping));
+ nrpages = get_inode_nrpages(i_mapping);
+
+ sprintf(header, "%s NRPAGES\n",
+ mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "INODE"));
+ fprintf(fp, "%s", header);
+
+ fprintf(fp, "%s %s\n\n",
+ mkstring(buf1, VADDR_PRLEN,
+ CENTER|RJUST|LONG_HEX,
+ MKSTR(inode)),
+ mkstring(buf2, strlen("NRPAGES"),
+ RJUST|LONG_DEC,
+ MKSTR(nrpages)));
+
+ root_rnode = i_mapping + OFFSET(address_space_page_tree);
+ rtp.index = 0;
+ rtp.value = (void *)&dump_inode_page;
+
+ count = do_radix_tree(root_rnode, RADIX_TREE_DUMP_CB, &rtp);
+
+ if (count != nrpages)
+ error(INFO, "page_tree count: %ld nrpages: %ld\n",
+ count, nrpages);
+
+ FREEBUF(inode_buf);
+ return;
+}
+
+/*
* This command displays information about the open files of a context.
* For each open file descriptor the file descriptor number, a pointer
* to the file struct, pointer to the dentry struct, pointer to the inode
@@ -2187,11 +2252,12 @@ cmd_files(void)
int subsequent;
struct reference reference, *ref;
char *refarg;
+ int open_flags = 0;
ref = NULL;
refarg = NULL;
- while ((c = getopt(argcnt, args, "d:R:")) != EOF) {
+ while ((c = getopt(argcnt, args, "d:R:p:c")) != EOF) {
switch(c)
{
case 'R':
@@ -2210,6 +2276,23 @@ cmd_files(void)
display_dentry_info(value);
return;
+ case 'p':
+ if (VALID_MEMBER(address_space_page_tree) &&
+ VALID_MEMBER(inode_i_mapping)) {
+ value = htol(optarg, FAULT_ON_ERROR, NULL);
+ dump_inode_page_cache_info(value);
+ } else
+ option_not_supported('p');
+ return;
+
+ case 'c':
+ if (VALID_MEMBER(address_space_page_tree) &&
+ VALID_MEMBER(inode_i_mapping))
+ open_flags |= PRINT_NRPAGES;
+ else
+ option_not_supported('c');
+ break;
+
default:
argerrs++;
break;
@@ -2222,7 +2305,9 @@ cmd_files(void)
if (!args[optind]) {
if (!ref)
print_task_header(fp, CURRENT_CONTEXT(), 0);
- open_files_dump(CURRENT_TASK(), 0, ref);
+
+ open_files_dump(CURRENT_TASK(), open_flags, ref);
+
return;
}
@@ -2241,7 +2326,7 @@ cmd_files(void)
for (tc = pid_to_context(value); tc; tc = tc->tc_next) {
if (!ref)
print_task_header(fp, tc, subsequent);
- open_files_dump(tc->task, 0, ref);
+ open_files_dump(tc->task, open_flags, ref);
fprintf(fp, "\n");
}
break;
@@ -2249,7 +2334,7 @@ cmd_files(void)
case STR_TASK:
if (!ref)
print_task_header(fp, tc, subsequent);
- open_files_dump(tc->task, 0, ref);
+ open_files_dump(tc->task, open_flags, ref);
break;
case STR_INVALID:
@@ -2321,6 +2406,7 @@ open_files_dump(ulong task, int flags, s
char buf4[BUFSIZE];
char root_pwd[BUFSIZE];
int root_pwd_printed = 0;
+ int file_dump_flags = 0;
BZERO(root_pathname, BUFSIZE);
BZERO(pwd_pathname, BUFSIZE);
@@ -2329,15 +2415,27 @@ open_files_dump(ulong task, int flags, s
fdtable_buf = GETBUF(SIZE(fdtable));
fill_task_struct(task);
- sprintf(files_header, " FD%s%s%s%s%s%s%sTYPE%sPATH\n",
- space(MINSPACE),
- mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "FILE"),
- space(MINSPACE),
- mkstring(buf2, VADDR_PRLEN, CENTER|LJUST, "DENTRY"),
- space(MINSPACE),
- mkstring(buf3, VADDR_PRLEN, CENTER|LJUST, "INODE"),
- space(MINSPACE),
- space(MINSPACE));
+ if (flags & PRINT_NRPAGES) {
+ sprintf(files_header, " FD%s%s%s%s%sNRPAGES%sTYPE%sPATH\n",
+ space(MINSPACE),
+ mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "INODE"),
+ space(MINSPACE),
+ mkstring(buf2, MAX(VADDR_PRLEN, strlen("I_MAPPING")),
+ BITS32() ? (CENTER|RJUST) : (CENTER|LJUST), "I_MAPPING"),
+ space(MINSPACE),
+ space(MINSPACE),
+ space(MINSPACE));
+ } else {
+ sprintf(files_header, " FD%s%s%s%s%s%s%sTYPE%sPATH\n",
+ space(MINSPACE),
+ mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "FILE"),
+ space(MINSPACE),
+ mkstring(buf2, VADDR_PRLEN, CENTER|LJUST, "DENTRY"),
+ space(MINSPACE),
+ mkstring(buf3, VADDR_PRLEN, CENTER|LJUST, "INODE"),
+ space(MINSPACE),
+ space(MINSPACE));
+ }
tc = task_to_context(task);
@@ -2523,6 +2621,10 @@ open_files_dump(ulong task, int flags, s
return;
}
+ file_dump_flags = DUMP_FULL_NAME | DUMP_EMPTY_FILE;
+ if (flags & PRINT_NRPAGES)
+ file_dump_flags |= DUMP_FILE_NRPAGES;
+
j = 0;
for (;;) {
unsigned long set;
@@ -2539,8 +2641,7 @@ open_files_dump(ulong task, int flags, s
if (ref && file) {
open_tmpfile();
- if (file_dump(file, 0, 0, i,
- DUMP_FULL_NAME|DUMP_EMPTY_FILE)) {
+ if (file_dump(file, 0, 0, i, file_dump_flags)) {
BZERO(buf4, BUFSIZE);
rewind(pc->tmpfile);
ret = fgets(buf4, BUFSIZE,
@@ -2558,8 +2659,7 @@ open_files_dump(ulong task, int flags, s
fprintf(fp, "%s", files_header);
header_printed = 1;
}
- file_dump(file, 0, 0, i,
- DUMP_FULL_NAME|DUMP_EMPTY_FILE);
+ file_dump(file, 0, 0, i, file_dump_flags);
}
}
i++;
@@ -2754,6 +2854,8 @@ file_dump(ulong file, ulong dentry, ulon
char buf1[BUFSIZE];
char buf2[BUFSIZE];
char buf3[BUFSIZE];
+ ulong i_mapping = 0;
+ ulong nrpages = 0;
file_buf = NULL;
@@ -2863,6 +2965,28 @@ file_dump(ulong file, ulong dentry, ulon
type,
space(MINSPACE),
pathname+1);
+ } else if (flags & DUMP_FILE_NRPAGES) {
+ i_mapping = ULONG(inode_buf + OFFSET(inode_i_mapping));
+ nrpages = get_inode_nrpages(i_mapping);
+
+ fprintf(fp, "%3d%s%s%s%s%s%s%s%s%s%s\n",
+ fd,
+ space(MINSPACE),
+ mkstring(buf1, VADDR_PRLEN,
+ CENTER|RJUST|LONG_HEX,
+ MKSTR(inode)),
+ space(MINSPACE),
+ mkstring(buf2, MAX(VADDR_PRLEN, strlen("I_MAPPING")),
+ CENTER|RJUST|LONG_HEX,
+ MKSTR(i_mapping)),
+ space(MINSPACE),
+ mkstring(buf3, strlen("NRPAGES"),
+ RJUST|LONG_DEC,
+ MKSTR(nrpages)),
+ space(MINSPACE),
+ type,
+ space(MINSPACE),
+ pathname);
} else {
fprintf(fp, "%3d%s%s%s%s%s%s%s%s%s%s\n",
fd,
@@ -3870,6 +3994,9 @@ ulong RADIX_TREE_MAP_MASK = UNINITIALIZE
* limit the number of returned entries by putting the array size
* (max count) in the rtp->index field of the first structure
* in the passed-in array.
+ * RADIX_TREE_DUMP_CB - Similar with RADIX_TREE_DUMP, but for each
+ * radix tree entry, a user defined callback at rtp->value will
+ * be invoked.
*
* rtp: Unused by RADIX_TREE_COUNT and RADIX_TREE_DUMP.
* A pointer to a radix_tree_pair structure for RADIX_TREE_SEARCH.
@@ -3877,6 +4004,8 @@ ulong RADIX_TREE_MAP_MASK = UNINITIALIZE
* RADIX_TREE_GATHER; the dimension (max count) of the array may
* be stored in the index field of the first structure to avoid
* any chance of an overrun.
+ * For RADIX_TREE_DUMP_CB, the rtp->value need to be initialized as
+ * callback function. The callback prototype must be int (*)(ulong);
*/
ulong
do_radix_tree(ulong root, int flag, struct radix_tree_pair *rtp)
@@ -3889,6 +4018,7 @@ do_radix_tree(ulong root, int flag, stru
struct radix_tree_pair *r;
ulong root_rnode;
void *ret;
+ int (*cb)(ulong) = NULL;
count = 0;
@@ -3932,14 +4062,13 @@ do_radix_tree(ulong root, int flag, stru
"radix_tree_root", FAULT_ON_ERROR);
height = UINT(radix_tree_root_buf + OFFSET(radix_tree_root_height));
- if (height > ilen) {
- fprintf(fp, "radix_tree_root at %lx:\n", root);
+ if ((height < 0) || (height > ilen)) {
+ error(INFO, "height_to_maxindex[] index: %ld\n", ilen);
+ fprintf(fp, "invalid height in radix_tree_root at %lx:\n", root);
dump_struct("radix_tree_root", (ulong)root, RADIX(16));
- error(FATAL,
- "height %d is greater than height_to_maxindex[] index %ld\n",
- height, ilen);
+ return 0;
}
-
+
maxindex = height_to_maxindex[height];
FREEBUF(height_to_maxindex);
FREEBUF(radix_tree_root_buf);
@@ -3993,6 +4122,27 @@ do_radix_tree(ulong root, int flag, stru
}
break;
+ case RADIX_TREE_DUMP_CB:
+ if (rtp->value == NULL) {
+ error(FATAL, "do_radix_tree: need set callback function");
+ return -EINVAL;
+ }
+ cb = (int (*)(ulong))rtp->value;
+ for (index = count = 0; index <= maxindex; index++) {
+ if ((ret =
+ radix_tree_lookup(root_rnode, index, height))) {
+ /* Caller defined operation */
+ if (!cb((ulong)ret)) {
+ error(FATAL, "do_radix_tree: callback "
+ "operation failed at entry: %ld\n",
+ count);
+ return -EIO;
+ }
+ count++;
+ }
+ }
+ break;
+
default:
error(FATAL, "do_radix_tree: invalid flag: %lx\n", flag);
}
--
Crash-utility mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/crash-utility