[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