From mboxrd@z Thu Jan 1 00:00:00 1970 From: Bob Peterson Date: Thu, 22 Jan 2015 15:41:09 -0500 (EST) Subject: [Cluster-devel] [fsck.gfs2 PATCH] fsck.gfs2: Change block_map to match bitmap In-Reply-To: <1442399810.13789822.1421959172642.JavaMail.zimbra@redhat.com> Message-ID: <651499900.13792931.1421959269755.JavaMail.zimbra@redhat.com> List-Id: To: cluster-devel.redhat.com MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Hi, This patch changes the old block_map structure for fsck.gfs2 to the simpler bitmap structure so that we have a 1:1 correspondence. This was done to reduce memory requirements of fsck.gfs2. Regards, Bob Peterson Red Hat File Systems Signed-off-by: Bob Peterson --- gfs2/fsck/lost_n_found.c | 4 +- gfs2/fsck/metawalk.c | 69 ++++++++------- gfs2/fsck/metawalk.h | 6 +- gfs2/fsck/pass1.c | 218 ++++++++++++++++++++++++++--------------------- gfs2/fsck/pass1b.c | 39 ++++----- gfs2/fsck/pass1c.c | 20 +++-- gfs2/fsck/pass2.c | 143 ++++++++++++------------------- gfs2/fsck/pass3.c | 27 +++--- gfs2/fsck/pass4.c | 15 ++-- gfs2/fsck/pass5.c | 2 +- gfs2/fsck/util.c | 59 +++++-------- gfs2/fsck/util.h | 113 +++--------------------- 12 files changed, 300 insertions(+), 415 deletions(-) diff --git a/gfs2/fsck/lost_n_found.c b/gfs2/fsck/lost_n_found.c index b2e35e2..ba3ae1d 100644 --- a/gfs2/fsck/lost_n_found.c +++ b/gfs2/fsck/lost_n_found.c @@ -132,7 +132,7 @@ void make_sure_lf_exists(struct gfs2_inode *ip) set_di_nlink(sdp->md.rooti); q = block_type(lf_dip->i_di.di_num.no_addr); - if (q != gfs2_inode_dir) { + if (q != GFS2_BLKST_DINODE) { lf_was_created = 1; /* This is a new lost+found directory, so set its block type and increment link counts for the directories */ @@ -140,7 +140,7 @@ void make_sure_lf_exists(struct gfs2_inode *ip) whether it created a new directory or just found an old one, and we used that instead of the block_type to run this */ fsck_blockmap_set(ip, lf_dip->i_di.di_num.no_addr, - _("lost+found dinode"), gfs2_inode_dir); + _("lost+found dinode"), GFS2_BLKST_DINODE); dirtree_insert(lf_dip->i_di.di_num); /* root inode links to lost+found */ incr_link_count(sdp->md.rooti->i_di.di_num, lf_dip, _("root")); diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c index b771b9e..90127d3 100644 --- a/gfs2/fsck/metawalk.c +++ b/gfs2/fsck/metawalk.c @@ -29,9 +29,9 @@ you'll get bitmap mismatches. This function checks the status of the bitmap whenever the blockmap changes, and fixes it accordingly. */ int check_n_fix_bitmap(struct gfs2_sbd *sdp, uint64_t blk, int error_on_dinode, - enum gfs2_mark_block new_blockmap_state) + int new_blockmap_state) { - int old_bitmap_state, new_bitmap_state; + int old_bitmap_state; struct rgrp_tree *rgd; rgd = gfs2_blk2rgrpd(sdp, blk); @@ -43,19 +43,18 @@ int check_n_fix_bitmap(struct gfs2_sbd *sdp, uint64_t blk, int error_on_dinode, (unsigned long long)blk, (unsigned long long)blk); return -1; } - new_bitmap_state = blockmap_to_bitmap(new_blockmap_state, sdp->gfs1); - if (old_bitmap_state != new_bitmap_state) { + if (old_bitmap_state != new_blockmap_state) { const char *allocdesc[2][5] = { /* gfs2 descriptions */ {"free", "data", "unlinked", "inode", "reserved"}, /* gfs1 descriptions: */ {"free", "data", "free meta", "metadata", "reserved"}}; if (error_on_dinode && old_bitmap_state == GFS2_BLKST_DINODE && - new_bitmap_state != GFS2_BLKST_FREE) { + new_blockmap_state != GFS2_BLKST_FREE) { log_debug(_("Reference as '%s' to block %llu (0x%llx) " "which was marked as dinode. Needs " "further investigation.\n"), - allocdesc[sdp->gfs1][new_bitmap_state], + allocdesc[sdp->gfs1][new_blockmap_state], (unsigned long long)blk, (unsigned long long)blk); return 1; @@ -65,7 +64,7 @@ int check_n_fix_bitmap(struct gfs2_sbd *sdp, uint64_t blk, int error_on_dinode, log_err( _("Block %llu (0x%llx) was '%s', should be %s.\n"), (unsigned long long)blk, (unsigned long long)blk, allocdesc[sdp->gfs1][old_bitmap_state], - allocdesc[sdp->gfs1][new_bitmap_state]); + allocdesc[sdp->gfs1][new_blockmap_state]); if (query( _("Fix the bitmap? (y/n)"))) { /* If the new bitmap state is free (and therefore the old state was not) we have to add to the free @@ -74,11 +73,12 @@ int check_n_fix_bitmap(struct gfs2_sbd *sdp, uint64_t blk, int error_on_dinode, subtract to the free space. If the type changed from dinode to data or data to dinode, no change in free space. */ - gfs2_set_bitmap(rgd, blk, new_bitmap_state); - if (new_bitmap_state == GFS2_BLKST_FREE) { + gfs2_set_bitmap(rgd, blk, new_blockmap_state); + if (new_blockmap_state == GFS2_BLKST_FREE) { /* If we're freeing a dinode, get rid of the hash table entries for it. */ - if (old_bitmap_state == GFS2_BLKST_DINODE) { + if (old_bitmap_state == GFS2_BLKST_DINODE || + old_bitmap_state == GFS2_BLKST_UNLINKED) { struct dir_info *dt; struct inode_info *ii; @@ -114,18 +114,18 @@ int check_n_fix_bitmap(struct gfs2_sbd *sdp, uint64_t blk, int error_on_dinode, * bitmap, and adjust free space accordingly. */ int _fsck_blockmap_set(struct gfs2_inode *ip, uint64_t bblock, - const char *btype, enum gfs2_mark_block mark, - int error_on_dinode, - const char *caller, int fline) + const char *btype, int mark, + int error_on_dinode, const char *caller, int fline) { int error; static int prev_ino_addr = 0; - static enum gfs2_mark_block prev_mark = 0; + static int prev_mark = 0; static int prevcount = 0; + static const char *prev_caller = NULL; if (print_level >= MSG_DEBUG) { if ((ip->i_di.di_num.no_addr == prev_ino_addr) && - (mark == prev_mark)) { + (mark == prev_mark) && caller == prev_caller) { log_info("(0x%llx) ", (unsigned long long)bblock); prevcount++; if (prevcount > 10) { @@ -145,7 +145,7 @@ int _fsck_blockmap_set(struct gfs2_inode *ip, uint64_t bblock, (unsigned long long)ip->i_di.di_num.no_addr, block_type_string(mark)); - } else if (mark == gfs2_bad_block || mark == gfs2_meta_inval) { + } else if (mark == GFS2_BLKST_UNLINKED) { if (prevcount) { log_info("\n"); prevcount = 0; @@ -170,6 +170,7 @@ int _fsck_blockmap_set(struct gfs2_inode *ip, uint64_t bblock, } prev_ino_addr = ip->i_di.di_num.no_addr; prev_mark = mark; + prev_caller = caller; } /* First, check the rgrp bitmap against what we think it should be. @@ -909,8 +910,9 @@ static int check_eattr_entries(struct gfs2_inode *ip, a single byte. */ fsck_blockmap_set(ip, ip->i_di.di_eattr, - _("extended attribute"), - gfs2_meta_eattr); + _("extended attribute"), + sdp->gfs1 ? GFS2_BLKST_DINODE : + GFS2_BLKST_USED); log_err( _("The EA was " "fixed.\n")); } else { @@ -986,7 +988,7 @@ int delete_block(struct gfs2_inode *ip, uint64_t block, void *private) { if (valid_block(ip->i_sbd, block)) { - fsck_blockmap_set(ip, block, btype, gfs2_block_free); + fsck_blockmap_set(ip, block, btype, GFS2_BLKST_FREE); return 0; } return -1; @@ -1041,7 +1043,7 @@ static int delete_block_if_notdup(struct gfs2_inode *ip, uint64_t block, return meta_error; q = block_type(block); - if (q == gfs2_block_free) { + if (q == GFS2_BLKST_FREE) { log_info( _("%s block %lld (0x%llx), part of inode " "%lld (0x%llx), was already free.\n"), btype, (unsigned long long)block, @@ -1060,7 +1062,7 @@ static int delete_block_if_notdup(struct gfs2_inode *ip, uint64_t block, (unsigned long long)ip->i_di.di_num.no_addr, (unsigned long long)block, (unsigned long long)block); } else { - fsck_blockmap_set(ip, block, btype, gfs2_block_free); + fsck_blockmap_set(ip, block, btype, GFS2_BLKST_FREE); } return meta_is_good; } @@ -1672,7 +1674,7 @@ undo_metalist: delete_all_dups(ip); /* Set the dinode as "bad" so it gets deleted */ fsck_blockmap_set(ip, ip->i_di.di_num.no_addr, - _("corrupt"), gfs2_block_free); + _("corrupt"), GFS2_BLKST_FREE); log_err(_("The corrupt inode was invalidated.\n")); out: free_metalist(ip, &metalist[0]); @@ -1763,8 +1765,8 @@ int remove_dentry_from_dir(struct gfs2_sbd *sdp, uint64_t dir, remove_dentry_fxns.check_dentry = remove_dentry; q = block_type(dir); - if (q != gfs2_inode_dir) { - log_info( _("Parent block is not a directory...ignoring\n")); + if (q != GFS2_BLKST_DINODE) { + log_info( _("Parent block is not an inode...ignoring\n")); return 1; } /* Need to run check_dir with a private var of dentryblock, @@ -1807,7 +1809,7 @@ static int del_eattr_generic(struct gfs2_inode *ip, uint64_t block, if (valid_block(ip->i_sbd, block)) { q = block_type(block); - if (q == gfs2_block_free) + if (q == GFS2_BLKST_FREE) was_free = 1; ret = delete_block_if_notdup(ip, block, NULL, eatype, NULL, private); @@ -1907,12 +1909,13 @@ static int alloc_metalist(struct gfs2_inode *ip, uint64_t block, *was_duplicate = 0; *bh = bread(ip->i_sbd, block); q = block_type(block); - if (blockmap_to_bitmap(q, ip->i_sbd->gfs1) == GFS2_BLKST_FREE) { + if (q == GFS2_BLKST_FREE) { log_debug(_("%s reference to new metadata block " "%lld (0x%llx) is now marked as indirect.\n"), desc, (unsigned long long)block, (unsigned long long)block); - gfs2_blockmap_set(bl, block, gfs2_indir_blk); + gfs2_blockmap_set(bl, block, ip->i_sbd->gfs1 ? + GFS2_BLKST_DINODE : GFS2_BLKST_USED); } return meta_is_good; } @@ -1927,12 +1930,12 @@ static int alloc_data(struct gfs2_inode *ip, uint64_t metablock, /* We can't check the bitmap here because this function is called after the bitmap has been set but before the blockmap has. */ q = block_type(block); - if (blockmap_to_bitmap(q, ip->i_sbd->gfs1) == GFS2_BLKST_FREE) { + if (q == GFS2_BLKST_FREE) { log_debug(_("%s reference to new data block " "%lld (0x%llx) is now marked as data.\n"), desc, (unsigned long long)block, (unsigned long long)block); - gfs2_blockmap_set(bl, block, gfs2_block_used); + gfs2_blockmap_set(bl, block, GFS2_BLKST_USED); } return 0; } @@ -1945,9 +1948,10 @@ static int alloc_leaf(struct gfs2_inode *ip, uint64_t block, void *private) /* We can't check the bitmap here because this function is called after the bitmap has been set but before the blockmap has. */ q = block_type(block); - if (blockmap_to_bitmap(q, ip->i_sbd->gfs1) == GFS2_BLKST_FREE) + if (q == GFS2_BLKST_FREE) fsck_blockmap_set(ip, block, _("newly allocated leaf"), - gfs2_leaf_blk); + ip->i_sbd->gfs1 ? GFS2_BLKST_DINODE : + GFS2_BLKST_USED); return 0; } @@ -2111,7 +2115,8 @@ int write_new_leaf(struct gfs2_inode *dip, int start_lindex, int num_copies, free(padbuf); return -1; } - fsck_blockmap_set(dip, *bn, _("directory leaf"), gfs2_leaf_blk); + fsck_blockmap_set(dip, *bn, _("directory leaf"), dip->i_sbd->gfs1 ? + GFS2_BLKST_DINODE : GFS2_BLKST_USED); log_err(_("A new directory leaf was allocated at block %lld " "(0x%llx) to fill the %d (0x%x) pointer gap %s the existing " "pointer at index %d (0x%x).\n"), (unsigned long long)*bn, diff --git a/gfs2/fsck/metawalk.h b/gfs2/fsck/metawalk.h index 06345c3..057e698 100644 --- a/gfs2/fsck/metawalk.h +++ b/gfs2/fsck/metawalk.h @@ -46,12 +46,10 @@ extern int delete_eattr_extentry(struct gfs2_inode *ip, uint64_t *ea_data_ptr, void *private); extern int _fsck_blockmap_set(struct gfs2_inode *ip, uint64_t bblock, - const char *btype, enum gfs2_mark_block mark, - int error_on_dinode, + const char *btype, int mark, int error_on_dinode, const char *caller, int line); extern int check_n_fix_bitmap(struct gfs2_sbd *sdp, uint64_t blk, - int error_on_dinode, - enum gfs2_mark_block new_blockmap_state); + int error_on_dinode, int new_blockmap_state); extern int check_i_goal(struct gfs2_inode *ip, uint64_t goal_blk, void *private); extern void reprocess_inode(struct gfs2_inode *ip, const char *desc); diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c index 5342701..b516a21 100644 --- a/gfs2/fsck/pass1.c +++ b/gfs2/fsck/pass1.c @@ -137,7 +137,7 @@ static int resuscitate_metalist(struct gfs2_inode *ip, uint64_t block, *bh = NULL; if (!valid_block(ip->i_sbd, block)){ /* blk outside of FS */ fsck_blockmap_set(ip, ip->i_di.di_num.no_addr, - _("itself"), gfs2_bad_block); + _("itself"), GFS2_BLKST_UNLINKED); log_err( _("Bad indirect block pointer (invalid or out of " "range) found in system inode %lld (0x%llx).\n"), (unsigned long long)ip->i_di.di_num.no_addr, @@ -146,9 +146,12 @@ static int resuscitate_metalist(struct gfs2_inode *ip, uint64_t block, return meta_is_good; } if (fsck_system_inode(ip->i_sbd, block)) - fsck_blockmap_set(ip, block, _("system file"), gfs2_indir_blk); + fsck_blockmap_set(ip, block, _("system file"), + ip->i_sbd->gfs1 ? + GFS2_BLKST_DINODE : GFS2_BLKST_USED); else - check_n_fix_bitmap(ip->i_sbd, block, 0, gfs2_indir_blk); + check_n_fix_bitmap(ip->i_sbd, block, 0, ip->i_sbd->gfs1 ? + GFS2_BLKST_DINODE : GFS2_BLKST_USED); bc->indir_count++; return meta_is_good; } @@ -168,7 +171,6 @@ static int resuscitate_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent, struct gfs2_dirent dentry, *de; char tmp_name[PATH_MAX]; uint64_t block; - enum gfs2_mark_block dinode_type; memset(&dentry, 0, sizeof(struct gfs2_dirent)); gfs2_dirent_in(&dentry, (char *)dent); @@ -188,21 +190,15 @@ static int resuscitate_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent, (unsigned long long)ip->i_di.di_num.no_addr); return 0; } - if (block == sdp->md.jiinode->i_di.di_num.no_addr) - dinode_type = gfs2_inode_dir; - else if (!sdp->gfs1 && (block == sdp->md.pinode->i_di.di_num.no_addr || - block == sdp->master_dir->i_di.di_num.no_addr)) - dinode_type = gfs2_inode_dir; - else - dinode_type = gfs2_inode_file; /* If this is a system dinode, we'll handle it later in check_system_inodes. If not, it'll be handled by pass1 but since it's in a system directory we need to make sure it's represented in the rgrp bitmap. */ if (fsck_system_inode(sdp, block)) - fsck_blockmap_set(ip, block, _("system file"), dinode_type); + fsck_blockmap_set(ip, block, _("system file"), + GFS2_BLKST_DINODE); else - check_n_fix_bitmap(sdp, block, 0, dinode_type); + check_n_fix_bitmap(sdp, block, 0, GFS2_BLKST_DINODE); /* Return the number of leaf entries so metawalk doesn't flag this leaf as having none. */ *count = be16_to_cpu(((struct gfs2_leaf *)bh->b_data)->lf_entries); @@ -225,7 +221,7 @@ static int p1check_leaf(struct gfs2_inode *ip, uint64_t block, void *private) So we know it's a leaf block. */ bc->indir_count++; q = block_type(block); - if (q != gfs2_block_free) { + if (q != GFS2_BLKST_FREE) { log_err( _("Found duplicate block #%llu (0x%llx) referenced " "as a directory leaf in dinode " "%llu (0x%llx) - was marked %d (%s)\n"), @@ -235,12 +231,15 @@ static int p1check_leaf(struct gfs2_inode *ip, uint64_t block, void *private) (unsigned long long)ip->i_di.di_num.no_addr, q, block_type_string(q)); add_duplicate_ref(ip, block, ref_as_meta, 0, INODE_VALID); - if (q == gfs2_leaf_blk) /* If the previous reference also saw - this as a leaf, it was already - checked, so don't check again. */ + if (q == (ip->i_sbd->gfs1 ? GFS2_BLKST_DINODE : + GFS2_BLKST_USED)) + /* If the previous reference also saw this as a leaf, + it was already checked, so don't check again. */ return EEXIST; /* non-fatal */ } - fsck_blockmap_set(ip, block, _("directory leaf"), gfs2_leaf_blk); + fsck_blockmap_set(ip, block, _("directory leaf"), + ip->i_sbd->gfs1 ? GFS2_BLKST_DINODE : + GFS2_BLKST_USED); return 0; } @@ -264,7 +263,7 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block, set "free" and removed from the inodetree by undo_check_metalist. */ fsck_blockmap_set(ip, ip->i_di.di_num.no_addr, - _("bad block referencing"), gfs2_bad_block); + _("bad block referencing"), GFS2_BLKST_UNLINKED); log_debug( _("Bad indirect block (invalid/out of range) " "found in inode %lld (0x%llx).\n"), (unsigned long long)ip->i_di.di_num.no_addr, @@ -280,7 +279,7 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block, blktypedesc = _("a journaled data block"); } q = block_type(block); - if (q != gfs2_block_free) { + if (q != GFS2_BLKST_FREE) { log_err( _("Found duplicate block #%llu (0x%llx) referenced " "as metadata in indirect block for dinode " "%llu (0x%llx) - was marked %d (%s)\n"), @@ -314,7 +313,8 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block, brelse(nbh); } else { *bh = nbh; - fsck_blockmap_set(ip, block, _("indirect"), gfs2_indir_blk); + fsck_blockmap_set(ip, block, _("indirect"), ip->i_sbd->gfs1 ? + GFS2_BLKST_DINODE : GFS2_BLKST_USED); } if (*is_valid) @@ -342,7 +342,7 @@ static int undo_reference(struct gfs2_inode *ip, uint64_t block, int meta, if (!valid_block(ip->i_sbd, block)) { /* blk outside of FS */ fsck_blockmap_set(ip, ip->i_di.di_num.no_addr, - _("bad block referencing"), gfs2_block_free); + _("bad block referencing"), GFS2_BLKST_FREE); return 1; } @@ -380,7 +380,7 @@ static int undo_reference(struct gfs2_inode *ip, uint64_t block, int meta, } fsck_blockmap_set(ip, block, meta ? _("bad indirect") : _("referenced data"), - gfs2_block_free); + GFS2_BLKST_FREE); return 0; } @@ -410,7 +410,7 @@ static int blockmap_set_as_data(struct gfs2_inode *ip, uint64_t block) struct gfs2_buffer_head *bh; struct gfs2_dinode *di; - error = fsck_blkmap_set_noino(ip, block, _("data"), gfs2_block_used); + error = fsck_blkmap_set_noino(ip, block, _("data"), GFS2_BLKST_USED); if (!error) return 0; @@ -436,7 +436,7 @@ static int blockmap_set_as_data(struct gfs2_inode *ip, uint64_t block) error = -1; out: if (!error) - fsck_blockmap_set(ip, block, _("data"), gfs2_block_used); + fsck_blockmap_set(ip, block, _("data"), GFS2_BLKST_USED); brelse(bh); return error; } @@ -464,12 +464,15 @@ static int check_data(struct gfs2_inode *ip, uint64_t metablock, * blocks later */ fsck_blockmap_set(ip, ip->i_di.di_num.no_addr, _("bad (out of range) data"), - gfs2_bad_block); + GFS2_BLKST_UNLINKED); return -1; } bc->data_count++; /* keep the count sane anyway */ q = block_type(block); - if (q != gfs2_block_free) { + if (q != GFS2_BLKST_FREE) { + struct gfs2_buffer_head *bh; + struct gfs2_meta_header mh; + log_err( _("Found duplicate %s block %llu (0x%llx) " "referenced as data by dinode %llu (0x%llx) "), block_type_string(q), @@ -483,11 +486,11 @@ static int check_data(struct gfs2_inode *ip, uint64_t metablock, log_err(_("from metadata block %llu (0x%llx)\n"), (unsigned long long)metablock, (unsigned long long)metablock); - - if (q >= gfs2_indir_blk && q <= gfs2_jdata) { - log_info(_("The block was processed earlier as valid " - "metadata, so it can't possibly be " - "data.\n")); + + switch (q) { + case GFS2_BLKST_DINODE: + log_info(_("The block was processed earlier as an " + "inode, so it can't possibly be data.\n")); /* We still need to add a duplicate record here because when check_metatree tries to delete the inode, we can't have the "undo" functions freeing the block @@ -495,8 +498,27 @@ static int check_data(struct gfs2_inode *ip, uint64_t metablock, add_duplicate_ref(ip, block, ref_as_data, 0, INODE_VALID); return 1; - } - if (q != gfs2_meta_inval) { + case GFS2_BLKST_USED: /* tough decision: May be data or meta */ + bh = bread(ip->i_sbd, block); + gfs2_meta_header_in(&mh, bh); + brelse(bh); + if (mh.mh_magic == GFS2_MAGIC && + mh.mh_type >= GFS2_METATYPE_RG && + mh.mh_type <= GFS2_METATYPE_QC && + mh.mh_type != GFS2_METATYPE_DI && + mh.mh_format % 100 == 0) { + log_info(_("The block was processed earlier " + "as valid metadata, so it can't " + "possibly be data.\n")); + /* We still need to add a duplicate record here + because when check_metatree tries to delete + the inode, we can't have the "undo" + functions freeing the block out from other + the original referencing inode. */ + add_duplicate_ref(ip, block, ref_as_data, 0, + INODE_VALID); + return 1; + } log_info( _("Seems to be a normal duplicate; I'll " "sort it out in pass1b.\n")); add_duplicate_ref(ip, block, ref_as_data, 0, @@ -504,11 +526,12 @@ static int check_data(struct gfs2_inode *ip, uint64_t metablock, /* This inode references the block as data. So if this all is validated, we want to keep this count. */ return 0; + case GFS2_BLKST_UNLINKED: + log_info( _("The block was invalid as metadata but might be " + "okay as data. I'll sort it out in pass1b.\n")); + add_duplicate_ref(ip, block, ref_as_data, 0, INODE_VALID); + return 0; } - log_info( _("The block was invalid as metadata but might be " - "okay as data. I'll sort it out in pass1b.\n")); - add_duplicate_ref(ip, block, ref_as_data, 0, INODE_VALID); - return 0; } /* In gfs1, rgrp indirect blocks are marked in the bitmap as "meta". In gfs2, "meta" is only for dinodes. So here we dummy up the @@ -517,13 +540,13 @@ static int check_data(struct gfs2_inode *ip, uint64_t metablock, log_info(_("Block %lld (0x%llx) is a GFS1 rindex block\n"), (unsigned long long)block, (unsigned long long)block); gfs2_special_set(&gfs1_rindex_blks, block); - fsck_blockmap_set(ip, block, _("rgrp"), gfs2_indir_blk); + fsck_blockmap_set(ip, block, _("rgrp"), GFS2_BLKST_DINODE); /*gfs2_meta_rgrp);*/ } else if (ip->i_sbd->gfs1 && ip->i_di.di_flags & GFS2_DIF_JDATA) { log_info(_("Block %lld (0x%llx) is a GFS1 journaled data " "block\n"), (unsigned long long)block, (unsigned long long)block); - fsck_blockmap_set(ip, block, _("jdata"), gfs2_jdata); + fsck_blockmap_set(ip, block, _("jdata"), GFS2_BLKST_DINODE); } else return blockmap_set_as_data(ip, block); return 0; @@ -618,7 +641,7 @@ static int check_eattr_indir(struct gfs2_inode *ip, uint64_t indirect, count it as a duplicate. */ *bh = bread(sdp, indirect); if (gfs2_check_meta(*bh, GFS2_METATYPE_IN)) { - if (q != gfs2_block_free) { /* Duplicate? */ + if (q != GFS2_BLKST_FREE) { /* Duplicate? */ add_duplicate_ref(ip, indirect, ref_as_ea, 0, INODE_VALID); if (!clear_eas(ip, bc, indirect, 1, @@ -632,7 +655,7 @@ static int check_eattr_indir(struct gfs2_inode *ip, uint64_t indirect, "type")); return 1; } - if (q != gfs2_block_free) { /* Duplicate? */ + if (q != GFS2_BLKST_FREE) { /* Duplicate? */ log_err( _("Inode #%llu (0x%llx): Duplicate Extended " "Attribute indirect block found at #%llu " "(0x%llx).\n"), @@ -645,8 +668,8 @@ static int check_eattr_indir(struct gfs2_inode *ip, uint64_t indirect, ret = 1; } else { fsck_blockmap_set(ip, indirect, - _("indirect Extended Attribute"), - gfs2_indir_blk); + _("indirect Extended Attribute"), sdp->gfs1 ? + GFS2_BLKST_DINODE : GFS2_BLKST_USED); bc->ea_count++; } return ret; @@ -715,7 +738,7 @@ static int check_ealeaf_block(struct gfs2_inode *ip, uint64_t block, int btype, If it isn't, clear it but don't count it as a duplicate. */ leaf_bh = bread(sdp, block); if (gfs2_check_meta(leaf_bh, btype)) { - if (q != gfs2_block_free) { /* Duplicate? */ + if (q != GFS2_BLKST_FREE) { /* Duplicate? */ add_duplicate_ref(ip, block, ref_as_ea, 0, INODE_VALID); clear_eas(ip, bc, block, 1, @@ -728,7 +751,7 @@ static int check_ealeaf_block(struct gfs2_inode *ip, uint64_t block, int btype, brelse(leaf_bh); return 1; } - if (q != gfs2_block_free) { /* Duplicate? */ + if (q != GFS2_BLKST_FREE) { /* Duplicate? */ log_debug( _("Duplicate block found at #%lld (0x%llx).\n"), (unsigned long long)block, (unsigned long long)block); @@ -748,9 +771,10 @@ static int check_ealeaf_block(struct gfs2_inode *ip, uint64_t block, int btype, return 1; } /* Point of confusion: We've got to set the ea block itself to - gfs2_meta_eattr here. Elsewhere we mark the inode with + GFS2_BLKST_USED here. Elsewhere we mark the inode with gfs2_eattr_block meaning it contains an eattr for pass1c. */ - fsck_blockmap_set(ip, block, _("Extended Attribute"), gfs2_meta_eattr); + fsck_blockmap_set(ip, block, _("Extended Attribute"), + sdp->gfs1 ? GFS2_BLKST_DINODE : GFS2_BLKST_USED); bc->ea_count++; *bh = leaf_bh; return 0; @@ -790,7 +814,7 @@ static int check_extended_leaf_eattr(struct gfs2_inode *ip, uint64_t *data_ptr, (unsigned long long)el_blk); fsck_blockmap_set(ip, ip->i_di.di_eattr, _("bad (out of range) Extended Attribute "), - gfs2_bad_block); + GFS2_BLKST_UNLINKED); return 1; } error = check_ealeaf_block(ip, el_blk, GFS2_METATYPE_ED, &bh, private); @@ -831,7 +855,7 @@ static int check_eattr_leaf(struct gfs2_inode *ip, uint64_t block, (unsigned long long)block, (unsigned long long)block); fsck_blockmap_set(ip, ip->i_di.di_eattr, _("bad (out of range) Extended " - "Attribute leaf"), gfs2_bad_block); + "Attribute leaf"), GFS2_BLKST_UNLINKED); return 1; } return check_ealeaf_block(ip, block, GFS2_METATYPE_EA, bh, private); @@ -910,7 +934,7 @@ static int mark_block_invalid(struct gfs2_inode *ip, uint64_t block, } q = block_type(block); - if (q != gfs2_block_free) { + if (q != GFS2_BLKST_FREE) { if (was_duplicate) *was_duplicate = 1; add_duplicate_ref(ip, block, reftype, 0, INODE_INVALID); @@ -923,7 +947,7 @@ static int mark_block_invalid(struct gfs2_inode *ip, uint64_t block, (unsigned long long)ip->i_di.di_num.no_addr); return meta_is_good; } - fsck_blockmap_set(ip, block, btype, gfs2_meta_inval); + fsck_blockmap_set(ip, block, btype, GFS2_BLKST_UNLINKED); return meta_is_good; } @@ -1008,7 +1032,7 @@ static int rangecheck_block(struct gfs2_inode *ip, uint64_t block, } /* See how many duplicate blocks it has */ q = block_type(block); - if (q != gfs2_block_free) { + if (q != GFS2_BLKST_FREE) { (*bad_pointers)++; log_info( _("Duplicated %s block pointer (violation %ld, block" " %lld (0x%llx)) found in inode %lld (0x%llx).\n"), @@ -1100,7 +1124,7 @@ static int handle_ip(struct gfs2_sbd *sdp, struct gfs2_inode *ip) (unsigned long long)ip->i_di.di_num.no_addr, BAD_POINTER_TOLERANCE); fsck_blockmap_set(ip, ip->i_di.di_num.no_addr, - _("badly corrupt"), gfs2_block_free); + _("badly corrupt"), GFS2_BLKST_FREE); return 0; } @@ -1113,7 +1137,7 @@ static int handle_ip(struct gfs2_sbd *sdp, struct gfs2_inode *ip) metadata will be flagged as metadata or data blocks yet. Therefore, we don't need to invalidate anything. */ fsck_blockmap_set(ip, ip->i_di.di_num.no_addr, - _("invalid mode"), gfs2_block_free); + _("invalid mode"), GFS2_BLKST_FREE); return 0; } else if (error) goto bad_dinode; @@ -1241,8 +1265,7 @@ static int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh, static int check_system_inode(struct gfs2_sbd *sdp, struct gfs2_inode **sysinode, const char *filename, - int builder(struct gfs2_sbd *sdp), - enum gfs2_mark_block mark, + int builder(struct gfs2_sbd *sdp), int isdir, struct gfs2_inode *sysdir, int needs_sysbit) { uint64_t iblock = 0; @@ -1263,8 +1286,8 @@ static int check_system_inode(struct gfs2_sbd *sdp, "%llu (0x%llx)\n"), (unsigned long long)iblock, (unsigned long long)iblock); - gfs2_blockmap_set(bl, iblock, gfs2_block_free); - check_n_fix_bitmap(sdp, iblock, 0, gfs2_block_free); + gfs2_blockmap_set(bl, iblock, GFS2_BLKST_FREE); + check_n_fix_bitmap(sdp, iblock, 0, GFS2_BLKST_FREE); inode_put(sysinode); } } @@ -1274,14 +1297,14 @@ static int check_system_inode(struct gfs2_sbd *sdp, be recovering from a corrupt bitmap. In that case, don't rebuild the inode. Just reuse the inode and fix the bitmap. */ - if (ds.q == gfs2_block_free) { + if (ds.q == GFS2_BLKST_FREE) { log_info( _("The inode exists but the block is not " "marked 'in use'; fixing it.\n")); fsck_blockmap_set(*sysinode, (*sysinode)->i_di.di_num.no_addr, - filename, mark); - ds.q = mark; - if (mark == gfs2_inode_dir) + filename, GFS2_BLKST_DINODE); + ds.q = GFS2_BLKST_DINODE; + if (isdir) dirtree_insert((*sysinode)->i_di.di_num); } /* Make sure it's marked as a system file/directory */ @@ -1297,7 +1320,7 @@ static int check_system_inode(struct gfs2_sbd *sdp, /* Set the blockmap (but not bitmap) back to 'free' so that it gets checked like any normal dinode. */ - gfs2_blockmap_set(bl, iblock, gfs2_block_free); + gfs2_blockmap_set(bl, iblock, GFS2_BLKST_FREE); log_err( _("Removed system inode \"%s\".\n"), filename); } @@ -1309,11 +1332,11 @@ static int check_system_inode(struct gfs2_sbd *sdp, inode and get it all setup - of course, everything will be in lost+found then, but we *need* our system inodes before we can do any of that. */ - if (!(*sysinode) || ds.q != mark) { - log_err( _("Invalid or missing %s system inode (should be " - "'%s', is '%s').\n"), filename, - block_type_string(mark), - block_type_string(ds.q)); + if (!(*sysinode) || ds.q != GFS2_BLKST_DINODE) { + log_err(_("Invalid or missing %s system inode (is '%s', " + "should be '%s').\n"), filename, + block_type_string(ds.q), + block_type_string(GFS2_BLKST_DINODE)); if (query(_("Create new %s system inode? (y/n) "), filename)) { log_err( _("Rebuilding system file \"%s\"\n"), filename); @@ -1328,9 +1351,9 @@ static int check_system_inode(struct gfs2_sbd *sdp, ji_update(sdp); fsck_blockmap_set(*sysinode, (*sysinode)->i_di.di_num.no_addr, - filename, mark); - ds.q = mark; - if (mark == gfs2_inode_dir) + filename, GFS2_BLKST_DINODE); + ds.q = GFS2_BLKST_DINODE; + if (isdir) dirtree_insert((*sysinode)->i_di.di_num); } else { log_err( _("Cannot continue without valid %s inode\n"), @@ -1389,10 +1412,9 @@ static int check_system_inodes(struct gfs2_sbd *sdp) if (!sdp->gfs1) { fsck_blockmap_set(sdp->master_dir, sdp->master_dir->i_di.di_num.no_addr, - "master", gfs2_inode_dir); + "master", GFS2_BLKST_DINODE); if (check_system_inode(sdp, &sdp->master_dir, "master", - build_master, gfs2_inode_dir, - NULL, 1)) { + build_master, 1, NULL, 1)) { stack; return -1; } @@ -1400,43 +1422,42 @@ static int check_system_inodes(struct gfs2_sbd *sdp) /* Mark the root dinode as a "dinode" in the block map as we did for master, since it has no parent. */ fsck_blockmap_set(sdp->md.rooti, sdp->md.rooti->i_di.di_num.no_addr, - "root", gfs2_inode_dir); - if (check_system_inode(sdp, &sdp->md.rooti, "root", build_root, - gfs2_inode_dir, NULL, 0)) { + "root", GFS2_BLKST_DINODE); + if (check_system_inode(sdp, &sdp->md.rooti, "root", build_root, 1, + NULL, 0)) { stack; return -1; } if (!sdp->gfs1 && - check_system_inode(sdp, &sdp->md.inum, "inum", build_inum, - gfs2_inode_file, sdp->master_dir, 1)) { + check_system_inode(sdp, &sdp->md.inum, "inum", build_inum, 0, + sdp->master_dir, 1)) { stack; return -1; } - if (check_system_inode(sdp, &sdp->md.statfs, "statfs", build_statfs, - gfs2_inode_file, sdp->master_dir, !sdp->gfs1)) { + if (check_system_inode(sdp, &sdp->md.statfs, "statfs", build_statfs, 0, + sdp->master_dir, !sdp->gfs1)) { stack; return -1; } if (check_system_inode(sdp, &sdp->md.jiinode, "jindex", build_jindex, - (sdp->gfs1 ? gfs2_inode_file : gfs2_inode_dir), - sdp->master_dir, !sdp->gfs1)) { + (sdp->gfs1 ? 0 : 1), sdp->master_dir, + !sdp->gfs1)) { stack; return -1; } if (check_system_inode(sdp, &sdp->md.riinode, "rindex", build_rindex, - gfs2_inode_file, sdp->master_dir, !sdp->gfs1)) { + 0, sdp->master_dir, !sdp->gfs1)) { stack; return -1; } if (check_system_inode(sdp, &sdp->md.qinode, "quota", build_quota, - gfs2_inode_file, sdp->master_dir, !sdp->gfs1)) { + 0, sdp->master_dir, !sdp->gfs1)) { stack; return -1; } if (!sdp->gfs1 && check_system_inode(sdp, &sdp->md.pinode, "per_node", - build_per_node, gfs2_inode_dir, - sdp->master_dir, 1)) { + build_per_node, 1, sdp->master_dir, 1)) { stack; return -1; } @@ -1464,8 +1485,8 @@ static int check_system_inodes(struct gfs2_sbd *sdp) sprintf(jname, "journal%d", sdp->md.journals); if (check_system_inode(sdp, &sdp->md.journal[sdp->md.journals], - jname, build_a_journal, - gfs2_inode_file, sdp->md.jiinode, 1)) { + jname, build_a_journal, 0, + sdp->md.jiinode, 1)) { stack; return -1; } @@ -1529,7 +1550,7 @@ static int pass1_process_bitmap(struct gfs2_sbd *sdp, struct rgrp_tree *rgd, uin (bh->b_data))->mh_magic; q = block_type(block); - if (q != gfs2_block_free) { + if (q != GFS2_BLKST_FREE) { if (be32_to_cpu(check_magic) == GFS2_MAGIC && sdp->gfs1 && !is_inode) { log_debug(_("Block 0x%llx assumed to be " @@ -1580,7 +1601,7 @@ 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); - check_n_fix_bitmap(sdp, block, 0, gfs2_block_free); + check_n_fix_bitmap(sdp, block, 0, GFS2_BLKST_FREE); } else if (handle_di(sdp, bh, rgd) < 0) { stack; brelse(bh); @@ -1615,6 +1636,8 @@ static int pass1_process_rgrp(struct gfs2_sbd *sdp, struct rgrp_tree *rgd) return ret; } + if (fsck_abort) + return 0; /* For GFS1, we have to count the "free meta" blocks in the resource group and mark them specially so we can count them @@ -1624,8 +1647,11 @@ static int pass1_process_rgrp(struct gfs2_sbd *sdp, struct rgrp_tree *rgd) continue; n = lgfs2_bm_scan(rgd, k, ibuf, GFS2_BLKST_UNLINKED); - for (i = 0; i < n; i++) - gfs2_blockmap_set(bl, ibuf[i], gfs2_freemeta); + for (i = 0; i < n; i++) { + gfs2_blockmap_set(bl, ibuf[i], GFS2_BLKST_UNLINKED); + if (fsck_abort) + return 0; + } } free(ibuf); @@ -1674,6 +1700,8 @@ int pass1(struct gfs2_sbd *sdp) * things - we can change the method later if necessary. */ for (n = osi_first(&sdp->rgtree); n; n = next, rg_count++) { + if (fsck_abort) + return FSCK_CANCELED; next = osi_next(n); log_debug( _("Checking metadata in Resource Group #%llu\n"), (unsigned long long)rg_count); @@ -1683,7 +1711,7 @@ int pass1(struct gfs2_sbd *sdp) "is now marked as 'rgrp data'\n"), rgd->ri.ri_addr + i, rgd->ri.ri_addr + i); if (gfs2_blockmap_set(bl, rgd->ri.ri_addr + i, - gfs2_indir_blk)) { + GFS2_BLKST_USED)) { stack; gfs2_special_free(&gfs1_rindex_blks); return FSCK_ERROR; diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c index f82f43b..a8f3d28 100644 --- a/gfs2/fsck/pass1b.c +++ b/gfs2/fsck/pass1b.c @@ -52,7 +52,6 @@ static void log_inode_reference(struct duptree *dt, osi_list_t *tmp, int inval) (unsigned long long)dt->block, reftypestring); } -/* delete_all_dups - delete all duplicate records for a given inode */ /* * resolve_dup_references - resolve all but the last dinode that has a * duplicate reference to a given block. @@ -114,7 +113,7 @@ static void resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *dt, !found_good_ref) { /* We haven't found a good reference */ /* If this is an invalid inode, but not on the invalid list, it's better to delete it. */ - if (q != gfs2_inode_invalid) { + if (q == GFS2_BLKST_DINODE) { found_good_ref = 1; log_warn( _("Inode %s (%lld/0x%llx)'s " "reference to block %llu (0x%llx) " @@ -158,7 +157,7 @@ static void resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *dt, dup_listent_delete(dt, id); continue; } - if (q == gfs2_block_free) + if (q == GFS2_BLKST_FREE) log_warn( _("Inode %lld (0x%llx) was previously " "deleted.\n"), (unsigned long long)id->block_no, @@ -172,7 +171,7 @@ static void resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *dt, /* If we've already deleted this dinode, don't try to delete it again. That could free blocks that used to be duplicate references that are now resolved (and gone). */ - if (q != gfs2_block_free) { + if (q != GFS2_BLKST_FREE) { /* 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 @@ -185,7 +184,7 @@ static void resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *dt, inodetree_delete(ii); fsck_blockmap_set(ip, ip->i_di.di_num.no_addr, _("duplicate referencing bad"), - gfs2_inode_invalid); + GFS2_BLKST_UNLINKED); /* We delete the dup_handler inode count and duplicate id BEFORE clearing the metadata, because if this is the last reference to @@ -391,7 +390,7 @@ static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *dt) ip = fsck_load_inode(sdp, id->block_no); q = block_type(id->block_no); - if (q == gfs2_inode_invalid) { + if (q == GFS2_BLKST_UNLINKED) { log_debug( _("The remaining reference inode %lld " "(0x%llx) is marked invalid: Marking " "the block as free.\n"), @@ -399,28 +398,32 @@ static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *dt) (unsigned long long)id->block_no); fsck_blockmap_set(ip, dt->block, _("reference-repaired leaf"), - gfs2_block_free); + 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_block_used); + 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"), - gfs2_leaf_blk); + sdp->gfs1 ? + GFS2_BLKST_DINODE : + GFS2_BLKST_USED); else fsck_blockmap_set(ip, dt->block, _("reference-repaired " - "indirect"), - gfs2_indir_blk); + "indirect"), sdp->gfs1 ? + GFS2_BLKST_DINODE : + GFS2_BLKST_USED); } else fsck_blockmap_set(ip, dt->block, _("reference-repaired extended " "attribute"), - gfs2_meta_eattr); + 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); @@ -441,8 +444,8 @@ static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *dt) if (dh.dt) dup_delete(dh.dt); /* Now fix the block type of the block in question. */ - gfs2_blockmap_set(bl, dup_blk, gfs2_block_free); - check_n_fix_bitmap(sdp, dup_blk, 0, gfs2_block_free); + gfs2_blockmap_set(bl, dup_blk, GFS2_BLKST_FREE); + check_n_fix_bitmap(sdp, dup_blk, 0, GFS2_BLKST_FREE); } } return 0; @@ -599,13 +602,11 @@ int pass1b(struct gfs2_sbd *sdp) } q = block_type(i); - if (q < gfs2_inode_dir) - continue; - if (q > gfs2_inode_invalid) + if (q == GFS2_BLKST_FREE || q == GFS2_BLKST_USED) continue; - if (q == gfs2_inode_invalid) - log_debug( _("Checking invalidated duplicate dinode " + if (q == GFS2_BLKST_UNLINKED) + log_debug( _("Checking invalidated duplicate block " "%lld (0x%llx)\n"), (unsigned long long)i, (unsigned long long)i); diff --git a/gfs2/fsck/pass1c.c b/gfs2/fsck/pass1c.c index ce9ca96..aa905da 100644 --- a/gfs2/fsck/pass1c.c +++ b/gfs2/fsck/pass1c.c @@ -97,7 +97,7 @@ static int check_eattr_indir(struct gfs2_inode *ip, uint64_t block, return ask_remove_eattr(ip); } q = block_type(block); - if (q != gfs2_indir_blk) { + if (q != (sdp->gfs1 ? GFS2_BLKST_DINODE : GFS2_BLKST_USED)) { log_err( _("Extended attributes indirect block #%llu" " (0x%llx) for inode #%llu" " (0x%llx) is invalid.\n"), @@ -122,16 +122,18 @@ static int check_eattr_leaf(struct gfs2_inode *ip, uint64_t block, uint8_t q; if (!valid_block(sdp, block)) { - log_err( _("Extended attributes block for inode #%llu" - " (0x%llx) is invalid.\n"), - (unsigned long long)ip->i_di.di_num.no_addr, - (unsigned long long)ip->i_di.di_num.no_addr); + log_err( _("Extended attributes block %lld (0x%llx) for " + "inode #%llu (0x%llx) is invalid.\n"), + (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); return ask_remove_eattr(ip); } q = block_type(block); - if (q != gfs2_meta_eattr) { - log_err( _("Extended attributes block for inode #%llu" - " (0x%llx) invalid.\n"), + if (q != (sdp->gfs1 ? GFS2_BLKST_DINODE : GFS2_BLKST_USED)) { + log_err( _("Extended attributes block %lld (0x%llx) for " + "inode #%llu (0x%llx) invalid.\n"), + (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); return ask_remove_eattr(ip); @@ -218,7 +220,7 @@ static int check_eattr_extentry(struct gfs2_inode *ip, uint64_t *ea_ptr, struct gfs2_sbd *sdp = ip->i_sbd; q = block_type(be64_to_cpu(*ea_ptr)); - if (q != gfs2_meta_eattr) { + if (q != (sdp->gfs1 ? GFS2_BLKST_DINODE : GFS2_BLKST_USED)) { if (remove_eattr_entry(sdp, leaf_bh, ea_hdr, ea_hdr_prev)){ stack; return -1; diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c index 74bcc26..1d32335 100644 --- a/gfs2/fsck/pass2.c +++ b/gfs2/fsck/pass2.c @@ -135,40 +135,28 @@ static const char *de_type_string(uint8_t de_type) return de_types[3]; /* invalid */ } -static int check_file_type(uint8_t de_type, uint8_t blk_type, int gfs1) +static int check_file_type(uint64_t block, uint8_t de_type, uint8_t q, + int gfs1, int *isdir) { - switch(blk_type) { - case gfs2_inode_dir: - if (de_type != (gfs1 ? GFS_FILE_DIR : DT_DIR)) - return 1; - break; - case gfs2_inode_file: - if (de_type != (gfs1 ? GFS_FILE_REG : DT_REG)) - return 1; - break; - case gfs2_inode_lnk: - if (de_type != (gfs1 ? GFS_FILE_LNK : DT_LNK)) - return 1; - break; - case gfs2_inode_device: - if ((de_type != (gfs1 ? GFS_FILE_BLK : DT_BLK)) && - (de_type != (gfs1 ? GFS_FILE_CHR : DT_CHR))) - return 1; - break; - case gfs2_inode_fifo: - if (de_type != (gfs1 ? GFS_FILE_FIFO : DT_FIFO)) - return 1; - break; - case gfs2_inode_sock: - if (de_type != (gfs1 ? GFS_FILE_SOCK : DT_SOCK)) - return 1; - break; - default: + struct dir_info *dt; + + *isdir = 0; + if (q != GFS2_BLKST_DINODE) { log_err( _("Invalid block type\n")); return -1; - break; } - return 0; + if (de_type == (gfs1 ? GFS_FILE_DIR : DT_DIR)) + *isdir = 1; + /* Check if the dinode is in the dir tree */ + dt = dirtree_find(block); + /* This is a bit confusing, so let me explain: + If the dirent says the inode supposed to be for a directory, + it should be in the dir tree. If it is, no problem, return 0. + If it's not, return 1 (wrong type). If it's not supposed to be + a directory, it shouldn't be in the dir tree. */ + if (dt) + return !(*isdir); + return *isdir; } struct metawalk_fxns pass2_fxns_delete = { @@ -209,7 +197,7 @@ static int bad_formal_ino(struct gfs2_inode *ip, struct gfs2_dirent *dent, (unsigned long long)entry.no_formal_ino, (unsigned long long)ii->di_num.no_formal_ino, (unsigned long long)ii->di_num.no_formal_ino); - if (q != gfs2_inode_dir || !strcmp("..", tmp_name)) { + if (q != GFS2_BLKST_DINODE || !strcmp("..", tmp_name)) { if (query( _("Remove the corrupt directory entry? (y/n) "))) return 1; log_err( _("Corrupt directory entry not removed.\n")); @@ -388,7 +376,8 @@ static int wrong_leaf(struct gfs2_inode *ip, struct gfs2_inum *entry, (unsigned long long)real_leaf, (unsigned long long)ip->i_di.di_blocks); fsck_blockmap_set(ip, real_leaf, _("split leaf"), - gfs2_indir_blk); + sdp->gfs1 ? GFS2_BLKST_DINODE : + GFS2_BLKST_USED); } /* If the misplaced dirent was supposed to be earlier in the hash table, we need to adjust our counts for the blocks @@ -449,7 +438,7 @@ static int basic_dentry_checks(struct gfs2_inode *ip, struct gfs2_dirent *dent, struct gfs2_inum *entry, const char *tmp_name, uint32_t *count, struct gfs2_dirent *de, struct dir_status *ds, uint8_t *q, - struct gfs2_buffer_head *bh) + struct gfs2_buffer_head *bh, int *isdir) { struct gfs2_sbd *sdp = ip->i_sbd; uint32_t calculated_hash; @@ -457,6 +446,7 @@ static int basic_dentry_checks(struct gfs2_inode *ip, struct gfs2_dirent *dent, int error; struct inode_info *ii; + *isdir = 0; if (!valid_block(ip->i_sbd, entry->no_addr)) { log_err( _("Block # referenced by directory entry %s in inode " "%lld (0x%llx) is invalid\n"), @@ -487,7 +477,7 @@ static int basic_dentry_checks(struct gfs2_inode *ip, struct gfs2_dirent *dent, /* Don't be tempted to do this: fsck_blockmap_set(ip, ip->i_di.di_num.no_addr, _("corrupt directory entry"), - gfs2_inode_invalid); + GFS2_BLKST_FREE); We can't free it because another dir may have a valid reference to it. Just return 1 so we can delete the bad dirent. */ log_err( _("Bad directory entry deleted.\n")); @@ -530,41 +520,7 @@ static int basic_dentry_checks(struct gfs2_inode *ip, struct gfs2_dirent *dent, * 2. Blocks marked "bad" need to have their entire * metadata tree deleted. */ - if (*q == gfs2_inode_invalid || *q == gfs2_bad_block) { - /* This entry's inode has bad blocks in it */ - - /* Handle bad blocks */ - log_err( _("Found directory entry '%s' pointing to invalid " - "block %lld (0x%llx)\n"), tmp_name, - (unsigned long long)entry->no_addr, - (unsigned long long)entry->no_addr); - - if (!query( _("Delete inode containing bad blocks? (y/n)"))) { - log_warn( _("Entry to inode containing bad blocks remains\n")); - return 0; - } - - if (*q == gfs2_bad_block) { - if (ip->i_di.di_num.no_addr == entry->no_addr) - entry_ip = ip; - else - entry_ip = fsck_load_inode(sdp, entry->no_addr); - if (ip->i_di.di_eattr) { - check_inode_eattr(entry_ip, - &pass2_fxns_delete); - } - check_metatree(entry_ip, &pass2_fxns_delete); - if (entry_ip != ip) - fsck_inode_put(&entry_ip); - } - fsck_blockmap_set(ip, entry->no_addr, - _("bad directory entry"), gfs2_block_free); - log_err( _("Inode %lld (0x%llx) was deleted.\n"), - (unsigned long long)entry->no_addr, - (unsigned long long)entry->no_addr); - return 1; - } - if (*q < gfs2_inode_dir || *q > gfs2_inode_sock) { + if (*q != GFS2_BLKST_DINODE) { log_err( _("Directory entry '%s' referencing inode %llu " "(0x%llx) in dir inode %llu (0x%llx) block type " "%d: %s.\n"), tmp_name, @@ -572,7 +528,7 @@ static int basic_dentry_checks(struct gfs2_inode *ip, struct gfs2_dirent *dent, (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, - *q, *q == gfs2_inode_invalid ? + *q, *q == GFS2_BLKST_FREE ? _("was previously marked invalid") : _("was deleted or is not an inode")); @@ -601,7 +557,8 @@ static int basic_dentry_checks(struct gfs2_inode *ip, struct gfs2_dirent *dent, return 1; } - error = check_file_type(de->de_type, *q, sdp->gfs1); + error = check_file_type(entry->no_addr, de->de_type, *q, sdp->gfs1, + isdir); if (error < 0) { log_err( _("Error: directory entry type is " "incompatible with block type@block %lld " @@ -674,6 +631,7 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent, struct gfs2_dirent dentry, *de; int hash_index; /* index into the hash table based on the hash */ int lindex_max; /* largest acceptable hash table index for hash */ + int isdir; memset(&dentry, 0, sizeof(struct gfs2_dirent)); gfs2_dirent_in(&dentry, (char *)dent); @@ -690,7 +648,7 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent, strncpy(tmp_name, filename, MAX_FILENAME - 1); error = basic_dentry_checks(ip, dent, &entry, tmp_name, count, de, - ds, &q, bh); + ds, &q, bh, &isdir); if (error) goto nuke_dentry; @@ -781,8 +739,7 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent, goto nuke_dentry; } - - if (q != gfs2_inode_dir) { + if (!isdir) { log_err( _("Found '..' entry in directory %llu (0x%llx) " "pointing to something that's not a directory"), (unsigned long long)ip->i_di.di_num.no_addr, @@ -831,7 +788,7 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent, } /* After this point we're only concerned with directories */ - if (q != gfs2_inode_dir) { + if (!isdir) { log_debug( _("Found non-dir inode dentry pointing to %lld " "(0x%llx)\n"), (unsigned long long)entry.no_addr, @@ -916,7 +873,8 @@ static void pad_with_leafblks(struct gfs2_inode *ip, uint64_t *tbl, (unsigned long long)new_leaf_blk, lindex, lindex, new_len); fsck_blockmap_set(ip, new_leaf_blk, _("pad leaf"), - gfs2_leaf_blk); + ip->i_sbd->gfs1 ? + GFS2_BLKST_DINODE : GFS2_BLKST_USED); /* Fix the hash table in memory to have the new leaf */ for (i = 0; i < new_len; i++) tbl[lindex + i] = cpu_to_be64(new_leaf_blk); @@ -941,6 +899,7 @@ static int lost_leaf(struct gfs2_inode *ip, uint64_t *tbl, uint64_t leafno, char *bh_end = bh->b_data + ip->i_sbd->bsize; struct gfs2_dirent de, *dent; int error; + int isdir = 0; log_err(_("Leaf block %llu (0x%llx) seems to be out of place and its " "contents need to be moved to lost+found.\n"), @@ -979,7 +938,7 @@ static int lost_leaf(struct gfs2_inode *ip, uint64_t *tbl, uint64_t leafno, error = basic_dentry_checks(ip, dent, &de.de_inum, tmp_name, &count, &de, - &ds, &q, bh); + &ds, &q, bh, &isdir); if (error) { log_err(_("Not relocating corrupt entry " "\"%s\".\n"), tmp_name); @@ -999,7 +958,7 @@ static int lost_leaf(struct gfs2_inode *ip, uint64_t *tbl, uint64_t leafno, _("from lost+found")); /* If it's a directory, lost+found is back-linked to it via .. */ - if (q == gfs2_inode_dir) + if (isdir) incr_link_count(lf_dip->i_di.di_num, NULL, _("to lost+found")); @@ -1017,7 +976,7 @@ static int lost_leaf(struct gfs2_inode *ip, uint64_t *tbl, uint64_t leafno, log_err(_("Directory entries from misplaced leaf block were relocated " "to lost+found.\n")); /* Free the lost leaf. */ - fsck_blockmap_set(ip, leafno, _("lost leaf"), gfs2_block_free); + fsck_blockmap_set(ip, leafno, _("lost leaf"), GFS2_BLKST_FREE); ip->i_di.di_blocks--; bmodified(ip->i_bh); /* Now we have to deal with the bad hash table entries pointing to the @@ -1039,6 +998,7 @@ static int basic_check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent, struct dir_status *ds = (struct dir_status *) priv; struct gfs2_dirent dentry, *de; int error; + int isdir; memset(&dentry, 0, sizeof(struct gfs2_dirent)); gfs2_dirent_in(&dentry, (char *)dent); @@ -1055,7 +1015,7 @@ static int basic_check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent, strncpy(tmp_name, filename, MAX_FILENAME - 1); error = basic_dentry_checks(ip, dent, &entry, tmp_name, count, de, - ds, &q, bh); + ds, &q, bh, &isdir); if (error) { dirent2_del(ip, bh, prev_de, dent); log_err( _("Bad directory entry '%s' cleared.\n"), tmp_name); @@ -1248,7 +1208,8 @@ static int fix_hashtable(struct gfs2_inode *ip, uint64_t *tbl, unsigned hsize, (unsigned long long)new_leaf_blk, (unsigned long long)new_leaf_blk, lindex, lindex); fsck_blockmap_set(ip, new_leaf_blk, _("split leaf"), - gfs2_leaf_blk); + ip->i_sbd->gfs1 ? + GFS2_BLKST_DINODE : GFS2_BLKST_USED); log_err(_("Hash table repaired.\n")); /* Fix up the hash table in memory to include the new leaf */ for (i = 0; i < *proper_len; i++) @@ -1712,7 +1673,7 @@ build_it: log_err(_("Error rebuilding %s.\n"), fn); return -1; } - fsck_blockmap_set(ip, ip->i_di.di_num.no_addr, fn, gfs2_inode_file); + fsck_blockmap_set(ip, ip->i_di.di_num.no_addr, fn, GFS2_BLKST_DINODE); reprocess_inode(ip, fn); log_err(_("System file %s rebuilt.\n"), fn); goto out_good; @@ -1740,7 +1701,7 @@ static int check_system_dir(struct gfs2_inode *sysinode, const char *dirname, ds.q = block_type(iblock); pass2_fxns.private = (void *) &ds; - if (ds.q == gfs2_bad_block) { + if (ds.q == GFS2_BLKST_UNLINKED) { astate_save(sysinode, &as); /* First check that the directory's metatree is valid */ error = check_metatree(sysinode, &pass2_fxns); @@ -1759,8 +1720,7 @@ static int check_system_dir(struct gfs2_inode *sysinode, const char *dirname, return -1; } if (error > 0) - fsck_blockmap_set(sysinode, iblock, dirname, - gfs2_inode_invalid); + fsck_blockmap_set(sysinode, iblock, dirname, GFS2_BLKST_FREE); if (check_inode_eattr(sysinode, &pass2_fxns)) { stack; @@ -1866,6 +1826,7 @@ int pass2(struct gfs2_sbd *sdp) struct dir_status ds = {0}; struct gfs2_inode *ip; int error = 0; + struct dir_info *dt; /* Check all the system directory inodes. */ if (!sdp->gfs1 && @@ -1908,7 +1869,11 @@ int pass2(struct gfs2_sbd *sdp) q = block_type(dirblk); - if (q != gfs2_inode_dir) + if (q != GFS2_BLKST_DINODE) + continue; + + dt = dirtree_find(dirblk); + if (dt == NULL) continue; /* If we created lost+found, its links should have been @@ -1924,7 +1889,7 @@ int pass2(struct gfs2_sbd *sdp) memset(&ds, 0, sizeof(ds)); pass2_fxns.private = (void *) &ds; - if (ds.q == gfs2_bad_block) { + if (ds.q == GFS2_BLKST_UNLINKED) { /* First check that the directory's metatree * is valid */ ip = fsck_load_inode(sdp, dirblk); @@ -1985,8 +1950,8 @@ int pass2(struct gfs2_sbd *sdp) (unsigned long long)dirblk); /* Can't use fsck_blockmap_set here because we don't have an inode in memory. */ - gfs2_blockmap_set(bl, dirblk, gfs2_inode_invalid); - check_n_fix_bitmap(sdp, dirblk, 0, gfs2_inode_invalid); + gfs2_blockmap_set(bl, dirblk, GFS2_BLKST_FREE); + check_n_fix_bitmap(sdp, dirblk, 0, GFS2_BLKST_FREE); } ip = fsck_load_inode(sdp, dirblk); if (!ds.dotdir) { diff --git a/gfs2/fsck/pass3.c b/gfs2/fsck/pass3.c index 3e183e5..054953f 100644 --- a/gfs2/fsck/pass3.c +++ b/gfs2/fsck/pass3.c @@ -67,6 +67,7 @@ static struct dir_info *mark_and_return_parent(struct gfs2_sbd *sdp, struct dir_info *pdi; uint8_t q_dotdot, q_treewalk; int error = 0; + struct dir_info *dt_dotdot, *dt_treewalk; di->checked = 1; @@ -75,7 +76,7 @@ static struct dir_info *mark_and_return_parent(struct gfs2_sbd *sdp, if (di->dotdot_parent.no_addr == di->treewalk_parent) { q_dotdot = block_type(di->dotdot_parent.no_addr); - if (q_dotdot != gfs2_inode_dir) { + if (q_dotdot != GFS2_BLKST_DINODE) { log_err( _("Orphaned directory at block %llu (0x%llx) " "moved to lost+found\n"), (unsigned long long)di->dinode.no_addr, @@ -95,7 +96,9 @@ static struct dir_info *mark_and_return_parent(struct gfs2_sbd *sdp, (unsigned long long)di->treewalk_parent, (unsigned long long)di->treewalk_parent); q_dotdot = block_type(di->dotdot_parent.no_addr); + dt_dotdot = dirtree_find(di->dotdot_parent.no_addr); q_treewalk = block_type(di->treewalk_parent); + dt_treewalk = dirtree_find(di->treewalk_parent); /* if the dotdot entry isn't a directory, but the * treewalk is, treewalk is correct - if the treewalk * entry isn't a directory, but the dotdot is, dotdot @@ -103,8 +106,8 @@ static struct dir_info *mark_and_return_parent(struct gfs2_sbd *sdp, * choose? if neither are directories, we have a * problem - need to move this directory into lost+found */ - if (q_dotdot != gfs2_inode_dir) { - if (q_treewalk != gfs2_inode_dir) { + if (q_dotdot != GFS2_BLKST_DINODE || dt_dotdot == NULL) { + if (q_treewalk != GFS2_BLKST_DINODE) { log_err( _("Orphaned directory, move to " "lost+found\n")); return NULL; @@ -120,7 +123,7 @@ static struct dir_info *mark_and_return_parent(struct gfs2_sbd *sdp, } goto out; } - if (q_treewalk == gfs2_inode_dir) { + if (dt_treewalk) { log_err( _("Both .. and treewalk parents are directories, " "going with treewalk...\n")); attach_dotdot_to(sdp, di->treewalk_parent, @@ -247,7 +250,7 @@ int pass3(struct gfs2_sbd *sdp) continue; } q = block_type(di->dinode.no_addr); - if (q == gfs2_bad_block) { + if (q == GFS2_BLKST_UNLINKED) { log_err( _("Found unlinked directory " "containing bad block at block %llu" " (0x%llx)\n"), @@ -264,16 +267,14 @@ int pass3(struct gfs2_sbd *sdp) /* Can't use fsck_blockmap_set because we don't have ip */ gfs2_blockmap_set(bl, di->dinode.no_addr, - gfs2_block_free); + GFS2_BLKST_FREE); check_n_fix_bitmap(sdp, di->dinode.no_addr, - 0, gfs2_block_free); + 0, GFS2_BLKST_FREE); break; } else log_err( _("Unlinked directory with bad block remains\n")); } - if (q != gfs2_inode_dir && q != gfs2_inode_file && - q != gfs2_inode_lnk && q != gfs2_inode_device && - q != gfs2_inode_fifo && q != gfs2_inode_sock) { + if (q != GFS2_BLKST_DINODE) { log_err( _("Unlinked block marked as an inode " "is not an inode\n")); if (!query(_("Clear the unlinked block?" @@ -289,9 +290,9 @@ int pass3(struct gfs2_sbd *sdp) /* Can't use fsck_blockmap_set because we don't have ip */ gfs2_blockmap_set(bl, di->dinode.no_addr, - gfs2_block_free); + GFS2_BLKST_FREE); check_n_fix_bitmap(sdp, di->dinode.no_addr, 0, - gfs2_block_free); + GFS2_BLKST_FREE); log_err( _("The block was cleared\n")); break; } @@ -310,7 +311,7 @@ int pass3(struct gfs2_sbd *sdp) fsck_blockmap_set(ip, di->dinode.no_addr, _("zero-sized unlinked inode"), - gfs2_block_free); + GFS2_BLKST_FREE); fsck_inode_put(&ip); break; } else { diff --git a/gfs2/fsck/pass4.c b/gfs2/fsck/pass4.c index 324ea9f..f307782 100644 --- a/gfs2/fsck/pass4.c +++ b/gfs2/fsck/pass4.c @@ -71,7 +71,7 @@ static int scan_inode_list(struct gfs2_sbd *sdp) { (unsigned long long)ii->di_num.no_addr, (unsigned long long)ii->di_num.no_addr); q = block_type(ii->di_num.no_addr); - if (q == gfs2_bad_block) { + if (q == GFS2_BLKST_UNLINKED) { log_err( _("Unlinked inode %llu (0x%llx) contains " "bad blocks\n"), (unsigned long long)ii->di_num.no_addr, @@ -84,18 +84,13 @@ static int scan_inode_list(struct gfs2_sbd *sdp) { check_metatree(ip, &pass4_fxns_delete); fsck_blockmap_set(ip, ii->di_num.no_addr, _("bad unlinked"), - gfs2_block_free); + GFS2_BLKST_FREE); fsck_inode_put(&ip); continue; } else log_err( _("Unlinked inode with bad blocks not cleared\n")); } - if (q != gfs2_inode_dir && - q != gfs2_inode_file && - q != gfs2_inode_lnk && - q != gfs2_inode_device && - q != gfs2_inode_fifo && - q != gfs2_inode_sock) { + if (q != GFS2_BLKST_DINODE) { log_err( _("Unlinked block %lld (0x%llx) " "marked as inode is " "not an inode (%d)\n"), @@ -108,7 +103,7 @@ static int scan_inode_list(struct gfs2_sbd *sdp) { check_metatree(ip, &pass4_fxns_delete); fsck_blockmap_set(ip, ii->di_num.no_addr, _("invalid unlinked"), - gfs2_block_free); + GFS2_BLKST_FREE); fsck_inode_put(&ip); log_err( _("The inode was deleted\n")); } else { @@ -129,7 +124,7 @@ static int scan_inode_list(struct gfs2_sbd *sdp) { "(y/n) "))) { fsck_blockmap_set(ip, ii->di_num.no_addr, _("unlinked zero-length"), - gfs2_block_free); + GFS2_BLKST_FREE); fsck_inode_put(&ip); continue; } diff --git a/gfs2/fsck/pass5.c b/gfs2/fsck/pass5.c index 2b8536d..fab3e5c 100644 --- a/gfs2/fsck/pass5.c +++ b/gfs2/fsck/pass5.c @@ -34,7 +34,7 @@ static int check_block_status(struct gfs2_sbd *sdp, char *buffer, if (skip_this_pass || fsck_abort) /* if asked to skip the rest */ return 0; - q = blockmap_to_bitmap(block_type(block), sdp->gfs1); + q = block_type(block); /* GFS1 file systems will have to suffer from slower fsck run * times because in GFS, there's no 1:1 relationship between * bits and counts. If a bit is marked "dinode" in GFS1, it diff --git a/gfs2/fsck/util.c b/gfs2/fsck/util.c index a0f6009..efdd132 100644 --- a/gfs2/fsck/util.c +++ b/gfs2/fsck/util.c @@ -375,7 +375,7 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block, q = block_type(ip->i_di.di_num.no_addr); /* If it's an invalid dinode, put it first on the invalid inode reference list otherwise put it on the normal list. */ - if (!inode_valid || q == gfs2_inode_invalid) + if (!inode_valid || q == GFS2_BLKST_UNLINKED) osi_list_add_prev(&id->list, &dt->ref_invinode_list); else { /* If this is a system dinode, we want the duplicate @@ -526,7 +526,7 @@ static int gfs2_blockmap_create(struct gfs2_bmap *bmap, uint64_t size) /* Have to add 1 to BLOCKMAP_SIZE since it's 0-based and mallocs * must be 1-based */ - bmap->mapsize = BLOCKMAP_SIZE4(size) + 1; + bmap->mapsize = BLOCKMAP_SIZE2(size) + 1; if (!(bmap->map = calloc(bmap->mapsize, sizeof(char)))) return -ENOMEM; @@ -560,8 +560,7 @@ struct gfs2_bmap *gfs2_bmap_create(struct gfs2_sbd *sdp, uint64_t size, return il; } -int gfs2_blockmap_set(struct gfs2_bmap *bmap, uint64_t bblock, - enum gfs2_mark_block mark) +int gfs2_blockmap_set(struct gfs2_bmap *bmap, uint64_t bblock, int mark) { static unsigned char *byte; static uint64_t b; @@ -571,10 +570,10 @@ int gfs2_blockmap_set(struct gfs2_bmap *bmap, uint64_t bblock, if (bblock > bmap->size) return -1; - byte = bmap->map + BLOCKMAP_SIZE4(bblock); - b = BLOCKMAP_BYTE_OFFSET4(bblock); - *byte &= ~(BLOCKMAP_MASK4 << b); - *byte |= (mark & BLOCKMAP_MASK4) << b; + byte = bmap->map + BLOCKMAP_SIZE2(bblock); + b = BLOCKMAP_BYTE_OFFSET2(bblock); + *byte &= ~(BLOCKMAP_MASK2 << b); + *byte |= (mark & BLOCKMAP_MASK2) << b; return 0; } @@ -598,61 +597,45 @@ void *gfs2_bmap_destroy(struct gfs2_sbd *sdp, struct gfs2_bmap *il) int set_ip_blockmap(struct gfs2_inode *ip, int instree) { uint64_t block = ip->i_bh->b_blocknr; - struct gfs2_sbd *sdp = ip->i_sbd; uint32_t mode; + const char *ty; - if (sdp->gfs1) + if (ip->i_sbd->gfs1) mode = gfs_to_gfs2_mode(ip); else mode = ip->i_di.di_mode & S_IFMT; switch (mode) { case S_IFDIR: - if (fsck_blockmap_set(ip, block, _("directory"), - gfs2_inode_dir)) - goto bad_dinode; - if (instree && !dirtree_insert(ip->i_di.di_num)) - goto bad_dinode; + ty = _("directory"); break; case S_IFREG: - if (fsck_blockmap_set(ip, block, _("file"), gfs2_inode_file)) - goto bad_dinode; + ty = _("file"); break; case S_IFLNK: - if (fsck_blockmap_set(ip, block, _("symlink"), - gfs2_inode_lnk)) - goto bad_dinode; + ty = _("symlink"); break; case S_IFBLK: - if (fsck_blockmap_set(ip, block, _("block device"), - gfs2_inode_device)) - goto bad_dinode; + ty = _("block device"); break; case S_IFCHR: - if (fsck_blockmap_set(ip, block, _("character device"), - gfs2_inode_device)) - goto bad_dinode; + ty = _("character device"); break; case S_IFIFO: - if (fsck_blockmap_set(ip, block, _("fifo"), - gfs2_inode_fifo)) - goto bad_dinode; + ty = _("fifo"); break; case S_IFSOCK: - if (fsck_blockmap_set(ip, block, _("socket"), - gfs2_inode_sock)) - goto bad_dinode; + ty = _("socket"); break; default: - fsck_blockmap_set(ip, block, _("invalid mode"), - gfs2_inode_invalid); return -EINVAL; } + if (fsck_blockmap_set(ip, block, ty, GFS2_BLKST_DINODE) || + (mode == S_IFDIR && instree && !dirtree_insert(ip->i_di.di_num))) { + stack; + return -EPERM; + } return 0; - -bad_dinode: - stack; - return -EPERM; } uint64_t find_free_blk(struct gfs2_sbd *sdp) diff --git a/gfs2/fsck/util.h b/gfs2/fsck/util.h index 66b9c7a..62f8ca6 100644 --- a/gfs2/fsck/util.h +++ b/gfs2/fsck/util.h @@ -28,9 +28,9 @@ extern void dup_listent_delete(struct duptree *dt, struct inode_with_dups *id); extern const char *reftypes[ref_types + 1]; -#define BLOCKMAP_SIZE4(size) ((size) >> 1) -#define BLOCKMAP_BYTE_OFFSET4(x) (((x) & 0x0000000000000001) << 2) -#define BLOCKMAP_MASK4 (0xf) +#define BLOCKMAP_SIZE2(size) ((size) >> 2) +#define BLOCKMAP_BYTE_OFFSET2(x) ((x & 0x0000000000000003) << 1) +#define BLOCKMAP_MASK2 (0x3) static inline void astate_save(struct gfs2_inode *ip, struct alloc_state *as) { @@ -53,110 +53,18 @@ static inline uint8_t block_type(uint64_t bblock) static uint64_t b; static uint8_t btype; - byte = bl->map + BLOCKMAP_SIZE4(bblock); - b = BLOCKMAP_BYTE_OFFSET4(bblock); - btype = (*byte & (BLOCKMAP_MASK4 << b )) >> b; + byte = bl->map + BLOCKMAP_SIZE2(bblock); + b = BLOCKMAP_BYTE_OFFSET2(bblock); + btype = (*byte & (BLOCKMAP_MASK2 << b )) >> b; return btype; } -/* blockmap declarations and functions */ -enum gfs2_mark_block { - gfs2_block_free = (0x0), - gfs2_block_used = (0x1), - gfs2_indir_blk = (0x2), - /* These are inode block types (only): */ - gfs2_inode_dir = (0x3), - gfs2_inode_file = (0x4), - - gfs2_inode_lnk = (0x5), - gfs2_inode_device = (0x6), /* char or block device */ - gfs2_inode_fifo = (0x7), - gfs2_inode_sock = (0x8), - gfs2_inode_invalid = (0x9), - - /* misc block types: */ - gfs2_jdata = (0xa), /* gfs journaled data blocks */ - gfs2_meta_inval = (0xb), - gfs2_leaf_blk = (0xc), - gfs2_freemeta = (0xd), /* was: gfs2_meta_rgrp */ - gfs2_meta_eattr = (0xe), - - gfs2_bad_block = (0xf), /* Contains at least one bad block */ -}; - static const inline char *block_type_string(uint8_t q) { - const char *blktyp[] = { - "free", - "data", - "indirect meta", - "directory", - "file", - - "symlink", - "device", - "fifo", - "socket", - "invalid inode", - - "journaled data", - "invalid meta", - "dir leaf", - "free metadata", - "eattribute", - - "bad"}; - if (q < 16) + const char *blktyp[] = {"free", "data", "other", "inode", "invalid"}; + if (q <= GFS2_BLKST_DINODE) return (blktyp[q]); - return blktyp[15]; -} - -/* Must be kept in sync with gfs2_mark_block enum above. Blocks marked as - invalid or bad are considered metadata until actually freed. */ -static inline int blockmap_to_bitmap(enum gfs2_mark_block m, int gfs1) -{ - static int bitmap_states[2][16] = { - /* ---------------------- gfs2 ------------------------------*/ - {GFS2_BLKST_FREE, /* free */ - GFS2_BLKST_USED, /* data */ - GFS2_BLKST_USED, /* indirect data or rgrp meta */ - GFS2_BLKST_DINODE, /* directory */ - GFS2_BLKST_DINODE, /* file */ - - GFS2_BLKST_DINODE, /* symlink */ - GFS2_BLKST_DINODE, /* block or char device */ - GFS2_BLKST_DINODE, /* fifo */ - GFS2_BLKST_DINODE, /* socket */ - GFS2_BLKST_FREE, /* invalid inode */ - - GFS2_BLKST_USED, /* journaled data */ - GFS2_BLKST_FREE, /* invalid meta */ - GFS2_BLKST_USED, /* dir leaf */ - GFS2_BLKST_UNLINKED, /* GFS unlinked metadata */ - GFS2_BLKST_USED, /* eattribute */ - - GFS2_BLKST_DINODE}, /* bad */ - /* ---------------------- gfs1 ----------------------------- */ - {GFS2_BLKST_FREE, /* free */ - GFS2_BLKST_USED, /* data */ - GFS2_BLKST_DINODE, /* indirect data or rgrp meta*/ - GFS2_BLKST_DINODE, /* directory */ - GFS2_BLKST_DINODE, /* file */ - - GFS2_BLKST_DINODE, /* symlink */ - GFS2_BLKST_DINODE, /* block or char device */ - GFS2_BLKST_DINODE, /* fifo */ - GFS2_BLKST_DINODE, /* socket */ - GFS2_BLKST_FREE, /* invalid inode */ - - GFS2_BLKST_DINODE, /* journaled data */ - GFS2_BLKST_FREE, /* invalid meta */ - GFS2_BLKST_DINODE, /* dir leaf */ - GFS2_BLKST_UNLINKED, /* GFS unlinked metadata */ - GFS2_BLKST_DINODE, /* eattribute */ - - GFS2_BLKST_DINODE}}; /* bad */ - return bitmap_states[gfs1][m]; + return blktyp[4]; } static inline int is_dir(struct gfs2_dinode *dinode, int gfs1) @@ -202,8 +110,7 @@ extern enum dup_ref_type get_ref_type(struct inode_with_dups *id); extern struct gfs2_bmap *gfs2_bmap_create(struct gfs2_sbd *sdp, uint64_t size, uint64_t *addl_mem_needed); extern void *gfs2_bmap_destroy(struct gfs2_sbd *sdp, struct gfs2_bmap *il); -extern int gfs2_blockmap_set(struct gfs2_bmap *il, uint64_t block, - enum gfs2_mark_block mark); +extern int gfs2_blockmap_set(struct gfs2_bmap *il, uint64_t block, int mark); extern int set_ip_blockmap(struct gfs2_inode *ip, int instree); extern char generic_interrupt(const char *caller, const char *where, const char *progress, const char *question,