cluster: RHEL6 - fsck.gfs2: don't invalidate files with duplicate data block refs
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=7e2edea6c24...
Commit: 7e2edea6c24a396abd88ea92e8cc405f5f03cf82
Parent: dcbe98785dec9af82e198175016197044b03d19d
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Wed Apr 3 09:28:09 2013 -0700
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri May 17 15:29:10 2013 -0500
fsck.gfs2: don't invalidate files with duplicate data block refs
Before this patch, whenever pass1 encountered a duplicated data block
pointer, it would mark the file as invalid. But if reason the block
was duplicated was due to a different bad inode, the inode with the
valid data block reference was still punished and deleted.
This patch adds an additional check to see if the previous reference
to the data block was as a _valid_ metadata block. If the previous
reference was as metadata, and the metadata checked out okay, then
it can't possibly be a data block for the second reference. In that
case, we know for a fact that the second reference is invalid. But
if the previous reference was also as data, the inode might be okay
and duplicate resolving in pass1b might sort it out and leave this
inode as the only valid reference. In that case, we should treat the
inode as valid, not invalid. So this patch basically treats duplicate
data block references as "innocent until proven guilty" rather than
just the opposite.
rhbz#902920
---
gfs2/fsck/pass1.c | 20 +++++++++++++++++---
1 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index ffa36b9..564f75d 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -424,18 +424,32 @@ static int check_data(struct gfs2_inode *ip, uint64_t metablock,
log_err(_("from metadata block %llu (0x%llx)\n"),
(unsigned long long)metablock,
(unsigned long long)metablock);
-
+
+ if (q >= gfs2_indir_blk && q <= gfs2_jdata) {
+ log_info(_("The block was processed earlier as valid "
+ "metadata, so it can't possibly be "
+ "data.\n"));
+ /* We still need to add a duplicate record here because
+ when check_metatree tries to delete the inode, we
+ can't have the "undo" functions freeing the block
+ out from other the original referencing inode. */
+ add_duplicate_ref(ip, block, ref_as_data, 0,
+ INODE_VALID);
+ return 1;
+ }
if (q != gfs2_meta_inval) {
log_info( _("Seems to be a normal duplicate; I'll "
"sort it out in pass1b.\n"));
add_duplicate_ref(ip, block, ref_as_data, 0,
INODE_VALID);
- return 1;
+ /* This inode references the block as data. So if this
+ all is validated, we want to keep this count. */
+ return 0;
}
log_info( _("The block was invalid as metadata but might be "
"okay as data. I'll sort it out in pass1b.\n"));
add_duplicate_ref(ip, block, ref_as_data, 0, INODE_VALID);
- return 1;
+ return 0;
}
/* In gfs1, rgrp indirect blocks are marked in the bitmap as "meta".
In gfs2, "meta" is only for dinodes. So here we dummy up the
10 years, 11 months
cluster: RHEL6 - fsck.gfs2: standardize check_metatree return codes
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=dcbe98785de...
Commit: dcbe98785dec9af82e198175016197044b03d19d
Parent: f4ebc1f1534ea1c3ba413dadb971d1e7063bde67
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Wed Apr 3 08:55:00 2013 -0700
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri May 17 15:29:05 2013 -0500
fsck.gfs2: standardize check_metatree return codes
This patch aims to not change functionality at all. What it does is
adds a standard set of three return codes with the following meanings:
meta_is_good - all is well, keep processing metadata normally
meta_skip_further - an non-fatal error occurred, so further metadata
processing for this inode should be skipped.
meta_error - a fatal error occurred in this metadata, so we need to
abort processing.
rhbz#902920
---
gfs2/fsck/metawalk.c | 14 +++++++-------
gfs2/fsck/metawalk.h | 6 ++++++
gfs2/fsck/pass1.c | 28 ++++++++++++++--------------
gfs2/fsck/pass1b.c | 6 +++---
gfs2/fsck/util.c | 12 ++++++------
5 files changed, 36 insertions(+), 30 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index a9fce81..7ce8524 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -994,9 +994,9 @@ int free_block_if_notdup(struct gfs2_inode *ip, uint64_t block,
{
if (!find_remove_dup(ip, block, btype)) { /* not a dup */
fsck_blockmap_set(ip, block, btype, gfs2_block_free);
- return 1;
+ return meta_skip_further;
}
- return 0;
+ return meta_is_good;
}
/**
@@ -1013,7 +1013,7 @@ static int delete_block_if_notdup(struct gfs2_inode *ip, uint64_t block,
uint8_t q;
if (!valid_block(ip->i_sbd, block))
- return -EFAULT;
+ return meta_error;
q = block_type(block);
if (q == gfs2_block_free) {
@@ -1023,7 +1023,7 @@ static int delete_block_if_notdup(struct gfs2_inode *ip, uint64_t block,
(unsigned long long)block,
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
- return 0;
+ return meta_is_good;
}
return free_block_if_notdup(ip, block, btype);
}
@@ -1253,12 +1253,12 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
pass->private);
/* check_metalist should hold any buffers
it gets with "bread". */
- if (err < 0) {
+ if (err == meta_error) {
stack;
error = err;
return error;
}
- if (err > 0) {
+ if (err == meta_skip_further) {
if (!error)
error = err;
log_debug( _("Skipping block %llu (0x%llx)\n"),
@@ -1658,7 +1658,7 @@ static int alloc_metalist(struct gfs2_inode *ip, uint64_t block,
(unsigned long long)block);
gfs2_blockmap_set(bl, block, gfs2_indir_blk);
}
- return 0;
+ return meta_is_good;
}
static int alloc_data(struct gfs2_inode *ip, uint64_t metablock,
diff --git a/gfs2/fsck/metawalk.h b/gfs2/fsck/metawalk.h
index 2ba0d72..49217cc 100644
--- a/gfs2/fsck/metawalk.h
+++ b/gfs2/fsck/metawalk.h
@@ -56,6 +56,12 @@ extern int free_block_if_notdup(struct gfs2_inode *ip, uint64_t block,
#define fsck_blockmap_set(ip, b, bt, m) _fsck_blockmap_set(ip, b, bt, m, \
__FUNCTION__, __LINE__)
+enum meta_check_rc {
+ meta_error = -1,
+ meta_is_good = 0,
+ meta_skip_further = 1,
+};
+
/* metawalk_fxns: function pointers to check various parts of the fs
*
* The functions should return -1 on fatal errors, 1 if the block
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index 0cf4373..ffa36b9 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -138,14 +138,14 @@ static int resuscitate_metalist(struct gfs2_inode *ip, uint64_t block,
"range) found in system inode %lld (0x%llx).\n"),
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
- return 1;
+ return meta_skip_further;
}
if (fsck_system_inode(ip->i_sbd, block))
fsck_blockmap_set(ip, block, _("system file"), gfs2_indir_blk);
else
check_n_fix_bitmap(ip->i_sbd, block, gfs2_indir_blk);
bc->indir_count++;
- return 0;
+ return meta_is_good;
}
/*
@@ -262,7 +262,7 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
- return 1;
+ return meta_skip_further;
}
if (is_dir(&ip->i_di, ip->i_sbd->gfs1) && h == ip->i_di.di_height) {
iblk_type = GFS2_METATYPE_JD;
@@ -299,7 +299,7 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
gfs2_meta_inval);
brelse(nbh);
nbh = NULL;
- return 1;
+ return meta_skip_further;
}
brelse(nbh);
nbh = NULL;
@@ -313,12 +313,12 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
nbh = NULL;
*bh = NULL;
}
- return 1; /* don't process the metadata again */
+ return meta_skip_further; /* don't process the metadata again */
} else
fsck_blockmap_set(ip, block, _("indirect"),
gfs2_indir_blk);
- return 0;
+ return meta_is_good;
}
/* undo_reference - undo previously processed data or metadata
@@ -824,7 +824,7 @@ static int mark_block_invalid(struct gfs2_inode *ip, uint64_t block,
* and as a result, they'll be freed when this dinode is deleted,
* despite being used by another dinode as a valid block. */
if (!valid_block(ip->i_sbd, block))
- return 0;
+ return meta_is_good;
q = block_type(block);
if (q != gfs2_block_free) {
@@ -836,10 +836,10 @@ static int mark_block_invalid(struct gfs2_inode *ip, uint64_t block,
(unsigned long long)block,
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
- return 0;
+ return meta_is_good;
}
fsck_blockmap_set(ip, block, btype, gfs2_meta_inval);
- return 0;
+ return meta_is_good;
}
static int invalidate_metadata(struct gfs2_inode *ip, uint64_t block,
@@ -909,9 +909,9 @@ static int rangecheck_block(struct gfs2_inode *ip, uint64_t block,
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
if ((*bad_pointers) <= BAD_POINTER_TOLERANCE)
- return ENOENT;
+ return meta_skip_further;
else
- return -ENOENT; /* Exits check_metatree quicker */
+ return meta_error; /* Exits check_metatree quicker */
}
/* See how many duplicate blocks it has */
q = block_type(block);
@@ -924,11 +924,11 @@ static int rangecheck_block(struct gfs2_inode *ip, uint64_t block,
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
if ((*bad_pointers) <= BAD_POINTER_TOLERANCE)
- return ENOENT;
+ return meta_skip_further;
else
- return -ENOENT; /* Exits check_metatree quicker */
+ return meta_error; /* Exits check_metatree quicker */
}
- return 0;
+ return meta_is_good;
}
static int rangecheck_metadata(struct gfs2_inode *ip, uint64_t block,
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index 7680bc1..03e47ec 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -213,7 +213,7 @@ static int clear_dup_metalist(struct gfs2_inode *ip, uint64_t block,
struct duptree *dt;
if (!valid_block(ip->i_sbd, block))
- return 0;
+ return meta_is_good;
/* This gets tricky. We're traversing a metadata tree trying to
delete an inode based on it having a duplicate block reference
@@ -229,7 +229,7 @@ static int clear_dup_metalist(struct gfs2_inode *ip, uint64_t block,
if (!dt) {
fsck_blockmap_set(ip, block, _("no longer valid"),
gfs2_block_free);
- return 0;
+ return meta_is_good;
}
/* This block, having failed the above test, is duplicated somewhere */
if (block == dh->dt->block) {
@@ -251,7 +251,7 @@ static int clear_dup_metalist(struct gfs2_inode *ip, uint64_t block,
be mistakenly freed as "no longer valid" (in this function above)
even though it's valid metadata for a different inode. Returning
1 ensures that the metadata isn't processed again. */
- return 1;
+ return meta_skip_further;
}
static int clear_dup_data(struct gfs2_inode *ip, uint64_t metablock,
diff --git a/gfs2/fsck/util.c b/gfs2/fsck/util.c
index 78d4e79..2111684 100644
--- a/gfs2/fsck/util.c
+++ b/gfs2/fsck/util.c
@@ -234,19 +234,19 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block,
struct duptree *dt;
if (!valid_block(ip->i_sbd, block))
- return 0;
+ return meta_is_good;
/* If this is not the first reference (i.e. all calls from pass1) we
need to create the duplicate reference. If this is pass1b, we want
to ignore references that aren't found. */
dt = gfs2_dup_set(block, !first);
if (!dt) /* If this isn't a duplicate */
- return 0;
+ return meta_is_good;
/* If we found the duplicate reference but we've already discovered
the first reference (in pass1b) and the other references in pass1,
we don't need to count it, so just return. */
if (dt->first_ref_found)
- return 0;
+ return meta_is_good;
/* The first time this is called from pass1 is actually the second
reference. When we go back in pass1b looking for the original
@@ -268,12 +268,12 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block,
if (!(id = malloc(sizeof(*id)))) {
log_crit( _("Unable to allocate "
"inode_with_dups structure\n"));
- return -1;
+ return meta_error;
}
if (!(memset(id, 0, sizeof(*id)))) {
log_crit( _("Unable to zero inode_with_dups "
"structure\n"));
- return -1;
+ return meta_error;
}
id->block_no = ip->i_di.di_num.no_addr;
q = block_type(ip->i_di.di_num.no_addr);
@@ -307,7 +307,7 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block,
else
log_info( _("This brings the total to: %d duplicate "
"references\n"), dt->refs);
- return 0;
+ return meta_is_good;
}
struct dir_info *dirtree_insert(struct gfs2_inum inum)
10 years, 11 months
cluster: RHEL6 - fsck.gfs2 pass2: check leaf blocks when fixing hash table
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=f4ebc1f1534...
Commit: f4ebc1f1534ea1c3ba413dadb971d1e7063bde67
Parent: c525fe7e12a59d5e09491dd0de48eadbb56b6a75
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Wed Apr 3 07:25:00 2013 -0700
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri May 17 15:28:58 2013 -0500
fsck.gfs2 pass2: check leaf blocks when fixing hash table
Before this patch, pass2 would attempt to fix the hash table without
first checking the basic integrity of the leaf blocks it was checking.
A misplaced leaf might have its entries relocated as a matter of course.
But if that leaf block had a problem, it could cause all kinds of
errors, including segfaults. This patch gives the hash table repair
function the ability to do basic integrity checks on the leaf block,
and perform repairs if necessary.
rhbz#902920
---
gfs2/fsck/pass2.c | 100 +++++++++++++++++++++++++++++++++++++++++-----------
1 files changed, 79 insertions(+), 21 deletions(-)
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index 9f477b8..81d4710 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -1048,6 +1048,66 @@ static int lost_leaf(struct gfs2_inode *ip, uint64_t *tbl, uint64_t leafno,
return 1;
}
+static int basic_check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
+ struct gfs2_dirent *prev_de,
+ struct gfs2_buffer_head *bh, char *filename,
+ uint32_t *count, int lindex, void *priv)
+{
+ uint8_t q = 0;
+ char tmp_name[MAX_FILENAME];
+ struct gfs2_inum entry;
+ struct dir_status *ds = (struct dir_status *) priv;
+ struct gfs2_dirent dentry, *de;
+ int error;
+
+ memset(&dentry, 0, sizeof(struct gfs2_dirent));
+ gfs2_dirent_in(&dentry, (char *)dent);
+ de = &dentry;
+
+ entry.no_addr = de->de_inum.no_addr;
+ entry.no_formal_ino = de->de_inum.no_formal_ino;
+
+ /* Start of checks */
+ memset(tmp_name, 0, MAX_FILENAME);
+ if (de->de_name_len < MAX_FILENAME)
+ strncpy(tmp_name, filename, de->de_name_len);
+ else
+ strncpy(tmp_name, filename, MAX_FILENAME - 1);
+
+ error = basic_dentry_checks(ip, dent, &entry, tmp_name, count, de,
+ ds, &q, bh);
+ if (error) {
+ dirent2_del(ip, bh, prev_de, dent);
+ log_err( _("Bad directory entry '%s' cleared.\n"), tmp_name);
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static int pass2_repair_leaf(struct gfs2_inode *ip, uint64_t *leaf_no,
+ int lindex, int ref_count, const char *msg,
+ void *private)
+{
+ return repair_leaf(ip, leaf_no, lindex, ref_count, msg);
+}
+
+/* The purpose of leafck_fxns is to provide a means for function fix_hashtable
+ * to do basic sanity checks on leaf blocks before manipulating them, for
+ * example, splitting them. If they're corrupt, splitting them or trying to
+ * move their contents can cause a segfault. We can't really use the standard
+ * pass2_fxns because that will do things we don't want. For example, it will
+ * find '.' and '..' and increment the directory link count, which would be
+ * done a second time when the dirent is really checked in pass2_fxns.
+ * We don't want it to do the "wrong leaf" thing, or set_parent_dir either.
+ * We just want a basic sanity check on pointers and lengths.
+ */
+struct metawalk_fxns leafck_fxns = {
+ .check_leaf_depth = check_leaf_depth,
+ .check_dentry = basic_check_dentry,
+ .repair_leaf = pass2_repair_leaf,
+};
+
/* fix_hashtable - fix a corrupt hash table
*
* The main intent of this function is to sort out hash table problems.
@@ -1077,10 +1137,11 @@ static int fix_hashtable(struct gfs2_inode *ip, uint64_t *tbl, unsigned hsize,
int len, int *proper_len, int factor)
{
struct gfs2_buffer_head *lbh;
- struct gfs2_leaf *leaf;
+ struct gfs2_leaf leaf;
struct gfs2_dirent dentry, *de;
int changes = 0, error, i, extras, hash_index;
uint64_t new_leaf_blk;
+ uint64_t leaf_no;
uint32_t leaf_proper_start;
*proper_len = len;
@@ -1094,14 +1155,20 @@ static int fix_hashtable(struct gfs2_inode *ip, uint64_t *tbl, unsigned hsize,
return 0;
}
+ memset(&leaf, 0, sizeof(leaf));
+ leaf_no = leafblk;
+ error = check_leaf(ip, lindex, &leafck_fxns, &leaf_no, &leaf, &len);
+ if (error) {
+ log_debug("Leaf repaired while fixing the hash table.\n");
+ error = 0;
+ }
lbh = bread(ip->i_sbd, leafblk);
- leaf = (struct gfs2_leaf *)lbh->b_data;
/* If the leaf's depth is out of range for this dinode, it's obviously
attached to the wrong dinode. Move the dirents to lost+found. */
- if (be16_to_cpu(leaf->lf_depth) > ip->i_di.di_depth) {
+ if (leaf.lf_depth > ip->i_di.di_depth) {
log_err(_("This leaf block's depth (%d) is too big for this "
"dinode's depth (%d)\n"),
- be16_to_cpu(leaf->lf_depth), ip->i_di.di_depth);
+ leaf.lf_depth, ip->i_di.di_depth);
error = lost_leaf(ip, tbl, leafblk, len, lindex, lbh);
brelse(lbh);
return error;
@@ -1127,7 +1194,7 @@ static int fix_hashtable(struct gfs2_inode *ip, uint64_t *tbl, unsigned hsize,
}
/* Calculate the proper number of pointers based on the leaf depth. */
- *proper_len = 1 << (ip->i_di.di_depth - be16_to_cpu(leaf->lf_depth));
+ *proper_len = 1 << (ip->i_di.di_depth - leaf.lf_depth);
/* Look at the first dirent and check its hash value to see if it's
at the proper starting offset. */
@@ -1160,7 +1227,7 @@ static int fix_hashtable(struct gfs2_inode *ip, uint64_t *tbl, unsigned hsize,
already at its maximum depth. */
if ((leaf_proper_start < proper_start) ||
((*proper_len > len || lindex > leaf_proper_start) &&
- be16_to_cpu(leaf->lf_depth) == ip->i_di.di_depth)) {
+ leaf.lf_depth == ip->i_di.di_depth)) {
log_err(_("Leaf block should start at 0x%x, but it appears at "
"0x%x in the hash table.\n"), leaf_proper_start,
proper_start);
@@ -1175,24 +1242,22 @@ static int fix_hashtable(struct gfs2_inode *ip, uint64_t *tbl, unsigned hsize,
later than they should, we can split the leaf to give it a smaller
footprint in the hash table. */
if ((*proper_len > len || lindex > leaf_proper_start) &&
- ip->i_di.di_depth > be16_to_cpu(leaf->lf_depth)) {
+ ip->i_di.di_depth > leaf.lf_depth) {
log_err(_("For depth %d, length %d, the proper start is: "
"0x%x.\n"), factor, len, proper_start);
changes++;
new_leaf_blk = find_free_blk(ip->i_sbd);
dir_split_leaf(ip, lindex, leafblk, lbh);
/* re-read the leaf to pick up dir_split_leaf's changes */
- gfs2_leaf_in(leaf, lbh);
- *proper_len = 1 << (ip->i_di.di_depth -
- be16_to_cpu(leaf->lf_depth));
+ gfs2_leaf_in(&leaf, lbh);
+ *proper_len = 1 << (ip->i_di.di_depth - leaf.lf_depth);
log_err(_("Leaf block %llu (0x%llx) was split from length "
"%d to %d\n"), (unsigned long long)leafblk,
(unsigned long long)leafblk, len, *proper_len);
if (*proper_len < 0) {
log_err(_("Programming error: proper_len=%d, "
"di_depth = %d, lf_depth = %d.\n"),
- *proper_len, ip->i_di.di_depth,
- be16_to_cpu(leaf->lf_depth));
+ *proper_len, ip->i_di.di_depth, leaf.lf_depth);
exit(FSCK_ERROR);
}
log_err(_("New split-off leaf block was allocated at %lld "
@@ -1217,8 +1282,8 @@ static int fix_hashtable(struct gfs2_inode *ip, uint64_t *tbl, unsigned hsize,
if (*proper_len < len) {
log_err(_("There are %d pointers, but leaf 0x%llx's "
"depth, %d, only allows %d\n"),
- len, (unsigned long long)leafblk,
- be16_to_cpu(leaf->lf_depth), *proper_len);
+ len, (unsigned long long)leafblk, leaf.lf_depth,
+ *proper_len);
}
brelse(lbh);
/* At this point, lindex should be at the proper end of the pointers.
@@ -1420,13 +1485,6 @@ static int check_hash_tbl(struct gfs2_inode *ip, uint64_t *tbl,
return error;
}
-static int pass2_repair_leaf(struct gfs2_inode *ip, uint64_t *leaf_no,
- int lindex, int ref_count, const char *msg,
- void *private)
-{
- return repair_leaf(ip, leaf_no, lindex, ref_count, msg);
-}
-
struct metawalk_fxns pass2_fxns = {
.private = NULL,
.check_leaf_depth = check_leaf_depth,
10 years, 11 months
cluster: RHEL6 - fsck.gfs2: externalize check_leaf
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=c525fe7e12a...
Commit: c525fe7e12a59d5e09491dd0de48eadbb56b6a75
Parent: 54904ce52d5658debffe92d8f1cdc5ab15ce96c3
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Wed Apr 3 07:13:52 2013 -0700
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri May 17 15:28:27 2013 -0500
fsck.gfs2: externalize check_leaf
This patch makes metawalk function check_leaf external so that it
may be called in a future patch for fixing hash tables.
rhbz#902920
---
gfs2/fsck/metawalk.c | 5 ++---
gfs2/fsck/metawalk.h | 3 +++
gfs2/fsck/pass1.c | 6 +++---
gfs2/fsck/pass1b.c | 6 +++---
4 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 16ddb97..a9fce81 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -481,9 +481,8 @@ static int check_entries(struct gfs2_inode *ip, struct gfs2_buffer_head *bh,
* Reads in the leaf block
* Leaves the buffer around for further analysis (caller must brelse)
*/
-static int check_leaf(struct gfs2_inode *ip, int lindex,
- struct metawalk_fxns *pass,
- uint64_t *leaf_no, struct gfs2_leaf *leaf, int *ref_count)
+int check_leaf(struct gfs2_inode *ip, int lindex, struct metawalk_fxns *pass,
+ uint64_t *leaf_no, struct gfs2_leaf *leaf, int *ref_count)
{
int error = 0, fix;
struct gfs2_buffer_head *lbh = NULL;
diff --git a/gfs2/fsck/metawalk.h b/gfs2/fsck/metawalk.h
index 05b0e7a..2ba0d72 100644
--- a/gfs2/fsck/metawalk.h
+++ b/gfs2/fsck/metawalk.h
@@ -15,6 +15,9 @@ extern int check_dir(struct gfs2_sbd *sdp, uint64_t block,
struct metawalk_fxns *pass);
extern int check_linear_dir(struct gfs2_inode *ip, struct gfs2_buffer_head *bh,
struct metawalk_fxns *pass);
+extern int check_leaf(struct gfs2_inode *ip, int lindex,
+ struct metawalk_fxns *pass, uint64_t *leaf_no,
+ struct gfs2_leaf *leaf, int *ref_count);
extern int remove_dentry_from_dir(struct gfs2_sbd *sdp, uint64_t dir,
uint64_t dentryblock);
extern int delete_block(struct gfs2_inode *ip, uint64_t block,
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index e10e4ce..0cf4373 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -34,7 +34,7 @@ struct block_count {
uint64_t ea_count;
};
-static int check_leaf(struct gfs2_inode *ip, uint64_t block, void *private);
+static int p1check_leaf(struct gfs2_inode *ip, uint64_t block, void *private);
static int check_metalist(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head **bh, int h, void *private);
static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
@@ -92,7 +92,7 @@ static int pass1_repair_leaf(struct gfs2_inode *ip, uint64_t *leaf_no,
struct metawalk_fxns pass1_fxns = {
.private = NULL,
- .check_leaf = check_leaf,
+ .check_leaf = p1check_leaf,
.check_metalist = check_metalist,
.check_data = check_data,
.check_eattr_indir = check_eattr_indir,
@@ -210,7 +210,7 @@ struct metawalk_fxns sysdir_fxns = {
.check_dentry = resuscitate_dentry,
};
-static int check_leaf(struct gfs2_inode *ip, uint64_t block, void *private)
+static int p1check_leaf(struct gfs2_inode *ip, uint64_t block, void *private)
{
struct block_count *bc = (struct block_count *) private;
uint8_t q;
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index d873aa6..7680bc1 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -26,7 +26,7 @@ struct dup_handler {
int ref_count;
};
-static int check_leaf(struct gfs2_inode *ip, uint64_t block, void *private);
+static int check_leaf_refs(struct gfs2_inode *ip, uint64_t block, void *private);
static int check_metalist(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head **bh, int h, void *private);
static int check_data(struct gfs2_inode *ip, uint64_t metablock,
@@ -54,7 +54,7 @@ static int find_dentry(struct gfs2_inode *ip, struct gfs2_dirent *de,
struct metawalk_fxns find_refs = {
.private = NULL,
- .check_leaf = check_leaf,
+ .check_leaf = check_leaf_refs,
.check_metalist = check_metalist,
.check_data = check_data,
.check_eattr_indir = check_eattr_indir,
@@ -76,7 +76,7 @@ struct metawalk_fxns find_dirents = {
.check_eattr_extentry = NULL,
};
-static int check_leaf(struct gfs2_inode *ip, uint64_t block, void *private)
+static int check_leaf_refs(struct gfs2_inode *ip, uint64_t block, void *private)
{
return add_duplicate_ref(ip, block, ref_as_meta, 1, INODE_VALID);
}
10 years, 11 months
cluster: RHEL6 - fsck.gfs2: Don't flag GFS1 non-dinode blocks as duplicates
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=54904ce52d5...
Commit: 54904ce52d5658debffe92d8f1cdc5ab15ce96c3
Parent: 84d59ca4ac7e0c1479c5a9718f622bcbcbd09adb
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Tue Apr 2 13:19:35 2013 -0700
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri May 17 15:28:04 2013 -0500
fsck.gfs2: Don't flag GFS1 non-dinode blocks as duplicates
Before this patch, fsck.gfs2 could get into problems when processing
a GFS1 file system. The issue goes back to the fact that all GFS1
metadata is marked as "Meta" in the bitmap, whereas that bitmap
designation is reserved for dinodes in GFS2. For example, take a
GFS1 file of height 2, which looks like this:
Block
------
0x1234 dinode
0x1235 |----> indirect meta
0x1236 |---->data at offset 0 of the file
Before this patch, fsck.gfs2 would:
1. Encounter the dinode at 0x1234 and mark it as "dinode" in the
blockmap.
2. Process its metadata, see block 0x1235, mark it as "indirect meta"
in the blockmap.
3. Process the metadata's data, see block 0x1236, mark it as "data".
4. When it's done with the dinode, it moves on to the next dinode.
But since GFS1 doesn't distinguish dinodes from other metadata,
the next block in the bitmap that has that designation is block
0x1235.
5. Since block 0x1235 was previously marked "indirect meta" pass1
gets confused and thinks the block is a duplicate reference,
and it's invalid as a dinode. This is a non-problem that's
treated as a problem, and it makes bad decisions based on it,
deleting what it perceives to be corruption.
This patch adds special checks for this problem and assumes the block
is just normal GFS1 non-dinode metadata.
rhbz#902920
---
gfs2/fsck/pass1.c | 89 +++++++++++++++++++++++++++++++++-------------------
1 files changed, 56 insertions(+), 33 deletions(-)
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index 90b865f..e10e4ce 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -1083,22 +1083,11 @@ bad_dinode:
*/
static int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh)
{
- uint8_t q;
int error = 0;
uint64_t block = bh->b_blocknr;
struct gfs2_inode *ip;
ip = fsck_inode_get(sdp, bh);
- q = block_type(block);
- if (q != gfs2_block_free) {
- log_err( _("Found a duplicate inode block at #%llu"
- " (0x%llx) previously marked as a %s\n"),
- (unsigned long long)block,
- (unsigned long long)block, block_type_string(q));
- add_duplicate_ref(ip, block, ref_as_meta, 0, INODE_VALID);
- fsck_inode_put(&ip);
- return 0;
- }
if (ip->i_di.di_num.no_addr != block) {
log_err( _("Inode #%llu (0x%llx): Bad inode address found: %llu "
@@ -1367,11 +1356,13 @@ int pass1(struct gfs2_sbd *sdp)
{
struct osi_node *n, *next = NULL;
struct gfs2_buffer_head *bh;
+ struct gfs2_inode *ip;
uint64_t block = 0;
struct rgrp_tree *rgd;
int first;
uint64_t i;
uint64_t rg_count = 0;
+ uint8_t q;
osi_list_init(&gfs1_rindex_blks.list);
@@ -1417,6 +1408,9 @@ int pass1(struct gfs2_sbd *sdp)
first = 1;
while (1) {
+ int is_inode;
+ uint32_t check_magic;
+
/* "block" is relative to the entire file system */
/* Get the next dinode in the file system, according
to the bitmap. This should ONLY be dinodes unless
@@ -1451,12 +1445,55 @@ int pass1(struct gfs2_sbd *sdp)
first = 0;
continue;
}
+
bh = bread(sdp, block);
+ is_inode = 0;
+ if (gfs2_check_meta(bh, GFS2_METATYPE_DI) == 0)
+ is_inode = 1;
+
+ check_magic = ((struct gfs2_meta_header *)
+ (bh->b_data))->mh_magic;
+
+ q = block_type(block);
+ if (q != gfs2_block_free) {
+ if (be32_to_cpu(check_magic) == GFS2_MAGIC &&
+ sdp->gfs1 && !is_inode) {
+ log_debug("Block 0x%llx assumed to be "
+ "previously processed GFS1 "
+ "non-dinode metadata.\n",
+ (unsigned long long)block);
+ brelse(bh);
+ first = 0;
+ continue;
+ }
+ log_err( _("Found a duplicate inode block at "
+ "#%llu (0x%llx) previously marked "
+ "as a %s\n"),
+ (unsigned long long)block,
+ (unsigned long long)block,
+ block_type_string(q));
+ ip = fsck_inode_get(sdp, bh);
+ if (is_inode &&
+ ip->i_di.di_num.no_addr == block)
+ add_duplicate_ref(ip, block,
+ ref_is_inode, 0,
+ INODE_VALID);
+ else
+ log_info(_("dinum.no_addr is wrong, "
+ "so I assume the bitmap is "
+ "just wrong.\n"));
+ fsck_inode_put(&ip);
+ brelse(bh);
+ first = 0;
+ continue;
+ }
+
/*log_debug( _("Checking metadata block #%" PRIu64
" (0x%" PRIx64 ")\n"), block, block);*/
- if (gfs2_check_meta(bh, GFS2_METATYPE_DI)) {
+ if (!is_inode) {
+ if (be32_to_cpu(check_magic) == GFS2_MAGIC) {
/* In gfs2, a bitmap mark of 2 means an inode,
but in gfs1 it means any metadata. So if
this is gfs1 and not an inode, it may be
@@ -1464,14 +1501,7 @@ int pass1(struct gfs2_sbd *sdp)
be referenced by an inode, so we need to
skip it here and it will be sorted out
when the referencing inode is checked. */
- if (sdp->gfs1) {
- uint32_t check_magic;
-
- check_magic = ((struct
- gfs2_meta_header *)
- (bh->b_data))->mh_magic;
- if (be32_to_cpu(check_magic) ==
- GFS2_MAGIC) {
+ if (sdp->gfs1) {
log_debug( _("Deferring GFS1 "
"metadata block #"
"%" PRIu64" (0x%"
@@ -1481,20 +1511,13 @@ int pass1(struct gfs2_sbd *sdp)
first = 0;
continue;
}
+ log_err( _("Found invalid inode at "
+ "block #%llu (0x%llx)\n"),
+ (unsigned long long)block,
+ (unsigned long long)block);
+ check_n_fix_bitmap(sdp, block,
+ gfs2_block_free);
}
- log_err( _("Found invalid inode at block #"
- "%llu (0x%llx)\n"),
- (unsigned long long)block,
- (unsigned long long)block);
- if (gfs2_blockmap_set(bl, block,
- gfs2_block_free)) {
- stack;
- brelse(bh);
- gfs2_special_free(&gfs1_rindex_blks);
- return FSCK_ERROR;
- }
- check_n_fix_bitmap(sdp, block,
- gfs2_block_free);
} else if (handle_di(sdp, bh) < 0) {
stack;
brelse(bh);
10 years, 11 months
cluster: RHEL6 - fsck.gfs2: don't remove buffers from the list when errors are found
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=84d59ca4ac7...
Commit: 84d59ca4ac7e0c1479c5a9718f622bcbcbd09adb
Parent: 6839b4acd056e8267b4fb1872e3d0783f49a4ef6
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Tue Apr 2 13:03:15 2013 -0700
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri May 17 15:27:55 2013 -0500
fsck.gfs2: don't remove buffers from the list when errors are found
Before this patch, if an error was encountered while marking the
data blocks, the blocks would be removed from the linked list.
Now that we've got "undo" functions, we need to be able to undo
the designations of those blocks, which means we need to keep those
buffers on the linked list so they're found later. If we don't,
the undo data block function won't process them, and therefore they'll
be marked as "data" blocks in the bitmap, but no files will reference
the blocks (because the error causes the inode to be deleted).
With this patch, the metadata that points to the faulty data is kept
on the linked list, and after the error is found, the undo function
will therefore find it and mark its blocks as "free".
rhbz#902920
---
gfs2/fsck/metawalk.c | 17 +++++------------
1 files changed, 5 insertions(+), 12 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 1cd377e..16ddb97 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -1381,7 +1381,7 @@ static int hdr_size(struct gfs2_buffer_head *bh, int height)
int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
{
osi_list_t metalist[GFS2_MAX_META_HEIGHT];
- osi_list_t *list;
+ osi_list_t *list, *tmp;
struct gfs2_buffer_head *bh;
uint32_t height = ip->i_di.di_height;
int i, head_size;
@@ -1421,23 +1421,16 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
if (ip->i_di.di_blocks > COMFORTABLE_BLKS)
last_reported_fblock = -10000000;
- while (!error && !osi_list_empty(list)) {
+ for (tmp = list->next; !error && tmp != list; tmp = tmp->next) {
if (fsck_abort) {
free_metalist(ip, &metalist[0]);
return 0;
}
- bh = osi_list_entry(list->next, struct gfs2_buffer_head,
- b_altlist);
-
+ bh = osi_list_entry(tmp, struct gfs2_buffer_head, b_altlist);
head_size = hdr_size(bh, height);
- if (!head_size) {
- if (bh == ip->i_bh)
- osi_list_del(&bh->b_altlist);
- else
- brelse(bh);
+ if (!head_size)
continue;
- }
-
+
if (pass->check_data)
error = check_data(ip, pass, bh, head_size,
&blks_checked);
10 years, 11 months
cluster: RHEL6 - fsck.gfs2: Log when unrecoverable data block errors are encountered
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=6839b4acd05...
Commit: 6839b4acd056e8267b4fb1872e3d0783f49a4ef6
Parent: 1db69f5d398482c2e121404c4376f6fb75031a70
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Tue Apr 2 12:59:16 2013 -0700
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri May 17 15:26:30 2013 -0500
fsck.gfs2: Log when unrecoverable data block errors are encountered
This patch adds a log message whenever unrecoverable data block errors
are found. Otherwise the output doesn't say why it stopped processing
data, and which block had the problem.
rhbz#902920
---
gfs2/fsck/metawalk.c | 9 +++++++--
1 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 9b6c391..1cd377e 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -1320,10 +1320,15 @@ static int check_data(struct gfs2_inode *ip, struct metawalk_fxns *pass,
pass1. Therefore the individual check_data functions
should do a range check. */
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,
+ (unsigned long long)block,
+ (unsigned long long)block);
+ }
if (rc < 0)
return rc;
- if (!error && rc)
- error = rc;
(*blks_checked)++;
}
return error;
10 years, 11 months
cluster: RHEL6 - fsck.gfs2: Do not invalidate metablocks of dinodes with invalid mode
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=1db69f5d398...
Commit: 1db69f5d398482c2e121404c4376f6fb75031a70
Parent: b178d9ade44ed9a8e8609920b96960d1e79f7c84
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Tue Apr 2 12:24:15 2013 -0700
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri May 17 15:26:20 2013 -0500
fsck.gfs2: Do not invalidate metablocks of dinodes with invalid mode
Before this patch, when fsck.gfs2 encountered a dinode with an invalid
mode, it would take steps to invalidate its metadata. That's wrong
because if the mode is invalid, you don't know how to treat it.
It's especially wrong if its metadata references the same blocks
that other valid dinodes reference, because then we could end up
deleting blocks belonging to valid files and directories.
rhbz#902920
---
gfs2/fsck/pass1.c | 25 ++++++++-----------------
1 files changed, 8 insertions(+), 17 deletions(-)
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index 92a8ff8..90b865f 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -1004,23 +1004,14 @@ static int handle_ip(struct gfs2_sbd *sdp, struct gfs2_inode *ip)
error = set_ip_blockmap(ip, 1);
if (error == -EINVAL) {
- /* We found a dinode that has an invalid mode, so we can't
- tell if it's a data file, directory or a socket.
- Regardless, we have to invalidate its metadata in case there
- are duplicate blocks referenced. If we don't call
- check_metatree, the blocks it references will be deleted
- wholesale by pass2, and if any of those blocks are
- duplicates--referenced by another dinode for some reason--
- we will mark it free, even though it's in use. In other
- words, we would introduce file system corruption. So we
- need to keep track of the fact that it's invalid and
- skip parts that we can't be sure of based on dinode type. */
- log_debug("Invalid mode dinode found at block %lld (0x%llx): "
- "Invalidating all its metadata.\n",
- (unsigned long long)ip->i_di.di_num.no_addr,
- (unsigned long long)ip->i_di.di_num.no_addr);
- check_metatree(ip, &invalidate_fxns);
- check_inode_eattr(ip, &invalidate_fxns);
+ /* We found a dinode that has an invalid mode. At this point
+ set_ip_blockmap returned an error, which means it never
+ got inserted into the inode tree. Since we haven't even
+ processed its metadata with pass1_fxns, none of its
+ metadata will be flagged as metadata or data blocks yet.
+ Therefore, we don't need to invalidate anything. */
+ fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
+ _("invalid mode"), gfs2_block_free);
return 0;
} else if (error)
goto bad_dinode;
10 years, 11 months
cluster: RHEL6 - fsck.gfs2: print block count values when fixing them
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=b178d9ade44...
Commit: b178d9ade44ed9a8e8609920b96960d1e79f7c84
Parent: d5a2afb07d27e1822f14d1dd3b33464a738fa6f6
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Tue Apr 2 11:50:31 2013 -0700
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri May 17 15:26:12 2013 -0500
fsck.gfs2: print block count values when fixing them
Before this patch, block counts were fixed, but it didn't log what
the new value was changed to. That made it very difficult to track
down block count problems. This patch changes the logging so that
it prints the new block count, and a breakdown of how many blocks
were counted for metadata, data, extended attributes, etc.
rhbz#902920
---
gfs2/fsck/pass1.c | 6 +++++-
1 files changed, 5 insertions(+), 1 deletions(-)
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index a4967a4..92a8ff8 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -612,7 +612,11 @@ static int finish_eattr_indir(struct gfs2_inode *ip, int leaf_pointers,
ip->i_di.di_blocks = 1 + bc->indir_count +
bc->data_count + bc->ea_count;
bmodified(ip->i_bh);
- log_err( _("Block count fixed.\n"));
+ log_err(_("Block count fixed: 1+%lld+%lld+%lld = %lld.\n"),
+ (unsigned long long)bc->indir_count,
+ (unsigned long long)bc->data_count,
+ (unsigned long long)bc->ea_count,
+ (unsigned long long)ip->i_di.di_blocks);
return 1;
}
log_err( _("Block count not fixed.\n"));
10 years, 11 months
cluster: RHEL6 - fsck.gfs2: print metadata block reference on data errors
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=d5a2afb07d2...
Commit: d5a2afb07d27e1822f14d1dd3b33464a738fa6f6
Parent: 15cc2f20f2a7003f74636b71611991e376007aa9
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Tue Apr 2 11:45:09 2013 -0700
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri May 17 15:25:52 2013 -0500
fsck.gfs2: print metadata block reference on data errors
Before this patch, fsck.gfs2 would cite data block errors, but it
wouldn't tell you which metadata block referenced the bad data block.
That's fine, but it makes it very difficult to backtrack problems.
This patch prints out which metadata block referenced the bad data
so it may be backtracked easier.
rhbz#902920
---
gfs2/fsck/metawalk.c | 17 ++++++++++-------
gfs2/fsck/metawalk.h | 7 ++++---
gfs2/fsck/pass1.c | 37 ++++++++++++++++++++++++++-----------
gfs2/fsck/pass1b.c | 9 ++++++---
4 files changed, 46 insertions(+), 24 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index c1c7bfb..9b6c391 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -1297,11 +1297,14 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
* 2 (ENOENT) is there were too many bad pointers
*/
static int check_data(struct gfs2_inode *ip, struct metawalk_fxns *pass,
- uint64_t *ptr_start, char *ptr_end,
+ struct gfs2_buffer_head *bh, int head_size,
uint64_t *blks_checked)
{
int error = 0, rc = 0;
uint64_t block, *ptr;
+ uint64_t *ptr_start = (uint64_t *)(bh->b_data + head_size);
+ char *ptr_end = (bh->b_data + ip->i_sbd->bsize);
+ uint64_t metablock = bh->b_blocknr;
/* If there isn't much pointer corruption check the pointers */
for (ptr = ptr_start ; (char *)ptr < ptr_end && !fsck_abort; ptr++) {
@@ -1316,7 +1319,7 @@ static int check_data(struct gfs2_inode *ip, struct metawalk_fxns *pass,
would defeat the rangecheck_block related functions in
pass1. Therefore the individual check_data functions
should do a range check. */
- rc = pass->check_data(ip, block, pass->private);
+ rc = pass->check_data(ip, metablock, block, pass->private);
if (rc < 0)
return rc;
if (!error && rc)
@@ -1431,9 +1434,7 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
}
if (pass->check_data)
- error = check_data(ip, pass, (uint64_t *)
- (bh->b_data + head_size),
- (bh->b_data + ip->i_sbd->bsize),
+ error = check_data(ip, pass, bh, head_size,
&blks_checked);
if (pass->big_file_msg && ip->i_di.di_blocks > COMFORTABLE_BLKS)
@@ -1601,7 +1602,8 @@ int delete_leaf(struct gfs2_inode *ip, uint64_t block, void *private)
return delete_block_if_notdup(ip, block, NULL, _("leaf"), private);
}
-int delete_data(struct gfs2_inode *ip, uint64_t block, void *private)
+int delete_data(struct gfs2_inode *ip, uint64_t metablock,
+ uint64_t block, void *private)
{
return delete_block_if_notdup(ip, block, NULL, _("data"), private);
}
@@ -1662,7 +1664,8 @@ static int alloc_metalist(struct gfs2_inode *ip, uint64_t block,
return 0;
}
-static int alloc_data(struct gfs2_inode *ip, uint64_t block, void *private)
+static int alloc_data(struct gfs2_inode *ip, uint64_t metablock,
+ uint64_t block, void *private)
{
uint8_t q;
const char *desc = (const char *)private;
diff --git a/gfs2/fsck/metawalk.h b/gfs2/fsck/metawalk.h
index f5e71e1..05b0e7a 100644
--- a/gfs2/fsck/metawalk.h
+++ b/gfs2/fsck/metawalk.h
@@ -23,7 +23,8 @@ extern int delete_block(struct gfs2_inode *ip, uint64_t block,
extern int delete_metadata(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head **bh, int h, void *private);
extern int delete_leaf(struct gfs2_inode *ip, uint64_t block, void *private);
-extern int delete_data(struct gfs2_inode *ip, uint64_t block, void *private);
+extern int delete_data(struct gfs2_inode *ip, uint64_t metablock,
+ uint64_t block, void *private);
extern int delete_eattr_indir(struct gfs2_inode *ip, uint64_t block, uint64_t parent,
struct gfs2_buffer_head **bh, void *private);
extern int delete_eattr_leaf(struct gfs2_inode *ip, uint64_t block, uint64_t parent,
@@ -76,8 +77,8 @@ struct metawalk_fxns {
int (*check_metalist) (struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head **bh, int h,
void *private);
- int (*check_data) (struct gfs2_inode *ip, uint64_t block,
- void *private);
+ int (*check_data) (struct gfs2_inode *ip, uint64_t metablock,
+ uint64_t block, void *private);
int (*check_eattr_indir) (struct gfs2_inode *ip, uint64_t block,
uint64_t parent,
struct gfs2_buffer_head **bh, void *private);
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index cdb1b46..a4967a4 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -39,7 +39,8 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head **bh, int h, void *private);
static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
int h, void *private);
-static int check_data(struct gfs2_inode *ip, uint64_t block, void *private);
+static int check_data(struct gfs2_inode *ip, uint64_t metablock,
+ uint64_t block, void *private);
static int undo_check_data(struct gfs2_inode *ip, uint64_t block,
void *private);
static int check_eattr_indir(struct gfs2_inode *ip, uint64_t indirect,
@@ -65,8 +66,8 @@ static int invalidate_metadata(struct gfs2_inode *ip, uint64_t block,
void *private);
static int invalidate_leaf(struct gfs2_inode *ip, uint64_t block,
void *private);
-static int invalidate_data(struct gfs2_inode *ip, uint64_t block,
- void *private);
+static int invalidate_data(struct gfs2_inode *ip, uint64_t metablock,
+ uint64_t block, void *private);
static int invalidate_eattr_indir(struct gfs2_inode *ip, uint64_t block,
uint64_t parent,
struct gfs2_buffer_head **bh,
@@ -381,17 +382,24 @@ static int undo_check_data(struct gfs2_inode *ip, uint64_t block,
return undo_reference(ip, block, 0, private);
}
-static int check_data(struct gfs2_inode *ip, uint64_t block, void *private)
+static int check_data(struct gfs2_inode *ip, uint64_t metablock,
+ uint64_t block, void *private)
{
uint8_t q;
struct block_count *bc = (struct block_count *) private;
if (!valid_block(ip->i_sbd, block)) {
log_err( _("inode %lld (0x%llx) has a bad data block pointer "
- "%lld (invalid or out of range)\n"),
+ "%lld (0x%llx) (invalid or out of range) "),
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr,
- (unsigned long long)block);
+ (unsigned long long)block, (unsigned long long)block);
+ if (metablock == ip->i_di.di_num.no_addr)
+ log_err("\n");
+ else
+ log_err(_("from metadata block %llu (0x%llx)\n"),
+ (unsigned long long)metablock,
+ (unsigned long long)metablock);
/* Mark the owner of this block with the bad_block
* designator so we know to check it for out of range
* blocks later */
@@ -404,12 +412,19 @@ static int check_data(struct gfs2_inode *ip, uint64_t block, void *private)
q = block_type(block);
if (q != gfs2_block_free) {
log_err( _("Found duplicate %s block %llu (0x%llx) "
- "referenced as data by dinode %llu (0x%llx)\n"),
+ "referenced as data by dinode %llu (0x%llx) "),
block_type_string(q),
(unsigned long long)block,
(unsigned long long)block,
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
+ if (metablock == ip->i_di.di_num.no_addr)
+ log_err("\n");
+ else
+ log_err(_("from metadata block %llu (0x%llx)\n"),
+ (unsigned long long)metablock,
+ (unsigned long long)metablock);
+
if (q != gfs2_meta_inval) {
log_info( _("Seems to be a normal duplicate; I'll "
"sort it out in pass1b.\n"));
@@ -836,8 +851,8 @@ static int invalidate_leaf(struct gfs2_inode *ip, uint64_t block,
return mark_block_invalid(ip, block, ref_as_meta, _("leaf"));
}
-static int invalidate_data(struct gfs2_inode *ip, uint64_t block,
- void *private)
+static int invalidate_data(struct gfs2_inode *ip, uint64_t metablock,
+ uint64_t block, void *private)
{
return mark_block_invalid(ip, block, ref_as_data, _("data"));
}
@@ -925,8 +940,8 @@ static int rangecheck_leaf(struct gfs2_inode *ip, uint64_t block,
return rangecheck_block(ip, block, NULL, btype_leaf, private);
}
-static int rangecheck_data(struct gfs2_inode *ip, uint64_t block,
- void *private)
+static int rangecheck_data(struct gfs2_inode *ip, uint64_t metablock,
+ uint64_t block, void *private)
{
return rangecheck_block(ip, block, NULL, btype_data, private);
}
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index 838b75e..d873aa6 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -29,7 +29,8 @@ struct dup_handler {
static int check_leaf(struct gfs2_inode *ip, uint64_t block, void *private);
static int check_metalist(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head **bh, int h, void *private);
-static int check_data(struct gfs2_inode *ip, uint64_t block, void *private);
+static int check_data(struct gfs2_inode *ip, uint64_t metablock,
+ uint64_t block, void *private);
static int check_eattr_indir(struct gfs2_inode *ip, uint64_t block,
uint64_t parent, struct gfs2_buffer_head **bh,
void *private);
@@ -86,7 +87,8 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
return add_duplicate_ref(ip, block, ref_as_meta, 1, INODE_VALID);
}
-static int check_data(struct gfs2_inode *ip, uint64_t block, void *private)
+static int check_data(struct gfs2_inode *ip, uint64_t metablock,
+ uint64_t block, void *private)
{
return add_duplicate_ref(ip, block, ref_as_data, 1, INODE_VALID);
}
@@ -252,7 +254,8 @@ static int clear_dup_metalist(struct gfs2_inode *ip, uint64_t block,
return 1;
}
-static int clear_dup_data(struct gfs2_inode *ip, uint64_t block, void *private)
+static int clear_dup_data(struct gfs2_inode *ip, uint64_t metablock,
+ uint64_t block, void *private)
{
return clear_dup_metalist(ip, block, NULL, 0, private);
}
10 years, 11 months