[Crash-utility] [PATCH] files: support dump file page cache

oliver yang yangoliver at gmail.com
Sat Jun 13 08:39:40 UTC 2015


Sorry,Ijust realized that my email setting is not correct.

Resend patch file here.

> Dave,
>
> This patch add -M and -m option for file commands, which allow to dump
> page cache for a file.
>
> Please review and let me know your comments. Thanks!
>
> Here is the usage,
>
> 1. Dump a process page cache number, default is crash, also work with given pid,
>
> crash> files -M
>
> PID: 22710  TASK: ffff8801077153e0  CPU: 1   COMMAND: "crash"
>
> ROOT: /    CWD: /auto/home2/yango/workspace/crash
>
> FD    ADDR-SPACE      PGCACHE-PGS         INODE       TYPE PATH
>
>    0 ffff8801031edbe8         0        ffff8801031edaa0 CHR  /2
>
>    1 ffff8801031edbe8         0        ffff8801031edaa0 CHR  /2
>
>    2 ffff8801031edbe8         0        ffff8801031edaa0 CHR  /2
>
>    3 ffff880139bf8950         0        ffff880139bf8808 CHR  /null
>
>    4 ffff88011e561390         0        ffff88011e561248 CHR  /crash
>
>    5 ffff88012f8345f0       37910      ffff88012f8344a8 REG
> /usr/lib/debug/lib/modules/3.11.10-301.fc20.x86_64/vmlinux
>
>    [snipped..........................]
>
>
> 2. Dump pages in a given addr-space, this exmaple is ffff88012f8345f0
> from above output.
>      page flags could indicates the dirty pages for fsync stress debugging,
>
> crash> files -m ffff88012f8345f0
>
> Address Space ffff88012f8345f0 : 37910 pages in page cache
>
>        PAGE       PHYSICAL      MAPPING       INDEX CNT FLAGS
>
> ffffea0001f5bc40 7d6f1000 ffff88012f8345f0        0  2 3ff0000000086c
> referenced,uptodate,lru,active,private
>
> ffffea0001f5bc80 7d6f2000 ffff88012f8345f0        1  2 3ff0000000082c
> referenced,uptodate,lru,private
>
> ..............................[snipped...].........................................................................
>
> ffffea00016226c0 5889b000 ffff88012f8345f0     9414  2 3ff0000000086c
> referenced,uptodate,lru,active,private
>
> ffffea000224f480 893d2000 ffff88012f8345f0     9415  2 3ff0000000086c
> referenced,uptodate,lru,active,private
>
> 3. For each files doesn't work with -m but it work with -M
>
> crash> foreach files -m
>
> foreach: foreach files command does not support -m option
>
> So we can use foreach to find which process or files have most page
> cache number,
>
> crash> foreach files -M | grep REG | sort -k3 -n | tail -10
>
> 20 ffff880137a70be0         2        ffff880137a70a98 REG  /ffinLFoAy
>
>    4 ffff880037630de0        131       ffff880037630c98 REG
> /var/log/audit/audit.log
>
>    4 ffff880037630de0        131       ffff880037630c98 REG
> /var/log/audit/audit.log
>
> 36 ffff8801352e91d8        574       ffff8801352e9090 REG
> /var/log/journal/2d6f0d3073ff4a60b1e52a8e38e48feb/user-530.journal
>
> 34 ffff8801352e81f8        590       ffff8801352e80b0 REG
> /var/log/journal/2d6f0d3073ff4a60b1e52a8e38e48feb/user-42.journal
>
>    5 ffff8800a90219c8       9816       ffff8800a9021880 REG
> /usr/lib/debug/lib/modules/3.11.10-301.fc20.x86_64/vmlinux
>
> 13 ffff880135267198       14051      ffff880135267050 REG
> /var/log/journal/2d6f0d3073ff4a60b1e52a8e38e48feb/system.journal
>
>    5 ffff88012f8345f0       37910      ffff88012f8344a8 REG
> /usr/lib/debug/lib/modules/3.11.10-301.fc20.x86_64/vmlinux
>
>    1 ffff8800704f3d80       59468      ffff8800704f3c38 REG
> /ws/irqstat/nohup.out
>
>    2 ffff8800704f3d80       59468      ffff8800704f3c38 REG
> /ws/irqstat/nohup.out
>
>
> With these commands, we can easily to debug some page cache flush
> stress issue, and find out which process or files had the problem.
>
>

-------------- next part --------------
From 759d4f4cdedf4c6b2a4f0f914253f3e147950db5 Mon Sep 17 00:00:00 2001
From: Yong Yang <yangoliver at gmail.com>
Date: Sat, 13 Jun 2015 04:45:14 +0800
Subject: [PATCH] files: support dump file page caches

Added two options in files command,

1. -M option, which allows dump page cache number for each files
2. -m option, which could dump each pages in given address mapping

The foreach command also could work with -M, so that we can easily
find which process hold most page cache pages within the system.

Signed-off-by: Yong Yang <yangoliver at gmail.com>
---
 defs.h    |  3 +++
 filesys.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++--------------
 memory.c  | 50 +++++++++++++++++++++++++++++++++++++
 task.c    | 25 ++++++++++++++++---
 4 files changed, 140 insertions(+), 22 deletions(-)

diff --git a/defs.h b/defs.h
index d2a8215..048c248 100644
--- a/defs.h
+++ b/defs.h
@@ -1111,6 +1111,7 @@ extern struct machdep_table *machdep;
 #define FOREACH_a_FLAG   (0x4000000)
 #define FOREACH_G_FLAG   (0x8000000)
 #define FOREACH_F_FLAG2 (0x10000000)
+#define FOREACH_M_FLAG  (0x20000000)
 
 #define FOREACH_PS_EXCLUSIVE \
   (FOREACH_g_FLAG|FOREACH_a_FLAG|FOREACH_t_FLAG|FOREACH_c_FLAG|FOREACH_p_FLAG|FOREACH_l_FLAG|FOREACH_r_FLAG|FOREACH_m_FLAG)
