gfs2-utils: master - fsck.gfs2: Add find_remove_dup, free_block_if_notdup
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/gfs2-utils.git?p=gfs2-utils.git;a=commitd...
Commit: e3bb6a63751dbe1f816030351f94b6d3de057514
Parent: 7bc8438a4cd6019174c8f2f93757765849d796df
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Tue Aug 9 15:29:35 2011 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon Aug 29 12:53:53 2011 -0500
fsck.gfs2: Add find_remove_dup, free_block_if_notdup
This patch adds a couple new functions to util.c: find_remove_dup
and free_block_if_notdup. This is a centralized function that
is used to remove a duplicate reference. Each reference needs to be
removed to determine when all duplicate references have been resolved.
The object is to get down to one reference, so we can set the proper
type based on the remaining reference. However, if the very last
reference is deleted as well, the block may be freed.
These functions present one consistent way to do all this rather than
before when the it wasn't very consistent and various bitmap
inaccuracies were sometimes left in the file system.
rhbz#675723
---
gfs2/fsck/metawalk.c | 64 ++++++++++++++++++++++++-------
gfs2/fsck/metawalk.h | 4 ++
gfs2/fsck/pass1.c | 34 +----------------
gfs2/fsck/util.c | 101 ++++++++++++++++++++++++++-----------------------
gfs2/fsck/util.h | 4 ++
5 files changed, 113 insertions(+), 94 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index adaf8a0..34e6192 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -823,6 +823,54 @@ int delete_block(struct gfs2_inode *ip, uint64_t block,
}
/**
+ * find_remove_dup - find out if this is a duplicate ref. If so, remove it.
+ * Returns: 0 if not a duplicate reference, 1 if it is.
+ */
+int find_remove_dup(struct gfs2_inode *ip, uint64_t block, const char *btype)
+{
+ struct duptree *d;
+ struct inode_with_dups *id;
+
+ d = dupfind(block);
+ if (!d)
+ return 0;
+
+ /* remove the inode reference id structure for this reference. */
+ id = find_dup_ref_inode(d, ip);
+ if (!id)
+ return 0;
+
+ dup_listent_delete(id);
+ log_err( _("Removing duplicate status of block %llu (0x%llx) "
+ "referenced as %s by dinode %llu (0x%llx)\n"),
+ (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) {
+ log_info( _("This leaves only one reference: it's "
+ "no longer a duplicate.\n"));
+ dup_delete(d); /* not duplicate now */
+ } else
+ log_info( _("%d block reference(s) remain.\n"),
+ d->refs);
+ return 1; /* but the original ref still exists so do not free it. */
+}
+
+/**
+ * free_block_if_notdup - free blocks associated with an inode, but if it's a
+ * duplicate, just remove that designation instead.
+ * Returns: 0 if the block was freed, 1 if a duplicate reference was removed
+ */
+int free_block_if_notdup(struct gfs2_inode *ip, uint64_t block,
+ const char *btype)
+{
+ if (!find_remove_dup(ip, block, btype))
+ fsck_blockmap_set(ip, block, btype, gfs2_block_free);
+ return 0;
+}
+
+/**
* delete_block_if_notdup - delete blocks associated with an inode
*
* Ignore blocks that are already marked free.
@@ -834,7 +882,6 @@ static int delete_block_if_notdup(struct gfs2_inode *ip, uint64_t block,
const char *btype, void *private)
{
uint8_t q;
- struct duptree *d;
if (!valid_block(ip->i_sbd, block))
return -EFAULT;
@@ -849,20 +896,7 @@ static int delete_block_if_notdup(struct gfs2_inode *ip, uint64_t block,
(unsigned long long)ip->i_di.di_num.no_addr);
return 0;
}
- d = dupfind(block);
- if (d) {
- log_info( _("Removing duplicate reference %d "
- "to block %lld (0x%llx).\n"), d->refs,
- (unsigned long long)block,
- (unsigned long long)block);
- d->refs--; /* one less reference */
- if (d->refs == 1) /* If down to the last reference */
- dup_delete(d); /* not duplicate now */
- return 1; /* but the original ref still exists
- so return (do not free it). */
- }
- fsck_blockmap_set(ip, block, btype, gfs2_block_free);
- return 0;
+ return free_block_if_notdup(ip, block, btype);
}
/**
diff --git a/gfs2/fsck/metawalk.h b/gfs2/fsck/metawalk.h
index 7a8ae4c..719bbd9 100644
--- a/gfs2/fsck/metawalk.h
+++ b/gfs2/fsck/metawalk.h
@@ -35,6 +35,10 @@ extern void reprocess_inode(struct gfs2_inode *ip, const char *desc);
extern struct duptree *dupfind(uint64_t block);
extern struct gfs2_inode *fsck_system_inode(struct gfs2_sbd *sdp,
uint64_t block);
+extern int find_remove_dup(struct gfs2_inode *ip, uint64_t block,
+ const char *btype);
+extern int free_block_if_notdup(struct gfs2_inode *ip, uint64_t block,
+ const char *btype);
#define is_duplicate(dblock) ((dupfind(dblock)) ? 1 : 0)
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index f72030e..8cbda72 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -440,7 +440,6 @@ static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head **bh, int h,
void *private)
{
- struct duptree *d;
int found_dup = 0, iblk_type;
struct gfs2_buffer_head *nbh;
struct block_count *bc = (struct block_count *)private;
@@ -457,20 +456,7 @@ static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
else
iblk_type = GFS2_METATYPE_IN;
- d = dupfind(block);
- if (d) {
- log_err( _("Reversing duplicate status of block %llu (0x%llx) "
- "referenced as metadata in indirect block for "
- "dinode %llu (0x%llx)\n"),
- (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);
- d->refs--; /* one less reference */
- if (d->refs == 1)
- dup_delete(d);
- found_dup = 1;
- }
+ found_dup = find_remove_dup(ip, block, _("Metadata"));
nbh = bread(ip->i_sbd, block);
if (gfs2_check_meta(nbh, iblk_type)) {
@@ -550,7 +536,6 @@ 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)
{
- struct duptree *d;
struct block_count *bc = (struct block_count *) private;
if (!valid_block(ip->i_sbd, block)) {
@@ -562,23 +547,8 @@ static int undo_check_data(struct gfs2_inode *ip, uint64_t block,
gfs2_block_free);
return 1;
}
- d = dupfind(block);
- if (d) {
- log_err( _("Reversing duplicate status of block %llu (0x%llx) "
- "referenced as data by dinode %llu (0x%llx)\n"),
- (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);
- d->refs--; /* one less reference */
- if (d->refs == 1)
- dup_delete(d);
- bc->data_count--;
- return 1;
- }
- fsck_blockmap_set(ip, block, _("data"), gfs2_block_free);
bc->data_count--;
- return 0;
+ return free_block_if_notdup(ip, block, _("data"));
}
static int remove_inode_eattr(struct gfs2_inode *ip, struct block_count *bc)
diff --git a/gfs2/fsck/util.c b/gfs2/fsck/util.c
index 66fa4ec..ab0a79f 100644
--- a/gfs2/fsck/util.c
+++ b/gfs2/fsck/util.c
@@ -188,6 +188,30 @@ static struct duptree *gfs2_dup_set(uint64_t dblock, int create)
return data;
}
+/**
+ * find_dup_ref_inode - find a duplicate reference inode entry for an inode
+ */
+struct inode_with_dups *find_dup_ref_inode(struct duptree *dt,
+ struct gfs2_inode *ip)
+{
+ osi_list_t *ref;
+ struct inode_with_dups *id;
+
+ osi_list_foreach(ref, &dt->ref_invinode_list) {
+ id = osi_list_entry(ref, struct inode_with_dups, list);
+
+ if (id->block_no == ip->i_di.di_num.no_addr)
+ return id;
+ }
+ 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)
+ return id;
+ }
+ return NULL;
+}
+
/*
* add_duplicate_ref - Add a duplicate reference to the duplicates tree list
* A new element of the tree will be created as needed
@@ -196,15 +220,19 @@ static struct duptree *gfs2_dup_set(uint64_t dblock, int create)
* So we need to recreate the duplicate reference structure if it's not there.
* Later, in pass1b, it has to go back through the file system
* and figure out those original references in order to resolve them.
+ *
+ * first - if 1, we're being called from pass1b, in which case we're trying
+ * to find the first reference to this block. If 0, we're being
+ * called from pass1, which is the second reference, which determined
+ * it was a duplicate..
*/
int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block,
enum dup_ref_type reftype, int first, int inode_valid)
{
- osi_list_t *ref;
- struct inode_with_dups *id, *found_id;
+ struct inode_with_dups *id;
struct duptree *dt;
- if (!valid_block(ip->i_sbd, block) != 0)
+ if (!valid_block(ip->i_sbd, block))
return 0;
/* 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
@@ -224,65 +252,42 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block,
reference, we don't want to increment the reference count because
it's already accounted for. */
if (first) {
- if (!dt->first_ref_found) {
- dt->first_ref_found = 1;
- dups_found_first++; /* We found another first ref. */
- }
+ dt->first_ref_found = 1;
+ dups_found_first++; /* We found another first ref. */
} else {
dt->refs++;
}
- /* Check for a previous reference to this duplicate on the "invalid
- inode" reference list. */
- found_id = NULL;
- osi_list_foreach(ref, &dt->ref_invinode_list) {
- id = osi_list_entry(ref, struct inode_with_dups, list);
-
- if (id->block_no == ip->i_di.di_num.no_addr) {
- found_id = id;
- break;
- }
- }
- if (found_id == NULL) {
- 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) {
- found_id = id;
- break;
- }
- }
- }
- if (found_id == NULL) {
+ /* Check for a previous reference to this duplicate */
+ id = find_dup_ref_inode(dt, ip);
+ if (id == NULL) {
/* Check for the inode on the invalid inode reference list. */
uint8_t q;
- if (!(found_id = malloc(sizeof(*found_id)))) {
+ if (!(id = malloc(sizeof(*id)))) {
log_crit( _("Unable to allocate "
"inode_with_dups structure\n"));
return -1;
}
- if (!(memset(found_id, 0, sizeof(*found_id)))) {
+ if (!(memset(id, 0, sizeof(*id)))) {
log_crit( _("Unable to zero inode_with_dups "
"structure\n"));
return -1;
}
- found_id->block_no = ip->i_di.di_num.no_addr;
+ id->block_no = ip->i_di.di_num.no_addr;
q = block_type(ip->i_di.di_num.no_addr);
/* If it's an invalid dinode, put it first on the invalid
inode reference list otherwise put it on the normal list. */
if (!inode_valid || q == gfs2_inode_invalid)
- osi_list_add_prev(&found_id->list,
- &dt->ref_invinode_list);
+ osi_list_add_prev(&id->list, &dt->ref_invinode_list);
else
- osi_list_add_prev(&found_id->list,
- &dt->ref_inode_list);
+ osi_list_add_prev(&id->list, &dt->ref_inode_list);
}
- found_id->reftypecount[reftype]++;
- found_id->dup_count++;
+ id->reftypecount[reftype]++;
+ id->dup_count++;
log_info( _("Found %d reference(s) to block %llu"
" (0x%llx) as %s in inode #%llu (0x%llx)\n"),
- found_id->dup_count, (unsigned long long)block,
+ id->dup_count, (unsigned long long)block,
(unsigned long long)block, reftypes[reftype],
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
@@ -346,6 +351,14 @@ struct dir_info *dirtree_find(uint64_t block)
return NULL;
}
+void dup_listent_delete(struct inode_with_dups *id)
+{
+ if (id->name)
+ free(id->name);
+ osi_list_del(&id->list);
+ free(id);
+}
+
void dup_delete(struct duptree *b)
{
struct inode_with_dups *id;
@@ -354,18 +367,12 @@ void dup_delete(struct duptree *b)
while (!osi_list_empty(&b->ref_invinode_list)) {
tmp = (&b->ref_invinode_list)->next;
id = osi_list_entry(tmp, struct inode_with_dups, list);
- if (id->name)
- free(id->name);
- osi_list_del(&id->list);
- free(id);
+ dup_listent_delete(id);
}
while (!osi_list_empty(&b->ref_inode_list)) {
tmp = (&b->ref_inode_list)->next;
id = osi_list_entry(tmp, struct inode_with_dups, list);
- if (id->name)
- free(id->name);
- osi_list_del(&id->list);
- free(id);
+ dup_listent_delete(id);
}
osi_erase(&b->node, &dup_blocks);
free(b);
diff --git a/gfs2/fsck/util.h b/gfs2/fsck/util.h
index d2c81db..56b83fe 100644
--- a/gfs2/fsck/util.h
+++ b/gfs2/fsck/util.h
@@ -15,6 +15,10 @@ void big_file_comfort(struct gfs2_inode *ip, uint64_t blks_checked);
void warm_fuzzy_stuff(uint64_t block);
int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block,
enum dup_ref_type reftype, int first, int inode_valid);
+extern struct inode_with_dups *find_dup_ref_inode(struct duptree *dt,
+ struct gfs2_inode *ip);
+extern void dup_listent_delete(struct inode_with_dups *id);
+
extern const char *reftypes[3];
static inline uint8_t block_type(uint64_t bblock)
12 years, 8 months
gfs2-utils: master - fsck.gfs2: Don't use old_leaf if it was a duplicate
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/gfs2-utils.git?p=gfs2-utils.git;a=commitd...
Commit: 7bc8438a4cd6019174c8f2f93757765849d796df
Parent: defac4ceed053f5d94a4e423d080719ec75800d5
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Tue Aug 9 14:22:12 2011 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon Aug 29 12:53:53 2011 -0500
fsck.gfs2: Don't use old_leaf if it was a duplicate
In function check_leaf_blks fsck.gfs2 keeps track of the current leaf
and the previous leaf. It can only check the number of pointers is
correct for the old leaf after it finds a new leaf block. However,
it was getting confused if the old leaf was a duplicate reference.
If the old leaf was a duplicate referenced by a different dinode, we
can't check the number of pointers because the number of pointers may
be for that other dinode's reference, not this one. The other dinode
referencing this leaf block may have the correct depth and this one
may not. This patch adds an extra check for the old leaf block being
a duplicate before checking the number of pointers.
rhbz#675723
---
gfs2/fsck/metawalk.c | 12 +++++++++---
1 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 860790d..adaf8a0 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -602,7 +602,7 @@ static int check_leaf_blks(struct gfs2_inode *ip, struct metawalk_fxns *pass)
struct gfs2_buffer_head *lbh;
int lindex;
struct gfs2_sbd *sdp = ip->i_sbd;
- int ref_count = 0;
+ int ref_count = 0, old_was_dup;
/* Find the first valid leaf pointer in range and use it as our "old"
leaf. That way, bad blocks at the beginning will be overwritten
@@ -630,7 +630,8 @@ static int check_leaf_blks(struct gfs2_inode *ip, struct metawalk_fxns *pass)
}
old_leaf = -1;
memset(&oldleaf, 0, sizeof(oldleaf));
- for(lindex = 0; lindex < (1 << ip->i_di.di_depth); lindex++) {
+ old_was_dup = 0;
+ for (lindex = 0; lindex < (1 << ip->i_di.di_depth); lindex++) {
if (fsck_abort)
break;
gfs2_get_leaf_nr(ip, lindex, &leaf_no);
@@ -649,7 +650,11 @@ static int check_leaf_blks(struct gfs2_inode *ip, struct metawalk_fxns *pass)
do {
if (fsck_abort)
return 0;
- if (pass->check_num_ptrs &&
+ /* If the old leaf was a duplicate referenced by a
+ previous dinode, we can't check the number of
+ pointers because the number of pointers may be for
+ that other dinode's reference, not this one. */
+ if (pass->check_num_ptrs && !old_was_dup &&
valid_block(ip->i_sbd, old_leaf)) {
error = pass->check_num_ptrs(ip, old_leaf,
&ref_count,
@@ -661,6 +666,7 @@ static int check_leaf_blks(struct gfs2_inode *ip, struct metawalk_fxns *pass)
error = check_leaf(ip, lindex, pass, &ref_count,
&leaf_no, old_leaf, &bad_leaf,
first_ok_leaf, &leaf, &oldleaf);
+ old_was_dup = (error == -EEXIST);
old_leaf = leaf_no;
memcpy(&oldleaf, &leaf, sizeof(oldleaf));
if (!leaf.lf_next || error)
12 years, 8 months
gfs2-utils: master - fsck.gfs2: misc cosmetic changes
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/gfs2-utils.git?p=gfs2-utils.git;a=commitd...
Commit: defac4ceed053f5d94a4e423d080719ec75800d5
Parent: 66d785102dde6bd0200b345b14bb2fefe7a406cd
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Tue Aug 9 14:07:21 2011 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon Aug 29 12:53:53 2011 -0500
fsck.gfs2: misc cosmetic changes
This patch is just cosmetic changes. It cleans up comments and code
but there should be no logic changes.
rhbz#675723
---
gfs2/fsck/metawalk.c | 17 +++++++----------
gfs2/fsck/pass1.c | 8 ++++----
gfs2/fsck/pass1b.c | 4 ++--
gfs2/fsck/pass2.c | 2 +-
gfs2/fsck/pass5.c | 10 ++++++----
5 files changed, 20 insertions(+), 21 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 5a275ca..860790d 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -452,15 +452,14 @@ static int warn_and_patch(struct gfs2_inode *ip, uint64_t *leaf_no,
}
if (*leaf_no == *bad_leaf ||
(okay_to_fix = query( _("Attempt to patch around it? (y/n) ")))) {
- if (!valid_block(ip->i_sbd, old_leaf) == 0)
+ if (valid_block(ip->i_sbd, old_leaf))
gfs2_put_leaf_nr(ip, pindex, old_leaf);
else
gfs2_put_leaf_nr(ip, pindex, first_ok_leaf);
log_err( _("Directory Inode %llu (0x%llx) repaired.\n"),
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
- }
- else
+ } else
log_err( _("Bad leaf left in place.\n"));
*bad_leaf = *leaf_no;
*leaf_no = old_leaf;
@@ -609,9 +608,9 @@ static int check_leaf_blks(struct gfs2_inode *ip, struct metawalk_fxns *pass)
leaf. That way, bad blocks at the beginning will be overwritten
with the first valid leaf. */
first_ok_leaf = leaf_no = -1;
- for(lindex = 0; lindex < (1 << ip->i_di.di_depth); lindex++) {
+ for (lindex = 0; lindex < (1 << ip->i_di.di_depth); lindex++) {
gfs2_get_leaf_nr(ip, lindex, &leaf_no);
- if (!valid_block(ip->i_sbd, leaf_no) == 0) {
+ if (valid_block(ip->i_sbd, leaf_no)) {
lbh = bread(sdp, leaf_no);
/* Make sure it's really a valid leaf block. */
if (gfs2_check_meta(lbh, GFS2_METATYPE_LF) == 0) {
@@ -637,11 +636,9 @@ static int check_leaf_blks(struct gfs2_inode *ip, struct metawalk_fxns *pass)
gfs2_get_leaf_nr(ip, lindex, &leaf_no);
/* GFS has multiple indirect pointers to the same leaf
- * until those extra pointers are needed, so skip the
- * dups */
+ * until those extra pointers are needed, so skip the dups */
if (leaf_no == bad_leaf) {
- gfs2_put_leaf_nr(ip, lindex, old_leaf); /* fill w/old
- leaf info */
+ gfs2_put_leaf_nr(ip, lindex, old_leaf);
ref_count++;
continue;
} else if (old_leaf == leaf_no) {
@@ -812,7 +809,7 @@ int delete_block(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head **bh, const char *btype,
void *private)
{
- if (!valid_block(ip->i_sbd, block) == 0) {
+ if (valid_block(ip->i_sbd, block)) {
fsck_blockmap_set(ip, block, btype, gfs2_block_free);
return 0;
}
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index 44e1422..f72030e 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -373,7 +373,7 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
*bh = NULL;
- if (!valid_block(ip->i_sbd, block)){ /* blk outside of FS */
+ if (!valid_block(ip->i_sbd, block)) { /* blk outside of FS */
fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
_("itself"), gfs2_bad_block);
log_debug( _("Bad indirect block (invalid/out of range) "
@@ -447,7 +447,7 @@ static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
*bh = NULL;
- if (!valid_block(ip->i_sbd, block)){ /* blk outside of FS */
+ if (!valid_block(ip->i_sbd, block)) { /* blk outside of FS */
fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
_("itself"), gfs2_block_free);
return 1;
@@ -868,7 +868,7 @@ static int check_extended_leaf_eattr(struct gfs2_inode *ip, uint64_t *data_ptr,
struct gfs2_buffer_head *bh = NULL;
int error;
- if (!valid_block(sdp, el_blk)){
+ if (!valid_block(sdp, el_blk)) {
log_err( _("Inode #%llu (0x%llx): Extended Attribute block "
"%llu (0x%llx) has an extended leaf block #%llu "
"(0x%llx) that is invalid or out of range.\n"),
@@ -1060,7 +1060,7 @@ static int rangecheck_block(struct gfs2_inode *ip, uint64_t block,
long *bad_pointers = (long *)private;
uint8_t q;
- if (!valid_block(ip->i_sbd, block) != 0) {
+ if (!valid_block(ip->i_sbd, block)) {
(*bad_pointers)++;
log_info( _("Bad %s block pointer (invalid or out of range "
"#%ld) found in inode %lld (0x%llx).\n"),
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index 452fb93..cabf641 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -211,7 +211,7 @@ static int clear_dup_metalist(struct gfs2_inode *ip, uint64_t block,
struct dup_handler *dh = (struct dup_handler *) private;
struct duptree *d;
- if (!valid_block(ip->i_sbd, block) != 0)
+ if (!valid_block(ip->i_sbd, block))
return 0;
/* This gets tricky. We're traversing a metadata tree trying to
@@ -631,7 +631,7 @@ int pass1b(struct gfs2_sbd *sdp)
log_debug( _("Filesystem has %llu (0x%llx) blocks total\n"),
(unsigned long long)last_fs_block,
(unsigned long long)last_fs_block);
- for(i = 0; i < last_fs_block; i++) {
+ for (i = 0; i < last_fs_block; i++) {
if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
goto out;
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index 4a6073a..83172af 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -776,7 +776,7 @@ int pass2(struct gfs2_sbd *sdp)
return FSCK_OK;
log_info( _("Checking directory inodes.\n"));
/* Grab each directory inode, and run checks on it */
- for(dirblk = 0; dirblk < last_fs_block; dirblk++) {
+ for (dirblk = 0; dirblk < last_fs_block; dirblk++) {
warm_fuzzy_stuff(dirblk);
if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
return FSCK_OK;
diff --git a/gfs2/fsck/pass5.c b/gfs2/fsck/pass5.c
index b83777b..191935f 100644
--- a/gfs2/fsck/pass5.c
+++ b/gfs2/fsck/pass5.c
@@ -45,13 +45,14 @@ static int convert_mark(uint8_t q, uint32_t *count)
default:
log_err( _("Invalid block type %d found\n"), q);
- return -1;
}
return -1;
}
-static int check_block_status(struct gfs2_sbd *sdp, char *buffer, unsigned int buflen,
- uint64_t *rg_block, uint64_t rg_data, uint32_t *count)
+
+static int check_block_status(struct gfs2_sbd *sdp, char *buffer,
+ unsigned int buflen, uint64_t *rg_block,
+ uint64_t rg_data, uint32_t *count)
{
unsigned char *byte, *end;
unsigned int bit;
@@ -154,7 +155,8 @@ static void update_rgrp(struct gfs2_sbd *sdp, struct rgrp_list *rgp,
/* update the bitmaps */
check_block_status(sdp, rgp->bh[i]->b_data + bits->bi_offset,
- bits->bi_len, &rg_block, rgp->ri.ri_data0, count);
+ bits->bi_len, &rg_block, rgp->ri.ri_data0,
+ count);
if (skip_this_pass || fsck_abort) /* if asked to skip the rest */
return;
}
12 years, 8 months
gfs2-utils: master - fsck.gfs2 pass3: Refactor mark_and_return_parent
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/gfs2-utils.git?p=gfs2-utils.git;a=commitd...
Commit: 66d785102dde6bd0200b345b14bb2fefe7a406cd
Parent: ae2132d6d92091666d662f158620993e4212ce26
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Tue Aug 9 13:27:01 2011 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon Aug 29 12:53:53 2011 -0500
fsck.gfs2 pass3: Refactor mark_and_return_parent
This patch refactors pass3 function "mark_and_return_parent". Before
it was so complex and indented you could hardly interpret it. Now you
can actually follow the logic.
rhbz#675723
---
gfs2/fsck/pass3.c | 162 ++++++++++++++++++++++++++---------------------------
1 files changed, 79 insertions(+), 83 deletions(-)
diff --git a/gfs2/fsck/pass3.c b/gfs2/fsck/pass3.c
index ea8c51d..a34dd36 100644
--- a/gfs2/fsck/pass3.c
+++ b/gfs2/fsck/pass3.c
@@ -80,102 +80,98 @@ static struct dir_info *mark_and_return_parent(struct gfs2_sbd *sdp,
{
struct dir_info *pdi;
uint8_t q_dotdot, q_treewalk;
+ int error = 0;
di->checked = 1;
if (!di->treewalk_parent)
return NULL;
- if (di->dotdot_parent != di->treewalk_parent) {
- log_warn( _("Directory '..' and treewalk connections disagree for inode %llu"
- " (0x%llx)\n"), (unsigned long long)di->dinode,
- (unsigned long long)di->dinode);
- log_notice( _("'..' has %llu (0x%llx), treewalk has %llu"
- " (0x%llx)\n"),
- (unsigned long long)di->dotdot_parent,
- (unsigned long long)di->dotdot_parent,
- (unsigned long long)di->treewalk_parent,
- (unsigned long long)di->treewalk_parent);
+ if (di->dotdot_parent == di->treewalk_parent) {
q_dotdot = block_type(di->dotdot_parent);
- q_treewalk = block_type(di->treewalk_parent);
- /* if the dotdot entry isn't a directory, but the
- * treewalk is, treewalk is correct - if the treewalk
- * entry isn't a directory, but the dotdot is, dotdot
- * is correct - if both are directories, which do we
- * choose? if neither are directories, we have a
- * problem - need to move this directory into lost+found
- */
if (q_dotdot != gfs2_inode_dir) {
- if (q_treewalk != gfs2_inode_dir) {
- log_err( _("Orphaned directory, move to lost+found\n"));
- return NULL;
- }
- else {
- log_warn( _("Treewalk parent is correct,"
- " fixing dotdot -> %llu (0x%llx)\n"),
- (unsigned long long)di->treewalk_parent,
- (unsigned long long)di->treewalk_parent);
- attach_dotdot_to(sdp, di->treewalk_parent,
- di->dotdot_parent, di->dinode);
- di->dotdot_parent = di->treewalk_parent;
- }
- } else {
- if (q_treewalk != gfs2_inode_dir) {
- int error = 0;
- log_warn( _(".. parent is valid, but treewalk"
- "is bad - reattaching to lost+found"));
-
- /* FIXME: add a dinode for this entry instead? */
-
- if (query( _("Remove directory entry for bad"
- " inode %llu (0x%llx) in %llu"
- " (0x%llx)? (y/n)"),
- (unsigned long long)di->dinode,
- (unsigned long long)di->dinode,
- (unsigned long long)di->treewalk_parent,
- (unsigned long long)di->treewalk_parent)) {
- error = remove_dentry_from_dir(sdp, di->treewalk_parent,
- di->dinode);
- if (error < 0) {
- stack;
- return NULL;
- }
- if (error > 0) {
- log_warn( _("Unable to find dentry for block %llu"
- " (0x%llx) in %llu (0x%llx)\n"),
- (unsigned long long)di->dinode,
- (unsigned long long)di->dinode,
- (unsigned long long)di->treewalk_parent,
- (unsigned long long)di->treewalk_parent);
- }
- log_warn( _("Directory entry removed\n"));
- } else {
- log_err( _("Directory entry to invalid inode remains\n"));
- }
- log_info( _("Marking directory unlinked\n"));
-
- return NULL;
- }
- else {
- log_err( _("Both .. and treewalk parents are "
- "directories, going with treewalk "
- "for now...\n"));
- attach_dotdot_to(sdp, di->treewalk_parent,
- di->dotdot_parent,
- di->dinode);
- di->dotdot_parent = di->treewalk_parent;
- }
+ log_err( _("Orphaned directory at block %llu (0x%llx) "
+ "moved to lost+found\n"),
+ (unsigned long long)di->dinode,
+ (unsigned long long)di->dinode);
+ return NULL;
}
+ goto out;
}
- else {
- q_dotdot = block_type(di->dotdot_parent);
- if (q_dotdot != gfs2_inode_dir) {
- log_err( _("Orphaned directory at block %llu (0x%llx) moved to lost+found\n"),
- (unsigned long long)di->dinode,
- (unsigned long long)di->dinode);
+
+ log_warn( _("Directory '..' and treewalk connections disagree for "
+ "inode %llu (0x%llx)\n"), (unsigned long long)di->dinode,
+ (unsigned long long)di->dinode);
+ log_notice( _("'..' has %llu (0x%llx), treewalk has %llu (0x%llx)\n"),
+ (unsigned long long)di->dotdot_parent,
+ (unsigned long long)di->dotdot_parent,
+ (unsigned long long)di->treewalk_parent,
+ (unsigned long long)di->treewalk_parent);
+ q_dotdot = block_type(di->dotdot_parent);
+ q_treewalk = block_type(di->treewalk_parent);
+ /* if the dotdot entry isn't a directory, but the
+ * treewalk is, treewalk is correct - if the treewalk
+ * entry isn't a directory, but the dotdot is, dotdot
+ * is correct - if both are directories, which do we
+ * choose? if neither are directories, we have a
+ * problem - need to move this directory into lost+found
+ */
+ if (q_dotdot != gfs2_inode_dir) {
+ if (q_treewalk != gfs2_inode_dir) {
+ log_err( _("Orphaned directory, move to "
+ "lost+found\n"));
return NULL;
+ } else {
+ log_warn( _("Treewalk parent is correct, fixing "
+ "dotdot -> %llu (0x%llx)\n"),
+ (unsigned long long)di->treewalk_parent,
+ (unsigned long long)di->treewalk_parent);
+ attach_dotdot_to(sdp, di->treewalk_parent,
+ di->dotdot_parent, di->dinode);
+ di->dotdot_parent = di->treewalk_parent;
}
+ goto out;
+ }
+ if (q_treewalk == gfs2_inode_dir) {
+ log_err( _("Both .. and treewalk parents are directories, "
+ "going with treewalk...\n"));
+ attach_dotdot_to(sdp, di->treewalk_parent,
+ di->dotdot_parent, di->dinode);
+ di->dotdot_parent = di->treewalk_parent;
+ goto out;
}
+ log_warn( _(".. parent is valid, but treewalk is bad - reattaching to "
+ "lost+found"));
+
+ /* FIXME: add a dinode for this entry instead? */
+
+ if (!query( _("Remove directory entry for bad inode %llu (0x%llx) in "
+ "%llu (0x%llx)? (y/n)"),
+ (unsigned long long)di->dinode,
+ (unsigned long long)di->dinode,
+ (unsigned long long)di->treewalk_parent,
+ (unsigned long long)di->treewalk_parent)) {
+ log_err( _("Directory entry to invalid inode remains\n"));
+ return NULL;
+ }
+ error = remove_dentry_from_dir(sdp, di->treewalk_parent, di->dinode);
+ if (error < 0) {
+ stack;
+ return NULL;
+ }
+ if (error > 0)
+ log_warn( _("Unable to find dentry for block %llu"
+ " (0x%llx) in %llu (0x%llx)\n"),
+ (unsigned long long)di->dinode,
+ (unsigned long long)di->dinode,
+ (unsigned long long)di->treewalk_parent,
+ (unsigned long long)di->treewalk_parent);
+ log_warn( _("Directory entry removed\n"));
+ log_info( _("Marking directory unlinked\n"));
+
+ return NULL;
+
+out:
pdi = dirtree_find(di->dotdot_parent);
return pdi;
12 years, 8 months
gfs2-utils: master - fsck.gfs2 pass2: Don't delete invalid inode metadata
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/gfs2-utils.git?p=gfs2-utils.git;a=commitd...
Commit: ae2132d6d92091666d662f158620993e4212ce26
Parent: 2d76dd52ac8668ab838cfefe209ddee5d40d61fa
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Tue Aug 9 13:01:05 2011 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon Aug 29 12:53:53 2011 -0500
fsck.gfs2 pass2: Don't delete invalid inode metadata
In pass2, all metadata was deleted for inodes that were marked either
"bad" or "invalid" but that is wrong, and here is why:
Blocks marked "invalid" were invalidated due to duplicate block references.
Pass1b should have already taken care of deleting their metadata, so in pass2
we only need to delete the directory entries pointing to them. We delete the
metadata in pass1b because we need to eliminate the inode referencing the
duplicate-referenced block from the list of candidates to keep. So we have a
delete-as-we-go policy. Blocks marked "bad" need to have their entire
metadata tree deleted.
rhbz#675723
---
gfs2/fsck/pass2.c | 30 ++++++++++++++++++++++--------
1 files changed, 22 insertions(+), 8 deletions(-)
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index 2ee3fe7..4a6073a 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -319,6 +319,18 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
q = block_type(entryblock);
/* Get the status of the directory inode */
+ /**
+ * 1. Blocks marked "invalid" were invalidated due to duplicate
+ * block references. Pass1b should have already taken care of deleting
+ * their metadata, so here we only need to delete the directory entries
+ * pointing to them. We delete the metadata in pass1b because we need
+ * to eliminate the inode referencing the duplicate-referenced block
+ * from the list of candidates to keep. So we have a delete-as-we-go
+ * policy.
+ *
+ * 2. Blocks marked "bad" need to have their entire
+ * metadata tree deleted.
+ */
if (q == gfs2_inode_invalid || q == gfs2_bad_block) {
/* This entry's inode has bad blocks in it */
@@ -333,14 +345,16 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
goto dentry_is_valid;
}
- if (ip->i_di.di_num.no_addr == entryblock)
- entry_ip = ip;
- else
- entry_ip = fsck_load_inode(sdp, entryblock);
- check_inode_eattr(entry_ip, &pass2_fxns_delete);
- check_metatree(entry_ip, &pass2_fxns_delete);
- if (entry_ip != ip)
- fsck_inode_put(&entry_ip);
+ if (q == gfs2_bad_block) {
+ if (ip->i_di.di_num.no_addr == entryblock)
+ entry_ip = ip;
+ else
+ entry_ip = fsck_load_inode(sdp, entryblock);
+ check_inode_eattr(entry_ip, &pass2_fxns_delete);
+ check_metatree(entry_ip, &pass2_fxns_delete);
+ if (entry_ip != ip)
+ fsck_inode_put(&entry_ip);
+ }
fsck_blockmap_set(ip, entryblock,
_("bad directory entry"), gfs2_block_free);
log_err( _("Inode %lld (0x%llx) was deleted.\n"),
12 years, 8 months
gfs2-utils: master - fsck.gfs2 pass2: Delete extended attributes with inode
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/gfs2-utils.git?p=gfs2-utils.git;a=commitd...
Commit: 2d76dd52ac8668ab838cfefe209ddee5d40d61fa
Parent: 20e366872c01061873a6172258fadf1b13698066
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Tue Aug 9 12:48:36 2011 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon Aug 29 12:53:53 2011 -0500
fsck.gfs2 pass2: Delete extended attributes with inode
When pass2 decided to delete a bad/corrupt dinode from disk, it was
not deleting extended attributes associated with that dinode. Oops.
This patch corrects the situation and allows it to delete them.
rhbz#675723
---
gfs2/fsck/pass2.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 55 insertions(+), 0 deletions(-)
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index 870a792..2ee3fe7 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -162,6 +162,59 @@ static int check_file_type(uint8_t de_type, uint8_t blk_type)
return 0;
}
+static int delete_eattr_entry (struct gfs2_inode *ip,
+ struct gfs2_buffer_head *leaf_bh,
+ struct gfs2_ea_header *ea_hdr,
+ struct gfs2_ea_header *ea_hdr_prev,
+ void *private)
+{
+ struct gfs2_sbd *sdp = ip->i_sbd;
+ char ea_name[256];
+
+ if (!ea_hdr->ea_name_len){
+ /* Skip this entry for now */
+ return 1;
+ }
+
+ memset(ea_name, 0, sizeof(ea_name));
+ strncpy(ea_name, (char *)ea_hdr + sizeof(struct gfs2_ea_header),
+ ea_hdr->ea_name_len);
+
+ if (!GFS2_EATYPE_VALID(ea_hdr->ea_type) &&
+ ((ea_hdr_prev) || (!ea_hdr_prev && ea_hdr->ea_type))){
+ /* Skip invalid entry */
+ return 1;
+ }
+
+ if (ea_hdr->ea_num_ptrs){
+ uint32_t avail_size;
+ int max_ptrs;
+
+ avail_size = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_meta_header);
+ max_ptrs = (be32_to_cpu(ea_hdr->ea_data_len) + avail_size - 1) /
+ avail_size;
+
+ if (max_ptrs > ea_hdr->ea_num_ptrs)
+ return 1;
+ else {
+ log_debug( _(" Pointers Required: %d\n Pointers Reported: %d\n"),
+ max_ptrs, ea_hdr->ea_num_ptrs);
+ }
+ }
+ return 0;
+}
+
+static int delete_eattr_extentry(struct gfs2_inode *ip, uint64_t *ea_data_ptr,
+ struct gfs2_buffer_head *leaf_bh,
+ struct gfs2_ea_header *ea_hdr,
+ struct gfs2_ea_header *ea_hdr_prev,
+ void *private)
+{
+ uint64_t block = be64_to_cpu(*ea_data_ptr);
+
+ return delete_metadata(ip, block, NULL, 0, private);
+}
+
struct metawalk_fxns pass2_fxns_delete = {
.private = NULL,
.check_metalist = delete_metadata,
@@ -169,6 +222,8 @@ struct metawalk_fxns pass2_fxns_delete = {
.check_leaf = delete_leaf,
.check_eattr_indir = delete_eattr_indir,
.check_eattr_leaf = delete_eattr_leaf,
+ .check_eattr_entry = delete_eattr_entry,
+ .check_eattr_extentry = delete_eattr_extentry,
};
/* FIXME: should maybe refactor this a bit - but need to deal with
12 years, 8 months
gfs2-utils: master - fsck.gfs pass2: Refactor function set_dotdor_dir
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/gfs2-utils.git?p=gfs2-utils.git;a=commitd...
Commit: 20e366872c01061873a6172258fadf1b13698066
Parent: dbdb6b1abafa601353f959f6cde3b9d13a0a1f3f
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Tue Aug 9 12:45:18 2011 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon Aug 29 12:53:52 2011 -0500
fsck.gfs pass2: Refactor function set_dotdor_dir
This patch refactors function set_dotdot_dir to make it more readable.
rhbz#675723
---
gfs2/fsck/pass2.c | 53 +++++++++++++++++++++++++++--------------------------
1 files changed, 27 insertions(+), 26 deletions(-)
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index 01f8000..870a792 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -61,39 +61,40 @@ static int set_parent_dir(struct gfs2_sbd *sdp, uint64_t childblock,
/* Set's the child's '..' directory inode number in dir_info structure */
static int set_dotdot_dir(struct gfs2_sbd *sdp, uint64_t childblock,
- uint64_t parentblock)
+ uint64_t parentblock)
{
struct dir_info *di;
di = dirtree_find(childblock);
- if (di) {
- if (di->dinode == childblock) {
- /* Special case for root inode because we set
- * it earlier */
- if (di->dotdot_parent && sdp->md.rooti->i_di.di_num.no_addr
- != di->dinode) {
- /* This should never happen */
- log_crit( _("Dotdot parent already set for"
- " block %llu (0x%llx) -> %llu"
- " (0x%llx)\n"),
- (unsigned long long)childblock,
- (unsigned long long)childblock,
- (unsigned long long)di->dotdot_parent,
- (unsigned long long)di->dotdot_parent);
- return -1;
- }
- di->dotdot_parent = parentblock;
- }
- } else {
- log_err( _("Unable to find block %llu (0x%llx"
- ") in dir_info list\n"),
- (unsigned long long)childblock,
- (unsigned long long)childblock);
+ if (!di) {
+ log_err( _("Unable to find block %"PRIu64" (0x%" PRIx64
+ ") in dir_info tree\n"), childblock, childblock);
return -1;
}
-
+ if (di->dinode != childblock) {
+ log_debug("'..' doesn't point to what we found: childblock "
+ "0x%llx != dinode 0x%llx\n",
+ (unsigned long long)childblock,
+ (unsigned long long)di->dinode);
+ return -1;
+ }
+ /* Special case for root inode because we set it earlier */
+ if (di->dotdot_parent &&
+ sdp->md.rooti->i_di.di_num.no_addr != di->dinode) {
+ /* This should never happen */
+ log_crit( _("Dotdot parent already set for block %llu (0x%llx)"
+ "-> %llu (0x%llx)\n"),
+ (unsigned long long)childblock,
+ (unsigned long long)childblock,
+ (unsigned long long)di->dotdot_parent,
+ (unsigned long long)di->dotdot_parent);
+ return -1;
+ }
+ log_debug("Setting '..' for directory block 0x%llx to parent 0x%llx\n",
+ (unsigned long long)childblock,
+ (unsigned long long)parentblock);
+ di->dotdot_parent = parentblock;
return 0;
-
}
static int check_eattr_indir(struct gfs2_inode *ip, uint64_t block,
12 years, 8 months
gfs2-utils: master - fsck.gfs2: Make output messages more sensible
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/gfs2-utils.git?p=gfs2-utils.git;a=commitd...
Commit: dbdb6b1abafa601353f959f6cde3b9d13a0a1f3f
Parent: 3527e52c3ed84708e888635195264ece16db4216
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Tue Aug 9 12:36:04 2011 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon Aug 29 12:53:52 2011 -0500
fsck.gfs2: Make output messages more sensible
This patch changes several fsck output messages so that they make more
sense. Digging through very big and complex fsck.gfs2 output, I found
myself lost in many occasions. This patch makes it a lot easier to see
what decisions are made by fsck.gfs2 and why.
rhbz#675723
---
gfs2/fsck/initialize.c | 23 ++++++++++++++++-------
gfs2/fsck/metawalk.c | 2 +-
gfs2/fsck/pass1.c | 4 ++++
gfs2/fsck/pass1b.c | 5 +++--
gfs2/fsck/pass2.c | 18 ++++++++++++++----
gfs2/fsck/pass5.c | 23 +++++++++++++----------
gfs2/fsck/util.c | 3 ++-
7 files changed, 53 insertions(+), 25 deletions(-)
diff --git a/gfs2/fsck/initialize.c b/gfs2/fsck/initialize.c
index c0e83a7..2d667fc 100644
--- a/gfs2/fsck/initialize.c
+++ b/gfs2/fsck/initialize.c
@@ -517,14 +517,14 @@ static int init_system_inodes(struct gfs2_sbd *sdp)
uint64_t addl_mem_needed;
const char *level_desc[] = {
_("Checking if all rgrp and rindex values are good"),
- _("Checking if rindex values are ascending and evenly spaced"),
+ _("Checking if rindex values may be easily repaired"),
_("Calculating where the rgrps should be if evenly spaced"),
_("Trying to rebuild rindex assuming evenly spaced rgrps"),
_("Trying to rebuild rindex assuming unevenly spaced rgrps"),
};
const char *fail_desc[] = {
_("Some damage was found; we need to take remedial measures"),
- _("rindex is unevenly spaced: converted from gfs1 or corrupt"),
+ _("rindex is unevenly spaced: either gfs1-style or corrupt"),
_("rindex calculations don't match: uneven rgrp boundaries"),
_("Too many rgrp misses: rgrps must be unevenly spaced"),
_("Too much damage found: we cannot rebuild this rindex"),
@@ -582,16 +582,25 @@ static int init_system_inodes(struct gfs2_sbd *sdp)
*******************************************************************/
log_warn( _("Validating Resource Group index.\n"));
for (trust_lvl = blind_faith; trust_lvl <= indignation; trust_lvl++) {
+ int ret;
+
log_warn( _("Level %d rgrp check: %s.\n"), trust_lvl + 1,
level_desc[trust_lvl]);
if ((rg_repair(sdp, trust_lvl, &rgcount, &sane) == 0) &&
- (ri_update(sdp, 0, &rgcount, &sane) == 0)) {
+ ((ret = ri_update(sdp, 0, &rgcount, &sane)) == 0)) {
log_warn( _("(level %d passed)\n"), trust_lvl + 1);
break;
+ } else {
+ if (ret < 0)
+ log_err( _("(level %d failed: %s)\n"),
+ trust_lvl + 1, fail_desc[trust_lvl]);
+ else
+ log_err( _("(level %d failed at block %lld "
+ "(0x%llx): %s)\n"), trust_lvl + 1,
+ (unsigned long long)ret,
+ (unsigned long long)ret,
+ fail_desc[trust_lvl]);
}
- else
- log_err( _("(level %d failed: %s)\n"), trust_lvl + 1,
- fail_desc[trust_lvl]);
if (fsck_abort)
break;
}
@@ -770,7 +779,7 @@ static void peruse_system_dinode(struct gfs2_sbd *sdp, struct gfs2_dinode *di,
if (di->di_num.no_formal_ino == 2) {
if (sdp->sd_sb.sb_master_dir.no_addr)
return;
- log_warn(_("Found system master directory at: 0x%llx\n"),
+ log_warn(_("Found system master directory at: 0x%llx.\n"),
di->di_num.no_addr);
sdp->sd_sb.sb_master_dir.no_addr = di->di_num.no_addr;
return;
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 065c9c4..5a275ca 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -335,7 +335,7 @@ static int check_entries(struct gfs2_inode *ip, struct gfs2_buffer_head *bh,
de.de_name_len ||
(de.de_inum.no_formal_ino && !de.de_name_len && !first)) {
log_err( _("Directory block %llu (0x%llx"
- "), entry %d of directory %llu"
+ "), entry %d of directory %llu "
"(0x%llx) is corrupt.\n"),
(unsigned long long)bh->b_blocknr,
(unsigned long long)bh->b_blocknr,
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index b891a68..44e1422 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -1215,6 +1215,10 @@ static int handle_ip(struct gfs2_sbd *sdp, struct gfs2_inode *ip)
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);
if (fsck_blockmap_set(ip, block, _("invalid mode"),
gfs2_inode_invalid))
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index 7c6ae3d..452fb93 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -429,7 +429,7 @@ static int clear_a_reference(struct gfs2_sbd *sdp, struct duptree *b,
log_warn( _("The bad inode was not cleared...\n"));
continue;
}
- log_warn( _("Clearing inode %lld (0x%llx)....\n"),
+ log_warn( _("Clearing inode %lld (0x%llx)...\n"),
(unsigned long long)id->block_no,
(unsigned long long)id->block_no);
clear_dup_fxns.private = (void *) dh;
@@ -600,7 +600,8 @@ static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *b)
gfs2_meta_eattr);
fsck_inode_put(&ip); /* out, brelse, free */
} else {
- log_debug( _("All duplicate references were resolved.\n"));
+ /* They may have answered no and not fixed all references. */
+ log_debug( _("All duplicate references were processed.\n"));
}
return 0;
}
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index 1143a15..01f8000 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -267,7 +267,10 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
/* This entry's inode has bad blocks in it */
/* Handle bad blocks */
- log_err( _("Found a bad directory entry: %s\n"), tmp_name);
+ log_err( _("Found directory entry '%s' pointing to invalid "
+ "block %lld (0x%llx)\n"), tmp_name,
+ (unsigned long long)entryblock,
+ (unsigned long long)entryblock);
if (!query( _("Delete inode containing bad blocks? (y/n)"))) {
log_warn( _("Entry to inode containing bad blocks remains\n"));
@@ -284,6 +287,9 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
fsck_inode_put(&entry_ip);
fsck_blockmap_set(ip, entryblock,
_("bad directory entry"), gfs2_block_free);
+ log_err( _("Inode %lld (0x%llx) was deleted.\n"),
+ (unsigned long long)entryblock,
+ (unsigned long long)entryblock);
goto nuke_dentry;
}
if (q < gfs2_inode_dir || q > gfs2_inode_sock) {
@@ -359,7 +365,9 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
}
if (!strcmp(".", tmp_name)) {
- log_debug( _("Found . dentry\n"));
+ log_debug( _("Found . dentry in directory %lld (0x%llx)\n"),
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr);
if (ds->dotdir) {
log_err( _("Already found '.' entry in directory %llu"
@@ -417,9 +425,11 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
goto dentry_is_valid;
}
if (!strcmp("..", tmp_name)) {
- log_debug( _("Found .. dentry\n"));
+ log_debug( _("Found '..' dentry in directory %lld (0x%llx)\n"),
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr);
if (ds->dotdotdir) {
- log_err( _("Already found '..' entry in directory %llu"
+ log_err( _("Already had a '..' entry in directory %llu"
"(0x%llx)\n"),
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
diff --git a/gfs2/fsck/pass5.c b/gfs2/fsck/pass5.c
index 1c50f55..b83777b 100644
--- a/gfs2/fsck/pass5.c
+++ b/gfs2/fsck/pass5.c
@@ -85,7 +85,8 @@ static int check_block_status(struct gfs2_sbd *sdp, char *buffer, unsigned int b
"(0x%llx).\n"),
(unsigned long long)block,
(unsigned long long)block);
- if (query(_("Do you want to fix the bitmap? (y/n) "))) {
+ if (query(_("Do you want to reclaim the block? "
+ "(y/n) "))) {
if (gfs2_set_bitmap(sdp, block, block_status))
log_err(_("Unlinked block %llu "
"(0x%llx) bitmap not fixed."
@@ -107,13 +108,12 @@ static int check_block_status(struct gfs2_sbd *sdp, char *buffer, unsigned int b
const char *blockstatus[] = {"Free", "Data",
"Unlinked", "inode"};
- log_err( _("Ondisk and fsck bitmaps differ at"
- " block %llu (0x%llx) \n"),
- (unsigned long long)block,
- (unsigned long long)block);
- log_err( _("Ondisk status is %u (%s) but FSCK thinks it should be "),
- rg_status, blockstatus[rg_status]);
- log_err("%u (%s)\n", block_status, blockstatus[block_status]);
+ log_err( _("Block %llu (0x%llx) bitmap says %u (%s) "
+ "but FSCK saw %u (%s)\n"),
+ (unsigned long long)block,
+ (unsigned long long)block, rg_status,
+ blockstatus[rg_status], block_status,
+ blockstatus[block_status]);
if (q) /* Don't print redundant "free" */
log_err( _("Metadata type is %u (%s)\n"), q,
block_type_string(q));
@@ -170,8 +170,11 @@ static void update_rgrp(struct gfs2_sbd *sdp, struct rgrp_list *rgp,
update = 1;
}
if (rgp->rg.rg_dinodes != count[1]) {
- log_err( _("Inode count inconsistent: is %u should be %u\n"),
- rgp->rg.rg_dinodes, count[1]);
+ log_err( _("RG #%llu (0x%llx) Inode count inconsistent: is "
+ "%u should be %u\n"),
+ (unsigned long long)rgp->ri.ri_addr,
+ (unsigned long long)rgp->ri.ri_addr,
+ rgp->rg.rg_dinodes, count[1]);
rgp->rg.rg_dinodes = count[1];
update = 1;
}
diff --git a/gfs2/fsck/util.c b/gfs2/fsck/util.c
index 706a386..66fa4ec 100644
--- a/gfs2/fsck/util.c
+++ b/gfs2/fsck/util.c
@@ -289,7 +289,8 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block,
if (first)
log_info( _("This is the original reference.\n"));
else
- log_info( _("This brings the total to: %d\n"), dt->refs);
+ log_info( _("This brings the total to: %d duplicate "
+ "references\n"), dt->refs);
return 0;
}
12 years, 8 months
gfs2-utils: master - fsck.gfs2: Shorten output
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/gfs2-utils.git?p=gfs2-utils.git;a=commitd...
Commit: 3527e52c3ed84708e888635195264ece16db4216
Parent: 76e593eba54483a1199590f6ef0e03979146d79f
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Tue Aug 9 11:38:18 2011 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon Aug 29 12:53:52 2011 -0500
fsck.gfs2: Shorten output
This patch shortens some of the output of fsck.gfs2, thereby making
the output files smaller and more manageable.
rhbz#675723
---
gfs2/fsck/lost_n_found.c | 6 +++---
gfs2/fsck/metawalk.c | 7 ++++---
gfs2/fsck/pass5.c | 13 +++++++------
3 files changed, 14 insertions(+), 12 deletions(-)
diff --git a/gfs2/fsck/lost_n_found.c b/gfs2/fsck/lost_n_found.c
index 7ce5db5..dbb2b58 100644
--- a/gfs2/fsck/lost_n_found.c
+++ b/gfs2/fsck/lost_n_found.c
@@ -69,8 +69,8 @@ static void add_dotdot(struct gfs2_inode *ip)
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)di->dotdot_parent);
else
- log_debug(_("Couldn't find a valid \"..\" entry "
- "for orphan directory %lld (0x%llx)\n"),
+ log_debug(_("Couldn't find directory %lld (0x%llx) "
+ "in directory tree.\n"),
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
}
@@ -226,7 +226,7 @@ int add_inode_to_lf(struct gfs2_inode *ip){
incr_link_count(lf_dip->i_di.di_num.no_addr,
ip->i_di.di_mode, _("to lost+found"));
- log_notice( _("Added inode #%llu (0x%llx) to lost+found dir\n"),
+ log_notice( _("Added inode #%llu (0x%llx) to lost+found\n"),
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
gfs2_dinode_out(&lf_dip->i_di, lf_dip->i_bh);
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index b908f69..065c9c4 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -47,12 +47,13 @@ int check_n_fix_bitmap(struct gfs2_sbd *sdp, uint64_t blk,
const char *allocdesc[] = {"free space", "data", "unlinked",
"inode", "reserved"};
- log_err( _("Block %llu (0x%llx) seems to be %s, but is "
- "marked as %s in the bitmap.\n"),
+ /* Keep these messages as short as possible, or the output
+ gets to be huge and unmanageable. */
+ log_err( _("Block %llu (0x%llx) was '%s', should be %s.\n"),
(unsigned long long)blk, (unsigned long long)blk,
allocdesc[new_bitmap_state],
allocdesc[old_bitmap_state]);
- if (query( _("Okay to fix the bitmap? (y/n)"))) {
+ if (query( _("Fix the bitmap? (y/n)"))) {
/* If the new bitmap state is free (and therefore the
old state was not) we have to add to the free
space in the rgrp. If the old bitmap state was
diff --git a/gfs2/fsck/pass5.c b/gfs2/fsck/pass5.c
index 742dfca..1c50f55 100644
--- a/gfs2/fsck/pass5.c
+++ b/gfs2/fsck/pass5.c
@@ -81,8 +81,8 @@ static int check_block_status(struct gfs2_sbd *sdp, char *buffer, unsigned int b
So we ignore it. */
if (rg_status == GFS2_BLKST_UNLINKED &&
block_status == GFS2_BLKST_FREE) {
- log_err( _("Unlinked inode block found at "
- "block %llu (0x%llx).\n"),
+ log_err( _("Unlinked inode found at block %llu "
+ "(0x%llx).\n"),
(unsigned long long)block,
(unsigned long long)block);
if (query(_("Do you want to fix the bitmap? (y/n) "))) {
@@ -114,16 +114,17 @@ static int check_block_status(struct gfs2_sbd *sdp, char *buffer, unsigned int b
log_err( _("Ondisk status is %u (%s) but FSCK thinks it should be "),
rg_status, blockstatus[rg_status]);
log_err("%u (%s)\n", block_status, blockstatus[block_status]);
- log_err( _("Metadata type is %u (%s)\n"), q,
- block_type_string(q));
+ if (q) /* Don't print redundant "free" */
+ log_err( _("Metadata type is %u (%s)\n"), q,
+ block_type_string(q));
if (query(_("Fix bitmap for block %llu (0x%llx) ? (y/n) "),
(unsigned long long)block,
(unsigned long long)block)) {
if (gfs2_set_bitmap(sdp, block, block_status))
- log_err( _("Failed.\n"));
+ log_err( _("Repair failed.\n"));
else
- log_err( _("Succeeded.\n"));
+ log_err( _("Fixed.\n"));
} else
log_err( _("Bitmap at block %llu (0x%llx) left inconsistent\n"),
(unsigned long long)block,
12 years, 8 months
gfs2-utils: master - fsck.gfs2: fsck.gfs2: split check_leaf_blks to be more readable
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/gfs2-utils.git?p=gfs2-utils.git;a=commitd...
Commit: 76e593eba54483a1199590f6ef0e03979146d79f
Parent: 6759a08320875da052809758fa94381d813cc456
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Tue Aug 9 10:08:21 2011 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Mon Aug 29 12:53:52 2011 -0500
fsck.gfs2: fsck.gfs2: split check_leaf_blks to be more readable
This patch splits function check_leaf_blks into two functions to make it
more understandable. Before, it had way too many levels of indentation and
spanned multiple screens. This makes it a lot more clear.
rhbz#675723
---
gfs2/fsck/metawalk.c | 255 +++++++++++++++++++++++++++-----------------------
1 files changed, 138 insertions(+), 117 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 622f9d7..b908f69 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -435,10 +435,12 @@ static int check_entries(struct gfs2_inode *ip, struct gfs2_buffer_head *bh,
/* so that they replace the bad ones. We have to hack up the old */
/* leaf a bit, but it's better than deleting the whole directory, */
/* which is what used to happen before. */
-static void warn_and_patch(struct gfs2_inode *ip, uint64_t *leaf_no,
- uint64_t *bad_leaf, uint64_t old_leaf,
- uint64_t first_ok_leaf, int pindex, const char *msg)
+static int warn_and_patch(struct gfs2_inode *ip, uint64_t *leaf_no,
+ uint64_t *bad_leaf, uint64_t old_leaf,
+ uint64_t first_ok_leaf, int pindex, const char *msg)
{
+ int okay_to_fix = 0;
+
if (*bad_leaf != *leaf_no) {
log_err( _("Directory Inode %llu (0x%llx) points to leaf %llu"
" (0x%llx) %s.\n"),
@@ -448,7 +450,7 @@ static void warn_and_patch(struct gfs2_inode *ip, uint64_t *leaf_no,
(unsigned long long)*leaf_no, msg);
}
if (*leaf_no == *bad_leaf ||
- query( _("Attempt to patch around it? (y/n) "))) {
+ (okay_to_fix = query( _("Attempt to patch around it? (y/n) ")))) {
if (!valid_block(ip->i_sbd, old_leaf) == 0)
gfs2_put_leaf_nr(ip, pindex, old_leaf);
else
@@ -461,6 +463,133 @@ static void warn_and_patch(struct gfs2_inode *ip, uint64_t *leaf_no,
log_err( _("Bad leaf left in place.\n"));
*bad_leaf = *leaf_no;
*leaf_no = old_leaf;
+ return okay_to_fix;
+}
+
+/**
+ * check_leaf - check a leaf block for errors
+ */
+static int check_leaf(struct gfs2_inode *ip, int lindex,
+ struct metawalk_fxns *pass, int *ref_count,
+ uint64_t *leaf_no, uint64_t old_leaf, uint64_t *bad_leaf,
+ uint64_t first_ok_leaf, struct gfs2_leaf *leaf,
+ struct gfs2_leaf *oldleaf)
+{
+ int error = 0, fix;
+ struct gfs2_buffer_head *lbh = NULL;
+ uint32_t count = 0;
+ struct gfs2_sbd *sdp = ip->i_sbd;
+ const char *msg;
+
+ *ref_count = 1;
+ /* 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"),
+ (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);
+ msg = _("that is out of range");
+ goto out_copy_old_leaf;
+ }
+
+ /* Try to read in the leaf block. */
+ lbh = bread(sdp, *leaf_no);
+ /* Make sure it's really a valid leaf block. */
+ if (gfs2_check_meta(lbh, GFS2_METATYPE_LF)) {
+ msg = _("that is not really a leaf");
+ goto out_copy_old_leaf;
+ }
+ if (pass->check_leaf) {
+ error = pass->check_leaf(ip, *leaf_no, pass->private);
+ if (error) {
+ log_info(_("Previous reference to leaf %lld (0x%llx) "
+ "has already checked it; skipping.\n"),
+ (unsigned long long)*leaf_no,
+ (unsigned long long)*leaf_no);
+ brelse(lbh);
+ return error;
+ }
+ }
+ /* Early versions of GFS2 had an endianess bug in the kernel that set
+ lf_dirent_format to cpu_to_be16(GFS2_FORMAT_DE). This was fixed
+ to use cpu_to_be32(), but we should check for incorrect values and
+ replace them with the correct value. */
+
+ gfs2_leaf_in(leaf, lbh);
+ if (leaf->lf_dirent_format == (GFS2_FORMAT_DE << 16)) {
+ log_debug( _("incorrect lf_dirent_format at leaf #%" PRIu64
+ "\n"), *leaf_no);
+ leaf->lf_dirent_format = GFS2_FORMAT_DE;
+ gfs2_leaf_out(leaf, lbh);
+ log_debug( _("Fixing lf_dirent_format.\n"));
+ }
+
+ /* Make sure it's really a leaf. */
+ if (leaf->lf_header.mh_type != GFS2_METATYPE_LF) {
+ log_err( _("Inode %llu (0x%llx) points to bad leaf %llu"
+ " (0x%llx).\n"),
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)*leaf_no,
+ (unsigned long long)*leaf_no);
+ msg = _("that is not a leaf");
+ goto out_copy_old_leaf;
+ }
+
+ if (pass->check_dentry && S_ISDIR(ip->i_di.di_mode)) {
+ error = check_entries(ip, lbh, DIR_EXHASH, &count, pass);
+
+ if (skip_this_pass || fsck_abort)
+ goto out;
+
+ if (error < 0) {
+ stack;
+ goto out;
+ }
+
+ if (count != leaf->lf_entries) {
+ /* release and re-read the leaf in case check_entries
+ changed it. */
+ brelse(lbh);
+ lbh = bread(sdp, *leaf_no);
+ gfs2_leaf_in(leaf, lbh);
+
+ log_err( _("Leaf %llu (0x%llx) entry count in "
+ "directory %llu (0x%llx) does not match "
+ "number of entries found - is %u, found %u\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,
+ leaf->lf_entries, count);
+ if (query( _("Update leaf entry count? (y/n) "))) {
+ leaf->lf_entries = count;
+ gfs2_leaf_out(leaf, lbh);
+ log_warn( _("Leaf entry count updated\n"));
+ } else
+ log_err( _("Leaf entry count left in "
+ "inconsistant state\n"));
+ }
+ }
+out:
+ brelse(lbh);
+ return 0;
+
+out_copy_old_leaf:
+ /* The leaf we read in is bad. So we'll copy the old leaf into the
+ * new one. However, that will make us shift our ref count. */
+ fix = warn_and_patch(ip, leaf_no, bad_leaf, old_leaf,
+ first_ok_leaf, lindex, msg);
+ (*ref_count)++;
+ memcpy(leaf, oldleaf, sizeof(struct gfs2_leaf));
+ if (lbh) {
+ if (fix)
+ bmodified(lbh);
+ brelse(lbh);
+ }
+ return 1;
}
/* Checks exhash directory entries */
@@ -473,8 +602,7 @@ static int check_leaf_blks(struct gfs2_inode *ip, struct metawalk_fxns *pass)
struct gfs2_buffer_head *lbh;
int lindex;
struct gfs2_sbd *sdp = ip->i_sbd;
- uint32_t count;
- int ref_count = 0, exp_count = 0;
+ int ref_count = 0;
/* Find the first valid leaf pointer in range and use it as our "old"
leaf. That way, bad blocks at the beginning will be overwritten
@@ -532,119 +660,12 @@ static int check_leaf_blks(struct gfs2_inode *ip, struct metawalk_fxns *pass)
if (error)
return error;
}
- ref_count = 1;
- count = 0;
- if (fsck_abort)
- break;
- /* 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"), (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);
- warn_and_patch(ip, &leaf_no, &bad_leaf,
- old_leaf, first_ok_leaf, lindex,
- _("that is out of range"));
- memcpy(&leaf, &oldleaf, sizeof(oldleaf));
- break;
- }
-
- /* Try to read in the leaf block. */
- lbh = bread(sdp, leaf_no);
- /* Make sure it's really a valid leaf block. */
- if (gfs2_check_meta(lbh, GFS2_METATYPE_LF)) {
- warn_and_patch(ip, &leaf_no, &bad_leaf,
- old_leaf, first_ok_leaf, lindex,
- _("that is not really a leaf"));
- memcpy(&leaf, &oldleaf, sizeof(oldleaf));
- bmodified(lbh);
- brelse(lbh);
- break;
- }
- gfs2_leaf_in(&leaf, lbh);
- if (pass->check_leaf)
- error = pass->check_leaf(ip, leaf_no,
- pass->private);
-
- /*
- * Early versions of GFS2 had an endianess bug in the
- * kernel that set lf_dirent_format to
- * cpu_to_be16(GFS2_FORMAT_DE). This was fixed to use
- * cpu_to_be32(), but we should check for incorrect
- * values and replace them with the correct value. */
-
- if (leaf.lf_dirent_format == (GFS2_FORMAT_DE << 16)) {
- log_debug( _("incorrect lf_dirent_format at leaf #%llu\n"), (unsigned long long)leaf_no);
- leaf.lf_dirent_format = GFS2_FORMAT_DE;
- gfs2_leaf_out(&leaf, lbh);
- log_debug( _("Fixing lf_dirent_format.\n"));
- }
-
- /* Make sure it's really a leaf. */
- if (leaf.lf_header.mh_type != GFS2_METATYPE_LF) {
- log_err( _("Inode %llu (0x%llx"
- ") points to bad leaf %llu"
- " (0x%llx).\n"),
- (unsigned long long)
- ip->i_di.di_num.no_addr,
- (unsigned long long)
- ip->i_di.di_num.no_addr,
- (unsigned long long)leaf_no,
- (unsigned long long)leaf_no);
- brelse(lbh);
- break;
- }
- exp_count = (1 << (ip->i_di.di_depth - leaf.lf_depth));
- /*log_debug( _("expected count %u - di_depth %u,
- leaf depth %u\n"),
- exp_count, ip->i_di.di_depth, leaf.lf_depth);*/
-
- if (pass->check_dentry && S_ISDIR(ip->i_di.di_mode)) {
- error = check_entries(ip, lbh, DIR_EXHASH,
- &count, pass);
-
- if (skip_this_pass || fsck_abort)
- return 0;
-
- if (error < 0) {
- stack;
- brelse(lbh);
- return -1;
- }
-
- if (count != leaf.lf_entries) {
- brelse(lbh);
- lbh = bread(sdp, leaf_no);
- gfs2_leaf_in(&leaf, lbh);
-
- log_err( _("Leaf %llu (0x%llx) entry "
- "count in directory %llu"
- " (0x%llx) doesn't match "
- "number of entries found "
- "- is %u, found %u\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,
- leaf.lf_entries, count);
- if (query( _("Update leaf entry count? (y/n) "))) {
- leaf.lf_entries = count;
- gfs2_leaf_out(&leaf, lbh);
- log_warn( _("Leaf entry count updated\n"));
- } else
- log_err( _("Leaf entry count left in inconsistant state\n"));
- }
- }
- brelse(lbh);
+ error = check_leaf(ip, lindex, pass, &ref_count,
+ &leaf_no, old_leaf, &bad_leaf,
+ first_ok_leaf, &leaf, &oldleaf);
old_leaf = leaf_no;
memcpy(&oldleaf, &leaf, sizeof(oldleaf));
- if (!leaf.lf_next)
+ if (!leaf.lf_next || error)
break;
leaf_no = leaf.lf_next;
log_debug( _("Leaf chain 0x%llx detected.\n"),
12 years, 8 months