aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJoel Becker <joel.becker@oracle.com>2009-01-06 17:57:08 -0500
committerJoel Becker <joel.becker@oracle.com>2009-06-03 22:15:36 -0400
commit73be192b17e43b6dc4f492dab41d70ab5b9d2908 (patch)
tree9482070421cda81f490036b28033d4f300a58a94 /fs
parent15633a220ffe74fc61bc8117e6a89a494011ea3d (diff)
ocfs2: Add statistics for the checksum and ecc operations.
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.becker@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/ocfs2/blockcheck.c184
-rw-r--r--fs/ocfs2/blockcheck.h29
-rw-r--r--fs/ocfs2/ocfs2.h4
-rw-r--r--fs/ocfs2/super.c42
4 files changed, 240 insertions, 19 deletions
diff --git a/fs/ocfs2/blockcheck.c b/fs/ocfs2/blockcheck.c
index 2a947c44e594..a1163b8b417c 100644
--- a/fs/ocfs2/blockcheck.c
+++ b/fs/ocfs2/blockcheck.c
@@ -22,6 +22,9 @@
22#include <linux/crc32.h> 22#include <linux/crc32.h>
23#include <linux/buffer_head.h> 23#include <linux/buffer_head.h>
24#include <linux/bitops.h> 24#include <linux/bitops.h>
25#include <linux/debugfs.h>
26#include <linux/module.h>
27#include <linux/fs.h>
25#include <asm/byteorder.h> 28#include <asm/byteorder.h>
26 29
27#include <cluster/masklog.h> 30#include <cluster/masklog.h>
@@ -222,6 +225,155 @@ void ocfs2_hamming_fix_block(void *data, unsigned int blocksize,
222 ocfs2_hamming_fix(data, blocksize * 8, 0, fix); 225 ocfs2_hamming_fix(data, blocksize * 8, 0, fix);
223} 226}
224 227
228
229/*
230 * Debugfs handling.
231 */
232
233#ifdef CONFIG_DEBUG_FS
234
235static int blockcheck_u64_get(void *data, u64 *val)
236{
237 *val = *(u64 *)data;
238 return 0;
239}
240DEFINE_SIMPLE_ATTRIBUTE(blockcheck_fops, blockcheck_u64_get, NULL, "%llu\n");
241
242static struct dentry *blockcheck_debugfs_create(const char *name,
243 struct dentry *parent,
244 u64 *value)
245{
246 return debugfs_create_file(name, S_IFREG | S_IRUSR, parent, value,
247 &blockcheck_fops);
248}
249
250static void ocfs2_blockcheck_debug_remove(struct ocfs2_blockcheck_stats *stats)
251{
252 if (stats) {
253 debugfs_remove(stats->b_debug_check);
254 stats->b_debug_check = NULL;
255 debugfs_remove(stats->b_debug_failure);
256 stats->b_debug_failure = NULL;
257 debugfs_remove(stats->b_debug_recover);
258 stats->b_debug_recover = NULL;
259 debugfs_remove(stats->b_debug_dir);
260 stats->b_debug_dir = NULL;
261 }
262}
263
264static int ocfs2_blockcheck_debug_install(struct ocfs2_blockcheck_stats *stats,
265 struct dentry *parent)
266{
267 int rc = -EINVAL;
268
269 if (!stats)
270 goto out;
271
272 stats->b_debug_dir = debugfs_create_dir("blockcheck", parent);
273 if (!stats->b_debug_dir)
274 goto out;
275
276 stats->b_debug_check =
277 blockcheck_debugfs_create("blocks_checked",
278 stats->b_debug_dir,
279 &stats->b_check_count);
280
281 stats->b_debug_failure =
282 blockcheck_debugfs_create("checksums_failed",
283 stats->b_debug_dir,
284 &stats->b_failure_count);
285
286 stats->b_debug_recover =
287 blockcheck_debugfs_create("ecc_recoveries",
288 stats->b_debug_dir,
289 &stats->b_recover_count);
290 if (stats->b_debug_check && stats->b_debug_failure &&
291 stats->b_debug_recover)
292 rc = 0;
293
294out:
295 if (rc)
296 ocfs2_blockcheck_debug_remove(stats);
297 return rc;
298}
299#else
300static inline int ocfs2_blockcheck_debug_install(struct ocfs2_blockcheck_stats *stats,
301 struct dentry *parent)
302{
303 return 0;
304}
305
306static inline void ocfs2_blockcheck_debug_remove(struct ocfs2_blockcheck_stats *stats)
307{
308}
309#endif /* CONFIG_DEBUG_FS */
310
311/* Always-called wrappers for starting and stopping the debugfs files */
312int ocfs2_blockcheck_stats_debugfs_install(struct ocfs2_blockcheck_stats *stats,
313 struct dentry *parent)
314{
315 return ocfs2_blockcheck_debug_install(stats, parent);
316}
317
318void ocfs2_blockcheck_stats_debugfs_remove(struct ocfs2_blockcheck_stats *stats)
319{
320 ocfs2_blockcheck_debug_remove(stats);
321}
322
323static void ocfs2_blockcheck_inc_check(struct ocfs2_blockcheck_stats *stats)
324{
325 u64 new_count;
326
327 if (!stats)
328 return;
329
330 spin_lock(&stats->b_lock);
331 stats->b_check_count++;
332 new_count = stats->b_check_count;
333 spin_unlock(&stats->b_lock);
334
335 if (!new_count)
336 mlog(ML_NOTICE, "Block check count has wrapped\n");
337}
338
339static void ocfs2_blockcheck_inc_failure(struct ocfs2_blockcheck_stats *stats)
340{
341 u64 new_count;
342
343 if (!stats)
344 return;
345
346 spin_lock(&stats->b_lock);
347 stats->b_failure_count++;
348 new_count = stats->b_failure_count;
349 spin_unlock(&stats->b_lock);
350
351 if (!new_count)
352 mlog(ML_NOTICE, "Checksum failure count has wrapped\n");
353}
354
355static void ocfs2_blockcheck_inc_recover(struct ocfs2_blockcheck_stats *stats)
356{
357 u64 new_count;
358
359 if (!stats)
360 return;
361
362 spin_lock(&stats->b_lock);
363 stats->b_recover_count++;
364 new_count = stats->b_recover_count;
365 spin_unlock(&stats->b_lock);
366
367 if (!new_count)
368 mlog(ML_NOTICE, "ECC recovery count has wrapped\n");
369}
370
371
372
373/*
374 * These are the low-level APIs for using the ocfs2_block_check structure.
375 */
376
225/* 377/*
226 * This function generates check information for a block. 378 * This function generates check information for a block.
227 * data is the block to be checked. bc is a pointer to the 379 * 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,
266 * Again, the data passed in should be the on-disk endian. 418 * Again, the data passed in should be the on-disk endian.
267 */ 419 */
268int ocfs2_block_check_validate(void *data, size_t blocksize, 420int ocfs2_block_check_validate(void *data, size_t blocksize,
269 struct ocfs2_block_check *bc) 421 struct ocfs2_block_check *bc,
422 struct ocfs2_blockcheck_stats *stats)
270{ 423{
271 int rc = 0; 424 int rc = 0;
272 struct ocfs2_block_check check; 425 struct ocfs2_block_check check;
273 u32 crc, ecc; 426 u32 crc, ecc;
274 427
428 ocfs2_blockcheck_inc_check(stats);
429
275 check.bc_crc32e = le32_to_cpu(bc->bc_crc32e); 430 check.bc_crc32e = le32_to_cpu(bc->bc_crc32e);
276 check.bc_ecc = le16_to_cpu(bc->bc_ecc); 431 check.bc_ecc = le16_to_cpu(bc->bc_ecc);
277 432
@@ -282,6 +437,7 @@ int ocfs2_block_check_validate(void *data, size_t blocksize,
282 if (crc == check.bc_crc32e) 437 if (crc == check.bc_crc32e)
283 goto out; 438 goto out;
284 439
440 ocfs2_blockcheck_inc_failure(stats);
285 mlog(ML_ERROR, 441 mlog(ML_ERROR,
286 "CRC32 failed: stored: %u, computed %u. Applying ECC.\n", 442 "CRC32 failed: stored: %u, computed %u. Applying ECC.\n",
287 (unsigned int)check.bc_crc32e, (unsigned int)crc); 443 (unsigned int)check.bc_crc32e, (unsigned int)crc);
@@ -292,8 +448,10 @@ int ocfs2_block_check_validate(void *data, size_t blocksize,
292 448
293 /* And check the crc32 again */ 449 /* And check the crc32 again */
294 crc = crc32_le(~0, data, blocksize); 450 crc = crc32_le(~0, data, blocksize);
295 if (crc == check.bc_crc32e) 451 if (crc == check.bc_crc32e) {
452 ocfs2_blockcheck_inc_recover(stats);
296 goto out; 453 goto out;
454 }
297 455
298 mlog(ML_ERROR, "Fixed CRC32 failed: stored: %u, computed %u\n", 456 mlog(ML_ERROR, "Fixed CRC32 failed: stored: %u, computed %u\n",
299 (unsigned int)check.bc_crc32e, (unsigned int)crc); 457 (unsigned int)check.bc_crc32e, (unsigned int)crc);
@@ -366,7 +524,8 @@ void ocfs2_block_check_compute_bhs(struct buffer_head **bhs, int nr,
366 * Again, the data passed in should be the on-disk endian. 524 * Again, the data passed in should be the on-disk endian.
367 */ 525 */
368int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr, 526int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr,
369 struct ocfs2_block_check *bc) 527 struct ocfs2_block_check *bc,
528 struct ocfs2_blockcheck_stats *stats)
370{ 529{
371 int i, rc = 0; 530 int i, rc = 0;
372 struct ocfs2_block_check check; 531 struct ocfs2_block_check check;
@@ -377,6 +536,8 @@ int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr,
377 if (!nr) 536 if (!nr)
378 return 0; 537 return 0;
379 538
539 ocfs2_blockcheck_inc_check(stats);
540
380 check.bc_crc32e = le32_to_cpu(bc->bc_crc32e); 541 check.bc_crc32e = le32_to_cpu(bc->bc_crc32e);
381 check.bc_ecc = le16_to_cpu(bc->bc_ecc); 542 check.bc_ecc = le16_to_cpu(bc->bc_ecc);
382 543
@@ -388,6 +549,7 @@ int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr,
388 if (crc == check.bc_crc32e) 549 if (crc == check.bc_crc32e)
389 goto out; 550 goto out;
390 551
552 ocfs2_blockcheck_inc_failure(stats);
391 mlog(ML_ERROR, 553 mlog(ML_ERROR,
392 "CRC32 failed: stored: %u, computed %u. Applying ECC.\n", 554 "CRC32 failed: stored: %u, computed %u. Applying ECC.\n",
393 (unsigned int)check.bc_crc32e, (unsigned int)crc); 555 (unsigned int)check.bc_crc32e, (unsigned int)crc);
@@ -416,8 +578,10 @@ int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr,
416 /* And check the crc32 again */ 578 /* And check the crc32 again */
417 for (i = 0, crc = ~0; i < nr; i++) 579 for (i = 0, crc = ~0; i < nr; i++)
418 crc = crc32_le(crc, bhs[i]->b_data, bhs[i]->b_size); 580 crc = crc32_le(crc, bhs[i]->b_data, bhs[i]->b_size);
419 if (crc == check.bc_crc32e) 581 if (crc == check.bc_crc32e) {
582 ocfs2_blockcheck_inc_recover(stats);
420 goto out; 583 goto out;
584 }
421 585
422 mlog(ML_ERROR, "Fixed CRC32 failed: stored: %u, computed %u\n", 586 mlog(ML_ERROR, "Fixed CRC32 failed: stored: %u, computed %u\n",
423 (unsigned int)check.bc_crc32e, (unsigned int)crc); 587 (unsigned int)check.bc_crc32e, (unsigned int)crc);
@@ -448,9 +612,11 @@ int ocfs2_validate_meta_ecc(struct super_block *sb, void *data,
448 struct ocfs2_block_check *bc) 612 struct ocfs2_block_check *bc)
449{ 613{
450 int rc = 0; 614 int rc = 0;
615 struct ocfs2_super *osb = OCFS2_SB(sb);
451 616
452 if (ocfs2_meta_ecc(OCFS2_SB(sb))) 617 if (ocfs2_meta_ecc(osb))
453 rc = ocfs2_block_check_validate(data, sb->s_blocksize, bc); 618 rc = ocfs2_block_check_validate(data, sb->s_blocksize, bc,
619 &osb->osb_ecc_stats);
454 620
455 return rc; 621 return rc;
456} 622}
@@ -468,9 +634,11 @@ int ocfs2_validate_meta_ecc_bhs(struct super_block *sb,
468 struct ocfs2_block_check *bc) 634 struct ocfs2_block_check *bc)
469{ 635{
470 int rc = 0; 636 int rc = 0;
637 struct ocfs2_super *osb = OCFS2_SB(sb);
471 638
472 if (ocfs2_meta_ecc(OCFS2_SB(sb))) 639 if (ocfs2_meta_ecc(osb))
473 rc = ocfs2_block_check_validate_bhs(bhs, nr, bc); 640 rc = ocfs2_block_check_validate_bhs(bhs, nr, bc,
641 &osb->osb_ecc_stats);
474 642
475 return rc; 643 return rc;
476} 644}
diff --git a/fs/ocfs2/blockcheck.h b/fs/ocfs2/blockcheck.h
index 70ec3feda32f..d4b69febf70a 100644
--- a/fs/ocfs2/blockcheck.h
+++ b/fs/ocfs2/blockcheck.h
@@ -21,6 +21,24 @@
21#define OCFS2_BLOCKCHECK_H 21#define OCFS2_BLOCKCHECK_H
22 22
23 23
24/* Count errors and error correction from blockcheck.c */
25struct ocfs2_blockcheck_stats {
26 spinlock_t b_lock;
27 u64 b_check_count; /* Number of blocks we've checked */
28 u64 b_failure_count; /* Number of failed checksums */
29 u64 b_recover_count; /* Number of blocks fixed by ecc */
30
31 /*
32 * debugfs entries, used if this is passed to
33 * ocfs2_blockcheck_stats_debugfs_install()
34 */
35 struct dentry *b_debug_dir; /* Parent of the debugfs files */
36 struct dentry *b_debug_check; /* Exposes b_check_count */
37 struct dentry *b_debug_failure; /* Exposes b_failure_count */
38 struct dentry *b_debug_recover; /* Exposes b_recover_count */
39};
40
41
24/* High level block API */ 42/* High level block API */
25void ocfs2_compute_meta_ecc(struct super_block *sb, void *data, 43void ocfs2_compute_meta_ecc(struct super_block *sb, void *data,
26 struct ocfs2_block_check *bc); 44 struct ocfs2_block_check *bc);
@@ -37,11 +55,18 @@ int ocfs2_validate_meta_ecc_bhs(struct super_block *sb,
37void ocfs2_block_check_compute(void *data, size_t blocksize, 55void ocfs2_block_check_compute(void *data, size_t blocksize,
38 struct ocfs2_block_check *bc); 56 struct ocfs2_block_check *bc);
39int ocfs2_block_check_validate(void *data, size_t blocksize, 57int ocfs2_block_check_validate(void *data, size_t blocksize,
40 struct ocfs2_block_check *bc); 58 struct ocfs2_block_check *bc,
59 struct ocfs2_blockcheck_stats *stats);
41void ocfs2_block_check_compute_bhs(struct buffer_head **bhs, int nr, 60void ocfs2_block_check_compute_bhs(struct buffer_head **bhs, int nr,
42 struct ocfs2_block_check *bc); 61 struct ocfs2_block_check *bc);
43int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr, 62int ocfs2_block_check_validate_bhs(struct buffer_head **bhs, int nr,
44 struct ocfs2_block_check *bc); 63 struct ocfs2_block_check *bc,
64 struct ocfs2_blockcheck_stats *stats);
65
66/* Debug Initialization */
67int ocfs2_blockcheck_stats_debugfs_install(struct ocfs2_blockcheck_stats *stats,
68 struct dentry *parent);
69void ocfs2_blockcheck_stats_debugfs_remove(struct ocfs2_blockcheck_stats *stats);
45 70
46/* 71/*
47 * Hamming code functions 72 * Hamming code functions
diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h
index ab285be023b2..18c1d9ec1c93 100644
--- a/fs/ocfs2/ocfs2.h
+++ b/fs/ocfs2/ocfs2.h
@@ -47,6 +47,9 @@
47#include "ocfs2_fs.h" 47#include "ocfs2_fs.h"
48#include "ocfs2_lockid.h" 48#include "ocfs2_lockid.h"
49 49
50/* For struct ocfs2_blockcheck_stats */
51#include "blockcheck.h"
52
50/* Most user visible OCFS2 inodes will have very few pieces of 53/* Most user visible OCFS2 inodes will have very few pieces of
51 * metadata, but larger files (including bitmaps, etc) must be taken 54 * metadata, but larger files (including bitmaps, etc) must be taken
52 * into account when designing an access scheme. We allow a small 55 * into account when designing an access scheme. We allow a small
@@ -305,6 +308,7 @@ struct ocfs2_super
305 struct ocfs2_dinode *local_alloc_copy; 308 struct ocfs2_dinode *local_alloc_copy;
306 struct ocfs2_quota_recovery *quota_rec; 309 struct ocfs2_quota_recovery *quota_rec;
307 310
311 struct ocfs2_blockcheck_stats osb_ecc_stats;
308 struct ocfs2_alloc_stats alloc_stats; 312 struct ocfs2_alloc_stats alloc_stats;
309 char dev_str[20]; /* "major,minor" of the device */ 313 char dev_str[20]; /* "major,minor" of the device */
310 314
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index d05f3caec410..86f500c5d63d 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);
118static int ocfs2_check_volume(struct ocfs2_super *osb); 118static int ocfs2_check_volume(struct ocfs2_super *osb);
119static int ocfs2_verify_volume(struct ocfs2_dinode *di, 119static int ocfs2_verify_volume(struct ocfs2_dinode *di,
120 struct buffer_head *bh, 120 struct buffer_head *bh,
121 u32 sectsize); 121 u32 sectsize,
122 struct ocfs2_blockcheck_stats *stats);
122static int ocfs2_initialize_super(struct super_block *sb, 123static int ocfs2_initialize_super(struct super_block *sb,
123 struct buffer_head *bh, 124 struct buffer_head *bh,
124 int sector_size); 125 int sector_size,
126 struct ocfs2_blockcheck_stats *stats);
125static int ocfs2_get_sector(struct super_block *sb, 127static int ocfs2_get_sector(struct super_block *sb,
126 struct buffer_head **bh, 128 struct buffer_head **bh,
127 int block, 129 int block,
@@ -711,7 +713,8 @@ out:
711 713
712static int ocfs2_sb_probe(struct super_block *sb, 714static int ocfs2_sb_probe(struct super_block *sb,
713 struct buffer_head **bh, 715 struct buffer_head **bh,
714 int *sector_size) 716 int *sector_size,
717 struct ocfs2_blockcheck_stats *stats)
715{ 718{
716 int status, tmpstat; 719 int status, tmpstat;
717 struct ocfs1_vol_disk_hdr *hdr; 720 struct ocfs1_vol_disk_hdr *hdr;
@@ -777,7 +780,8 @@ static int ocfs2_sb_probe(struct super_block *sb,
777 goto bail; 780 goto bail;
778 } 781 }
779 di = (struct ocfs2_dinode *) (*bh)->b_data; 782 di = (struct ocfs2_dinode *) (*bh)->b_data;
780 status = ocfs2_verify_volume(di, *bh, blksize); 783 memset(stats, 0, sizeof(struct ocfs2_blockcheck_stats));
784 status = ocfs2_verify_volume(di, *bh, blksize, stats);
781 if (status >= 0) 785 if (status >= 0)
782 goto bail; 786 goto bail;
783 brelse(*bh); 787 brelse(*bh);
@@ -983,6 +987,7 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
983 struct ocfs2_super *osb = NULL; 987 struct ocfs2_super *osb = NULL;
984 struct buffer_head *bh = NULL; 988 struct buffer_head *bh = NULL;
985 char nodestr[8]; 989 char nodestr[8];
990 struct ocfs2_blockcheck_stats stats;
986 991
987 mlog_entry("%p, %p, %i", sb, data, silent); 992 mlog_entry("%p, %p, %i", sb, data, silent);
988 993
@@ -992,13 +997,13 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
992 } 997 }
993 998
994 /* probe for superblock */ 999 /* probe for superblock */
995 status = ocfs2_sb_probe(sb, &bh, &sector_size); 1000 status = ocfs2_sb_probe(sb, &bh, &sector_size, &stats);
996 if (status < 0) { 1001 if (status < 0) {
997 mlog(ML_ERROR, "superblock probe failed!\n"); 1002 mlog(ML_ERROR, "superblock probe failed!\n");
998 goto read_super_error; 1003 goto read_super_error;
999 } 1004 }
1000 1005
1001 status = ocfs2_initialize_super(sb, bh, sector_size); 1006 status = ocfs2_initialize_super(sb, bh, sector_size, &stats);
1002 osb = OCFS2_SB(sb); 1007 osb = OCFS2_SB(sb);
1003 if (status < 0) { 1008 if (status < 0) {
1004 mlog_errno(status); 1009 mlog_errno(status);
@@ -1108,6 +1113,18 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
1108 goto read_super_error; 1113 goto read_super_error;
1109 } 1114 }
1110 1115
1116 if (ocfs2_meta_ecc(osb)) {
1117 status = ocfs2_blockcheck_stats_debugfs_install(
1118 &osb->osb_ecc_stats,
1119 osb->osb_debug_root);
1120 if (status) {
1121 mlog(ML_ERROR,
1122 "Unable to create blockcheck statistics "
1123 "files\n");
1124 goto read_super_error;
1125 }
1126 }
1127
1111 status = ocfs2_mount_volume(sb); 1128 status = ocfs2_mount_volume(sb);
1112 if (osb->root_inode) 1129 if (osb->root_inode)
1113 inode = igrab(osb->root_inode); 1130 inode = igrab(osb->root_inode);
@@ -1849,6 +1866,7 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err)
1849 if (osb->cconn) 1866 if (osb->cconn)
1850 ocfs2_dlm_shutdown(osb, hangup_needed); 1867 ocfs2_dlm_shutdown(osb, hangup_needed);
1851 1868
1869 ocfs2_blockcheck_stats_debugfs_remove(&osb->osb_ecc_stats);
1852 debugfs_remove(osb->osb_debug_root); 1870 debugfs_remove(osb->osb_debug_root);
1853 1871
1854 if (hangup_needed) 1872 if (hangup_needed)
@@ -1896,7 +1914,8 @@ static int ocfs2_setup_osb_uuid(struct ocfs2_super *osb, const unsigned char *uu
1896 1914
1897static int ocfs2_initialize_super(struct super_block *sb, 1915static int ocfs2_initialize_super(struct super_block *sb,
1898 struct buffer_head *bh, 1916 struct buffer_head *bh,
1899 int sector_size) 1917 int sector_size,
1918 struct ocfs2_blockcheck_stats *stats)
1900{ 1919{
1901 int status; 1920 int status;
1902 int i, cbits, bbits; 1921 int i, cbits, bbits;
@@ -1955,6 +1974,9 @@ static int ocfs2_initialize_super(struct super_block *sb,
1955 atomic_set(&osb->alloc_stats.bg_allocs, 0); 1974 atomic_set(&osb->alloc_stats.bg_allocs, 0);
1956 atomic_set(&osb->alloc_stats.bg_extends, 0); 1975 atomic_set(&osb->alloc_stats.bg_extends, 0);
1957 1976
1977 /* Copy the blockcheck stats from the superblock probe */
1978 osb->osb_ecc_stats = *stats;
1979
1958 ocfs2_init_node_maps(osb); 1980 ocfs2_init_node_maps(osb);
1959 1981
1960 snprintf(osb->dev_str, sizeof(osb->dev_str), "%u,%u", 1982 snprintf(osb->dev_str, sizeof(osb->dev_str), "%u,%u",
@@ -2192,7 +2214,8 @@ bail:
2192 */ 2214 */
2193static int ocfs2_verify_volume(struct ocfs2_dinode *di, 2215static int ocfs2_verify_volume(struct ocfs2_dinode *di,
2194 struct buffer_head *bh, 2216 struct buffer_head *bh,
2195 u32 blksz) 2217 u32 blksz,
2218 struct ocfs2_blockcheck_stats *stats)
2196{ 2219{
2197 int status = -EAGAIN; 2220 int status = -EAGAIN;
2198 2221
@@ -2205,7 +2228,8 @@ static int ocfs2_verify_volume(struct ocfs2_dinode *di,
2205 OCFS2_FEATURE_INCOMPAT_META_ECC) { 2228 OCFS2_FEATURE_INCOMPAT_META_ECC) {
2206 status = ocfs2_block_check_validate(bh->b_data, 2229 status = ocfs2_block_check_validate(bh->b_data,
2207 bh->b_size, 2230 bh->b_size,
2208 &di->i_check); 2231 &di->i_check,
2232 stats);
2209 if (status) 2233 if (status)
2210 goto out; 2234 goto out;
2211 } 2235 }