----- 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 Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility