Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=54904ce52d5658... Commit: 54904ce52d5658debffe92d8f1cdc5ab15ce96c3 Parent: 84d59ca4ac7e0c1479c5a9718f622bcbcbd09adb Author: Bob Peterson rpeterso@redhat.com AuthorDate: Tue Apr 2 13:19:35 2013 -0700 Committer: Bob Peterson rpeterso@redhat.com CommitterDate: Fri May 17 15:28:04 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.
rhbz#902920 --- gfs2/fsck/pass1.c | 89 +++++++++++++++++++++++++++++++++------------------- 1 files changed, 56 insertions(+), 33 deletions(-)
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c index 90b865f..e10e4ce 100644 --- a/gfs2/fsck/pass1.c +++ b/gfs2/fsck/pass1.c @@ -1083,22 +1083,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 " @@ -1367,11 +1356,13 @@ int pass1(struct gfs2_sbd *sdp) { struct osi_node *n, *next = NULL; struct gfs2_buffer_head *bh; + struct gfs2_inode *ip; uint64_t block = 0; struct rgrp_tree *rgd; int first; uint64_t i; uint64_t rg_count = 0; + uint8_t q;
osi_list_init(&gfs1_rindex_blks.list);
@@ -1417,6 +1408,9 @@ int pass1(struct gfs2_sbd *sdp) first = 1;
while (1) { + int is_inode; + uint32_t check_magic; + /* "block" is relative to the entire file system */ /* Get the next dinode in the file system, according to the bitmap. This should ONLY be dinodes unless @@ -1451,12 +1445,55 @@ int pass1(struct gfs2_sbd *sdp) first = 0; continue; } + bh = bread(sdp, block);
+ 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); + first = 0; + 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); + first = 0; + continue; + } + /*log_debug( _("Checking metadata block #%" PRIu64 " (0x%" PRIx64 ")\n"), block, block);*/
- if (gfs2_check_meta(bh, GFS2_METATYPE_DI)) { + 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 @@ -1464,14 +1501,7 @@ int pass1(struct gfs2_sbd *sdp) 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%" @@ -1481,20 +1511,13 @@ int pass1(struct gfs2_sbd *sdp) first = 0; continue; } + log_err( _("Found invalid inode at " + "block #%llu (0x%llx)\n"), + (unsigned long long)block, + (unsigned long long)block); + check_n_fix_bitmap(sdp, block, + gfs2_block_free); } - log_err( _("Found invalid inode at block #" - "%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; brelse(bh);
cluster-commits@lists.fedorahosted.org