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

Goldwyn Rodrigues rgoldwyn at gmail.com
Fri Sep 23 09:49:25 PDT 2011


Hi Sunil,

I like the idea.. anything to do with improving performance is great.

On Thu, Sep 22, 2011 at 9:04 PM, Sunil Mushran <sunil.mushran at oracle.com> wrote:
> 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;
> +       }
> +}
> +

Why don't you use standard library functions such as timersub() and timeradd()?

> +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

-- 
Goldwyn



More information about the Ocfs2-tools-devel mailing list