--- 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);
 	}
