gfs2-utils: master - fsck.gfs2: Refactor function check_indirect_eattr
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=9944c792...
Commit: 9944c79285b7a1bd65c7b5a27d0e682ed0fd9da3
Parent: bce4edab765816449c1b26379c7163ffea1a87da
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Wed Sep 23 14:18:35 2015 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Tue Sep 29 13:23:21 2015 -0500
fsck.gfs2: Refactor function check_indirect_eattr
Function check_indirect_eattr was messy because the if statements
were nested too deep and the function was too long. This patch moves
some of its function into the smaller calling function, function
check_inode_eattr. The functionality should remain unchanged.
---
gfs2/fsck/metawalk.c | 141 ++++++++++++++++++++++++--------------------------
1 files changed, 68 insertions(+), 73 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 1ecd756..b4330fb 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -1078,89 +1078,71 @@ static int delete_block_if_notdup(struct gfs2_inode *ip, uint64_t block,
* Returns: 0 on success -1 on error
*/
static int check_indirect_eattr(struct gfs2_inode *ip, uint64_t indirect,
+ struct gfs2_buffer_head *indirect_buf,
struct metawalk_fxns *pass)
{
int error = 0;
uint64_t *ea_leaf_ptr, *end;
uint64_t block;
- struct gfs2_buffer_head *indirect_buf = NULL;
struct gfs2_sbd *sdp = ip->i_sbd;
int first_ea_is_bad = 0;
uint64_t di_eattr_save = ip->i_di.di_eattr;
uint64_t offset = ip->i_sbd->gfs1 ? sizeof(struct gfs_indirect) : sizeof(struct gfs2_meta_header);
+ int leaf_pointers = 0, leaf_pointer_errors = 0;
- log_debug( _("Checking EA indirect block #%llu (0x%llx).\n"),
- (unsigned long long)indirect,
- (unsigned long long)indirect);
+ ea_leaf_ptr = (uint64_t *)(indirect_buf->b_data + offset);
+ end = ea_leaf_ptr + ((sdp->sd_sb.sb_bsize - offset) / 8);
- if (!pass->check_eattr_indir)
- return 0;
- error = pass->check_eattr_indir(ip, indirect, ip->i_di.di_num.no_addr,
- &indirect_buf, pass->private);
- if (!error) {
- int leaf_pointers = 0, leaf_pointer_errors = 0;
-
- ea_leaf_ptr = (uint64_t *)(indirect_buf->b_data + offset);
- end = ea_leaf_ptr + ((sdp->sd_sb.sb_bsize - offset) / 8);
-
- while (*ea_leaf_ptr && (ea_leaf_ptr < end)){
- block = be64_to_cpu(*ea_leaf_ptr);
- leaf_pointers++;
- error = check_leaf_eattr(ip, block, indirect, pass);
- if (error) {
- leaf_pointer_errors++;
- if (query( _("Fix the indirect "
- "block too? (y/n) ")))
- *ea_leaf_ptr = 0;
- }
- /* If the first eattr lead is bad, we can't have
- a hole, so we have to treat this as an unrecoverable
- eattr error and delete all eattr info. Calling
- finish_eattr_indir here causes ip->i_di.di_eattr = 0
- and that ensures that subsequent calls to
- check_leaf_eattr result in the eattr
- check_leaf_block nuking them all "due to previous
- errors" */
- if (leaf_pointers == 1 && leaf_pointer_errors == 1) {
- first_ea_is_bad = 1;
- if (pass->finish_eattr_indir)
- pass->finish_eattr_indir(ip,
- leaf_pointers,
- leaf_pointer_errors,
- pass->private);
- } else if (leaf_pointer_errors) {
- /* This is a bit tricky. We can't have eattr
- holes. So if we have 4 good eattrs, 1 bad
- eattr and 5 more good ones: GGGGBGGGGG,
- we need to tell check_leaf_eattr to delete
- all eattrs after the bad one. So we want:
- GGGG when we finish. To do that, we set
- di_eattr to 0 temporarily. */
- ip->i_di.di_eattr = 0;
- bmodified(ip->i_bh);
- }
- ea_leaf_ptr++;
+ while (*ea_leaf_ptr && (ea_leaf_ptr < end)){
+ block = be64_to_cpu(*ea_leaf_ptr);
+ leaf_pointers++;
+ error = check_leaf_eattr(ip, block, indirect, pass);
+ if (error) {
+ leaf_pointer_errors++;
+ if (query( _("Fix the indirect block too? (y/n) ")))
+ *ea_leaf_ptr = 0;
}
- if (pass->finish_eattr_indir) {
- if (!first_ea_is_bad) {
- /* If the first ea is good but subsequent ones
- were bad and deleted, we need to restore
- the saved di_eattr block. */
- if (leaf_pointer_errors)
- ip->i_di.di_eattr = di_eattr_save;
+ /* If the first eattr lead is bad, we can't have a hole, so we
+ have to treat this as an unrecoverable eattr error and
+ delete all eattr info. Calling finish_eattr_indir here
+ causes ip->i_di.di_eattr = 0 and that ensures that
+ subsequent calls to check_leaf_eattr result in the eattr
+ check_leaf_block nuking them all "due to previous errors" */
+ if (leaf_pointers == 1 && leaf_pointer_errors == 1) {
+ first_ea_is_bad = 1;
+ if (pass->finish_eattr_indir)
pass->finish_eattr_indir(ip, leaf_pointers,
leaf_pointer_errors,
pass->private);
- }
- if (leaf_pointer_errors &&
- leaf_pointer_errors == leaf_pointers) {
- delete_block(ip, indirect, NULL, "leaf", NULL);
- error = 1;
- }
+ } else if (leaf_pointer_errors) {
+ /* This is a bit tricky. We can't have eattr holes.
+ So if we have 4 good eattrs, 1 bad eattr and 5 more
+ good ones: GGGGBGGGGG, we need to tell
+ check_leaf_eattr to delete all eattrs after the bad
+ one. So we want: GGGG when we finish. To do that,
+ we set di_eattr to 0 temporarily. */
+ ip->i_di.di_eattr = 0;
+ bmodified(ip->i_bh);
+ }
+ ea_leaf_ptr++;
+ }
+ if (pass->finish_eattr_indir) {
+ if (!first_ea_is_bad) {
+ /* If the first ea is good but subsequent ones were
+ bad and deleted, we need to restore the saved
+ di_eattr block. */
+ if (leaf_pointer_errors)
+ ip->i_di.di_eattr = di_eattr_save;
+ pass->finish_eattr_indir(ip, leaf_pointers,
+ leaf_pointer_errors,
+ pass->private);
+ }
+ if (leaf_pointer_errors &&
+ leaf_pointer_errors == leaf_pointers) {
+ delete_block(ip, indirect, NULL, "leaf", NULL);
+ error = 1;
}
}
- if (indirect_buf)
- brelse(indirect_buf);
return error;
}
@@ -1174,25 +1156,38 @@ static int check_indirect_eattr(struct gfs2_inode *ip, uint64_t indirect,
int check_inode_eattr(struct gfs2_inode *ip, struct metawalk_fxns *pass)
{
int error = 0;
+ struct gfs2_buffer_head *indirect_buf = NULL;
if (!ip->i_di.di_eattr)
return 0;
if (ip->i_di.di_flags & GFS2_DIF_EA_INDIRECT){
+ if (!pass->check_eattr_indir)
+ return 0;
+
log_debug( _("Checking EA indirect block #%llu (0x%llx) for "
"inode #%llu (0x%llx)..\n"),
(unsigned long long)ip->i_di.di_eattr,
(unsigned long long)ip->i_di.di_eattr,
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
- if ((error = check_indirect_eattr(ip, ip->i_di.di_eattr, pass)))
- stack;
- } else {
- error = check_leaf_eattr(ip, ip->i_di.di_eattr,
- ip->i_di.di_num.no_addr, pass);
- if (error)
- stack;
+ error = pass->check_eattr_indir(ip, ip->i_di.di_eattr,
+ ip->i_di.di_num.no_addr,
+ &indirect_buf, pass->private);
+ if (!error) {
+ error = check_indirect_eattr(ip, ip->i_di.di_eattr,
+ indirect_buf, pass);
+ if (error)
+ stack;
+ }
+ if (indirect_buf)
+ brelse(indirect_buf);
+ return error;
}
+ error = check_leaf_eattr(ip, ip->i_di.di_eattr,
+ ip->i_di.di_num.no_addr, pass);
+ if (error)
+ stack;
return error;
}
8 years, 7 months
gfs2-utils: master - fsck.gfs2: Don't traverse EAs that belong to another inode
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=bce4edab...
Commit: bce4edab765816449c1b26379c7163ffea1a87da
Parent: 29c87d36a746016cb7f60dc1dd8a78b82fa0e0bf
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Wed Sep 23 13:46:59 2015 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Tue Sep 29 13:23:17 2015 -0500
fsck.gfs2: Don't traverse EAs that belong to another inode
Before this patch, pass1b would find a duplicate reference to
extended attributes, which may be an entire tree structure. After
deciding which inode gets to keep the extended attributes, it
removes the extended attributes from other dinodes with another
pointer to it. However, if the EAs are big, and there's a whole
list of them as indirect blocks, we only want to traverse the
indirect list if that list is owned by the second (bad) reference.
If we do traverse the tree, we're basically freeing EA blocks
belonging to the only remaining valid reference, and that's wrong.
This patch adds a check to function resolve_dup_references that
avoids a whole EA tree traversal if the duplicate EA reference is
the root of the EAs (not an indirect list of blocks). Instead,
the reference to the block is just removed from the inode.
---
gfs2/fsck/pass1b.c | 23 +++++++++++++++++++++--
1 files changed, 21 insertions(+), 2 deletions(-)
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index 382d5e9..4c41fef 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -198,8 +198,27 @@ static void resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *dt,
it again. That could free blocks that used to be duplicate
references that are now resolved (and gone). */
if (q != GFS2_BLKST_FREE) {
- /* Clear the EAs for the inode first */
- check_inode_eattr(ip, &pass1b_fxns_delete);
+ /* If the inode's eattr pointer is to the duplicate
+ ref block, we don't want to call check_inode_eattr
+ because that would traverse the structure, and it's
+ not ours to do anymore; it rightly belongs to a
+ different dinode. On the other hand, if the dup
+ block is buried deep within the eattr structure
+ of this dinode, we need to traverse the structure
+ because it IS ours, and we need to remove all the
+ eattr leaf blocks: they do belong to us (except for
+ the duplicate referenced one, which is handled). */
+ if (ip->i_di.di_eattr == dt->block) {
+ ip->i_di.di_eattr = 0;
+ if (ip->i_di.di_blocks > 0)
+ ip->i_di.di_blocks--;
+ ip->i_di.di_flags &= ~GFS2_DIF_EA_INDIRECT;
+ bmodified(ip->i_bh);
+ dup_listent_delete(dt, id);
+ } else {
+ /* Clear the EAs for the inode first */
+ check_inode_eattr(ip, &pass1b_fxns_delete);
+ }
/* If the reference was as metadata or data, we've got
a corrupt dinode that will be deleted. */
if ((this_ref != ref_as_ea) &&
8 years, 7 months
gfs2-utils: master - fsck.gfs2: Don't delete inode for duplicate reference in EA
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=29c87d36...
Commit: 29c87d36a746016cb7f60dc1dd8a78b82fa0e0bf
Parent: af10124e7a98670e049797b5f59f8b2331c583d1
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Wed Sep 23 13:41:50 2015 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Tue Sep 29 13:23:13 2015 -0500
fsck.gfs2: Don't delete inode for duplicate reference in EA
Before this patch, when pass1b came across an extended attribute
referenced by multiple inodes, its solution was to delete one of
the inodes entirely. This is rather harsh and unnecessary treatment.
It's enough to just remove the extended attributes and keep the
rest of the file intact. This patch gives pass1b the added ability
to remove only the corrupt extended attribute.
---
gfs2/fsck/pass1b.c | 42 +++++++++++++++++++++++++++++++++---------
1 files changed, 33 insertions(+), 9 deletions(-)
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index 4d16635..382d5e9 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -147,11 +147,28 @@ static void resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *dt,
(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) "),
- (inval ? _("invalidated") : ""),
- (unsigned long long)id->block_no,
- (unsigned long long)id->block_no))) {
+ if (this_ref == ref_as_ea) {
+ if (!(query( _("Okay to remove extended attributes "
+ "from %s inode %lld (0x%llx)? (y/n) "),
+ (inval ? _("invalidated") : ""),
+ (unsigned long long)id->block_no,
+ (unsigned long long)id->block_no))) {
+ log_warn( _("The bad EA reference was not "
+ "cleared."));
+ /* delete the list entry so we don't leak
+ memory but leave the reference count. If we
+ decrement the ref count, we could get down
+ to 1 and the dinode would be changed
+ without a 'Yes' answer. */
+ /* (dh->ref_inode_count)--;*/
+ dup_listent_delete(dt, id);
+ continue;
+ }
+ } else if (!(query( _("Okay to delete %s inode %lld (0x%llx)? "
+ "(y/n) "),
+ (inval ? _("invalidated") : ""),
+ (unsigned long long)id->block_no,
+ (unsigned long long)id->block_no))) {
log_warn( _("The bad inode was not cleared."));
/* delete the list entry so we don't leak memory but
leave the reference count. If we decrement the
@@ -166,6 +183,11 @@ static void resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *dt,
"deleted.\n"),
(unsigned long long)id->block_no,
(unsigned long long)id->block_no);
+ else if (this_ref == ref_as_ea)
+ log_warn(_("Pass1b is removing extended attributes "
+ "from inode %lld (0x%llx).\n"),
+ (unsigned long long)id->block_no,
+ (unsigned long long)id->block_no);
else
log_warn(_("Pass1b is deleting inode %lld (0x%llx).\n"),
(unsigned long long)id->block_no,
@@ -180,8 +202,9 @@ static void resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *dt,
check_inode_eattr(ip, &pass1b_fxns_delete);
/* If the reference was as metadata or data, we've got
a corrupt dinode that will be deleted. */
- if (inval || id->reftypecount[ref_as_data] ||
- id->reftypecount[ref_as_meta]) {
+ if ((this_ref != ref_as_ea) &&
+ (inval || id->reftypecount[ref_as_data] ||
+ id->reftypecount[ref_as_meta])) {
/* Remove the inode from the inode tree */
ii = inodetree_find(ip->i_di.di_num.no_addr);
if (ii)
@@ -204,7 +227,7 @@ static void resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *dt,
check_metatree(ip, &pass1b_fxns_delete);
}
}
- /* Now we've got to go through an delete any other duplicate
+ /* Now we've got to go through and delete any other duplicate
references from this dinode we're deleting. If we don't,
pass1b will discover the other duplicate record, try to
delete this dinode a second time, and this time its earlier
@@ -212,7 +235,8 @@ static void resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *dt,
(because they were eliminated earlier in pass1b). And so
the blocks will be mistakenly freed, when, in fact, they're
still being referenced by a valid dinode. */
- delete_all_dups(ip);
+ if (this_ref != ref_as_ea)
+ delete_all_dups(ip);
fsck_inode_put(&ip); /* out, brelse, free */
}
return;
8 years, 7 months
gfs2-utils: master - fsck.gfs2: Don't just assume the remaining EA reference is good
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=af10124e...
Commit: af10124e7a98670e049797b5f59f8b2331c583d1
Parent: cd7a3ddc01a243bc571dd281a9d70e7b1b4dc8fa
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Wed Sep 23 12:58:55 2015 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Tue Sep 29 13:23:10 2015 -0500
fsck.gfs2: Don't just assume the remaining EA reference is good
When pass1b is resolving duplicate block references, it pares them
down to the last reference, then sets the block type from that
last reference. However, the last reference might be bad too.
For example, consider a block referenced as data by two corrupt inodes
and referenced as an extended attribute by a third corrupt inode.
In pass1b, it might eliminate the two inodes that referenced it as
data, then set the block as extended attribute based on the remaining
reference. However, if the block is not really an extended attribute,
that would be an error that would only be caught on a subsequent run.
This patch adds a check to make sure the remaining reference as an
extended attribute is also valid. If not, the block is freed.
---
gfs2/fsck/pass1b.c | 39 ++++++++++++++++++++++++++++++++++-----
1 files changed, 34 insertions(+), 5 deletions(-)
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index 83a506c..4d16635 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -417,11 +417,40 @@ static void resolve_last_reference(struct gfs2_sbd *sdp, struct duptree *dt,
sdp->gfs1 ? GFS2_BLKST_DINODE :
GFS2_BLKST_USED);
} else {
- fsck_blockmap_set(ip, dt->block,
- _("reference-repaired extended "
- "attribute"),
- sdp->gfs1 ? GFS2_BLKST_DINODE :
- GFS2_BLKST_USED);
+ if (acceptable_ref == ref_as_ea)
+ fsck_blockmap_set(ip, dt->block,
+ _("reference-repaired extended "
+ "attribute"),
+ sdp->gfs1 ? GFS2_BLKST_DINODE :
+ GFS2_BLKST_USED);
+ else {
+ log_err(_("Error: The remaining reference to block "
+ " %lld (0x%llx) is as extended attribute, "
+ "in inode %lld (0x%llx) but the block is "
+ "not an EA.\n"),
+ (unsigned long long)dt->block,
+ (unsigned long long)dt->block,
+ (unsigned long long)id->block_no,
+ (unsigned long long)id->block_no);
+ if (query(_("Okay to remove the bad extended "
+ "attribute from inode %lld (0x%llx)? "
+ "(y/n) "),
+ (unsigned long long)id->block_no,
+ (unsigned long long)id->block_no)) {
+ ip->i_di.di_eattr = 0;
+ ip->i_di.di_flags &= ~GFS2_DIF_EA_INDIRECT;
+ ip->i_di.di_blocks--;
+ bmodified(ip->i_bh);
+ fsck_blockmap_set(ip, dt->block,
+ _("reference-repaired EA"),
+ GFS2_BLKST_FREE);
+ log_err(_("The bad extended attribute was "
+ "removed.\n"));
+ } else {
+ log_err(_("The bad extended attribute was not "
+ "removed.\n"));
+ }
+ }
}
fsck_inode_put(&ip); /* out, brelse, free */
log_debug(_("Done with duplicate reference to block 0x%llx\n"),
8 years, 7 months
gfs2-utils: master - fsck.gfs2: Only preserve the _first_ acceptable inode reference
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=cd7a3ddc...
Commit: cd7a3ddc01a243bc571dd281a9d70e7b1b4dc8fa
Parent: 1849ca24fed43fdc2964b6097dbae9354e3f9f59
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Wed Sep 23 12:51:30 2015 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Tue Sep 29 13:23:06 2015 -0500
fsck.gfs2: Only preserve the _first_ acceptable inode reference
Function resolve_dup_references starts out with a loop that traverses
the references for a given duplicate block. If it finds an acceptable
reference, it is supposed to preserve the first reference and resolve
the others. However, the logic allowed for multiple inodes to be
preserved, which can lead to fsck errors that need resolving with yet
another run of fsck.gfs2. This patch adds a check to see if we've
already preserved one, and if so, to not preserve others that might
happen to be acceptable.
---
gfs2/fsck/pass1b.c | 3 +--
1 files changed, 1 insertions(+), 2 deletions(-)
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index 845227e..83a506c 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -114,8 +114,7 @@ static void resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *dt,
if (acceptable_ref != ref_types && /* If we're nuking all but
an acceptable reference
type and */
- this_ref == acceptable_ref && /* this ref is acceptable */
- !found_good_ref) { /* We haven't found a good reference */
+ this_ref == acceptable_ref) { /* this ref is acceptable */
/* If this is an invalid inode, but not on the invalid
list, it's better to delete it. */
if (q == GFS2_BLKST_DINODE) {
8 years, 7 months
gfs2-utils: master - fsck.gfs2: Break up funtion handle_dup_blk
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=1849ca24...
Commit: 1849ca24fed43fdc2964b6097dbae9354e3f9f59
Parent: 65306dde6b09e1c70a4b579fe9df0a19c89dc2f5
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Wed Sep 23 12:46:17 2015 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Tue Sep 29 13:23:03 2015 -0500
fsck.gfs2: Break up funtion handle_dup_blk
This patch just breaks function handle_dup_blk into a new function
resolve_last_reference to increase readability.
---
gfs2/fsck/pass1b.c | 131 ++++++++++++++++++++++++++-------------------------
1 files changed, 67 insertions(+), 64 deletions(-)
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index c1598ff..845227e 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -364,6 +364,72 @@ static void clone_dup_ref_in_inode(struct gfs2_inode *ip, struct duptree *dt)
}
}
+static void resolve_last_reference(struct gfs2_sbd *sdp, struct duptree *dt,
+ enum dup_ref_type acceptable_ref)
+{
+ struct gfs2_inode *ip;
+ struct inode_with_dups *id;
+ osi_list_t *tmp;
+ uint8_t q;
+
+ log_notice( _("Block %llu (0x%llx) has only one remaining "
+ "valid inode referencing it.\n"),
+ (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 = 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 "
+ "reference in inode %lld (0x%llx).\n"),
+ (unsigned long long)id->block_no,
+ (unsigned long long)id->block_no);
+ ip = fsck_load_inode(sdp, id->block_no);
+
+ if (dt->dup_flags & DUPFLAG_REF1_IS_DUPL)
+ clone_dup_ref_in_inode(ip, dt);
+
+ q = block_type(id->block_no);
+ if (q == GFS2_BLKST_UNLINKED) {
+ log_debug( _("The remaining reference inode %lld (0x%llx) is "
+ "marked invalid: Marking the block as free.\n"),
+ (unsigned long long)id->block_no,
+ (unsigned long long)id->block_no);
+ fsck_blockmap_set(ip, dt->block, _("reference-repaired leaf"),
+ GFS2_BLKST_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, dt->block, _("reference-repaired data"),
+ GFS2_BLKST_USED);
+ } else if (id->reftypecount[ref_as_meta]) {
+ if (is_dir(&ip->i_di, sdp->gfs1))
+ fsck_blockmap_set(ip, dt->block,
+ _("reference-repaired leaf"),
+ sdp->gfs1 ? GFS2_BLKST_DINODE :
+ GFS2_BLKST_USED);
+ else
+ fsck_blockmap_set(ip, dt->block,
+ _("reference-repaired indirect"),
+ sdp->gfs1 ? GFS2_BLKST_DINODE :
+ GFS2_BLKST_USED);
+ } else {
+ fsck_blockmap_set(ip, dt->block,
+ _("reference-repaired extended "
+ "attribute"),
+ sdp->gfs1 ? GFS2_BLKST_DINODE :
+ GFS2_BLKST_USED);
+ }
+ fsck_inode_put(&ip); /* out, brelse, free */
+ log_debug(_("Done with duplicate reference to block 0x%llx\n"),
+ (unsigned long long)dt->block);
+ dup_delete(dt);
+}
+
/* handle_dup_blk - handle a duplicate block reference.
*
* This function should resolve and delete the duplicate block reference given,
@@ -372,8 +438,6 @@ static void clone_dup_ref_in_inode(struct gfs2_inode *ip, struct duptree *dt)
static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *dt)
{
osi_list_t *tmp;
- struct gfs2_inode *ip;
- struct inode_with_dups *id;
struct dup_handler dh = {0};
struct gfs2_buffer_head *bh;
uint32_t cmagic, ctype;
@@ -484,68 +548,7 @@ static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *dt)
reference, use it to determine the correct block type for our
blockmap and bitmap. */
if (dh.ref_inode_count == 1 && !osi_list_empty(&dt->ref_inode_list)) {
- uint8_t q;
-
- log_notice( _("Block %llu (0x%llx) has only one remaining "
- "valid inode referencing it.\n"),
- (unsigned long long)dup_blk,
- (unsigned long long)dup_blk);
- /* 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 = 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 "
- "reference in inode %lld (0x%llx).\n"),
- (unsigned long long)id->block_no,
- (unsigned long long)id->block_no);
- ip = fsck_load_inode(sdp, id->block_no);
-
- if (dt->dup_flags & DUPFLAG_REF1_IS_DUPL)
- clone_dup_ref_in_inode(ip, dt);
-
- q = block_type(id->block_no);
- if (q == GFS2_BLKST_UNLINKED) {
- log_debug( _("The remaining reference inode %lld "
- "(0x%llx) is marked invalid: Marking "
- "the block as free.\n"),
- (unsigned long long)id->block_no,
- (unsigned long long)id->block_no);
- fsck_blockmap_set(ip, dt->block,
- _("reference-repaired leaf"),
- GFS2_BLKST_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, dt->block,
- _("reference-repaired data"),
- GFS2_BLKST_USED);
- } else if (id->reftypecount[ref_as_meta]) {
- if (is_dir(&ip->i_di, sdp->gfs1))
- fsck_blockmap_set(ip, dt->block,
- _("reference-repaired leaf"),
- sdp->gfs1 ?
- GFS2_BLKST_DINODE :
- GFS2_BLKST_USED);
- else
- fsck_blockmap_set(ip, dt->block,
- _("reference-repaired "
- "indirect"), sdp->gfs1 ?
- GFS2_BLKST_DINODE :
- GFS2_BLKST_USED);
- } else
- fsck_blockmap_set(ip, dt->block,
- _("reference-repaired extended "
- "attribute"),
- sdp->gfs1 ? GFS2_BLKST_DINODE :
- GFS2_BLKST_USED);
- fsck_inode_put(&ip); /* out, brelse, free */
- log_debug(_("Done with duplicate reference to block 0x%llx\n"),
- (unsigned long long)dt->block);
- dup_delete(dt);
+ resolve_last_reference(sdp, dt, acceptable_ref);
} else {
/* They may have answered no and not fixed all references. */
log_debug( _("All duplicate references to block 0x%llx were "
8 years, 7 months
gfs2-utils: master - fsck.gfs2: Make debug messages more succinct wrt extended attributes
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=65306dde...
Commit: 65306dde6b09e1c70a4b579fe9df0a19c89dc2f5
Parent: ec1544385e555a8c890ee4ff4fafc948bc258bc5
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Wed Sep 23 12:22:33 2015 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Tue Sep 29 13:22:59 2015 -0500
fsck.gfs2: Make debug messages more succinct wrt extended attributes
This patch changes function check_inode_eattr, which is called from
several passes, to remove the debug message that says basically
Extended attributes exist for inode X. That way the debug output is
not cluttered with those messages for every inode for every pass.
Instead, the existing message regarding the processing of EA leaf blocks
has been enhanced to add the inode number. Similarly, a new debug
message was added to function check_inode_eattr for indirect EA block
processing. This makes the output much more clear.
---
gfs2/fsck/metawalk.c | 17 +++++++++++------
1 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 9923d94..1ecd756 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -955,9 +955,12 @@ static int check_leaf_eattr(struct gfs2_inode *ip, uint64_t block,
if (pass->check_eattr_leaf) {
int error = 0;
- log_debug( _("Checking EA leaf block #%llu (0x%llx).\n"),
+ log_debug( _("Checking EA leaf block #%llu (0x%llx) for "
+ "inode #%llu (0x%llx).\n"),
(unsigned long long)block,
- (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);
error = pass->check_eattr_leaf(ip, block, parent, &bh,
pass->private);
@@ -1175,11 +1178,13 @@ int check_inode_eattr(struct gfs2_inode *ip, struct metawalk_fxns *pass)
if (!ip->i_di.di_eattr)
return 0;
- log_debug( _("Extended attributes exist for inode #%llu (0x%llx).\n"),
- (unsigned long long)ip->i_di.di_num.no_addr,
- (unsigned long long)ip->i_di.di_num.no_addr);
-
if (ip->i_di.di_flags & GFS2_DIF_EA_INDIRECT){
+ log_debug( _("Checking EA indirect block #%llu (0x%llx) for "
+ "inode #%llu (0x%llx)..\n"),
+ (unsigned long long)ip->i_di.di_eattr,
+ (unsigned long long)ip->i_di.di_eattr,
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr);
if ((error = check_indirect_eattr(ip, ip->i_di.di_eattr, pass)))
stack;
} else {
8 years, 7 months
gfs2-utils: master - fsck.gfs2: Add check for gfs1 invalid inode refs in dentry
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=ec154438...
Commit: ec1544385e555a8c890ee4ff4fafc948bc258bc5
Parent: ff58f4d283573bd7e2f1b6c5e42a35290aac5b66
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Mon Sep 14 16:23:49 2015 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Tue Sep 29 13:22:56 2015 -0500
fsck.gfs2: Add check for gfs1 invalid inode refs in dentry
This patch adds a check to function basic_dentry_checks for a
special case where a GFS1 dirent points to a non-inode. Since
GFS1 marked all its metadata as "metadata" (not just dinodes as
GFS2 does), we need to verify that GFS1 dirents actually point
to GFS1 dinodes. If they point to a different kind of metadata
block, we need to treat it as an error.
---
gfs2/fsck/pass2.c | 21 +++++++++++++++++++++
1 files changed, 21 insertions(+), 0 deletions(-)
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index 900d4e1..11777eb 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -611,6 +611,27 @@ static int basic_dentry_checks(struct gfs2_inode *ip, struct gfs2_dirent *dent,
(unsigned long long)ii->di_num.no_formal_ino);
return 1;
}
+ /* Check for a special case where a (bad) GFS1 dirent points to what
+ * is not a known inode. It could be other GFS1 metadata, such as an
+ * eattr or indirect block, but marked "dinode" in the bitmap because
+ * gfs1 marked all gfs1 metadata that way. */
+ if (ii == NULL && sdp->gfs1) {
+ struct gfs2_buffer_head *tbh;
+
+ tbh = bread(sdp, entry->no_addr);
+ if (gfs2_check_meta(tbh, GFS2_METATYPE_DI)) { /* not dinode */
+ log_err( _("Directory entry '%s' pointing to block "
+ "%llu (0x%llx) in directory %llu (0x%llx) "
+ "is not really a GFS1 dinode.\n"), tmp_name,
+ (unsigned long long)entry->no_addr,
+ (unsigned long long)entry->no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr);
+ brelse(tbh);
+ return 1;
+ }
+ brelse(tbh);
+ }
return 0;
}
8 years, 7 months
gfs2-utils: master - libgfs2: Check rgd->bits before referencing it
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=ff58f4d2...
Commit: ff58f4d283573bd7e2f1b6c5e42a35290aac5b66
Parent: 5055de123b8b117c43f2897b8eb925b4eea65ec5
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Mon Sep 14 09:55:51 2015 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Tue Sep 29 13:22:52 2015 -0500
libgfs2: Check rgd->bits before referencing it
This patch adds a check to function gfs2_rgrp_free to make sure
rgd->bits is non-zero before attempting to reference it.
This might be NULL because no buffers actually existed because
it was concocted in an attempt to repair damaged rgrps in fsck.
---
gfs2/libgfs2/rgrp.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/gfs2/libgfs2/rgrp.c b/gfs2/libgfs2/rgrp.c
index cf4385a..2a55523 100644
--- a/gfs2/libgfs2/rgrp.c
+++ b/gfs2/libgfs2/rgrp.c
@@ -244,7 +244,7 @@ void gfs2_rgrp_free(struct osi_root *rgrp_tree)
while ((n = osi_first(rgrp_tree))) {
rgd = (struct rgrp_tree *)n;
- if (rgd->bits[0].bi_bh) { /* if a buffer exists */
+ if (rgd->bits && rgd->bits[0].bi_bh) { /* if a buffer exists */
rgs_since_sync++;
if (rgs_since_sync >= RG_SYNC_TOLERANCE) {
if (!sdp)
8 years, 7 months
gfs2-utils: master - libgfs2: Check block range when inserting into rgrp tree
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=5055de12...
Commit: 5055de123b8b117c43f2897b8eb925b4eea65ec5
Parent: 243caa0b1d3e5debbeba9c99e1ad002b6eae93c9
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Mon Sep 14 09:52:47 2015 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Tue Sep 29 13:22:48 2015 -0500
libgfs2: Check block range when inserting into rgrp tree
This patch adds checks to function rindex_read to make sure the
rgrp starting address isn't grossly outside the file system.
It may be in the case of severely corrupt file systems from fsck.
If we added them to the rgrp tree, our calculations will get
screwed up, eventually causing a segfault.
---
gfs2/libgfs2/super.c | 6 ++++++
1 files changed, 6 insertions(+), 0 deletions(-)
diff --git a/gfs2/libgfs2/super.c b/gfs2/libgfs2/super.c
index b956366..73354ff 100644
--- a/gfs2/libgfs2/super.c
+++ b/gfs2/libgfs2/super.c
@@ -166,6 +166,12 @@ int rindex_read(struct gfs2_sbd *sdp, int fd, int *count1, int *sane)
return -1;
gfs2_rindex_in(&ri, (char *)&buf.bufgfs2);
+ if (gfs2_check_range(sdp, ri.ri_addr) != 0) {
+ *sane = 0;
+ if (prev_rgd == NULL)
+ return -1;
+ ri.ri_addr = prev_rgd->ri.ri_addr + prev_rgd->length;
+ }
rgd = rgrp_insert(&sdp->rgtree, ri.ri_addr);
memcpy(&rgd->ri, &ri, sizeof(struct gfs2_rindex));
8 years, 7 months