Blob Blame History Raw
commit 4707be4ee1e214cc420679650e1897b3b0817638
Author: Andrew Price <anprice@redhat.com>
Date:   Fri Oct 18 19:43:48 2019 +0100

    fsck.gfs2: Clear bad indirect block pointers when bitmap meets expectations
    
    This issue only occurs when an indirect pointer of a 'system' directory
    points to an invalid block but the block's bitmap state is as expected.
    If the block's state is not as expected, the corruption is fixed by an
    earlier check.
    
    In this scenario, pass1_check_metalist() checks the type of a block and
    compares it with what it expected the indirect pointer to point to. If
    there is a metadata mismatch a bad indirect pointer is reported but the
    entire inode is considered invalid, causing it to be removed later, or
    rebuilt in the case of protected structures such as the root inode.
    This is heavy-handed and the right thing to do is to zero the indirect
    block pointer.
    
    Previously we had no access to the pointer block itself to update it in
    pass1_check_metalist() but now that an iptr is passed in, it's just a
    case of zeroing the pointer at the correct offset and marking the bh as
    modified. This means that fsck.gfs2 can now fix bad indirect pointers of
    the root directory without throwing away the entire directory tree.
    
    Resolves: rhbz#1487726
    
    Signed-off-by: Andrew Price <anprice@redhat.com>

diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index 66cf6dc6..deef1425 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -401,8 +401,15 @@ static int pass1_check_metalist(struct iptr iptr, struct gfs2_buffer_head **bh,
 			 (unsigned long long)ip->i_di.di_num.no_addr,
 			 (unsigned long long)block,
 			 (unsigned long long)block, blktypedesc);
-		brelse(nbh);
-		return meta_skip_further;
+		if (query(_("Zero the indirect block pointer? (y/n) "))){
+			*iptr_ptr(iptr) = 0;
+			bmodified(iptr.ipt_bh);
+			*is_valid = 1;
+			return meta_skip_one;
+		} else {
+			brelse(nbh);
+			return meta_skip_further;
+		}
 	}
 
 	bc->indir_count++;