gfs2-utils: master - fsck.gfs2: Don't flag GFS1 non-dinode blocks as duplicates

Bob Peterson rpeterso at fedoraproject.org
Mon May 20 16:18:38 UTC 2013


Gitweb:        http://git.fedorahosted.org/git/?p=gfs2-utils.git;a=commitdiff;h=5befaedc6b7f8cea80989994ec1934953f4db404
Commit:        5befaedc6b7f8cea80989994ec1934953f4db404
Parent:        bbb17b6bc32e8006afbf199f98555283c453ce05
Author:        Bob Peterson <rpeterso at redhat.com>
AuthorDate:    Tue Apr 2 13:19:35 2013 -0700
Committer:     Bob Peterson <rpeterso at redhat.com>
CommitterDate: Mon May 20 11:12:46 2013 -0500

fsck.gfs2: Don't flag GFS1 non-dinode blocks as duplicates

Before this patch, fsck.gfs2 could get into problems when processing
a GFS1 file system. The issue goes back to the fact that all GFS1
metadata is marked as "Meta" in the bitmap, whereas that bitmap
designation is reserved for dinodes in GFS2. For example, take a
GFS1 file of height 2, which looks like this:

Block
------
0x1234 dinode
0x1235 |----> indirect meta
0x1236        |---->data at offset 0 of the file

Before this patch, fsck.gfs2 would:

1. Encounter the dinode at 0x1234 and mark it as "dinode" in the
   blockmap.
2. Process its metadata, see block 0x1235, mark it as "indirect meta"
   in the blockmap.
3. Process the metadata's data, see block 0x1236, mark it as "data".
4. When it's done with the dinode, it moves on to the next dinode.
   But since GFS1 doesn't distinguish dinodes from other metadata,
   the next block in the bitmap that has that designation is block
   0x1235.
5. Since block 0x1235 was previously marked "indirect meta" pass1
   gets confused and thinks the block is a duplicate reference,
   and it's invalid as a dinode. This is a non-problem that's
   treated as a problem, and it makes bad decisions based on it,
   deleting what it perceives to be corruption.

This patch adds special checks for this problem and assumes the block
is just normal GFS1 non-dinode metadata.
---
 gfs2/fsck/pass1.c |   69 ++++++++++++++++++++++++++++++++++------------------
 1 files changed, 45 insertions(+), 24 deletions(-)

diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index 0f3adfe..004ca78 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -1084,22 +1084,11 @@ bad_dinode:
  */
 static int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh)
 {
-	uint8_t q;
 	int error = 0;
 	uint64_t block = bh->b_blocknr;
 	struct gfs2_inode *ip;
 
 	ip = fsck_inode_get(sdp, bh);
-	q = block_type(block);
-	if (q != gfs2_block_free) {
-		log_err( _("Found a duplicate inode block at #%llu"
-			   " (0x%llx) previously marked as a %s\n"),
-			 (unsigned long long)block,
-			 (unsigned long long)block, block_type_string(q));
-		add_duplicate_ref(ip, block, ref_as_meta, 0, INODE_VALID);
-		fsck_inode_put(&ip);
-		return 0;
-	}
 
 	if (ip->i_di.di_num.no_addr != block) {
 		log_err( _("Inode #%llu (0x%llx): Bad inode address found: %llu "
@@ -1359,8 +1348,13 @@ static int pass1_process_bitmap(struct gfs2_sbd *sdp, struct rgrp_tree *rgd, uin
 	struct gfs2_buffer_head *bh;
 	unsigned i;
 	uint64_t block;
+	struct gfs2_inode *ip;
+	uint8_t q;
 
 	for (i = 0; i < n; i++) {
+		int is_inode;
+		uint32_t check_magic;
+
 		block = ibuf[i];
 
 		/* skip gfs1 rindex indirect blocks */
@@ -1389,9 +1383,47 @@ static int pass1_process_bitmap(struct gfs2_sbd *sdp, struct rgrp_tree *rgd, uin
 				  (unsigned long long)block);
 			continue;
 		}
+
 		bh = bread(sdp, block);
 
-		if (gfs2_check_meta(bh, GFS2_METATYPE_DI)) {
+		is_inode = 0;
+		if (gfs2_check_meta(bh, GFS2_METATYPE_DI) == 0)
+			is_inode = 1;
+
+		check_magic = ((struct gfs2_meta_header *)
+			       (bh->b_data))->mh_magic;
+
+		q = block_type(block);
+		if (q != gfs2_block_free) {
+			if (be32_to_cpu(check_magic) == GFS2_MAGIC &&
+			    sdp->gfs1 && !is_inode) {
+				log_debug("Block 0x%llx assumed to be "
+					  "previously processed GFS1 "
+					  "non-dinode metadata.\n",
+					  (unsigned long long)block);
+				brelse(bh);
+				continue;
+			}
+			log_err( _("Found a duplicate inode block at #%llu "
+				   "(0x%llx) previously marked as a %s\n"),
+				 (unsigned long long)block,
+				 (unsigned long long)block,
+				 block_type_string(q));
+			ip = fsck_inode_get(sdp, bh);
+			if (is_inode && ip->i_di.di_num.no_addr == block)
+				add_duplicate_ref(ip, block, ref_is_inode, 0,
+						  INODE_VALID);
+			else
+				log_info(_("dinum.no_addr is wrong, so I "
+					   "assume the bitmap is just "
+					   "wrong.\n"));
+			fsck_inode_put(&ip);
+			brelse(bh);
+			continue;
+		}
+
+		if (!is_inode) {
+			if (be32_to_cpu(check_magic) == GFS2_MAGIC) {
 			/* In gfs2, a bitmap mark of 2 means an inode,
 			   but in gfs1 it means any metadata.  So if
 			   this is gfs1 and not an inode, it may be
@@ -1399,12 +1431,7 @@ static int pass1_process_bitmap(struct gfs2_sbd *sdp, struct rgrp_tree *rgd, uin
 			   be referenced by an inode, so we need to
 			   skip it here and it will be sorted out
 			   when the referencing inode is checked. */
-			if (sdp->gfs1) {
-				uint32_t check_magic;
-
-				check_magic = ((struct gfs2_meta_header *)
-					       (bh->b_data))->mh_magic;
-				if (be32_to_cpu(check_magic) == GFS2_MAGIC) {
+				if (sdp->gfs1) {
 					log_debug( _("Deferring GFS1 "
 						     "metadata block #"
 						     "%" PRIu64" (0x%"
@@ -1418,12 +1445,6 @@ static int pass1_process_bitmap(struct gfs2_sbd *sdp, struct rgrp_tree *rgd, uin
 				   "%llu (0x%llx)\n"),
 				 (unsigned long long)block,
 				 (unsigned long long)block);
-			if (gfs2_blockmap_set(bl, block, gfs2_block_free)) {
-				stack;
-				brelse(bh);
-				gfs2_special_free(&gfs1_rindex_blks);
-				return FSCK_ERROR;
-			}
 			check_n_fix_bitmap(sdp, block, gfs2_block_free);
 		} else if (handle_di(sdp, bh) < 0) {
 			stack;


More information about the cluster-commits mailing list