[Ocfs2-tools-devel] [PATCH 01/11] fsck.ocfs2: Track and show statistics

Sunil Mushran sunil.mushran at oracle.com
Thu Sep 22 19:04:29 PDT 2011


Patch adds the capability to track statistics. This includes counting
the numbers of files and directories, bytes read/written from disk/cache,
time taken, etc.

The stats are not printed by default. The consolidated stats are printed
by specifying -t. Per pass stats are printed by specifying -tt.

The extended stats looks like:

Checking OCFS2 filesystem in /dev/sdd1:
  Label:              mylabel
  UUID:               8AB016CD59FC4327A2CDAB69F08518E3
  Number of blocks:   13107168
  Block size:         4096
  Number of clusters: 409599
  Cluster size:       131072
  Number of slots:    8

/dev/sdd1 was run with -f, check forced.
Pass 0a: Checking cluster allocation chains
  I/O read disk/cache: 1MB / 1MB, write: 0MB, rate: 4.46MB/s
  Times real: 0.224s, user: 0.000s, sys: 0.000s
Pass 0b: Checking inode allocation chains
  I/O read disk/cache: 1463MB / 4MB, write: 0MB, rate: 30.09MB/s
  Times real: 48.727s, user: 3.300s, sys: 0.480s
Pass 0c: Checking extent block allocation chains
  I/O read disk/cache: 65MB / 1MB, write: 0MB, rate: 32.21MB/s
  Times real: 2.018s, user: 0.150s, sys: 0.010s
Pass 1: Checking inodes and blocks
  I/O read disk/cache: 1334MB / 129MB, write: 0MB, rate: 60.47MB/s
  Times real: 24.193s, user: 5.150s, sys: 1.170s
Pass 2: Checking directory entries
  I/O read disk/cache: 106MB / 682MB, write: 0MB, rate: 52.38MB/s
  Times real: 15.044s, user: 4.350s, sys: 0.440s
Pass 3: Checking directory connectivity
  I/O read disk/cache: 0MB / 1MB, write: 0MB, rate: 134.92MB/s
  Times real: 0.007s, user: 0.010s, sys: 0.000s
Pass 4a: Checking for orphaned inodes
  I/O read disk/cache: 0MB / 1MB, write: 0MB, rate: 2150.54MB/s
  Times real: 0.000s, user: 0.000s, sys: 0.000s
Pass 4b: Checking inodes link counts
  I/O read disk/cache: 0MB / 0MB, write: 0MB, rate: 0.00MB/s
  Times real: 0.366s, user: 0.360s, sys: 0.000s
All passes succeeded.

  Cache size: 199MB
  I/O read disk/cache: 2966MB / 815MB, write: 0MB, rate: 41.73MB/s
  Times real: 90.580s, user: 13.320s, sys: 2.100s

  # of inodes with depth 0/1/2/3/4/5: 188418/0/0/0/0/0
  # of orphaned inodes found/deleted: 0/0

      350177 regular files (161871 inlines, 4 reflinks)
       21903 directories (21757 inlines)
           0 character device files
           0 block device files
           0 fifos
           1 link
          10 symbolic links (10 fast symbolic links)
           0 sockets

Signed-off-by: Sunil Mushran <sunil.mushran at oracle.com>
---
 fsck.ocfs2/fsck.c          |   61 +++++++++++++++++++-
 fsck.ocfs2/fsck.ocfs2.8.in |    5 ++
 fsck.ocfs2/include/fsck.h  |   39 ++++++++++++-
 fsck.ocfs2/include/util.h  |   11 ++++
 fsck.ocfs2/pass0.c         |   20 +++++++
 fsck.ocfs2/pass1.c         |   52 ++++++++++++++---
 fsck.ocfs2/pass2.c         |   10 +++-
 fsck.ocfs2/pass3.c         |   10 +++-
 fsck.ocfs2/pass4.c         |   22 +++++++-
 fsck.ocfs2/pass5.c         |   10 +++-
 fsck.ocfs2/util.c          |  134 ++++++++++++++++++++++++++++++++++++++++++-
 include/ocfs2/ocfs2.h      |   12 ++++
 libocfs2/unix_io.c         |   39 +++++++++++++
 13 files changed, 405 insertions(+), 20 deletions(-)

diff --git a/fsck.ocfs2/fsck.c b/fsck.ocfs2/fsck.c
index e032dfd..28eddf9 100644
--- a/fsck.ocfs2/fsck.c
+++ b/fsck.ocfs2/fsck.c
@@ -133,6 +133,8 @@ static void print_usage(void)
 		" -b superblock	Treat given block as the super block\n"
 		" -B blocksize	Force the given block size\n"
 		" -G		Ask to fix mismatched inode generations\n"
+		" -t		Show I/O statistics\n"
+		" -tt		Show I/O statistics per pass\n"
 		" -u		Access the device with buffering\n"
 		" -V		Output fsck.ocfs2's version\n"
 		" -v		Provide verbose debugging output\n"
@@ -407,6 +409,52 @@ static void print_version(void)
 	fprintf(stderr, "%s %s\n", whoami, VERSION);
 }
 