@@ -2598,6 +2599,7 @@ struct load_module {
 #define PRINT_SINGLE_VMA  (0x80)
 #define PRINT_RADIX_10   (0x100)
 #define PRINT_RADIX_16   (0x200)
+#define PRINT_PAGES      (0x400)
 
 #define MIN_PAGE_SIZE  (4096)
 
@@ -4769,6 +4771,7 @@ int file_dump(ulong, ulong, ulong, int, int);
 #define DUMP_INODE_ONLY  2
 #define DUMP_DENTRY_ONLY 4
 #define DUMP_EMPTY_FILE  8
+#define DUMP_FILE_PAGE   16
 #endif  /* !GDB_COMMON */
 int same_file(char *, char *);
 #ifndef GDB_COMMON
diff --git a/filesys.c b/filesys.c
index 0573fe6..da8c930 100644
--- a/filesys.c
+++ b/filesys.c
@@ -2187,11 +2187,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:m:M")) != EOF) {
                 switch(c)
 		{
 		case 'R':
@@ -2209,7 +2210,13 @@ cmd_files(void)
 			value = htol(optarg, FAULT_ON_ERROR, NULL);
 			display_dentry_info(value);
 			return;
-
+		case 'm':
+			value = htol(optarg, FAULT_ON_ERROR, NULL);
+			dump_file_address_mappings(value);
+			return;
+		case 'M':
+			open_flags |= PRINT_PAGES;
+			break;
 		default:
 			argerrs++;
 			break;
@@ -2222,7 +2229,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 +2250,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 +2258,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 +2330,7 @@ open_files_dump(ulong task, int flags, struct reference *ref)
 	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 +2339,27 @@ open_files_dump(ulong task, int flags, struct reference *ref)
 		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_PAGES) {
+		sprintf(files_header, " FD%s%s%s%s%s%s%sTYPE%sPATH\n",
+			space(MINSPACE),
+			mkstring(buf1, VADDR_PRLEN, CENTER|LJUST, "ADDR-SPACE"),
+			space(MINSPACE),
+			mkstring(buf2, VADDR_PRLEN, CENTER|LJUST, "PGCACHE-PGS"),
+			space(MINSPACE),
+			mkstring(buf3, VADDR_PRLEN, CENTER|LJUST, "INODE"),
+			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 +2545,9 @@ open_files_dump(ulong task, int flags, struct reference *ref)
 		return;
 	}
 
+	file_dump_flags = flags & PRINT_PAGES ?
+	    DUMP_FILE_PAGE : (DUMP_FULL_NAME|DUMP_EMPTY_FILE);
+
 	j = 0;
 	for (;;) {
 		unsigned long set;
@@ -2539,8 +2564,7 @@ open_files_dump(ulong task, int flags, struct reference *ref)
 
 				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 +2582,7 @@ open_files_dump(ulong task, int flags, struct reference *ref)
 						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 +2777,8 @@ file_dump(ulong file, ulong dentry, ulong inode, int fd, int flags)
 	char buf1[BUFSIZE];
 	char buf2[BUFSIZE];
 	char buf3[BUFSIZE];
+	ulong i_mapping = 0;
+	ulong count = 0;
 
 	file_buf = NULL;
 
@@ -2863,6 +2888,29 @@ file_dump(ulong file, ulong dentry, ulong inode, int fd, int flags)
 				type, 
 				space(MINSPACE),
 				pathname+1);
+		} else if (flags & DUMP_FILE_PAGE) {
+
+			i_mapping = ULONG(inode_buf + OFFSET(inode_i_mapping));
+			count = get_page_tree_count(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(i_mapping)),
+                                space(MINSPACE),
+				mkstring(buf2, VADDR_PRLEN,
+				CENTER|RJUST|LONG_DEC,
+				MKSTR(count)),
+                                space(MINSPACE),
+				mkstring(buf3, VADDR_PRLEN,
+				CENTER|RJUST|LONG_HEX,
+				MKSTR(inode)),
+                                space(MINSPACE),
+                                type,
+                                space(MINSPACE),
+                                pathname);
 		} else {
                         fprintf(fp, "%3d%s%s%s%s%s%s%s%s%s%s\n",
                                 fd,
diff --git a/memory.c b/memory.c
index 700cbf4..def29a0 100644
--- a/memory.c
+++ b/memory.c
@@ -132,6 +132,7 @@ struct searchinfo {
 	char buf[BUFSIZE];
 };
 
+void dump_file_address_mappings(ulong);
 static char *memtype_string(int, int);
 static char *error_handle_string(ulong);
 static void dump_mem_map(struct meminfo *);
@@ -6161,6 +6162,55 @@ translate_page_flags(char *buffer, ulong flags)
 }
 
 /*
+ * The address space file mapping radix tree walker.
+ */
+void
+dump_file_address_mappings(ulong i_mapping)
+{
+	ulong radix_tree_rnode;
+	ulong root_rnode;
+	ulong index, count, ret;
+	struct radix_tree_pair rtp;
+	struct meminfo meminfo;
+
+
+	root_rnode = i_mapping + OFFSET(radix_tree_root_rnode);
+
+	count = do_radix_tree(root_rnode, RADIX_TREE_COUNT, NULL);
+
+	fprintf(fp,
+	    "Address Space %lx : %ld pages in page cache\n\n", i_mapping, count);
+
+	/* Now walk the tree, counting all the pages in the tree */
+	for (index = 0; index <= count; index++) {
+		rtp.index = index;
+	        if (do_radix_tree(root_rnode, RADIX_TREE_SEARCH, &rtp)) {
+			meminfo.spec_addr = (ulong)rtp.value;
+			meminfo.memtype = KVADDR;
+			meminfo.flags = ADDRESS_SPECIFIED;
+			dump_mem_map_SPARSEMEM(&meminfo);
+		}
+	}
+
+	return;
+}
+
+/* Get the page count for the specific mapping */
+long
+get_page_tree_count(ulong i_mapping)
+{
+	ulong   radix_tree_rnode;
+	ulong	root_rnode;
+	ulong   count;
+
+	root_rnode = i_mapping + OFFSET(radix_tree_root_rnode);
+
+	count = do_radix_tree(root_rnode, RADIX_TREE_COUNT, NULL);
+
+	return count;
+}
+
+/*
  *  dump_page_hash_table() displays the entries in each page_hash_table.
  */
 
diff --git a/task.c b/task.c
index bc7911b..6e8d7e6 100644
--- a/task.c
+++ b/task.c
@@ -5601,7 +5601,7 @@ cmd_foreach(void)
 	BZERO(&foreach_data, sizeof(struct foreach_data));
 	fd = &foreach_data;
 
-        while ((c = getopt(argcnt, args, "R:vomlgersStTpukcfFxhdaG")) != EOF) {
+        while ((c = getopt(argcnt, args, "R:vomMlgersStTpukcfFxhdaG")) != EOF) {
                 switch(c)
 		{
 		case 'R':
@@ -5625,6 +5625,10 @@ cmd_foreach(void)
 			fd->flags |= FOREACH_m_FLAG;
 			break;
 
+		case 'M':
+			fd->flags |= FOREACH_M_FLAG;
+			break;
+
 		case 'l':
 			fd->flags |= FOREACH_l_FLAG;
 			break;
@@ -6129,6 +6133,13 @@ foreach(struct foreach_data *fd)
 			print_header = FALSE;
 			break;
 
+		case FOREACH_FILES:
+			if (fd->flags & FOREACH_m_FLAG)
+				error(FATAL,
+				    "foreach files command does not "
+				    "support -m option\n");
+			break;
+
 		case FOREACH_TEST:
 			break;
 		}
@@ -6355,9 +6366,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_M_FLAG)
+					cmdflags |= PRINT_PAGES;
+
+				open_files_dump(tc->task,
+					cmdflags,
 					fd->reference ? ref : NULL);
 				break;
 
-- 
1.9.3



More information about the Crash-utility mailing list