cluster: RHEL6 - fsck.gfs2: Keep proper counts when duplicates are found
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=15cc2f20f2a...
Commit: 15cc2f20f2a7003f74636b71611991e376007aa9
Parent: f7b8a81a21d93398873fd96dd3329f2e0b120e5b
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Tue Apr 2 11:14:55 2013 -0700
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri May 17 15:24:50 2013 -0500
fsck.gfs2: Keep proper counts when duplicates are found
When fsck.gfs2 discovered a duplicate reference to the same block,
it was not properly incrementing the block counters for data and
metadata. Therefore, when the duplicate situation is resolved, the
resulting dinode is likely to have the wrong block count. This patch
makes it increment the counters, regardless of whether the block is
a duplicate reference.
rhbz#902920
---
gfs2/fsck/pass1.c | 9 ++-------
1 files changed, 2 insertions(+), 7 deletions(-)
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index 05e7c68..cdb1b46 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -217,6 +217,7 @@ static int check_leaf(struct gfs2_inode *ip, uint64_t block, void *private)
/* Note if we've gotten this far, the block has already passed the
check in metawalk: gfs2_check_meta(lbh, GFS2_METATYPE_LF).
So we know it's a leaf block. */
+ bc->indir_count++;
q = block_type(block);
if (q != gfs2_block_free) {
log_err( _("Found duplicate block #%llu (0x%llx) referenced "
@@ -234,7 +235,6 @@ static int check_leaf(struct gfs2_inode *ip, uint64_t block, void *private)
return -EEXIST;
}
fsck_blockmap_set(ip, block, _("directory leaf"), gfs2_leaf_blk);
- bc->indir_count++;
return 0;
}
@@ -400,6 +400,7 @@ static int check_data(struct gfs2_inode *ip, uint64_t block, void *private)
gfs2_bad_block);
return 1;
}
+ bc->data_count++; /* keep the count sane anyway */
q = block_type(block);
if (q != gfs2_block_free) {
log_err( _("Found duplicate %s block %llu (0x%llx) "
@@ -414,16 +415,11 @@ static int check_data(struct gfs2_inode *ip, uint64_t block, void *private)
"sort it out in pass1b.\n"));
add_duplicate_ref(ip, block, ref_as_data, 0,
INODE_VALID);
- /* If the prev ref was as data, this is likely a data
- block, so keep the block count for both refs. */
- if (q == gfs2_block_used)
- bc->data_count++;
return 1;
}
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);
- bc->data_count++;
return 1;
}
/* In gfs1, rgrp indirect blocks are marked in the bitmap as "meta".
@@ -442,7 +438,6 @@ static int check_data(struct gfs2_inode *ip, uint64_t block, void *private)
fsck_blockmap_set(ip, block, _("jdata"), gfs2_jdata);
} else
fsck_blockmap_set(ip, block, _("data"), gfs2_block_used);
- bc->data_count++;
return 0;
}
10 years, 11 months
cluster: RHEL6 - fsck.gfs2: Consistent naming of struct duptree variables
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=f7b8a81a21d...
Commit: f7b8a81a21d93398873fd96dd3329f2e0b120e5b
Parent: 29114a11a4e8f8a8e3f83376b4431714d10c4ec0
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Tue Apr 2 10:39:26 2013 -0700
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri May 17 15:24:44 2013 -0500
fsck.gfs2: Consistent naming of struct duptree variables
There were several places in the fsck.gfs2 code that referenced
variables of type struct duptree, but sometimes they were called
dt, d, b or even data. This patch achieves a level of consistency
and calls them all dt. This helps readability: when you see a
variable dt, you know it's a struct duptree.
rhbz#902920
---
gfs2/fsck/fsck.h | 2 +-
gfs2/fsck/metawalk.c | 24 +++++-----
gfs2/fsck/pass1b.c | 113 +++++++++++++++++++++++++-------------------------
gfs2/fsck/util.c | 40 +++++++++---------
4 files changed, 90 insertions(+), 89 deletions(-)
diff --git a/gfs2/fsck/fsck.h b/gfs2/fsck/fsck.h
index e4f84c1..87d0a04 100644
--- a/gfs2/fsck/fsck.h
+++ b/gfs2/fsck/fsck.h
@@ -117,7 +117,7 @@ extern int fsck_query(const char *format, ...)
__attribute__((format(printf,1,2)));
extern struct dir_info *dirtree_find(uint64_t block);
extern void dup_listent_delete(struct inode_with_dups *id);
-extern void dup_delete(struct duptree *b);
+extern void dup_delete(struct duptree *dt);
extern void dirtree_delete(struct dir_info *b);
/* FIXME: Hack to get this going for pass2 - this should be pulled out
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 39c39ce..c1c7bfb 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -177,14 +177,14 @@ struct duptree *dupfind(uint64_t block)
struct osi_node *node = dup_blocks.osi_node;
while (node) {
- struct duptree *data = (struct duptree *)node;
+ struct duptree *dt = (struct duptree *)node;
- if (block < data->block)
+ if (block < dt->block)
node = node->osi_left;
- else if (block > data->block)
+ else if (block > dt->block)
node = node->osi_right;
else
- return data;
+ return dt;
}
return NULL;
}
@@ -953,15 +953,15 @@ int delete_block(struct gfs2_inode *ip, uint64_t block,
*/
int find_remove_dup(struct gfs2_inode *ip, uint64_t block, const char *btype)
{
- struct duptree *d;
+ struct duptree *dt;
struct inode_with_dups *id;
- d = dupfind(block);
- if (!d)
+ dt = dupfind(block);
+ if (!dt)
return 0;
/* remove the inode reference id structure for this reference. */
- id = find_dup_ref_inode(d, ip);
+ id = find_dup_ref_inode(dt, ip);
if (!id)
return 0;
@@ -971,14 +971,14 @@ int find_remove_dup(struct gfs2_inode *ip, uint64_t block, const char *btype)
(unsigned long long)block, (unsigned long long)block,
btype, (unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
- d->refs--; /* one less reference */
- if (d->refs == 1) {
+ dt->refs--; /* one less reference */
+ if (dt->refs == 1) {
log_info( _("This leaves only one reference: it's "
"no longer a duplicate.\n"));
- dup_delete(d); /* not duplicate now */
+ dup_delete(dt); /* not duplicate now */
} else
log_info( _("%d block reference(s) remain.\n"),
- d->refs);
+ dt->refs);
return 1; /* but the original ref still exists so do not free it. */
}
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index d6b52e0..838b75e 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -20,7 +20,7 @@ struct fxn_info {
};
struct dup_handler {
- struct duptree *b;
+ struct duptree *dt;
struct inode_with_dups *id;
int ref_inode_count;
int ref_count;
@@ -177,21 +177,21 @@ static int find_dentry(struct gfs2_inode *ip, struct gfs2_dirent *de,
{
struct osi_node *n, *next = NULL;
osi_list_t *tmp2;
- struct duptree *b;
+ struct duptree *dt;
int found;
for (n = osi_first(&dup_blocks); n; n = next) {
next = osi_next(n);
- b = (struct duptree *)n;
+ dt = (struct duptree *)n;
found = 0;
- osi_list_foreach(tmp2, &b->ref_invinode_list) {
+ osi_list_foreach(tmp2, &dt->ref_invinode_list) {
if (check_dir_dup_ref(ip, de, tmp2, filename)) {
found = 1;
break;
}
}
if (!found) {
- osi_list_foreach(tmp2, &b->ref_inode_list) {
+ osi_list_foreach(tmp2, &dt->ref_inode_list) {
if (check_dir_dup_ref(ip, de, tmp2, filename))
break;
}
@@ -208,7 +208,7 @@ static int clear_dup_metalist(struct gfs2_inode *ip, uint64_t block,
void *private)
{
struct dup_handler *dh = (struct dup_handler *) private;
- struct duptree *d;
+ struct duptree *dt;
if (!valid_block(ip->i_sbd, block))
return 0;
@@ -223,14 +223,14 @@ static int clear_dup_metalist(struct gfs2_inode *ip, uint64_t block,
to delete it altogether. If the block is a duplicate referenced
block, we need to keep its type intact and let the caller sort
it out once we're down to a single reference. */
- d = dupfind(block);
- if (!d) {
+ dt = dupfind(block);
+ if (!dt) {
fsck_blockmap_set(ip, block, _("no longer valid"),
gfs2_block_free);
return 0;
}
/* This block, having failed the above test, is duplicated somewhere */
- if (block == dh->b->block) {
+ if (block == dh->dt->block) {
log_err( _("Not clearing duplicate reference in inode \"%s\" "
"at block #%llu (0x%llx) to block #%llu (0x%llx) "
"because it's valid for another inode.\n"),
@@ -396,7 +396,7 @@ static enum dup_ref_type get_ref_type(struct inode_with_dups *id)
return ref_types;
}
-static void log_inode_reference(struct duptree *b, osi_list_t *tmp, int inval)
+static void log_inode_reference(struct duptree *dt, osi_list_t *tmp, int inval)
{
char reftypestring[32];
struct inode_with_dups *id;
@@ -416,8 +416,8 @@ static void log_inode_reference(struct duptree *b, osi_list_t *tmp, int inval)
"block %llu (0x%llx) (%s)\n"), id->name,
(unsigned long long)id->block_no,
(unsigned long long)id->block_no, id->dup_count,
- (unsigned long long)b->block,
- (unsigned long long)b->block, reftypestring);
+ (unsigned long long)dt->block,
+ (unsigned long long)dt->block, reftypestring);
}
/*
* resolve_dup_references - resolve all but the last dinode that has a
@@ -432,7 +432,7 @@ static void log_inode_reference(struct duptree *b, osi_list_t *tmp, int inval)
* acceptable_ref - Delete dinodes that reference the given block as anything
* _but_ this type. Try to save references as this type.
*/
-static int resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *b,
+static int resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *dt,
osi_list_t *ref_list, struct dup_handler *dh,
int inval, int acceptable_ref)
{
@@ -459,7 +459,7 @@ static int resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *b,
return FSCK_OK;
id = osi_list_entry(tmp, struct inode_with_dups, list);
- dh->b = b;
+ dh->dt = dt;
dh->id = id;
if (dh->ref_inode_count == 1) /* down to the last reference */
@@ -490,8 +490,8 @@ static int resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *b,
id->name,
(unsigned long long)id->block_no,
(unsigned long long)id->block_no,
- (unsigned long long)b->block,
- (unsigned long long)b->block,
+ (unsigned long long)dt->block,
+ (unsigned long long)dt->block,
reftypes[this_ref]);
continue; /* don't delete the dinode */
}
@@ -509,8 +509,8 @@ static int resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *b,
"really %s.\n"),
id->name, (unsigned long long)id->block_no,
(unsigned long long)id->block_no,
- (unsigned long long)b->block,
- (unsigned long long)b->block,
+ (unsigned long long)dt->block,
+ (unsigned long long)dt->block,
reftypes[this_ref], reftypes[acceptable_ref]);
if (!(query( _("Okay to delete %s inode %lld (0x%llx)? "
"(y/n) "),
@@ -560,7 +560,7 @@ static int resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *b,
return 0;
}
-static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *b)
+static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *dt)
{
struct gfs2_inode *ip;
osi_list_t *tmp;
@@ -572,12 +572,12 @@ static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *b)
enum dup_ref_type acceptable_ref;
/* Count the duplicate references, both valid and invalid */
- osi_list_foreach(tmp, &b->ref_invinode_list) {
+ osi_list_foreach(tmp, &dt->ref_invinode_list) {
id = osi_list_entry(tmp, struct inode_with_dups, list);
dh.ref_inode_count++;
dh.ref_count += id->dup_count;
}
- osi_list_foreach(tmp, &b->ref_inode_list) {
+ osi_list_foreach(tmp, &dt->ref_inode_list) {
id = osi_list_entry(tmp, struct inode_with_dups, list);
dh.ref_inode_count++;
dh.ref_count += id->dup_count;
@@ -586,13 +586,14 @@ static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *b)
/* Log the duplicate references */
log_notice( _("Block %llu (0x%llx) has %d inodes referencing it"
" for a total of %d duplicate references:\n"),
- (unsigned long long)b->block, (unsigned long long)b->block,
- dh.ref_inode_count, dh.ref_count);
+ (unsigned long long)dt->block,
+ (unsigned long long)dt->block,
+ dh.ref_inode_count, dh.ref_count);
- osi_list_foreach(tmp, &b->ref_invinode_list)
- log_inode_reference(b, tmp, 1);
- osi_list_foreach(tmp, &b->ref_inode_list)
- log_inode_reference(b, tmp, 0);
+ osi_list_foreach(tmp, &dt->ref_invinode_list)
+ log_inode_reference(dt, tmp, 1);
+ osi_list_foreach(tmp, &dt->ref_inode_list)
+ log_inode_reference(dt, tmp, 0);
/* Figure out the block type to see if we can eliminate references
to a different type. In other words, if the duplicate block looks
@@ -601,7 +602,7 @@ static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *b)
references to it as metadata. Dinodes with such references are
clearly corrupt and need to be deleted.
And if we're left with a single reference, problem solved. */
- bh = bread(sdp, b->block);
+ bh = bread(sdp, dt->block);
cmagic = ((struct gfs2_meta_header *)(bh->b_data))->mh_magic;
ctype = ((struct gfs2_meta_header *)(bh->b_data))->mh_type;
brelse(bh);
@@ -646,10 +647,10 @@ static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *b)
"Step 1: Eliminate references to block %llu "
"(0x%llx) that were previously marked "
"invalid.\n"),
- (unsigned long long)b->block,
- (unsigned long long)b->block);
- last_reference = resolve_dup_references(sdp, b,
- &b->ref_invinode_list,
+ (unsigned long long)dt->block,
+ (unsigned long long)dt->block);
+ last_reference = resolve_dup_references(sdp, dt,
+ &dt->ref_invinode_list,
&dh, 1, ref_types);
}
/* Step 2 - eliminate reference from inodes that reference it as the
@@ -661,10 +662,10 @@ static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *b)
log_debug( _("----------------------------------------------\n"
"Step 2: Eliminate references to block %llu "
"(0x%llx) that need the wrong block type.\n"),
- (unsigned long long)b->block,
- (unsigned long long)b->block);
- last_reference = resolve_dup_references(sdp, b,
- &b->ref_inode_list,
+ (unsigned long long)dt->block,
+ (unsigned long long)dt->block);
+ last_reference = resolve_dup_references(sdp, dt,
+ &dt->ref_inode_list,
&dh, 0,
acceptable_ref);
}
@@ -676,20 +677,20 @@ static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *b)
log_debug( _("----------------------------------------------\n"
"Step 3: Choose one reference to block %llu "
"(0x%llx) to keep.\n"),
- (unsigned long long)b->block,
- (unsigned long long)b->block);
- last_reference = resolve_dup_references(sdp, b,
- &b->ref_inode_list,
+ (unsigned long long)dt->block,
+ (unsigned long long)dt->block);
+ last_reference = resolve_dup_references(sdp, dt,
+ &dt->ref_inode_list,
&dh, 0, ref_types);
}
/* Now fix the block type of the block in question. */
- if (osi_list_empty(&b->ref_inode_list)) {
+ if (osi_list_empty(&dt->ref_inode_list)) {
log_notice( _("Block %llu (0x%llx) has no more references; "
"Marking as 'free'.\n"),
- (unsigned long long)b->block,
- (unsigned long long)b->block);
- gfs2_blockmap_set(bl, b->block, gfs2_block_free);
- check_n_fix_bitmap(sdp, b->block, gfs2_block_free);
+ (unsigned long long)dt->block,
+ (unsigned long long)dt->block);
+ gfs2_blockmap_set(bl, dt->block, gfs2_block_free);
+ check_n_fix_bitmap(sdp, dt->block, gfs2_block_free);
return 0;
}
if (last_reference) {
@@ -697,14 +698,14 @@ static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *b)
log_notice( _("Block %llu (0x%llx) has only one remaining "
"reference.\n"),
- (unsigned long long)b->block,
- (unsigned long long)b->block);
+ (unsigned long long)dt->block,
+ (unsigned long long)dt->block);
/* If we're down to a single reference (and not all references
deleted, which may be the case of an inode that has only
itself and a reference), we need to reset the block type
from invalid to data or metadata. Start at the first one
in the list, not the structure's place holder. */
- tmp = (&b->ref_inode_list)->next;
+ tmp = (&dt->ref_inode_list)->next;
id = osi_list_entry(tmp, struct inode_with_dups, list);
log_debug( _("----------------------------------------------\n"
"Step 4. Set block type based on the remaining "
@@ -720,27 +721,27 @@ static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *b)
"the block as free.\n"),
(unsigned long long)id->block_no,
(unsigned long long)id->block_no);
- fsck_blockmap_set(ip, b->block,
+ fsck_blockmap_set(ip, dt->block,
_("reference-repaired leaf"),
gfs2_block_free);
} else if (id->reftypecount[ref_is_inode]) {
set_ip_blockmap(ip, 0); /* 0=do not add to dirtree */
} else if (id->reftypecount[ref_as_data]) {
- fsck_blockmap_set(ip, b->block,
+ fsck_blockmap_set(ip, dt->block,
_("reference-repaired data"),
gfs2_block_used);
} else if (id->reftypecount[ref_as_meta]) {
if (is_dir(&ip->i_di, sdp->gfs1))
- fsck_blockmap_set(ip, b->block,
+ fsck_blockmap_set(ip, dt->block,
_("reference-repaired leaf"),
gfs2_leaf_blk);
else
- fsck_blockmap_set(ip, b->block,
+ fsck_blockmap_set(ip, dt->block,
_("reference-repaired "
"indirect"),
gfs2_indir_blk);
} else
- fsck_blockmap_set(ip, b->block,
+ fsck_blockmap_set(ip, dt->block,
_("reference-repaired extended "
"attribute"),
gfs2_meta_eattr);
@@ -757,7 +758,7 @@ static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *b)
* use in pass2 */
int pass1b(struct gfs2_sbd *sdp)
{
- struct duptree *b;
+ struct duptree *dt;
uint64_t i;
uint8_t q;
struct osi_node *n, *next = NULL;
@@ -813,9 +814,9 @@ int pass1b(struct gfs2_sbd *sdp)
out:
for (n = osi_first(&dup_blocks); n; n = next) {
next = osi_next(n);
- b = (struct duptree *)n;
+ dt = (struct duptree *)n;
if (!skip_this_pass && !rc) /* no error & not asked to skip the rest */
- handle_dup_blk(sdp, b);
+ handle_dup_blk(sdp, dt);
/* Do not attempt to free the dup_blocks list or its parts
here because any func that calls check_metatree needs
to check duplicate status based on this linked list.
diff --git a/gfs2/fsck/util.c b/gfs2/fsck/util.c
index a33e452..78d4e79 100644
--- a/gfs2/fsck/util.c
+++ b/gfs2/fsck/util.c
@@ -156,7 +156,7 @@ int fsck_query(const char *format, ...)
static struct duptree *gfs2_dup_set(uint64_t dblock, int create)
{
struct osi_node **newn = &dup_blocks.osi_node, *parent = NULL;
- struct duptree *data;
+ struct duptree *dt;
/* Figure out where to put new node */
while (*newn) {
@@ -173,20 +173,20 @@ static struct duptree *gfs2_dup_set(uint64_t dblock, int create)
if (!create)
return NULL;
- data = malloc(sizeof(struct duptree));
+ dt = malloc(sizeof(struct duptree));
dups_found++;
- memset(data, 0, sizeof(struct duptree));
+ memset(dt, 0, sizeof(struct duptree));
/* Add new node and rebalance tree. */
- data->block = dblock;
- data->refs = 1; /* reference 1 is actually the reference we need to
- discover in pass1b. */
- data->first_ref_found = 0;
- osi_list_init(&data->ref_inode_list);
- osi_list_init(&data->ref_invinode_list);
- osi_link_node(&data->node, parent, newn);
- osi_insert_color(&data->node, &dup_blocks);
-
- return data;
+ dt->block = dblock;
+ dt->refs = 1; /* reference 1 is actually the reference we need to
+ discover in pass1b. */
+ dt->first_ref_found = 0;
+ osi_list_init(&dt->ref_inode_list);
+ osi_list_init(&dt->ref_invinode_list);
+ osi_link_node(&dt->node, parent, newn);
+ osi_insert_color(&dt->node, &dup_blocks);
+
+ return dt;
}
/**
@@ -371,23 +371,23 @@ void dup_listent_delete(struct inode_with_dups *id)
free(id);
}
-void dup_delete(struct duptree *b)
+void dup_delete(struct duptree *dt)
{
struct inode_with_dups *id;
osi_list_t *tmp;
- while (!osi_list_empty(&b->ref_invinode_list)) {
- tmp = (&b->ref_invinode_list)->next;
+ while (!osi_list_empty(&dt->ref_invinode_list)) {
+ tmp = (&dt->ref_invinode_list)->next;
id = osi_list_entry(tmp, struct inode_with_dups, list);
dup_listent_delete(id);
}
- while (!osi_list_empty(&b->ref_inode_list)) {
- tmp = (&b->ref_inode_list)->next;
+ while (!osi_list_empty(&dt->ref_inode_list)) {
+ tmp = (&dt->ref_inode_list)->next;
id = osi_list_entry(tmp, struct inode_with_dups, list);
dup_listent_delete(id);
}
- osi_erase(&b->node, &dup_blocks);
- free(b);
+ osi_erase(&dt->node, &dup_blocks);
+ free(dt);
}
void dirtree_delete(struct dir_info *b)
10 years, 11 months
cluster: RHEL6 - fsck.gfs2: Check for interrupt when resolving duplicates
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=29114a11a4e...
Commit: 29114a11a4e8f8a8e3f83376b4431714d10c4ec0
Parent: 988a76cb1d229832aea0d0f928ae4a9a24e8feaa
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Fri Mar 15 12:28:56 2013 -0700
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri May 17 15:24:13 2013 -0500
fsck.gfs2: Check for interrupt when resolving duplicates
This patch adds another check for interrupts while resolving duplicate
block references in pass1b.
rhbz#902920
---
gfs2/fsck/pass1b.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index 05f270e..d6b52e0 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -455,6 +455,9 @@ static int resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *b,
int found_good_ref = 0;
osi_list_foreach_safe(tmp, ref_list, x) {
+ if (skip_this_pass || fsck_abort)
+ return FSCK_OK;
+
id = osi_list_entry(tmp, struct inode_with_dups, list);
dh->b = b;
dh->id = id;
10 years, 11 months
cluster: RHEL6 - fsck.gfs2: Rework the "undo" functions
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=988a76cb1d2...
Commit: 988a76cb1d229832aea0d0f928ae4a9a24e8feaa
Parent: 790a299e775f2a4aab64b37c3cdf03e11e52ccf5
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Tue Mar 12 06:54:39 2013 -0700
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri May 17 15:23:36 2013 -0500
fsck.gfs2: Rework the "undo" functions
In pass1, it traverses the metadata free, processing each dinode and
marking which blocks are used by that dinode. If a dinode is found
to have unrecoverable errors, it does a bunch of work to "undo" the
things it did. This is especially important for the processing of
duplicate block references. Suppose dinode X references block 1234.
Later in pass1, suppose a different dinode, Y, also references block
1234. This is flagged as a duplicate block reference. Still later,
suppose pass1 determines dinode Y is bad. Now it has to undo the
work it did. It needs to properly unmark the data and metadata
blocks it marked as no longer "free" so that valid references that
follow aren't flagged as duplicate references. At the same time,
it needs to unflag block 1234 as a duplicate reference as well, so
that dinode X's original reference is still considered valid.
Before this patch, fsck.gfs2 was trying to traverse the entire
metadata tree for the bad dinode, trying to "undo" the designations.
That becomes a huge problem if the damage was discovered in the
middle of the metadata, in which case it may never have flagged any
of the data blocks as "in use as data" in its blockmap. The result
of "undoing" the designations sometimes resulted in blocks improperly
being marked as "free" when they were, in fact, referenced by other
valid dinodes.
For example, suppose corrupt dinode Y references metadata blocks
1234, 1235, and 1236. Now suppose a serious problem is found as part
of its processing of block 1234, and so it stopped its metadata tree
traversal there. Metadata blocks 1235 and 1236 are still listed as
metadata for the bad dinode, but if we traverse the entire tree,
those two blocks may be improperly processed. If another dinode
actually uses blocks 1235 or 1236, the improper "undo" processing
of those two blocks can screw up the valid references.
This patch reworks the "undo" functions so that the "undo" functions
don't get called on the entire metadata and data of the defective
dinode. Instead, only the metadata and data blocks queued onto the
metadata list are processed. This should ensure that the "undo"
functions only operate on blocks that were processed in the first
place.
rhbz#902920
---
gfs2/fsck/metawalk.c | 119 +++++++++++++++++++++++-----------
gfs2/fsck/metawalk.h | 4 +
gfs2/fsck/pass1.c | 172 +++++++++++++++----------------------------------
3 files changed, 137 insertions(+), 158 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index e0fbd33..39c39ce 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -1257,7 +1257,7 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
if (err < 0) {
stack;
error = err;
- goto fail;
+ return error;
}
if (err > 0) {
if (!error)
@@ -1276,14 +1276,11 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
}
if (!nbh)
nbh = bread(ip->i_sbd, block);
- osi_list_add(&nbh->b_altlist, cur_list);
+ osi_list_add_prev(&nbh->b_altlist, cur_list);
} /* for all data on the indirect block */
} /* for blocks at that height */
} /* for height */
- return error;
-fail:
- free_metalist(ip, mlp);
- return error;
+ return 0;
}
/**
@@ -1329,6 +1326,27 @@ static int check_data(struct gfs2_inode *ip, struct metawalk_fxns *pass,
return error;
}
+static int undo_check_data(struct gfs2_inode *ip, struct metawalk_fxns *pass,
+ uint64_t *ptr_start, char *ptr_end)
+{
+ int rc = 0;
+ uint64_t block, *ptr;
+
+ /* If there isn't much pointer corruption check the pointers */
+ for (ptr = ptr_start ; (char *)ptr < ptr_end && !fsck_abort; ptr++) {
+ if (!*ptr)
+ continue;
+
+ if (skip_this_pass || fsck_abort)
+ return 1;
+ block = be64_to_cpu(*ptr);
+ rc = pass->undo_check_data(ip, block, pass->private);
+ if (rc < 0)
+ return rc;
+ }
+ return 0;
+}
+
static int hdr_size(struct gfs2_buffer_head *bh, int height)
{
if (height > 1) {
@@ -1361,6 +1379,7 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
int i, head_size;
uint64_t blks_checked = 0;
int error, rc;
+ int metadata_clean = 0;
if (!height && !is_dir(&ip->i_di, ip->i_sbd->gfs1))
return 0;
@@ -1372,35 +1391,21 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
error = build_and_check_metalist(ip, &metalist[0], pass);
if (error) {
stack;
- free_metalist(ip, &metalist[0]);
- return error;
+ goto undo_metalist;
}
+ metadata_clean = 1;
/* For directories, we've already checked the "data" blocks which
* comprise the directory hash table, so we perform the directory
* checks and exit. */
if (is_dir(&ip->i_di, ip->i_sbd->gfs1)) {
- free_metalist(ip, &metalist[0]);
if (!(ip->i_di.di_flags & GFS2_DIF_EXHASH))
- return 0;
+ goto out;
/* check validity of leaf blocks and leaf chains */
error = check_leaf_blks(ip, pass);
- return error;
- }
-
- /* Free the metalist buffers from heights we don't need to check.
- For the rest we'll free as we check them to save time.
- metalist[0] will only have the dinode bh, so we can skip it. */
- for (i = 1; i < height - 1; i++) {
- list = &metalist[i];
- while (!osi_list_empty(list)) {
- bh = osi_list_entry(list->next,
- struct gfs2_buffer_head, b_altlist);
- if (bh == ip->i_bh)
- osi_list_del(&bh->b_altlist);
- else
- brelse(bh);
- }
+ if (error)
+ goto undo_metalist;
+ goto out;
}
/* check data blocks */
@@ -1408,7 +1413,7 @@ 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 >= 0 && !osi_list_empty(list)) {
+ while (!error && !osi_list_empty(list)) {
if (fsck_abort) {
free_metalist(ip, &metalist[0]);
return 0;
@@ -1426,21 +1431,13 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
}
if (pass->check_data)
- rc = check_data(ip, pass, (uint64_t *)
- (bh->b_data + head_size),
- (bh->b_data + ip->i_sbd->bsize),
- &blks_checked);
- else
- rc = 0;
+ error = check_data(ip, pass, (uint64_t *)
+ (bh->b_data + head_size),
+ (bh->b_data + ip->i_sbd->bsize),
+ &blks_checked);
- if (rc && (!error || rc < 0))
- error = rc;
if (pass->big_file_msg && ip->i_di.di_blocks > COMFORTABLE_BLKS)
pass->big_file_msg(ip, blks_checked);
- if (bh == ip->i_bh)
- osi_list_del(&bh->b_altlist);
- else
- brelse(bh);
}
if (pass->big_file_msg && ip->i_di.di_blocks > COMFORTABLE_BLKS) {
log_notice( _("\rLarge file at %lld (0x%llx) - 100 percent "
@@ -1450,6 +1447,50 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
(unsigned long long)ip->i_di.di_num.no_addr);
fflush(stdout);
}
+undo_metalist:
+ if (!error)
+ goto out;
+ log_err( _("Error: inode %llu (0x%llx) had unrecoverable errors.\n"),
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr);
+ if (!query( _("Remove the invalid inode? (y/n) "))) {
+ free_metalist(ip, &metalist[0]);
+ log_err(_("Invalid inode not deleted.\n"));
+ return error;
+ }
+ for (i = 0; pass->undo_check_meta && i < height; i++) {
+ while (!osi_list_empty(&metalist[i])) {
+ list = &metalist[i];
+ bh = osi_list_entry(list->next,
+ struct gfs2_buffer_head,
+ b_altlist);
+ log_err(_("Undoing metadata work for block %llu "
+ "(0x%llx)\n"),
+ (unsigned long long)bh->b_blocknr,
+ (unsigned long long)bh->b_blocknr);
+ if (i)
+ rc = pass->undo_check_meta(ip, bh->b_blocknr,
+ i, pass->private);
+ else
+ rc = 0;
+ if (metadata_clean && rc == 0 && i == height - 1) {
+ head_size = hdr_size(bh, height);
+ if (head_size)
+ undo_check_data(ip, pass, (uint64_t *)
+ (bh->b_data + head_size),
+ (bh->b_data + ip->i_sbd->bsize));
+ }
+ if (bh == ip->i_bh)
+ osi_list_del(&bh->b_altlist);
+ else
+ brelse(bh);
+ }
+ }
+ /* Set the dinode as "bad" so it gets deleted */
+ fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
+ _("corrupt"), gfs2_block_free);
+ log_err(_("The corrupt inode was invalidated.\n"));
+out:
free_metalist(ip, &metalist[0]);
return error;
}
diff --git a/gfs2/fsck/metawalk.h b/gfs2/fsck/metawalk.h
index 486c6eb..f5e71e1 100644
--- a/gfs2/fsck/metawalk.h
+++ b/gfs2/fsck/metawalk.h
@@ -108,6 +108,10 @@ struct metawalk_fxns {
int (*repair_leaf) (struct gfs2_inode *ip, uint64_t *leaf_no,
int lindex, int ref_count, const char *msg,
void *private);
+ int (*undo_check_meta) (struct gfs2_inode *ip, uint64_t block,
+ int h, void *private);
+ int (*undo_check_data) (struct gfs2_inode *ip, uint64_t block,
+ void *private);
};
#endif /* _METAWALK_H */
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index 6f9a953..05e7c68 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -38,8 +38,7 @@ 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 undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, int h,
- void *private);
+ int h, void *private);
static int check_data(struct gfs2_inode *ip, uint64_t block, void *private);
static int undo_check_data(struct gfs2_inode *ip, uint64_t block,
void *private);
@@ -103,12 +102,8 @@ struct metawalk_fxns pass1_fxns = {
.finish_eattr_indir = finish_eattr_indir,
.big_file_msg = big_file_comfort,
.repair_leaf = pass1_repair_leaf,
-};
-
-struct metawalk_fxns undo_fxns = {
- .private = NULL,
- .check_metalist = undo_check_metalist,
- .check_data = undo_check_data,
+ .undo_check_meta = undo_check_metalist,
+ .undo_check_data = undo_check_data,
};
struct metawalk_fxns invalidate_fxns = {
@@ -325,53 +320,67 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
return 0;
}
-static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
- struct gfs2_buffer_head **bh, int h,
- void *private)
+/* undo_reference - undo previously processed data or metadata
+ * We've treated the metadata for this dinode as good so far, but not we
+ * realize it's bad. So we need to undo what we've done.
+ *
+ * Returns: 0 - We need to process the block as metadata. In other words,
+ * we need to undo any blocks it refers to.
+ * 1 - We can't process the block as metadata.
+ */
+
+static int undo_reference(struct gfs2_inode *ip, uint64_t block, int meta,
+ void *private)
{
- int found_dup = 0, iblk_type;
- struct gfs2_buffer_head *nbh;
struct block_count *bc = (struct block_count *)private;
-
- *bh = NULL;
+ struct duptree *dt;
+ struct inode_with_dups *id;
if (!valid_block(ip->i_sbd, block)) { /* blk outside of FS */
fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
_("bad block referencing"), gfs2_block_free);
return 1;
}
- if (is_dir(&ip->i_di, ip->i_sbd->gfs1) && h == ip->i_di.di_height)
- iblk_type = GFS2_METATYPE_JD;
- else
- iblk_type = GFS2_METATYPE_IN;
- found_dup = find_remove_dup(ip, block, _("Metadata"));
- nbh = bread(ip->i_sbd, block);
+ if (meta)
+ bc->indir_count--;
+ dt = dupfind(block);
+ if (dt) {
+ /* remove all duplicate reference structures from this inode */
+ do {
+ id = find_dup_ref_inode(dt, ip);
+ if (!id)
+ break;
- if (gfs2_check_meta(nbh, iblk_type)) {
- if (!found_dup) {
- fsck_blockmap_set(ip, block, _("bad indirect"),
- gfs2_block_free);
- brelse(nbh);
+ dup_listent_delete(id);
+ } while (id);
+
+ if (dt->refs) {
+ log_err(_("Block %llu (0x%llx) is still referenced "
+ "from another inode; not freeing.\n"),
+ (unsigned long long)block,
+ (unsigned long long)block);
return 1;
}
- brelse(nbh);
- nbh = NULL;
- } else /* blk check ok */
- *bh = nbh;
-
- bc->indir_count--;
- if (found_dup) {
- if (nbh)
- brelse(nbh);
- *bh = NULL;
- return 1; /* don't process the metadata again */
- } else
- fsck_blockmap_set(ip, block, _("bad indirect"),
- gfs2_block_free);
+ }
+ fsck_blockmap_set(ip, block,
+ meta ? _("bad indirect") : _("referenced data"),
+ gfs2_block_free);
return 0;
}
+static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
+ int h, void *private)
+{
+ return undo_reference(ip, block, 1, private);
+}
+
+static int undo_check_data(struct gfs2_inode *ip, uint64_t block,
+ void *private)
+{
+ return undo_reference(ip, block, 0, private);
+}
+
static int check_data(struct gfs2_inode *ip, uint64_t block, void *private)
{
uint8_t q;
@@ -437,71 +446,9 @@ static int check_data(struct gfs2_inode *ip, uint64_t block, void *private)
return 0;
}
-static int undo_check_data(struct gfs2_inode *ip, uint64_t block,
- void *private)
-{
- struct block_count *bc = (struct block_count *) private;
-
- if (!valid_block(ip->i_sbd, block)) {
- /* Mark the owner of this block with the bad_block
- * designator so we know to check it for out of range
- * blocks later */
- fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
- _("bad (invalid or out of range) data"),
- gfs2_block_free);
- return 1;
- }
- bc->data_count--;
- return free_block_if_notdup(ip, block, _("data"));
-}
-
static int remove_inode_eattr(struct gfs2_inode *ip, struct block_count *bc)
{
- struct duptree *dt;
- struct inode_with_dups *id;
- osi_list_t *ref;
- int moved = 0;
-
- /* If it's a duplicate reference to the block, we need to check
- if the reference is on the valid or invalid inodes list.
- If it's on the valid inode's list, move it to the invalid
- inodes list. The reason is simple: This inode, although
- valid, has an now-invalid reference, so we should not give
- this reference preferential treatment over others. */
- dt = dupfind(ip->i_di.di_eattr);
- if (dt) {
- osi_list_foreach(ref, &dt->ref_inode_list) {
- id = osi_list_entry(ref, struct inode_with_dups, list);
- if (id->block_no == ip->i_di.di_num.no_addr) {
- log_debug( _("Moving inode %lld (0x%llx)'s "
- "duplicate reference to %lld "
- "(0x%llx) from the valid to the "
- "invalid reference list.\n"),
- (unsigned long long)
- ip->i_di.di_num.no_addr,
- (unsigned long long)
- ip->i_di.di_num.no_addr,
- (unsigned long long)
- ip->i_di.di_eattr,
- (unsigned long long)
- ip->i_di.di_eattr);
- /* Move from the normal to the invalid list */
- osi_list_del(&id->list);
- osi_list_add_prev(&id->list,
- &dt->ref_invinode_list);
- moved = 1;
- break;
- }
- }
- if (!moved)
- log_debug( _("Duplicate reference to %lld "
- "(0x%llx) not moved.\n"),
- (unsigned long long)ip->i_di.di_eattr,
- (unsigned long long)ip->i_di.di_eattr);
- } else {
- delete_block(ip, ip->i_di.di_eattr, NULL,
- "extended attribute", NULL);
- }
+ undo_reference(ip, ip->i_di.di_eattr, 0, bc);
ip->i_di.di_eattr = 0;
bc->ea_count = 0;
ip->i_di.di_blocks = 1 + bc->indir_count + bc->data_count;
@@ -1079,23 +1026,10 @@ static int handle_ip(struct gfs2_sbd *sdp, struct gfs2_inode *ip)
if (lf_dip && lf_dip->i_di.di_blocks != lf_blks)
reprocess_inode(lf_dip, "lost+found");
- if (fsck_abort || error < 0)
+ /* We there was an error, we return 0 because we want fsck to continue
+ and analyze the other dinodes as well. */
+ if (fsck_abort || error != 0)
return 0;
- if (error > 0) {
- log_err( _("Error: inode %llu (0x%llx) has unrecoverable "
- "errors; invalidating.\n"),
- (unsigned long long)ip->i_di.di_num.no_addr,
- (unsigned long long)ip->i_di.di_num.no_addr);
- undo_fxns.private = &bc;
- check_metatree(ip, &undo_fxns);
- /* If we undo the metadata accounting, including metadatas
- duplicate block status, we need to make sure later passes
- don't try to free up the metadata referenced by this inode.
- Therefore we mark the inode as free space. */
- fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
- _("corrupt"), gfs2_block_free);
- return 0;
- }
error = check_inode_eattr(ip, &pass1_fxns);
10 years, 11 months
cluster: RHEL6 - fsck.gfs2: separate function to calculate metadata block header size
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=790a299e775...
Commit: 790a299e775f2a4aab64b37c3cdf03e11e52ccf5
Parent: 97389a0558db6d316c766dcb4cbadeae7fee3688
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Tue Apr 2 12:49:50 2013 -0700
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri May 17 15:17:02 2013 -0500
fsck.gfs2: separate function to calculate metadata block header size
This patch creates a new function hdr_size that calculates the size
of a GFS2 metadata header depending on the height and type of block.
rhbz#902920
---
gfs2/fsck/metawalk.c | 44 +++++++++++++++++++++++---------------------
1 files changed, 23 insertions(+), 21 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 1f0c221..e0fbd33 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -1329,6 +1329,23 @@ static int check_data(struct gfs2_inode *ip, struct metawalk_fxns *pass,
return error;
}
+static int hdr_size(struct gfs2_buffer_head *bh, int height)
+{
+ if (height > 1) {
+ if (gfs2_check_meta(bh, GFS2_METATYPE_IN))
+ return 0;
+ if (bh->sdp->gfs1)
+ return sizeof(struct gfs_indirect);
+ else
+ return sizeof(struct gfs2_meta_header);
+ }
+ /* if this isn't really a dinode, skip it */
+ if (gfs2_check_meta(bh, GFS2_METATYPE_DI))
+ return 0;
+
+ return sizeof(struct gfs2_dinode);
+}
+
/**
* check_metatree
* @ip: inode structure in memory
@@ -1399,28 +1416,13 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
bh = osi_list_entry(list->next, struct gfs2_buffer_head,
b_altlist);
- if (height > 1) {
- if (gfs2_check_meta(bh, GFS2_METATYPE_IN)) {
- if (bh == ip->i_bh)
- osi_list_del(&bh->b_altlist);
- else
- brelse(bh);
- continue;
- }
- if (ip->i_sbd->gfs1)
- head_size = sizeof(struct gfs_indirect);
+ head_size = hdr_size(bh, height);
+ if (!head_size) {
+ if (bh == ip->i_bh)
+ osi_list_del(&bh->b_altlist);
else
- head_size = sizeof(struct gfs2_meta_header);
- } else {
- /* if this isn't really a dinode, skip it */
- if (gfs2_check_meta(bh, GFS2_METATYPE_DI)) {
- if (bh == ip->i_bh)
- osi_list_del(&bh->b_altlist);
- else
- brelse(bh);
- continue;
- }
- head_size = sizeof(struct gfs2_dinode);
+ brelse(bh);
+ continue;
}
if (pass->check_data)
10 years, 11 months
cluster: RHEL6 - fsck.gfs2: Add clarifying message to duplicate processing
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=97389a0558d...
Commit: 97389a0558db6d316c766dcb4cbadeae7fee3688
Parent: 7b98f01103283f5d925b03d643999b93617299c6
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Mon Mar 11 07:06:36 2013 -0700
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri May 17 15:16:56 2013 -0500
fsck.gfs2: Add clarifying message to duplicate processing
This patch adds a message to the fsck output that indicates which
block reference is acceptable. That helps to determine if fsck made
the right decision when a duplicate is resolved.
rhbz#902920
---
gfs2/fsck/pass1b.c | 9 +++++++++
1 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index 1cc2473..05f270e 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -481,6 +481,15 @@ static int resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *b,
q = block_type(id->block_no);
if (q != gfs2_inode_invalid) {
found_good_ref = 1;
+ log_warn( _("Inode %s (%lld/0x%llx)'s "
+ "reference to block %llu (0x%llx) "
+ "as '%s' is acceptable.\n"),
+ id->name,
+ (unsigned long long)id->block_no,
+ (unsigned long long)id->block_no,
+ (unsigned long long)b->block,
+ (unsigned long long)b->block,
+ reftypes[this_ref]);
continue; /* don't delete the dinode */
}
}
10 years, 11 months
cluster: RHEL6 - fsck.gfs2: link dinodes that only have extended attribute problems
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=7b98f011032...
Commit: 7b98f01103283f5d925b03d643999b93617299c6
Parent: 7467be5dc58d4b71281666f365fd01fde91e87fd
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Fri Mar 8 11:50:56 2013 -0700
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri May 17 15:16:51 2013 -0500
fsck.gfs2: link dinodes that only have extended attribute problems
The job of pass1b is to resolve duplicate references to the same block.
Eventually it does a fair job of determining the rightful owner of the
block, and then it has to deal with the other dinode(s) that referenced
the block improperly. If another dinode improperly referenced the block
as data or metadata, it's obvious file corruption and the dinode should
be deleted. However, if the other dinode improperly referenced the
block as an extended attribute, it can fix the situation by removing
the extended attributes from the dinode. Prior to this patch, there
was a check in the code for this situation so that the dinode was only
deleted if the bad block reference was as data or metadata. However,
regardless of the situation, the code removed the inode from the
inode rbtree. That resulted in the dinode being considered unlinked,
so it would get improperly tossed into lost+found and left in a
indeterminate state. Subsequent runs of fsck.gfs2 could find the
discrepancy and flag it as unlinked again. This patch adds another
check so that the inode is not removed from the inode rbtree, so it
is linked properly during pass2.
rhbz#902920
---
gfs2/fsck/pass1b.c | 9 ++++++---
1 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index c9e6494..1cc2473 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -519,9 +519,12 @@ static int resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *b,
(unsigned long long)id->block_no);
ip = fsck_load_inode(sdp, id->block_no);
- ii = inodetree_find(ip->i_di.di_num.no_addr);
- if (ii)
- inodetree_delete(ii);
+ if (id->reftypecount[ref_as_data] ||
+ id->reftypecount[ref_as_meta]) {
+ ii = inodetree_find(ip->i_di.di_num.no_addr);
+ if (ii)
+ inodetree_delete(ii);
+ }
clear_dup_fxns.private = (void *) dh;
/* Clear the EAs for the inode first */
check_inode_eattr(ip, &clear_dup_fxns);
10 years, 11 months
cluster: RHEL6 - fsck.gfs2: Remove redundant leaf depth check
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=7467be5dc58...
Commit: 7467be5dc58d4b71281666f365fd01fde91e87fd
Parent: c63b6da44b40a40d646ab546ae5b107894fb6043
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Fri Mar 8 10:16:14 2013 -0700
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri May 17 15:16:45 2013 -0500
fsck.gfs2: Remove redundant leaf depth check
A previous patch changed the way we check leaf block depth.
This patch removes the redundant check from pass1.
rhbz#902920
---
gfs2/fsck/pass1.c | 16 ----------------
1 files changed, 0 insertions(+), 16 deletions(-)
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index 95138fe..6f9a953 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -1020,7 +1020,6 @@ static int handle_ip(struct gfs2_sbd *sdp, struct gfs2_inode *ip)
int error;
struct block_count bc = {0};
long bad_pointers;
- uint64_t block = ip->i_bh->b_blocknr;
uint64_t lf_blks = 0;
bad_pointers = 0L;
@@ -1068,21 +1067,6 @@ static int handle_ip(struct gfs2_sbd *sdp, struct gfs2_inode *ip)
if (set_di_nlink(ip))
goto bad_dinode;
- if (is_dir(&ip->i_di, sdp->gfs1) && (ip->i_di.di_flags & GFS2_DIF_EXHASH)) {
- if (((1 << ip->i_di.di_depth) * sizeof(uint64_t)) != ip->i_di.di_size){
- log_warn( _("Directory dinode block #%llu (0x%llx"
- ") has bad depth. Found %u, Expected %u\n"),
- (unsigned long long)ip->i_di.di_num.no_addr,
- (unsigned long long)ip->i_di.di_num.no_addr,
- ip->i_di.di_depth,
- (1 >> (ip->i_di.di_size/sizeof(uint64_t))));
- if (fsck_blockmap_set(ip, block, _("bad depth"),
- gfs2_block_free))
- goto bad_dinode;
- return 0;
- }
- }
-
if (lf_dip)
lf_blks = lf_dip->i_di.di_blocks;
10 years, 11 months
cluster: RHEL6 - fsck.gfs2: reprocess inodes when blocks are added
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=c63b6da44b4...
Commit: c63b6da44b40a40d646ab546ae5b107894fb6043
Parent: 205ffdc992e944e6bd1db5c7bb024f01d8b6d731
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Fri Mar 8 10:12:16 2013 -0700
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri May 17 15:16:39 2013 -0500
fsck.gfs2: reprocess inodes when blocks are added
This patch adds several calls to reprocess_inode when functions
may have potentially added blocks to a dinode. This happens, for
example, when leaf blocks are split or new leaf blocks are added.
The purpose of reprocessing the inode is to properly mark the new
blocks in the fsck blockmap. If we don't, the new blocks may be
flagged as wrong in the bitmap, and set free in pass5.
rhbz#902920
---
gfs2/fsck/metawalk.c | 6 ++++++
gfs2/fsck/pass1.c | 11 +++++++++++
gfs2/fsck/pass2.c | 15 +++++++++------
3 files changed, 26 insertions(+), 6 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 8df32a0..1f0c221 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -1472,9 +1472,12 @@ int check_dir(struct gfs2_sbd *sdp, uint64_t block, struct metawalk_fxns *pass)
{
struct gfs2_inode *ip;
int error = 0;
+ uint64_t cur_blks;
ip = fsck_load_inode(sdp, block);
+ cur_blks = ip->i_di.di_blocks;
+
if (ip->i_di.di_flags & GFS2_DIF_EXHASH)
error = check_leaf_blks(ip, pass);
else
@@ -1483,6 +1486,9 @@ int check_dir(struct gfs2_sbd *sdp, uint64_t block, struct metawalk_fxns *pass)
if (error < 0)
stack;
+ if (ip->i_di.di_blocks != cur_blks)
+ reprocess_inode(ip, _("Current"));
+
fsck_inode_put(&ip); /* does a brelse */
return error;
}
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index fa74b76..95138fe 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -1021,6 +1021,7 @@ static int handle_ip(struct gfs2_sbd *sdp, struct gfs2_inode *ip)
struct block_count bc = {0};
long bad_pointers;
uint64_t block = ip->i_bh->b_blocknr;
+ uint64_t lf_blks = 0;
bad_pointers = 0L;
@@ -1082,8 +1083,18 @@ static int handle_ip(struct gfs2_sbd *sdp, struct gfs2_inode *ip)
}
}
+ if (lf_dip)
+ lf_blks = lf_dip->i_di.di_blocks;
+
pass1_fxns.private = &bc;
error = check_metatree(ip, &pass1_fxns);
+
+ /* Pass1 may have added some blocks to lost+found by virtue of leafs
+ that were misplaced. If it did, we need to reprocess lost+found
+ to correctly account for its blocks. */
+ if (lf_dip && lf_dip->i_di.di_blocks != lf_blks)
+ reprocess_inode(lf_dip, "lost+found");
+
if (fsck_abort || error < 0)
return 0;
if (error > 0) {
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index f68faab..9f477b8 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -1446,7 +1446,7 @@ struct metawalk_fxns pass2_fxns = {
static int check_system_dir(struct gfs2_inode *sysinode, const char *dirname,
int builder(struct gfs2_sbd *sdp))
{
- uint64_t iblock = 0;
+ uint64_t iblock = 0, cur_blks;
struct dir_status ds = {0};
char *filename;
int filename_len;
@@ -1461,12 +1461,15 @@ static int check_system_dir(struct gfs2_inode *sysinode, const char *dirname,
}
pass2_fxns.private = (void *) &ds;
if (ds.q == gfs2_bad_block) {
+ cur_blks = sysinode->i_di.di_blocks;
/* First check that the directory's metatree is valid */
error = check_metatree(sysinode, &pass2_fxns);
if (error < 0) {
stack;
return error;
}
+ if (sysinode->i_di.di_blocks != cur_blks)
+ reprocess_inode(sysinode, _("System inode"));
}
error = check_dir(sysinode->i_sbd, iblock, &pass2_fxns);
if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
@@ -1486,8 +1489,7 @@ static int check_system_dir(struct gfs2_inode *sysinode, const char *dirname,
if (!ds.dotdir) {
log_err( _("No '.' entry found for %s directory.\n"), dirname);
if (query( _("Is it okay to add '.' entry? (y/n) "))) {
- uint64_t cur_blks = sysinode->i_di.di_blocks;
-
+ cur_blks = sysinode->i_di.di_blocks;
sprintf(tmp_name, ".");
filename_len = strlen(tmp_name); /* no trailing NULL */
if (!(filename = malloc(sizeof(char) * filename_len))) {
@@ -1578,7 +1580,7 @@ static inline int is_system_dir(struct gfs2_sbd *sdp, uint64_t block)
*/
int pass2(struct gfs2_sbd *sdp)
{
- uint64_t dirblk;
+ uint64_t dirblk, cur_blks;
uint8_t q;
struct dir_status ds = {0};
struct gfs2_inode *ip;
@@ -1640,12 +1642,15 @@ int pass2(struct gfs2_sbd *sdp)
/* First check that the directory's metatree
* is valid */
ip = fsck_load_inode(sdp, dirblk);
+ cur_blks = ip->i_di.di_blocks;
error = check_metatree(ip, &pass2_fxns);
fsck_inode_put(&ip);
if (error < 0) {
stack;
return error;
}
+ if (ip->i_di.di_blocks != cur_blks)
+ reprocess_inode(ip, "current");
}
error = check_dir(sdp, dirblk, &pass2_fxns);
if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
@@ -1704,8 +1709,6 @@ int pass2(struct gfs2_sbd *sdp)
(unsigned long long)dirblk);
if (query( _("Is it okay to add '.' entry? (y/n) "))) {
- uint64_t cur_blks;
-
sprintf(tmp_name, ".");
filename_len = strlen(tmp_name); /* no trailing
NULL */
10 years, 11 months
cluster: RHEL6 - fsck.gfs2: small cleanups
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=205ffdc992e...
Commit: 205ffdc992e944e6bd1db5c7bb024f01d8b6d731
Parent: 0d0256d317fe73aa7e5322df91053e2f4d3408af
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Fri Mar 8 09:49:31 2013 -0700
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri May 17 15:16:33 2013 -0500
fsck.gfs2: small cleanups
This patch just fixes some messages that were wrong, adds comments,
and so forth.
rhbz#902920
---
gfs2/fsck/metawalk.c | 24 +++++++++++++-----------
gfs2/fsck/pass2.c | 9 +++------
gfs2/fsck/util.h | 2 +-
3 files changed, 17 insertions(+), 18 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 1659da0..8df32a0 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -354,14 +354,12 @@ static int check_entries(struct gfs2_inode *ip, struct gfs2_buffer_head *bh,
if (type == DIR_LINEAR) {
dent = (struct gfs2_dirent *)(bh->b_data + sizeof(struct gfs2_dinode));
- }
- else if (type == DIR_EXHASH) {
+ } else if (type == DIR_EXHASH) {
dent = (struct gfs2_dirent *)(bh->b_data + sizeof(struct gfs2_leaf));
- log_debug( _("Checking leaf %llu (0x%llu)\n"),
+ log_debug( _("Checking leaf %llu (0x%llx)\n"),
(unsigned long long)bh->b_blocknr,
(unsigned long long)bh->b_blocknr);
- }
- else {
+ } else {
log_err( _("Invalid directory type %d specified\n"), type);
return -1;
}
@@ -496,11 +494,12 @@ static int check_leaf(struct gfs2_inode *ip, int lindex,
/* Make sure the block number is in range. */
if (!valid_block(ip->i_sbd, *leaf_no)) {
log_err( _("Leaf block #%llu (0x%llx) is out of range for "
- "directory #%llu (0x%llx).\n"),
+ "directory #%llu (0x%llx) at index %d (0x%x).\n"),
(unsigned long long)*leaf_no,
(unsigned long long)*leaf_no,
(unsigned long long)ip->i_di.di_num.no_addr,
- (unsigned long long)ip->i_di.di_num.no_addr);
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ lindex, lindex);
msg = _("that is out of range");
goto bad_leaf;
}
@@ -1332,8 +1331,8 @@ static int check_data(struct gfs2_inode *ip, struct metawalk_fxns *pass,
/**
* check_metatree
- * @ip:
- * @rgd:
+ * @ip: inode structure in memory
+ * @pass: structure passed in from caller to determine the sub-functions
*
*/
int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
@@ -1682,8 +1681,11 @@ void reprocess_inode(struct gfs2_inode *ip, const char *desc)
int error;
alloc_fxns.private = (void *)desc;
- log_info( _("%s had blocks added; reprocessing its metadata tree "
- "at height=%d.\n"), desc, ip->i_di.di_height);
+ log_info( _("%s inode %llu (0x%llx) had blocks added; reprocessing "
+ "its metadata tree at height=%d.\n"), desc,
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ ip->i_di.di_height);
error = check_metatree(ip, &alloc_fxns);
if (error)
log_err( _("Error %d reprocessing the %s metadata tree.\n"),
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index 4000610..f68faab 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -44,9 +44,9 @@ static int set_parent_dir(struct gfs2_sbd *sdp, struct gfs2_inum child,
if (di->dinode.no_addr == child.no_addr &&
di->dinode.no_formal_ino == child.no_formal_ino) {
if (di->treewalk_parent) {
- log_err( _("Another directory at block %llx (0x%llx) "
- "already contains this child %lld (%llx) - "
- "checking parent %llx (0x%llx)\n"),
+ log_err( _("Another directory at block %lld (0x%llx) "
+ "already contains this child %lld (0x%llx)"
+ " - checking parent %lld (0x%llx)\n"),
(unsigned long long)di->treewalk_parent,
(unsigned long long)di->treewalk_parent,
(unsigned long long)child.no_addr,
@@ -1777,6 +1777,3 @@ int pass2(struct gfs2_sbd *sdp)
gfs2_dup_free();
return FSCK_OK;
}
-
-
-
diff --git a/gfs2/fsck/util.h b/gfs2/fsck/util.h
index 3f15fca..a4ff437 100644
--- a/gfs2/fsck/util.h
+++ b/gfs2/fsck/util.h
@@ -65,7 +65,7 @@ static const inline char *block_type_string(uint8_t q)
const char *blktyp[] = {
"free",
"data",
- "indirect data",
+ "indirect meta",
"directory",
"file",
10 years, 11 months