+#define P_(singular, plural, n) ((n) == 1 ? (singular) : (plural))
+
+static void show_stats(o2fsck_state *ost)
+{
+	uint32_t dir_links, num_links;
+
+	if (!ost->ost_show_stats)
+		return;
+
+	dir_links = ost->ost_dir_count;
+	num_links = ost->ost_links_count - ost->ost_dir_count;
+
+	printf("\n  # of inodes with depth 0/1/2/3/4/5: %u/%u/%u/%u/%u/%u\n",
+	       ost->ost_tree_depth_count[0], ost->ost_tree_depth_count[1],
+	       ost->ost_tree_depth_count[2], ost->ost_tree_depth_count[3],
+	       ost->ost_tree_depth_count[4], ost->ost_tree_depth_count[5]);
+	printf("  # of orphaned inodes found/deleted: %u/%u\n",
+	       ost->ost_orphan_count, ost->ost_orphan_deleted_count);
+
+	printf(P_("\n%12u regular file", "\n%12u regular files",
+		  ost->ost_file_count), ost->ost_file_count);
+	printf(P_(" (%u inline,", " (%u inlines,",
+		  ost->ost_inline_file_count), ost->ost_inline_file_count);
+	printf(P_(" %u reflink)\n", " %u reflinks)\n",
+		  ost->ost_reflinks_count), ost->ost_reflinks_count);
+	printf(P_("%12u directory", "%12u directories",
+		  ost->ost_dir_count), ost->ost_dir_count);
+	printf(P_(" (%u inline)\n", " (%u inlines)\n",
+		  ost->ost_inline_dir_count), ost->ost_inline_dir_count);
+	printf(P_("%12u character device file\n",
+		  "%12u character device files\n", ost->ost_chardev_count),
+	       ost->ost_chardev_count);
+	printf(P_("%12u block device file\n", "%12u block device files\n",
+		  ost->ost_blockdev_count), ost->ost_blockdev_count);
+	printf(P_("%12u fifo\n", "%12u fifos\n", ost->ost_fifo_count),
+	       ost->ost_fifo_count);
+	printf(P_("%12u link\n", "%12u links\n", num_links), num_links);
+	printf(P_("%12u symbolic link", "%12u symbolic links",
+		  ost->ost_symlinks_count), ost->ost_symlinks_count);
+	printf(P_(" (%u fast symbolic link)\n", " (%u fast symbolic links)\n",
+		  ost->ost_fast_symlinks_count), ost->ost_fast_symlinks_count);
+	printf(P_("%12u socket\n", "%12u sockets\n", ost->ost_sockets_count),
+	       ost->ost_sockets_count);
+	printf("\n");
+}
+
 static errcode_t open_and_check(o2fsck_state *ost, char *filename,
 				int open_flags, uint64_t blkno,
 				uint64_t blksize)
@@ -655,7 +703,7 @@ int main(int argc, char **argv)
 	setlinebuf(stderr);
 	setlinebuf(stdout);
 
