Why not one "statistics" debugfs file where we can keep adding all the 
stats?

Joel Becker wrote:
> It would be nice to know how often we get checksum failures.  Even
> better, how many of them we can fix with the single bit ecc.  So, we add
> a statistics structure.  The structure can be installed into debugfs
> wherever the user wants.
>
> For ocfs2, we'll put it in the superblock-specific debugfs directory and
> pass it down from our higher-level functions.  The stats are only
> registered with debugfs when the filesystem supports metadata ecc.
>
> Signed-off-by: Joel Becker <joel.bec...@oracle.com>
> ---
>  fs/ocfs2/blockcheck.c |  184 ++++++++++++++++++++++++++++++++++++++++++++++--
>  fs/ocfs2/blockcheck.h |   29 +++++++-
>  fs/ocfs2/ocfs2.h      |    4 +
>  fs/ocfs2/super.c      |   42 +++++++++---
>  4 files changed, 240 insertions(+), 19 deletions(-)
>
> diff --git a/fs/ocfs2/blockcheck.c b/fs/ocfs2/blockcheck.c
> index 2a947c4..a1163b8 100644
> --- a/fs/ocfs2/blockcheck.c
> +++ b/fs/ocfs2/blockcheck.c
> @@ -22,6 +22,9 @@
>  #include <linux/crc32.h>
>  #include <linux/buffer_head.h>
>  #include <linux/bitops.h>
> +#include <linux/debugfs.h>
> +#include <linux/module.h>
> +#include <linux/fs.h>
>  #include <asm/byteorder.h>
>  
>  #include <cluster/masklog.h>
> @@ -222,6 +225,155 @@ void ocfs2_hamming_fix_block(void *data, unsigned int 
> blocksize,
>       ocfs2_hamming_fix(data, blocksize * 8, 0, fix);
>  }
>  
> +
> +/*
> + * Debugfs handling.
> + */
> +
> +#ifdef CONFIG_DEBUG_FS
> +
> +static int blockcheck_u64_get(void *data, u64 *val)
> +{
> +     *val = *(u64 *)data;
> +     return 0;
> +}
> +DEFINE_SIMPLE_ATTRIBUTE(blockcheck_fops, blockcheck_u64_get, NULL, "%llu\n");
> +
> +static struct dentry *blockcheck_debugfs_create(const char *name,
> +                                             struct dentry *parent,
> +                                             u64 *value)
> +{
> +     return debugfs_create_file(name, S_IFREG | S_IRUSR, parent, value,
> +                                &blockcheck_fops);
> +}
> +
> +static void ocfs2_blockcheck_debug_remove(struct ocfs2_blockcheck_stats 
> *stats)
> +{
> +     if (stats) {
> +             debugfs_remove(stats->b_debug_check);
> +             stats->b_debug_check = NULL;
> +             debugfs_remove(stats->b_debug_failure);
> +             stats->b_debug_failure = NULL;
> +             debugfs_remove(stats->b_debug_recover);
> +             stats->b_debug_recover = NULL;
> +             debugfs_remove(stats->b_debug_dir);
> +             stats->b_debug_dir = NULL;
> +     }
> +}
> +
> +static int ocfs2_blockcheck_debug_install(struct ocfs2_blockcheck_stats 
> *stats,
> +                                       struct dentry *parent)
> +{
> +     int rc = -EINVAL;
> +
> +     if (!stats)
> +             goto out;
> +
> +     stats->b_debug_dir = debugfs_create_dir("blockcheck", parent);
> +     if (!stats->b_debug_dir)
> +             goto out;
> +
> +     stats->b_debug_check =
> +             blockcheck_debugfs_create("blocks_checked",
> +                                       stats->b_debug_dir,
> +                                       &stats->b_check_count);
> +
> +     stats->b_debug_failure =
> +             blockcheck_debugfs_create("checksums_failed",
> +                                       stats->b_debug_dir,
> +                                       &stats->b_failure_count);
> +
> +     stats->b_debug_recover =
> +             blockcheck_debugfs_create("ecc_recoveries",
> +                                       stats->b_debug_dir,
> +                                       &stats->b_recover_count);
> +     if (stats->b_debug_check && stats->b_debug_failure &&
> +         stats->b_debug_recover)
> +             rc = 0;
> +
> +out:
> +     if (rc)
> +             ocfs2_blockcheck_debug_remove(stats);
> +     return rc;
> +}
> +#else
> +static inline int ocfs2_blockcheck_debug_install(struct 
> ocfs2_blockcheck_stats *stats,
> +                                              struct dentry *parent)
> +{
> +     return 0;
> +}
> +
> +static inline void ocfs2_blockcheck_debug_remove(struct 
> ocfs2_blockcheck_stats *stats)
> +{
> +}
> +#endif  /* CONFIG_DEBUG_FS */
> +
> +/* Always-called wrappers for starting and stopping the debugfs files */
> +int ocfs2_blockcheck_stats_debugfs_install(struct ocfs2_blockcheck_stats 
> *stats,
> +                                        struct dentry *parent)
> +{
> +     return ocfs2_blockcheck_debug_install(stats, parent);
> +}
> +
> +void ocfs2_blockcheck_stats_debugfs_remove(struct ocfs2_blockcheck_stats 
> *stats)
> +{
> +     ocfs2_blockcheck_debug_remove(stats);
> +}
> +
> +static void ocfs2_blockcheck_inc_check(struct ocfs2_blockcheck_stats *stats)
> +{
> +     u64 new_count;
> +
> +     if (!stats)
> +             return;
> +
> +     spin_lock(&stats->b_lock);
> +     stats->b_check_count++;
> +     new_count = stats->b_check_count;
> +     spin_unlock(&stats->b_lock);
> +
> +     if (!new_count)
> +             mlog(ML_NOTICE, "Block check count has wrapped\n");
> +}
> +
> +static void ocfs2_blockcheck_inc_failure(struct ocfs2_blockcheck_stats 
> *stats)
> +{
> +     u64 new_count;
> +
> +     if (!stats)
> +             return;
> +
> +     spin_lock(&stats->b_lock);
> +     stats->b_failure_count++;
> +     new_count = stats->b_failure_count;
> +     spin_unlock(&stats->b_lock);
> +
> +     if (!new_count)
> +             mlog(ML_NOTICE, "Checksum failure count has wrapped\n");
> +}
> +
> +static void ocfs2_blockcheck_inc_recover(struct ocfs2_blockcheck_stats 
> *stats)
> +{
> +     u64 new_count;
> +
> +     if (!stats)
> +             return;
> +
> +     spin_lock(&stats->b_lock);
> +     stats->b_recover_count++;
> +     new_count = stats->b_recover_count;
> +     spin_unlock(&stats->b_lock);
> +
> +     if (!new_count)
> +             mlog(ML_NOTICE, "ECC recovery count has wrapped\n");
> +}
> +
> +
> +
> +/*
> + * These are the low-level APIs for using the ocfs2_block_check structure.
> + */
> +
>  /*
>   * This function generates check information for a block.
>   * data is the block to be checked.  bc is a pointer to the
> @@ -266,12 +418,15 @@ void ocfs2_block_check_compute(void *data, size_t 
> blocksize,
>   * Again, the data passed in should be the on-disk endian.
>   */
>  int ocfs2_block_check_validate(void *data, size_t blocksize,
> -                            struct ocfs2_block_check *bc)
> +                            struct ocfs2_block_check *bc,
> +                            struct ocfs2_blockcheck_stats *stats)
>  {
>       int rc = 0;
>       struct ocfs2_block_check check;
>       u32 crc, ecc;
>  
> +     ocfs2_blockcheck_inc_check(stats);
> +
>       check.bc_crc32e = le32_to_cpu(bc->bc_crc32e);
>       check.bc_ecc = le16_to_cpu(bc->bc_ecc);
>  
> @@ -282,6 +437,7 @@ int ocfs2_block_check_validate(void *data, size_t 
> blocksize,
>       if (crc == check.bc_crc32e)
>               goto out;
>  
> +     ocfs2_blockcheck_inc_failure(stats);
>       mlog(ML_ERROR,
>            "CRC32 failed: stored: %u, computed %u.  Applying ECC.\n",
>            (unsigned int)check.bc_crc32e, (unsigned int)crc);
> @@ -292,8 +448,10 @@ int ocfs2_block_check_validate(void *data, size_t 
> blocksize,
>  
>       /* And check the crc32 again */
>       crc = crc32_le(~0, data, blocksize);
> -     if (crc == check.bc_crc32e)
> +     if (crc == check.bc_crc32e) {
> +             ocfs2_blockcheck_inc_recover(stats);
>               goto out;
> +     }
>  
>       mlog(ML_ERROR, "Fixed CRC32 failed: stored: %u, computed %u\n",
>            (unsigned int)check.bc_crc32e, (unsigned int)crc);
> @@ -366,7 +524,8 @@ void ocfs2_block_check_compute_bhs(struct buffer_head 
> **bhs, int nr,
>   * Again, the data passed in should be the on-disk endian.
>   */
>  int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr,
> -                                struct ocfs2_block_check *bc)
> +                                struct ocfs2_block_check *bc,
> +                                struct ocfs2_blockcheck_stats *stats)
>  {
>       int i, rc = 0;
>       struct ocfs2_block_check check;
> @@ -377,6 +536,8 @@ int ocfs2_block_check_validate_bhs(struct buffer_head 
> **bhs, int nr,
>       if (!nr)
>               return 0;
>  
> +     ocfs2_blockcheck_inc_check(stats);
> +
>       check.bc_crc32e = le32_to_cpu(bc->bc_crc32e);
>       check.bc_ecc = le16_to_cpu(bc->bc_ecc);
>  
> @@ -388,6 +549,7 @@ int ocfs2_block_check_validate_bhs(struct buffer_head 
> **bhs, int nr,
>       if (crc == check.bc_crc32e)
>               goto out;
>  
> +     ocfs2_blockcheck_inc_failure(stats);
>       mlog(ML_ERROR,
>            "CRC32 failed: stored: %u, computed %u.  Applying ECC.\n",
>            (unsigned int)check.bc_crc32e, (unsigned int)crc);
> @@ -416,8 +578,10 @@ int ocfs2_block_check_validate_bhs(struct buffer_head 
> **bhs, int nr,
>       /* And check the crc32 again */
>       for (i = 0, crc = ~0; i < nr; i++)
>               crc = crc32_le(crc, bhs[i]->b_data, bhs[i]->b_size);
> -     if (crc == check.bc_crc32e)
> +     if (crc == check.bc_crc32e) {
> +             ocfs2_blockcheck_inc_recover(stats);
>               goto out;
> +     }
>  
>       mlog(ML_ERROR, "Fixed CRC32 failed: stored: %u, computed %u\n",
>            (unsigned int)check.bc_crc32e, (unsigned int)crc);
> @@ -448,9 +612,11 @@ int ocfs2_validate_meta_ecc(struct super_block *sb, void 
> *data,
>                           struct ocfs2_block_check *bc)
>  {
>       int rc = 0;
> +     struct ocfs2_super *osb = OCFS2_SB(sb);
>  
> -     if (ocfs2_meta_ecc(OCFS2_SB(sb)))
> -             rc = ocfs2_block_check_validate(data, sb->s_blocksize, bc);
> +     if (ocfs2_meta_ecc(osb))
> +             rc = ocfs2_block_check_validate(data, sb->s_blocksize, bc,
> +                                             &osb->osb_ecc_stats);
>  
>       return rc;
>  }
> @@ -468,9 +634,11 @@ int ocfs2_validate_meta_ecc_bhs(struct super_block *sb,
>                               struct ocfs2_block_check *bc)
>  {
>       int rc = 0;
> +     struct ocfs2_super *osb = OCFS2_SB(sb);
>  
> -     if (ocfs2_meta_ecc(OCFS2_SB(sb)))
> -             rc = ocfs2_block_check_validate_bhs(bhs, nr, bc);
> +     if (ocfs2_meta_ecc(osb))
> +             rc = ocfs2_block_check_validate_bhs(bhs, nr, bc,
> +                                                 &osb->osb_ecc_stats);
>  
>       return rc;
>  }
> diff --git a/fs/ocfs2/blockcheck.h b/fs/ocfs2/blockcheck.h
> index 70ec3fe..d4b69fe 100644
> --- a/fs/ocfs2/blockcheck.h
> +++ b/fs/ocfs2/blockcheck.h
> @@ -21,6 +21,24 @@
>  #define OCFS2_BLOCKCHECK_H
>  
>  
> +/* Count errors and error correction from blockcheck.c */
> +struct ocfs2_blockcheck_stats {
> +     spinlock_t b_lock;
> +     u64 b_check_count;      /* Number of blocks we've checked */
> +     u64 b_failure_count;    /* Number of failed checksums */
> +     u64 b_recover_count;    /* Number of blocks fixed by ecc */
> +
> +     /*
> +      * debugfs entries, used if this is passed to
> +      * ocfs2_blockcheck_stats_debugfs_install()
> +      */
> +     struct dentry *b_debug_dir;     /* Parent of the debugfs  files */
> +     struct dentry *b_debug_check;   /* Exposes b_check_count */
> +     struct dentry *b_debug_failure; /* Exposes b_failure_count */
> +     struct dentry *b_debug_recover; /* Exposes b_recover_count */
> +};
> +
> +
>  /* High level block API */
>  void ocfs2_compute_meta_ecc(struct super_block *sb, void *data,
>                           struct ocfs2_block_check *bc);
> @@ -37,11 +55,18 @@ int ocfs2_validate_meta_ecc_bhs(struct super_block *sb,
>  void ocfs2_block_check_compute(void *data, size_t blocksize,
>                              struct ocfs2_block_check *bc);
>  int ocfs2_block_check_validate(void *data, size_t blocksize,
> -                            struct ocfs2_block_check *bc);
> +                            struct ocfs2_block_check *bc,
> +                            struct ocfs2_blockcheck_stats *stats);
>  void ocfs2_block_check_compute_bhs(struct buffer_head **bhs, int nr,
>                                  struct ocfs2_block_check *bc);
>  int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr,
> -                                struct ocfs2_block_check *bc);
> +                                struct ocfs2_block_check *bc,
> +                                struct ocfs2_blockcheck_stats *stats);
> +
> +/* Debug Initialization */
> +int ocfs2_blockcheck_stats_debugfs_install(struct ocfs2_blockcheck_stats 
> *stats,
> +                                        struct dentry *parent);
> +void ocfs2_blockcheck_stats_debugfs_remove(struct ocfs2_blockcheck_stats 
> *stats);
>  
>  /*
>   * Hamming code functions
> diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h
> index ad5c24a..ba37433 100644
> --- a/fs/ocfs2/ocfs2.h
> +++ b/fs/ocfs2/ocfs2.h
> @@ -47,6 +47,9 @@
>  #include "ocfs2_fs.h"
>  #include "ocfs2_lockid.h"
>  
> +/* For struct ocfs2_blockcheck_stats */
> +#include "blockcheck.h"
> +
>  /* Most user visible OCFS2 inodes will have very few pieces of
>   * metadata, but larger files (including bitmaps, etc) must be taken
>   * into account when designing an access scheme. We allow a small
> @@ -297,6 +300,7 @@ struct ocfs2_super
>       struct ocfs2_dinode *local_alloc_copy;
>       struct ocfs2_quota_recovery *quota_rec;
>  
> +     struct ocfs2_blockcheck_stats osb_ecc_stats;
>       struct ocfs2_alloc_stats alloc_stats;
>       char dev_str[20];               /* "major,minor" of the device */
>  
> diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
> index 43ed113..518b08a 100644
> --- a/fs/ocfs2/super.c
> +++ b/fs/ocfs2/super.c
> @@ -118,10 +118,12 @@ static void ocfs2_release_system_inodes(struct 
> ocfs2_super *osb);
>  static int ocfs2_check_volume(struct ocfs2_super *osb);
>  static int ocfs2_verify_volume(struct ocfs2_dinode *di,
>                              struct buffer_head *bh,
> -                            u32 sectsize);
> +                            u32 sectsize,
> +                            struct ocfs2_blockcheck_stats *stats);
>  static int ocfs2_initialize_super(struct super_block *sb,
>                                 struct buffer_head *bh,
> -                               int sector_size);
> +                               int sector_size,
> +                               struct ocfs2_blockcheck_stats *stats);
>  static int ocfs2_get_sector(struct super_block *sb,
>                           struct buffer_head **bh,
>                           int block,
> @@ -539,7 +541,8 @@ out:
>  
>  static int ocfs2_sb_probe(struct super_block *sb,
>                         struct buffer_head **bh,
> -                       int *sector_size)
> +                       int *sector_size,
> +                       struct ocfs2_blockcheck_stats *stats)
>  {
>       int status, tmpstat;
>       struct ocfs1_vol_disk_hdr *hdr;
> @@ -605,7 +608,8 @@ static int ocfs2_sb_probe(struct super_block *sb,
>                       goto bail;
>               }
>               di = (struct ocfs2_dinode *) (*bh)->b_data;
> -             status = ocfs2_verify_volume(di, *bh, blksize);
> +             memset(stats, 0, sizeof(struct ocfs2_blockcheck_stats));
> +             status = ocfs2_verify_volume(di, *bh, blksize, stats);
>               if (status >= 0)
>                       goto bail;
>               brelse(*bh);
> @@ -811,6 +815,7 @@ static int ocfs2_fill_super(struct super_block *sb, void 
> *data, int silent)
>       struct ocfs2_super *osb = NULL;
>       struct buffer_head *bh = NULL;
>       char nodestr[8];
> +     struct ocfs2_blockcheck_stats stats;
>  
>       mlog_entry("%p, %p, %i", sb, data, silent);
>  
> @@ -820,13 +825,13 @@ static int ocfs2_fill_super(struct super_block *sb, 
> void *data, int silent)
>       }
>  
>       /* probe for superblock */
> -     status = ocfs2_sb_probe(sb, &bh, &sector_size);
> +     status = ocfs2_sb_probe(sb, &bh, &sector_size, &stats);
>       if (status < 0) {
>               mlog(ML_ERROR, "superblock probe failed!\n");
>               goto read_super_error;
>       }
>  
> -     status = ocfs2_initialize_super(sb, bh, sector_size);
> +     status = ocfs2_initialize_super(sb, bh, sector_size, &stats);
>       osb = OCFS2_SB(sb);
>       if (status < 0) {
>               mlog_errno(status);
> @@ -926,6 +931,18 @@ static int ocfs2_fill_super(struct super_block *sb, void 
> *data, int silent)
>               goto read_super_error;
>       }
>  
> +     if (ocfs2_meta_ecc(osb)) {
> +             status = ocfs2_blockcheck_stats_debugfs_install(
> +                                             &osb->osb_ecc_stats,
> +                                             osb->osb_debug_root);
> +             if (status) {
> +                     mlog(ML_ERROR,
> +                          "Unable to create blockcheck statistics "
> +                          "files\n");
> +                     goto read_super_error;
> +             }
> +     }
> +
>       status = ocfs2_mount_volume(sb);
>       if (osb->root_inode)
>               inode = igrab(osb->root_inode);
> @@ -1656,6 +1673,7 @@ static void ocfs2_dismount_volume(struct super_block 
> *sb, int mnt_err)
>       if (osb->cconn)
>               ocfs2_dlm_shutdown(osb, hangup_needed);
>  
> +     ocfs2_blockcheck_stats_debugfs_remove(&osb->osb_ecc_stats);
>       debugfs_remove(osb->osb_debug_root);
>  
>       if (hangup_needed)
> @@ -1703,7 +1721,8 @@ static int ocfs2_setup_osb_uuid(struct ocfs2_super 
> *osb, const unsigned char *uu
>  
>  static int ocfs2_initialize_super(struct super_block *sb,
>                                 struct buffer_head *bh,
> -                               int sector_size)
> +                               int sector_size,
> +                               struct ocfs2_blockcheck_stats *stats)
>  {
>       int status;
>       int i, cbits, bbits;
> @@ -1755,6 +1774,9 @@ static int ocfs2_initialize_super(struct super_block 
> *sb,
>       atomic_set(&osb->alloc_stats.bg_allocs, 0);
>       atomic_set(&osb->alloc_stats.bg_extends, 0);
>  
> +     /* Copy the blockcheck stats from the superblock probe */
> +     osb->osb_ecc_stats = *stats;
> +
>       ocfs2_init_node_maps(osb);
>  
>       snprintf(osb->dev_str, sizeof(osb->dev_str), "%u,%u",
> @@ -1982,7 +2004,8 @@ bail:
>   */
>  static int ocfs2_verify_volume(struct ocfs2_dinode *di,
>                              struct buffer_head *bh,
> -                            u32 blksz)
> +                            u32 blksz,
> +                            struct ocfs2_blockcheck_stats *stats)
>  {
>       int status = -EAGAIN;
>  
> @@ -1995,7 +2018,8 @@ static int ocfs2_verify_volume(struct ocfs2_dinode *di,
>                   OCFS2_FEATURE_INCOMPAT_META_ECC) {
>                       status = ocfs2_block_check_validate(bh->b_data,
>                                                           bh->b_size,
> -                                                         &di->i_check);
> +                                                         &di->i_check,
> +                                                         stats);
>                       if (status)
>                               goto out;
>               }
>   


_______________________________________________
Ocfs2-devel mailing list
Ocfs2-devel@oss.oracle.com
http://oss.oracle.com/mailman/listinfo/ocfs2-devel

Reply via email to