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.
rhbz#1257625
---
gfs2/fsck/pass1b.c | 39 ++++++++++++++++++++++++++++++++++-----
1 file 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"),
--
2.4.3