Gitweb:
http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=100e0e1961e...
Commit: 100e0e1961e7f26c72ae59b57f5c86873053eb2f
Parent: ed5f3f4009893b393817ac7c45189cd34bbbf429
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Fri Apr 12 08:31:30 2013 -0700
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri May 17 15:32:01 2013 -0500
fsck.gfs2: Stop "undo" process when error data block is reached
When fsck.gfs2 discovers a data block in error, it flags the error
and especially in pass1, it tries to "undo" the block designations
it previously marked in the blockmap. Before this patch, the "undo"
functions didn't know when to stop. So it could "undo" designations
in the blockmap that it hadn't "done" in the first place. With this
patch, if an error is encountered while processing data blocks
(not counting duplicate references--for example, blocks marked as
'data' that are really dinodes which it hasn't gotten to yet) it
saves off the block where the error occurred. Later, during the
"undo" processing, it stops when it reaches the block that flagged
the error.
rhbz#902920
---
gfs2/fsck/metawalk.c | 36 +++++++++++++++++++++++++++---------
gfs2/fsck/pass1.c | 2 +-
2 files changed, 28 insertions(+), 10 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index d3decd5..37b2d4b 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -1323,7 +1323,7 @@ static int build_and_check_metalist(struct gfs2_inode *ip,
osi_list_t *mlp,
*/
static int check_data(struct gfs2_inode *ip, struct metawalk_fxns *pass,
struct gfs2_buffer_head *bh, int head_size,
- uint64_t *blks_checked)
+ uint64_t *blks_checked, uint64_t *error_blk)
{
int error = 0, rc = 0;
uint64_t block, *ptr;
@@ -1347,8 +1347,13 @@ static int check_data(struct gfs2_inode *ip, struct metawalk_fxns
*pass,
rc = pass->check_data(ip, metablock, block, pass->private);
if (!error && rc) {
error = rc;
- log_info(_("\nUnrecoverable data block error %d on "
- "block %llu (0x%llx).\n"), rc,
+ log_info("\n");
+ if (rc < 0) {
+ *error_blk = block;
+ log_info(_("Unrecoverable "));
+ }
+ log_info(_("data block error %d on block %llu "
+ "(0x%llx).\n"), rc,
(unsigned long long)block,
(unsigned long long)block);
}
@@ -1360,7 +1365,8 @@ static int check_data(struct gfs2_inode *ip, struct metawalk_fxns
*pass,
}
static int undo_check_data(struct gfs2_inode *ip, struct metawalk_fxns *pass,
- uint64_t *ptr_start, char *ptr_end)
+ uint64_t *ptr_start, char *ptr_end,
+ uint64_t error_blk)
{
int rc = 0;
uint64_t block, *ptr;
@@ -1373,6 +1379,8 @@ static int undo_check_data(struct gfs2_inode *ip, struct
metawalk_fxns *pass,
if (skip_this_pass || fsck_abort)
return 1;
block = be64_to_cpu(*ptr);
+ if (block == error_blk)
+ return 1;
rc = pass->undo_check_data(ip, block, pass->private);
if (rc < 0)
return rc;
@@ -1413,6 +1421,8 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns
*pass)
uint64_t blks_checked = 0;
int error, rc;
int metadata_clean = 0;
+ uint64_t error_blk = 0;
+ int hit_error_blk = 0;
if (!height && !is_dir(&ip->i_di, ip->i_sbd->gfs1))
return 0;
@@ -1458,7 +1468,7 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns
*pass)
if (pass->check_data)
error = check_data(ip, pass, bh, head_size,
- &blks_checked);
+ &blks_checked, &error_blk);
if (pass->big_file_msg && ip->i_di.di_blocks > COMFORTABLE_BLKS)
pass->big_file_msg(ip, blks_checked);
@@ -1497,12 +1507,20 @@ undo_metalist:
i, pass->private);
else
rc = 0;
- if (metadata_clean && rc == 0 && i == height - 1) {
+ if (metadata_clean && rc == 0 && i == height - 1 &&
+ !hit_error_blk) {
head_size = hdr_size(bh, height);
- if (head_size)
- undo_check_data(ip, pass, (uint64_t *)
+ if (head_size) {
+ rc = undo_check_data(ip, pass,
+ (uint64_t *)
(bh->b_data + head_size),
- (bh->b_data + ip->i_sbd->bsize));
+ (bh->b_data + ip->i_sbd->bsize),
+ error_blk);
+ if (rc > 0) {
+ hit_error_blk = 1;
+ rc = 0;
+ }
+ }
}
if (bh == ip->i_bh)
osi_list_del(&bh->b_altlist);
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index fbeca0b..2355de2 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -461,7 +461,7 @@ static int check_data(struct gfs2_inode *ip, uint64_t metablock,
fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
_("bad (out of range) data"),
gfs2_bad_block);
- return 1;
+ return -1;
}
bc->data_count++; /* keep the count sane anyway */
q = block_type(block);