-	while((c = getopt(argc, argv, "b:B:DfFGnupavVyr:")) != EOF) {
+	while((c = getopt(argc, argv, "b:B:DfFGnupavVytr:")) != EOF) {
 		switch (c) {
 			case 'b':
 				blkno = read_number(optarg);
@@ -738,6 +786,12 @@ int main(int argc, char **argv)
 				sb_num = read_number(optarg);
 				break;
 
+			case 't':
+				if (ost->ost_show_stats)
+					ost->ost_show_extended_stats = 1;
+				ost->ost_show_stats = 1;
+				break;
+
 			default:
 				fsck_mask |= FSCK_USAGE;
 				print_usage();
@@ -984,7 +1038,10 @@ done:
 	else {
 		fsck_mask = FSCK_OK;
 		ost->ost_saw_error = 0;
-		printf("All passes succeeded.\n");
+		printf("All passes succeeded.\n\n");
+		o2fsck_print_resource_track(NULL, ost, &ost->ost_rt,
+					    ost->ost_fs->fs_io);
+		show_stats(ost);
 	}
 
 clear_dirty_flag:
diff --git a/fsck.ocfs2/fsck.ocfs2.8.in b/fsck.ocfs2/fsck.ocfs2.8.in
index 21706dd..58fe261 100644
--- a/fsck.ocfs2/fsck.ocfs2.8.in
+++ b/fsck.ocfs2/fsck.ocfs2.8.in
@@ -79,6 +79,11 @@ Use this option to specify the backup, 1 thru 6, to use to recover the
 superblock.
 
 .TP
+\fB\-t\fR
+Show I/O statistics. If this option is specified twice, it shows the statistics
+on a pass by pass basis.
+
+.TP
 \fB\-y\fR 
 Give the 'yes' answer to all questions that fsck will ask.  This will repair
 all faults that \fBfsck.ocfs2\fR finds but will not give the operator a chance to intervene if \fBfsck.ocfs2\fR decides that it wants to drastically repair the file system.
diff --git a/fsck.ocfs2/include/fsck.h b/fsck.ocfs2/include/fsck.h
index 2ca295a..2822fe1 100644
--- a/fsck.ocfs2/include/fsck.h
+++ b/fsck.ocfs2/include/fsck.h
@@ -31,6 +31,17 @@
 
 struct refcount_file;
 
+/*
+ * This structure is used for keeping track of how much resources have
+ * been used for a particular pass of fsck.ocfs2.
+ */
+struct o2fsck_resource_track {
+	struct timeval		rt_real_time;
+	struct timeval		rt_user_time;
+	struct timeval		rt_sys_time;
+	struct ocfs2_io_stats	rt_io_stats;
+};
+
 typedef struct _o2fsck_state {
 	ocfs2_filesys 	*ost_fs;
 
@@ -79,12 +90,38 @@ typedef struct _o2fsck_state {
  					     * that still indicated mounted */
 			ost_fix_fs_gen:1,
 			ost_has_journal_dirty:1,
-			ost_compress_dirs:1;
+			ost_compress_dirs:1,
+			ost_show_stats:1,
+			ost_show_extended_stats:1;
 	errcode_t ost_err;
+
+	struct o2fsck_resource_track	ost_rt;
+
+	/* counters */
+	uint32_t	ost_file_count;
+	uint32_t	ost_inline_file_count;
+	uint32_t	ost_dir_count;
+	uint32_t	ost_inline_dir_count;
+	uint32_t	ost_reflinks_count;
+	uint32_t	ost_links_count;
+	uint32_t	ost_chardev_count;
+	uint32_t	ost_sockets_count;
+	uint32_t	ost_fifo_count;
+	uint32_t	ost_blockdev_count;
+	uint32_t	ost_symlinks_count;
+	uint32_t	ost_fast_symlinks_count;
+	uint32_t	ost_orphan_count;
+	uint32_t	ost_orphan_deleted_count;
+#define OCFS2_MAX_PATH_DEPTH	5
+	uint32_t	ost_tree_depth_count[OCFS2_MAX_PATH_DEPTH + 1];
 } o2fsck_state;
 
 errcode_t o2fsck_state_reinit(ocfs2_filesys *fs, o2fsck_state *ost);
 
+#define kbytes(x)		(((x) + 1023) / 1024)
+#define mbytes(x)		(((x) + 1048575) / 1048576)
+#define gbytes(x)		(((x) + 1073741823) / 1073741824)
+
 /* The idea is to let someone off-site run fsck and have it give us 
  * enough information to diagnose problems with */
 extern int verbose;
diff --git a/fsck.ocfs2/include/util.h b/fsck.ocfs2/include/util.h
index e36c6ae..b3d3a6f 100644
--- a/fsck.ocfs2/include/util.h
+++ b/fsck.ocfs2/include/util.h
@@ -83,4 +83,15 @@ void __o2fsck_bitmap_clear(ocfs2_bitmap *bitmap, uint64_t bitno, int *oldval,
 	__o2fsck_bitmap_set((_map), (_bit), (_old), __FUNCTION__)
 #define o2fsck_bitmap_clear(_map, _bit, _old)				\
 	__o2fsck_bitmap_clear((_map), (_bit), (_old), __FUNCTION__);
+
+void o2fsck_init_resource_track(struct o2fsck_resource_track *rt,
+				io_channel *channel);
+void o2fsck_compute_resource_track(struct o2fsck_resource_track *rt,
+				   io_channel *channel);
+void o2fsck_print_resource_track(char *pass, o2fsck_state *ost,
+				 struct o2fsck_resource_track *rt,
+				 io_channel *channel);
+void o2fsck_add_resource_track(struct o2fsck_resource_track *rt1,
+			       struct o2fsck_resource_track *rt2);
+
 #endif /* __O2FSCK_UTIL_H__ */
diff --git a/fsck.ocfs2/pass0.c b/fsck.ocfs2/pass0.c
index 0f6f14c..3d8957e 100644
--- a/fsck.ocfs2/pass0.c
+++ b/fsck.ocfs2/pass0.c
@@ -48,6 +48,7 @@
 #include <string.h>
 #include <inttypes.h>
 #include <time.h>
+#include <sys/times.h>
 
 #include "ocfs2/ocfs2.h"
 #include "ocfs2/bitops.h"
@@ -1280,9 +1281,12 @@ errcode_t o2fsck_pass0(o2fsck_state *ost)
 	ocfs2_cached_inode **ci;
 	int max_slots = OCFS2_RAW_SB(fs->fs_super)->s_max_slots;
 	int i, type, bitmap_retried = 0;
+	struct o2fsck_resource_track rt;
 
 	printf("Pass 0a: Checking cluster allocation chains\n");
 
+	o2fsck_init_resource_track(&rt, fs->fs_io);
+
 	/*
 	 * The I/O buffer is 3 blocks. We apportion our I/O buffer
 	 * thusly:
@@ -1417,8 +1421,14 @@ retry_bitmap:
 		}
 	}
 
+	o2fsck_compute_resource_track(&rt, fs->fs_io);
+	o2fsck_print_resource_track("Pass 0a", ost, &rt, fs->fs_io);
+	o2fsck_add_resource_track(&ost->ost_rt, &rt);
+
 	printf("Pass 0b: Checking inode allocation chains\n");
 
+	o2fsck_init_resource_track(&rt, fs->fs_io);
+
 	/* first the global inode alloc and then each of the node's
 	 * inode allocators */
 	type = GLOBAL_INODE_ALLOC_SYSTEM_INODE;
@@ -1474,8 +1484,14 @@ retry_bitmap:
 		}
 	}
 
+	o2fsck_compute_resource_track(&rt, fs->fs_io);
+	o2fsck_print_resource_track("Pass 0b", ost, &rt, fs->fs_io);
+	o2fsck_add_resource_track(&ost->ost_rt, &rt);
+
 	printf("Pass 0c: Checking extent block allocation chains\n");
 
+	o2fsck_init_resource_track(&rt, fs->fs_io);
+
 	for (i = 0; i < max_slots; i++) {
 		ret = ocfs2_lookup_system_inode(fs, EXTENT_ALLOC_SYSTEM_INODE,
 						i, &blkno);
@@ -1506,6 +1522,10 @@ retry_bitmap:
 			goto out;
 	}
 
+	o2fsck_compute_resource_track(&rt, fs->fs_io);
+	o2fsck_print_resource_track("Pass 0c", ost, &rt, fs->fs_io);
+	o2fsck_add_resource_track(&ost->ost_rt, &rt);
+
 out:
 	if (pre_cache_buf)
 		ocfs2_free(&pre_cache_buf);
diff --git a/fsck.ocfs2/pass1.c b/fsck.ocfs2/pass1.c
index 22dafdf..ac79037 100644
--- a/fsck.ocfs2/pass1.c
+++ b/fsck.ocfs2/pass1.c
@@ -438,6 +438,7 @@ static void o2fsck_verify_inode_fields(ocfs2_filesys *fs,
 				       struct ocfs2_dinode *di)
 {
 	int clear = 0;
+	int depth;
 
 	verbosef("checking inode %"PRIu64"'s fields\n", blkno);
 
@@ -538,27 +539,55 @@ static void o2fsck_verify_inode_fields(ocfs2_filesys *fs,
 		o2fsck_bitmap_set(ost->ost_dir_inodes, blkno, NULL);
 		o2fsck_add_dir_parent(&ost->ost_dir_parents, blkno, 0, 0,
 				      di->i_flags & OCFS2_ORPHANED_FL);
+		ost->ost_dir_count++;
+		if (di->i_dyn_features & OCFS2_INLINE_DATA_FL)
+			ost->ost_inline_dir_count++;
 	} else if (S_ISREG(di->i_mode)) {
 		o2fsck_bitmap_set(ost->ost_reg_inodes, blkno, NULL);
+		ost->ost_file_count++;
+		if (di->i_dyn_features & OCFS2_INLINE_DATA_FL)
+			ost->ost_inline_file_count++;
 	} else if (S_ISLNK(di->i_mode)) {
 		/* we only make sure a link's i_size matches
 		 * the link names length in the file data later when
 		 * we walk the inode's blocks */
+		ost->ost_symlinks_count++;
+		if (!di->i_clusters)
+			ost->ost_fast_symlinks_count++;
+	} else if (S_ISCHR(di->i_mode)) {
+		/* i_size?  what other sanity testing for devices? */
+		ost->ost_chardev_count++;
+	} else if (S_ISBLK(di->i_mode)) {
+		ost->ost_blockdev_count++;
+	} else if (S_ISFIFO(di->i_mode)) {
+		ost->ost_fifo_count++;
+	} else if (S_ISSOCK(di->i_mode)) {
+		ost->ost_sockets_count++;
 	} else {
-		if (!S_ISCHR(di->i_mode) && !S_ISBLK(di->i_mode) &&
-		    !S_ISFIFO(di->i_mode) && !S_ISSOCK(di->i_mode)) {
-			clear = 1;
-			goto out;
-		}
+		clear = 1;
+		goto out;
+	}
 
-		/* i_size?  what other sanity testing for devices? */
+	if (!(S_ISLNK(di->i_mode) && !di->i_clusters) &&
+	    !(di->i_dyn_features & OCFS2_INLINE_DATA_FL) &&
+	    !(di->i_flags & (OCFS2_LOCAL_ALLOC_FL |
+			     OCFS2_CHAIN_FL | OCFS2_DEALLOC_FL))) {
+		depth = di->id2.i_list.l_tree_depth;
+		depth = ocfs2_min(depth, OCFS2_MAX_PATH_DEPTH);
+		ost->ost_tree_depth_count[depth]++;
 	}
 
+	if (di->i_dyn_features & OCFS2_HAS_REFCOUNT_FL)
+		ost->ost_reflinks_count++;
+
 	/* put this after all opportunities to clear so we don't have to
 	 * unwind it */
-	if (di->i_links_count)
+	if (di->i_links_count) {
 		o2fsck_icount_set(ost->ost_icount_in_inodes, di->i_blkno,
 					di->i_links_count);
+		if (di->i_links_count > 1)
+			ost->ost_links_count++;
+	}
 
 	/* orphan inodes are a special case. if -n is given pass4 will try
 	 * and assert that their links_count should include the dirent
@@ -1427,8 +1456,11 @@ errcode_t o2fsck_pass1(o2fsck_state *ost)
 	ocfs2_inode_scan *scan;
 	ocfs2_filesys *fs = ost->ost_fs;
 	int valid;
+	struct o2fsck_resource_track rt;
+
+	printf("Pass 1: Checking inodes and blocks\n");
 
-	printf("Pass 1: Checking inodes and blocks.\n");
+	o2fsck_init_resource_track(&rt, fs->fs_io);
 
 	ret = ocfs2_malloc_block(fs->fs_io, &buf);
 	if (ret) {
@@ -1511,6 +1543,10 @@ out_free:
 	if (!ret && ost->ost_duplicate_clusters)
 		ret = ocfs2_pass1_dups(ost);
 
+	o2fsck_compute_resource_track(&rt, fs->fs_io);
+	o2fsck_print_resource_track("Pass 1", ost, &rt, fs->fs_io);
+	o2fsck_add_resource_track(&ost->ost_rt, &rt);
+
 out:
 	return ret;
 }
diff --git a/fsck.ocfs2/pass2.c b/fsck.ocfs2/pass2.c
index 4b43a22..44ebd83 100644
--- a/fsck.ocfs2/pass2.c
+++ b/fsck.ocfs2/pass2.c
@@ -948,8 +948,12 @@ errcode_t o2fsck_pass2(o2fsck_state *ost)
 		.last_ino = 0,
 		.re_idx_dirs = RB_ROOT,
 	};
+	ocfs2_filesys *fs = ost->ost_fs;
+	struct o2fsck_resource_track rt;
 
-	printf("Pass 2: Checking directory entries.\n");
+	printf("Pass 2: Checking directory entries\n");
+
+	o2fsck_init_resource_track(&rt, fs->fs_io);
 
 	o2fsck_strings_init(&dd.strings);
 
@@ -993,6 +997,10 @@ errcode_t o2fsck_pass2(o2fsck_state *ost)
 	release_re_idx_dirs_rbtree(&dd.re_idx_dirs);
 
 	o2fsck_strings_free(&dd.strings);
+
+	o2fsck_compute_resource_track(&rt, fs->fs_io);
+	o2fsck_print_resource_track("Pass 2", ost, &rt, fs->fs_io);
+	o2fsck_add_resource_track(&ost->ost_rt, &rt);
 out:
 	if (dd.dirblock_buf)
 		ocfs2_free(&dd.dirblock_buf);
diff --git a/fsck.ocfs2/pass3.c b/fsck.ocfs2/pass3.c
index 94d9fbd..61fde80 100644
--- a/fsck.ocfs2/pass3.c
+++ b/fsck.ocfs2/pass3.c
@@ -397,8 +397,12 @@ errcode_t o2fsck_pass3(o2fsck_state *ost)
 {
 	o2fsck_dir_parent *dp;
 	errcode_t ret = 0;
+	ocfs2_filesys *fs = ost->ost_fs;
+	struct o2fsck_resource_track rt;
 
-	printf("Pass 3: Checking directory connectivity.\n");
+	printf("Pass 3: Checking directory connectivity\n");
+
+	o2fsck_init_resource_track(&rt, fs->fs_io);
 
 	/* these could probably share more code.  We might need to treat the
 	 * other required directories like root here */
@@ -435,6 +439,10 @@ errcode_t o2fsck_pass3(o2fsck_state *ost)
 			goto out;
 	}
 
+	o2fsck_compute_resource_track(&rt, fs->fs_io);
+	o2fsck_print_resource_track("Pass 3", ost, &rt, fs->fs_io);
+	o2fsck_add_resource_track(&ost->ost_rt, &rt);
+
 out:
 	return ret;
 }
diff --git a/fsck.ocfs2/pass4.c b/fsck.ocfs2/pass4.c
index 5ca4f17..7737cc9 100644
--- a/fsck.ocfs2/pass4.c
+++ b/fsck.ocfs2/pass4.c
@@ -119,6 +119,8 @@ static int replay_orphan_iterate(struct ocfs2_dir_entry *dirent,
 		goto out;
 	}
 
+	ost->ost_orphan_count++;
+
 	/* Only ask for confirmation in force check. */
 	if (ost->ost_force) {
 		if (!prompt(ost, PY, PR_INODE_ORPHANED,
@@ -144,6 +146,8 @@ static int replay_orphan_iterate(struct ocfs2_dir_entry *dirent,
 		goto out;
 	}
 
+	ost->ost_orphan_deleted_count++;
+
 	/* Only calculate icount in force check. */
 	if (ost->ost_force) {
 		/*
@@ -310,8 +314,12 @@ errcode_t o2fsck_pass4(o2fsck_state *ost)
 	char *buf = NULL;
 	errcode_t ret;
 	uint64_t blkno = 0, start;
+	ocfs2_filesys *fs = ost->ost_fs;
+	struct o2fsck_resource_track rt;
+
+	printf("Pass 4a: Checking for orphaned inodes\n");
 
-	printf("Pass 4a: checking for orphaned inodes\n");
+	o2fsck_init_resource_track(&rt, fs->fs_io);
 
 	ret = replay_orphan_dir(ost, 0);
 	if (ret) {
@@ -320,7 +328,13 @@ errcode_t o2fsck_pass4(o2fsck_state *ost)
 		goto out;
 	}
 
-	printf("Pass 4b: Checking inodes link counts.\n");
+	o2fsck_compute_resource_track(&rt, fs->fs_io);
+	o2fsck_print_resource_track("Pass 4a", ost, &rt, fs->fs_io);
+	o2fsck_add_resource_track(&ost->ost_rt, &rt);
+
+	printf("Pass 4b: Checking inodes link counts\n");
+
+	o2fsck_init_resource_track(&rt, fs->fs_io);
 
 	ret = ocfs2_malloc_block(ost->ost_fs->fs_io, &buf);
 	if (ret) {
@@ -336,6 +350,10 @@ errcode_t o2fsck_pass4(o2fsck_state *ost)
 		start = blkno + 1;
 	}
 
+	o2fsck_compute_resource_track(&rt, fs->fs_io);
+	o2fsck_print_resource_track("Pass 4b", ost, &rt, fs->fs_io);
+	o2fsck_add_resource_track(&ost->ost_rt, &rt);
+
 out:
 	if (buf)
 		ocfs2_free(&buf);
diff --git a/fsck.ocfs2/pass5.c b/fsck.ocfs2/pass5.c
index 1f5ed82..065fee8 100644
--- a/fsck.ocfs2/pass5.c
+++ b/fsck.ocfs2/pass5.c
@@ -460,6 +460,7 @@ errcode_t o2fsck_pass5(o2fsck_state *ost)
 	ocfs2_filesys *fs = ost->ost_fs;
 	struct ocfs2_super_block *super = OCFS2_RAW_SB(fs->fs_super);
 	int has_usrquota, has_grpquota;
+	struct o2fsck_resource_track rt;
 
 	has_usrquota = OCFS2_HAS_RO_COMPAT_FEATURE(super,
 				OCFS2_FEATURE_RO_COMPAT_USRQUOTA);
@@ -468,7 +469,10 @@ errcode_t o2fsck_pass5(o2fsck_state *ost)
 	/* Nothing to check? */
 	if (!has_usrquota && !has_grpquota)
 		return 0;
-	printf("Pass 5: Checking quota information.\n");
+	printf("Pass 5: Checking quota information\n");
+
+	o2fsck_init_resource_track(&rt, fs->fs_io);
+
 	if (has_usrquota) {
 		ret = ocfs2_new_quota_hash(qhash + USRQUOTA);
 		if (ret) {
@@ -517,6 +521,10 @@ errcode_t o2fsck_pass5(o2fsck_state *ost)
 		}
 	}
 
+	o2fsck_compute_resource_track(&rt, fs->fs_io);
+	o2fsck_print_resource_track("Pass 5", ost, &rt, fs->fs_io);
+	o2fsck_add_resource_track(&ost->ost_rt, &rt);
+
 	return 0;
 out:
 	if (qhash[USRQUOTA]) {
diff --git a/fsck.ocfs2/util.c b/fsck.ocfs2/util.c
index ccd935d..5753cf1 100644
--- a/fsck.ocfs2/util.c
+++ b/fsck.ocfs2/util.c
@@ -31,8 +31,11 @@
 #include <sys/types.h>
 #include <signal.h>
 #include <unistd.h>
+#include <sys/time.h>
+#include <sys/resource.h>
 #include "ocfs2/ocfs2.h"
 
+
 #include "util.h"
 
 void o2fsck_write_inode(o2fsck_state *ost, uint64_t blkno,
@@ -193,6 +196,128 @@ bail:
 	return ret;
 }
 
+void o2fsck_init_resource_track(struct o2fsck_resource_track *rt,
+				io_channel *channel)
+{
+	struct rusage r;
+
+	io_get_stats(channel, &rt->rt_io_stats);
+
+	memset(&r, 0, sizeof(struct rusage));
+	getrusage(RUSAGE_SELF, &r);
+	rt->rt_user_time = r.ru_utime;
+	rt->rt_sys_time = r.ru_stime;
+
+	gettimeofday(&rt->rt_real_time, 0);
+}
+
+static inline float timeval_in_secs(struct timeval *tv)
+{
+	return tv->tv_sec + ((float)(tv->tv_usec) / 1000000);
+}
+
+static inline void diff_timeval(struct timeval *tv1, struct timeval *tv2)
+{
+	tv1->tv_sec -=  tv2->tv_sec;
+	if (tv1->tv_usec < tv2->tv_usec) {
+		tv1->tv_usec = 1000000 - tv2->tv_usec + tv1->tv_usec;
+		tv1->tv_sec--;
+	} else
+		tv1->tv_usec -= tv2->tv_usec;
+}
+
+static inline void add_timeval(struct timeval *tv1, struct timeval *tv2)
+{
+	tv1->tv_sec +=  tv2->tv_sec;
+	tv1->tv_usec += tv2->tv_usec;
+	if (tv1->tv_usec > 1000000) {
+		tv1->tv_sec++;
+		tv1->tv_usec -= 1000000;
+	}
+}
+
+void o2fsck_add_resource_track(struct o2fsck_resource_track *rt1,
+			       struct o2fsck_resource_track *rt2)
+{
+	struct ocfs2_io_stats *io1 = &rt1->rt_io_stats;
+	struct ocfs2_io_stats *io2 = &rt2->rt_io_stats;
+
+	add_timeval(&rt1->rt_real_time, &rt2->rt_real_time);
+	add_timeval(&rt1->rt_user_time, &rt2->rt_user_time);
+	add_timeval(&rt1->rt_sys_time, &rt2->rt_sys_time);
+
+	io1->is_bytes_read += io2->is_bytes_read;
+	io1->is_bytes_written += io2->is_bytes_written;
+	io1->is_cache_hits += io2->is_cache_hits;
+	io1->is_cache_misses += io2->is_cache_misses;
+	io1->is_cache_inserts += io2->is_cache_inserts;
+	io1->is_cache_removes += io2->is_cache_removes;
+
+}
+
+void o2fsck_compute_resource_track(struct o2fsck_resource_track *rt,
+				   io_channel *channel)
+{
+	struct rusage r;
+	struct timeval time_end;
+	struct ocfs2_io_stats _ios, *ios = &_ios;
+	struct ocfs2_io_stats *rtio = &rt->rt_io_stats;
+
+	gettimeofday(&time_end, 0);
+
+	getrusage(RUSAGE_SELF, &r);
+	diff_timeval(&r.ru_utime, &rt->rt_user_time);
+	diff_timeval(&r.ru_stime, &rt->rt_sys_time);
+	diff_timeval(&time_end, &rt->rt_real_time);
+
+	memcpy(&rt->rt_user_time, &r.ru_utime, sizeof(struct timeval));
+	memcpy(&rt->rt_sys_time, &r.ru_stime, sizeof(struct timeval));
+	memcpy(&rt->rt_real_time, &time_end, sizeof(struct timeval));
+
+	io_get_stats(channel, ios);
+
+	rtio->is_bytes_read = ios->is_bytes_read - rtio->is_bytes_read;
+	rtio->is_bytes_written = ios->is_bytes_written - rtio->is_bytes_written;
+	rtio->is_cache_hits = ios->is_cache_hits - rtio->is_cache_hits;
+	rtio->is_cache_misses = ios->is_cache_misses - rtio->is_cache_misses;
+	rtio->is_cache_inserts = ios->is_cache_inserts - rtio->is_cache_inserts;
+	rtio->is_cache_removes = ios->is_cache_removes - rtio->is_cache_removes;
+}
+
+void o2fsck_print_resource_track(char *pass, o2fsck_state *ost,
+				 struct o2fsck_resource_track *rt,
+				 io_channel *channel)
+{
+	struct ocfs2_io_stats *rtio = &rt->rt_io_stats;
+	uint64_t total_io, cache_read;
+	float rtime, utime, stime;
+
+	if (!ost->ost_show_stats)
+		return ;
+
+	if (pass && !ost->ost_show_extended_stats)
+		return;
+
+	rtime = timeval_in_secs(&rt->rt_real_time);
+	utime = timeval_in_secs(&rt->rt_user_time);
+	stime = timeval_in_secs(&rt->rt_sys_time);
+
+	cache_read = (uint64_t)rtio->is_cache_hits * io_get_blksize(channel);
+	total_io = cache_read + rtio->is_bytes_read + rtio->is_bytes_written;
+
+	if (!pass)
+		printf("  Cache size: %uMB\n",
+		       mbytes(io_get_cache_size(channel)));
+
+	printf("  I/O read disk/cache: %lluMB / %lluMB, write: %lluMB, "
+	       "rate: %.2fMB/s\n", mbytes(rtio->is_bytes_read),
+	       mbytes(cache_read), mbytes(rtio->is_bytes_written),
+	       (double)(mbytes(total_io) / rtime));
+
+	printf("  Times real: %.3fs, user: %.3fs, sys: %.3fs\n", rtime, utime,
+	       stime);
+}
+
 /* Number of blocks available in the I/O cache */
 static int cache_blocks;
 /*
@@ -222,8 +347,10 @@ void o2fsck_init_cache(o2fsck_state *ost, enum o2fsck_cache_hint hint)
 			 * data.  Let's guess at 256M journals.
 			 */
 			leave_room = 0;
-			blocks_wanted = ocfs2_blocks_in_bytes(fs,
-					max_slots * 1024 * 1024 * 256);
+
+			blocks_wanted = (uint64_t)max_slots * 1024 * 1024 * 256;
+			blocks_wanted = ocfs2_bytes_to_blocks(fs,
+							      blocks_wanted);
 			break;
 		case O2FSCK_CACHE_MODE_NONE:
 			return;
@@ -285,8 +412,7 @@ void o2fsck_init_cache(o2fsck_state *ost, enum o2fsck_cache_hint hint)
 				break;
 			}
 
-			verbosef("Leaving room for other %s\n",
-				 "allocations");
+			verbosef("Leaving room for other %s\n", "allocations");
 			leave_room = 0;
 		}
 
diff --git a/include/ocfs2/ocfs2.h b/include/ocfs2/ocfs2.h
index 2f8f8c2..5d46313 100644
--- a/include/ocfs2/ocfs2.h
+++ b/include/ocfs2/ocfs2.h
@@ -313,6 +313,17 @@ errcode_t io_set_blksize(io_channel *channel, int blksize);
 int io_get_blksize(io_channel *channel);
 int io_get_fd(io_channel *channel);
 
+struct ocfs2_io_stats {
+	uint64_t is_bytes_read;
+	uint64_t is_bytes_written;
+	uint32_t is_cache_hits;
+	uint32_t is_cache_misses;
+	uint32_t is_cache_inserts;
+	uint32_t is_cache_removes;
+};
+
+void io_get_stats(io_channel *channel, struct ocfs2_io_stats *stats);
+
 /*
  * Raw I/O functions.  They will use the I/O cache if available.  The
  * _nocache version will not add a block to the cache, but if the block is
@@ -338,6 +349,7 @@ errcode_t io_write_block_nocache(io_channel *channel, int64_t blkno, int count,
 errcode_t io_init_cache(io_channel *channel, size_t nr_blocks);
 void io_set_nocache(io_channel *channel, bool nocache);
 errcode_t io_init_cache_size(io_channel *channel, size_t bytes);
+size_t io_get_cache_size(io_channel *channel);
 errcode_t io_share_cache(io_channel *from, io_channel *to);
 errcode_t io_mlock_cache(io_channel *channel);
 void io_destroy_cache(io_channel *channel);
diff --git a/libocfs2/unix_io.c b/libocfs2/unix_io.c
index 7437fca..a805ffc 100644
--- a/libocfs2/unix_io.c
+++ b/libocfs2/unix_io.c
@@ -87,6 +87,12 @@ struct io_cache {
 	unsigned long ic_data_buffer_len;
 	int ic_locked;
 	int ic_use_count;
+
+	/* stats */
+	uint32_t ic_hits;
+	uint32_t ic_misses;
+	uint32_t ic_inserts;
+	uint32_t ic_removes;
 };
 
 struct _io_channel {
@@ -97,6 +103,10 @@ struct _io_channel {
 	int io_fd;
 	bool io_nocache;
 	struct io_cache *io_cache;
+
+	/* stats */
+	uint64_t io_bytes_read;
+	uint64_t io_bytes_written;
 };
 
 /*
@@ -144,6 +154,8 @@ out:
 		memset(data + tot, 0, size - tot);
 	}
 
+	channel->io_bytes_read += tot;
+
 	return ret;
 }
 
@@ -182,6 +194,8 @@ out:
 	if (!ret && (tot != size))
 		ret = OCFS2_ET_SHORT_WRITE;
 
+	channel->io_bytes_written += tot;
+
 	return ret;
 }
 
@@ -238,6 +252,7 @@ static void io_cache_insert(struct io_cache *ic,
 
 	rb_link_node(&insert_icb->icb_node, parent, p);
 	rb_insert_color(&insert_icb->icb_node, &ic->ic_lookup);
+	ic->ic_inserts++;
 }
 
 static void io_cache_seen(struct io_cache *ic, struct io_cache_block *icb)
@@ -278,6 +293,7 @@ static struct io_cache_block *io_cache_pop_lru(struct io_cache *ic)
 
 	icb = list_entry(ic->ic_lru.next, struct io_cache_block, icb_list);
 	io_cache_disconnect(ic, icb);
+	ic->ic_removes++;
 
 	return icb;
 }
@@ -312,10 +328,12 @@ static errcode_t io_cache_read_blocks(io_channel *channel, int64_t blkno,
 		icb = io_cache_lookup(ic, blkno + good_blocks);
 		if (!icb)
 			break;
+		ic->ic_hits++;
 	}
 
 	/* Read any blocks not in the cache */
 	if (good_blocks < count) {
+		ic->ic_misses += (count - good_blocks);
 		ret = unix_io_read_block(channel, blkno + good_blocks,
 					 count - good_blocks,
 					 data + (channel->io_blksize *
@@ -585,6 +603,12 @@ errcode_t io_init_cache_size(io_channel *channel, size_t bytes)
 	return io_init_cache(channel, blocks);
 }
 
+size_t io_get_cache_size(io_channel *channel)
+{
+	if (channel->io_cache)
+		return channel->io_cache->ic_data_buffer_len;
+	return 0;
+}
 
 errcode_t io_share_cache(io_channel *from, io_channel *to)
 {
@@ -771,6 +795,21 @@ int io_get_fd(io_channel *channel)
 	return channel->io_fd;
 }
 
+void io_get_stats(io_channel *channel, struct ocfs2_io_stats *stats)
+{
+	struct io_cache *ioc = channel->io_cache;
+
+	memset(stats, 0, sizeof(struct ocfs2_io_stats));
+	stats->is_bytes_read = channel->io_bytes_read;
+	stats->is_bytes_written = channel->io_bytes_written;
+	if (ioc) {
+		stats->is_cache_hits = ioc->ic_hits;
+		stats->is_cache_misses = ioc->ic_misses;
+		stats->is_cache_inserts = ioc->ic_inserts;
+		stats->is_cache_removes = ioc->ic_removes;
+	}
+}
+
 /*
  * If a channel is set to 'nocache', it will use the _nocache() functions
  * even if called via the regular functions.  This allows control of
-- 
1.7.4.1




More information about the Ocfs2-tools-devel mailing list