gfs2-utils: master - Misc cleanups
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/gfs2-utils.git?p=gfs2-utils.git;a=commitd...
Commit: 467c97dc20e5d7fa37f0d43381fd6b9eccd21eb0
Parent: 692fa870a1a810b3c66c8316ffedf1e9ab847ab3
Author: Bob Peterson <bob(a)ganesha.peterson>
AuthorDate: Fri Jan 22 16:51:44 2010 -0600
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Tue Jan 26 15:09:49 2010 -0600
Misc cleanups
This patch contains mostly formatting, cleanups, spelling
corrections and code refactoring / restructuring in order for the
code to be more readable. There are a few small things that might
make a difference, but hopefully only a positive one. For example
I fixed an uninitialized variable for lost+found inode pointer,
and when checking directory entries, I make sure the file names
are all printable characters.
rhbz#455300
---
gfs2/fsck/lost_n_found.c | 24 ++++++-----
gfs2/fsck/main.c | 2 +-
gfs2/fsck/metawalk.c | 5 ++
gfs2/fsck/pass1.c | 38 +++++++++++++----
gfs2/fsck/pass2.c | 103 ++++++++++++++++++++++++++--------------------
gfs2/fsck/pass3.c | 1 -
gfs2/fsck/pass4.c | 3 +-
gfs2/fsck/pass5.c | 19 ++------
gfs2/fsck/rgrepair.c | 10 ++--
gfs2/libgfs2/libgfs2.h | 6 +-
10 files changed, 121 insertions(+), 90 deletions(-)
diff --git a/gfs2/fsck/lost_n_found.c b/gfs2/fsck/lost_n_found.c
index d77e951..ab2bedb 100644
--- a/gfs2/fsck/lost_n_found.c
+++ b/gfs2/fsck/lost_n_found.c
@@ -30,21 +30,22 @@ int add_inode_to_lf(struct gfs2_inode *ip){
char tmp_name[256];
__be32 inode_type;
uint64_t lf_blocks;
+ struct gfs2_sbd *sdp = ip->i_sbd;
struct dir_info *di;
if(!lf_dip) {
uint8_t q;
- log_info( _("Locating/Creating lost and found directory\n"));
+ log_info( _("Locating/Creating lost+found directory\n"));
- lf_dip = createi(ip->i_sbd->md.rooti, "lost+found",
+ lf_dip = createi(sdp->md.rooti, "lost+found",
S_IFDIR | 0700, 0);
/* createi will have incremented the di_nlink link count for
the root directory. We must increment the nlink value
in the hash table to keep them in sync so that pass4 can
- detect and fix any discrepancies. */
- set_link_count(ip->i_sbd->sd_sb.sb_root_dir.no_addr,
- ip->i_sbd->md.rooti->i_di.di_nlink);
+ detect and fix any descrepancies. */
+ set_link_count(sdp->sd_sb.sb_root_dir.no_addr,
+ sdp->md.rooti->i_di.di_nlink);
q = block_type(lf_dip->i_di.di_num.no_addr);
if(q != gfs2_inode_dir) {
@@ -60,14 +61,14 @@ int add_inode_to_lf(struct gfs2_inode *ip){
_("lost+found dinode"),
gfs2_inode_dir);
/* root inode links to lost+found */
- increment_link(ip->i_sbd->md.rooti->i_di.di_num.no_addr,
+ increment_link(sdp->md.rooti->i_di.di_num.no_addr,
lf_dip->i_di.di_num.no_addr, _("root"));
/* lost+found link for '.' from itself */
increment_link(lf_dip->i_di.di_num.no_addr,
lf_dip->i_di.di_num.no_addr, "\".\"");
/* lost+found link for '..' back to root */
increment_link(lf_dip->i_di.di_num.no_addr,
- ip->i_sbd->md.rooti->i_di.di_num.no_addr,
+ sdp->md.rooti->i_di.di_num.no_addr,
"\"..\"");
}
log_info( _("lost+found directory is dinode %lld (0x%llx)\n"),
@@ -96,7 +97,7 @@ int add_inode_to_lf(struct gfs2_inode *ip){
/* If there's a pre-existing .. directory entry, we have to
back out the links. */
di = dirtree_find(ip->i_di.di_num.no_addr);
- if (di && gfs2_check_range(ip->i_sbd, di->dotdot_parent) == 0){
+ if (di && gfs2_check_range(sdp, di->dotdot_parent) == 0) {
struct gfs2_inode *dip;
log_debug(_("Directory %lld (0x%llx) already had a "
@@ -108,7 +109,7 @@ int add_inode_to_lf(struct gfs2_inode *ip){
decrement_link(di->dotdot_parent,
ip->i_di.di_num.no_addr,
_(".. unlinked, moving to lost+found"));
- dip = fsck_load_inode(ip->i_sbd, di->dotdot_parent);
+ dip = fsck_load_inode(sdp, di->dotdot_parent);
dip->i_di.di_nlink--;
log_debug(_("Decrementing its links to %d\n"),
dip->i_di.di_nlink);
@@ -121,7 +122,7 @@ int add_inode_to_lf(struct gfs2_inode *ip){
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
if(gfs2_dirent_del(ip, "..", 2))
- log_warn( _("add_inode_to_lf: Unable to remove "
+ log_warn( _("add_inode_to_lf: Unable to remove "
"\"..\" directory entry.\n"));
dir_add(ip, "..", 2, &(lf_dip->i_di.di_num), DT_DIR);
@@ -181,7 +182,8 @@ int add_inode_to_lf(struct gfs2_inode *ip){
increment_link(lf_dip->i_di.di_num.no_addr,
ip->i_di.di_mode, _("to lost+found"));
- log_notice( _("Added inode #%llu to lost+found dir\n"),
+ log_notice( _("Added inode #%llu (0x%llx) to lost+found dir\n"),
+ (unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
return 0;
}
diff --git a/gfs2/fsck/main.c b/gfs2/fsck/main.c
index 700e80e..7081560 100644
--- a/gfs2/fsck/main.c
+++ b/gfs2/fsck/main.c
@@ -21,7 +21,7 @@
#include "util.h"
struct gfs2_options opts = {0};
-struct gfs2_inode *lf_dip; /* Lost and found directory inode */
+struct gfs2_inode *lf_dip = NULL; /* Lost and found directory inode */
struct gfs2_bmap *bl = NULL;
uint64_t last_fs_block, last_reported_block = -1;
int64_t last_reported_fblock = -1000000;
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index b5339d2..2846c0e 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -251,6 +251,7 @@ static int dirent_repair(struct gfs2_inode *ip, struct gfs2_buffer_head *bh,
/* first, figure out a probable name length */
p = (char *)dent + sizeof(struct gfs2_dirent);
while (*p && /* while there's a non-zero char and */
+ isprint(*p) && /* a printable character and */
p < bh_end) { /* not past end of buffer */
calc_de_name_len++;
p++;
@@ -1116,6 +1117,8 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
for (ptr = (uint64_t *)(bh->b_data + head_size);
(char *)ptr < (bh->b_data + ip->i_sbd->bsize);
ptr++) {
+ if (skip_this_pass || fsck_abort)
+ return FSCK_OK;
nbh = NULL;
if (!*ptr)
@@ -1248,6 +1251,8 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
last_reported_fblock = -10000000;
while (error >= 0 && !osi_list_empty(list)) {
+ if (fsck_abort)
+ return 0;
bh = osi_list_entry(list->next, struct gfs2_buffer_head,
b_altlist);
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index 09c6a77..5900fee 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -85,31 +85,53 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head **bh, void *private)
{
uint8_t q;
- int found_dup = 0;
+ int found_dup = 0, iblk_type;
struct gfs2_buffer_head *nbh;
struct block_count *bc = (struct block_count *)private;
+ const char *blktypedesc;
*bh = NULL;
if (gfs2_check_range(ip->i_sbd, block)){ /* blk outside of FS */
fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
_("itself"), gfs2_bad_block);
- log_debug( _("Bad indirect block pointer (out of range).\n"));
+ log_debug( _("Bad indirect block pointer (out of range) "
+ "found in inode %lld (0x%llx).\n"),
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr);
return 1;
}
+ if (S_ISDIR(ip->i_di.di_mode)) {
+ iblk_type = GFS2_METATYPE_JD;
+ blktypedesc = _("a directory hash table block");
+ } else {
+ iblk_type = GFS2_METATYPE_IN;
+ blktypedesc = _("a journaled data block");
+ }
q = block_type(block);
if(q != gfs2_block_free) {
- log_err( _("Found duplicate block referenced as metadata in "
- "indirect block - was marked %d\n"), q);
+ log_err( _("Found duplicate block %llu (0x%llx) referenced "
+ "as metadata in indirect block for dinode "
+ "%llu (0x%llx) - was marked %d (%s)\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, q,
+ block_type_string(q));
gfs2_dup_set(block);
found_dup = 1;
}
nbh = bread(ip->i_sbd, block);
- if (gfs2_check_meta(nbh, GFS2_METATYPE_IN)){
- log_debug( _("Bad indirect block pointer (points to "
- "something that is not an indirect block).\n"));
+ if (gfs2_check_meta(nbh, iblk_type)){
+ log_debug( _("Inode %lld (0x%llx) has a bad indirect block "
+ "pointer %lld (0x%llx) (points to something "
+ "that is not %s).\n"),
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)block,
+ (unsigned long long)block, blktypedesc);
if(!found_dup) {
fsck_blockmap_set(ip, block, _("bad indirect"),
gfs2_meta_inval);
@@ -380,7 +402,6 @@ static int check_leaf_block(struct gfs2_inode *ip, uint64_t block, int btype,
clear_eas(ip, bc, block, 0,
_("Extended Attribute block removed due to "
"previous errors.\n"));
- bmodified(leaf_bh);
brelse(leaf_bh);
return 1;
}
@@ -559,7 +580,6 @@ static int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
PRIu64 " (0x%" PRIx64 ")? (y/n) "),
block, block)) {
ip->i_di.di_num.no_addr = ip->i_di.di_num.no_formal_ino = block;
- gfs2_dinode_out(&ip->i_di, ip->i_bh);
bmodified(ip->i_bh);
} else
log_err( _("Address in inode at block #%" PRIu64
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index 4d73c1c..d635eb3 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -26,24 +26,32 @@ static int set_parent_dir(struct gfs2_sbd *sbp, uint64_t childblock,
struct dir_info *di;
di = dirtree_find(childblock);
- if (di) {
- if(di->dinode == childblock) {
- if (di->treewalk_parent) {
- log_err( _("Another directory at block %" PRIu64
- " (0x%" PRIx64 ") already contains"
- " this child - checking %" PRIu64 " (0x%" PRIx64 ")\n"),
- di->treewalk_parent, di->treewalk_parent,
- parentblock, parentblock);
- return 1;
- }
- di->treewalk_parent = parentblock;
- }
- } else {
+ if(!di) {
log_err( _("Unable to find block %"PRIu64" (0x%" PRIx64
") in dir_info list\n"), childblock, childblock);
return -1;
}
+ if(di->dinode == childblock) {
+ if (di->treewalk_parent) {
+ log_err( _("Another directory at block %" PRIu64
+ " (0x%" PRIx64 ") already contains this "
+ "child %lld (%llx) - checking parent %"
+ PRIu64 " (0x%" PRIx64 ")\n"),
+ di->treewalk_parent, di->treewalk_parent,
+ (unsigned long long)childblock,
+ (unsigned long long)childblock,
+ parentblock, parentblock);
+ return 1;
+ }
+ log_debug( _("Child %lld (0x%llx) has parent %lld (0x%llx)\n"),
+ (unsigned long long)childblock,
+ (unsigned long long)childblock,
+ (unsigned long long)parentblock,
+ (unsigned long long)parentblock);
+ di->treewalk_parent = parentblock;
+ }
+
return 0;
}
@@ -249,7 +257,7 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
/* This entry's inode has bad blocks in it */
/* Handle bad blocks */
- log_err( _("Found a bad directory entry: %s\n"), filename);
+ log_err( _("Found a bad directory entry: %s\n"), tmp_name);
if(!query( _("Delete inode containing bad blocks? (y/n)"))) {
log_warn( _("Entry to inode containing bad blocks remains\n"));
@@ -530,9 +538,10 @@ static int check_system_dir(struct gfs2_inode *sysinode, const char *dirname,
pass2_fxns.private = (void *) &ds;
if(ds.q == gfs2_bad_block) {
/* First check that the directory's metatree is valid */
- if(check_metatree(sysinode, &pass2_fxns)) {
+ error = check_metatree(sysinode, &pass2_fxns);
+ if (error < 0) {
stack;
- return -1;
+ return error;
}
}
error = check_dir(sysinode->i_sbd, iblock, &pass2_fxns);
@@ -683,10 +692,11 @@ int pass2(struct gfs2_sbd *sbp)
/* First check that the directory's metatree
* is valid */
ip = fsck_load_inode(sbp, dirblk);
- if(check_metatree(ip, &pass2_fxns)) {
- fsck_inode_put(&ip);
+ error = check_metatree(ip, &pass2_fxns);
+ fsck_inode_put(&ip);
+ if (error < 0) {
stack;
- return FSCK_ERROR;
+ return error;
}
}
error = check_dir(sbp, dirblk, &pass2_fxns);
@@ -695,40 +705,43 @@ int pass2(struct gfs2_sbd *sbp)
return FSCK_ERROR;
}
if (error > 0) {
- struct dir_info *di = NULL;
+ struct dir_info *di;
di = dirtree_find(dirblk);
if(!di) {
stack;
return FSCK_ERROR;
}
- if(error == 0) {
- /* FIXME: factor */
- if(query( _("Remove directory entry for bad"
- " inode %"PRIu64" (0x%" PRIx64 ") in %"PRIu64
- " (0x%" PRIx64 ")? (y/n)"),
- dirblk, dirblk, di->treewalk_parent,
- di->treewalk_parent)) {
- error = remove_dentry_from_dir(sbp,
- di->treewalk_parent,
- dirblk);
- if(error < 0) {
- stack;
- return FSCK_ERROR;
- }
- if(error > 0) {
- log_warn( _("Unable to find dentry for %"
- PRIu64 " (0x%" PRIx64 ") in %" PRIu64
- " (0x%" PRIx64 ")\n"), dirblk, dirblk,
- di->treewalk_parent, di->treewalk_parent);
- }
- log_warn( _("Directory entry removed\n"));
- } else
- log_err( _("Directory entry to invalid inode remains.\n"));
- }
+ if(query( _("Remove directory entry for bad"
+ " inode %"PRIu64" (0x%" PRIx64 ") in %"PRIu64
+ " (0x%" PRIx64 ")? (y/n)"), dirblk,
+ dirblk, di->treewalk_parent,
+ di->treewalk_parent)) {
+ error = remove_dentry_from_dir(sbp, di->treewalk_parent,
+ dirblk);
+ if(error < 0) {
+ stack;
+ return FSCK_ERROR;
+ }
+ if(error > 0) {
+ log_warn( _("Unable to find dentry for %"
+ PRIu64 " (0x%" PRIx64 ") in %" PRIu64
+ " (0x%" PRIx64 ")\n"),
+ dirblk, dirblk,
+ di->treewalk_parent,
+ di->treewalk_parent);
+ }
+ log_warn( _("Directory entry removed\n"));
+ } else
+ log_err( _("Directory entry to invalid inode remains.\n"));
+ log_debug( _("Directory block %lld (0x%llx) "
+ "is now marked as 'invalid'\n"),
+ (unsigned long long)dirblk,
+ (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_meta_inval);
+ check_n_fix_bitmap(sbp, dirblk, gfs2_meta_inval);
}
ip = fsck_load_inode(sbp, dirblk);
if(!ds.dotdir) {
@@ -780,7 +793,7 @@ int pass2(struct gfs2_sbd *sbp)
}
}
- if(ip->i_di.di_entries != ds.entry_count) {
+ if(!fsck_abort && ip->i_di.di_entries != ds.entry_count) {
log_err( _("Entries is %d - should be %d for inode "
"block %llu (0x%llx)\n"),
ip->i_di.di_entries, ds.entry_count,
diff --git a/gfs2/fsck/pass3.c b/gfs2/fsck/pass3.c
index 8608678..9b277be 100644
--- a/gfs2/fsck/pass3.c
+++ b/gfs2/fsck/pass3.c
@@ -64,7 +64,6 @@ static int attach_dotdot_to(struct gfs2_sbd *sbp, uint64_t newdotdot,
reprocess_inode(ip, dirname);
}
increment_link(newdotdot, block, _("new \"..\""));
- bmodified(ip->i_bh);
fsck_inode_put(&ip);
fsck_inode_put(&pip);
free(filename);
diff --git a/gfs2/fsck/pass4.c b/gfs2/fsck/pass4.c
index 47a1eaa..9db27d9 100644
--- a/gfs2/fsck/pass4.c
+++ b/gfs2/fsck/pass4.c
@@ -116,7 +116,8 @@ static int scan_inode_list(struct gfs2_sbd *sbp) {
* them. */
if(!ip->i_di.di_size && !ip->i_di.di_eattr){
log_err( _("Unlinked inode has zero size\n"));
- if(query( _("Clear zero-size unlinked inode? (y/n) "))) {
+ if(query(_("Clear zero-size unlinked inode? "
+ "(y/n) "))) {
fsck_blockmap_set(ip, ii->inode,
_("unlinked zero-length"),
gfs2_block_free);
diff --git a/gfs2/fsck/pass5.c b/gfs2/fsck/pass5.c
index 66c7677..1297a80 100644
--- a/gfs2/fsck/pass5.c
+++ b/gfs2/fsck/pass5.c
@@ -59,7 +59,6 @@ static int check_block_status(struct gfs2_sbd *sbp, char *buffer, unsigned int b
unsigned char rg_status, block_status;
uint8_t q;
uint64_t block;
- static int free_unlinked = -1;
/* FIXME verify cast */
byte = (unsigned char *) buffer;
@@ -83,19 +82,11 @@ static int check_block_status(struct gfs2_sbd *sbp, char *buffer, unsigned int b
So we ignore it. */
if (rg_status == GFS2_BLKST_UNLINKED &&
block_status == GFS2_BLKST_FREE) {
- if (free_unlinked == -1) {
- log_err( _("Unlinked inode block found at "
- "block %llu (0x%llx).\n"),
- (unsigned long long)block,
- (unsigned long long)block);
- if(query( _("Do you want me to fix the "
- "bitmap for all unlinked "
- "blocks? (y/n) ")))
- free_unlinked = 1;
- else
- free_unlinked = 0;
- }
- if (free_unlinked) {
+ log_err( _("Unlinked inode block found at "
+ "block %llu (0x%llx).\n"),
+ (unsigned long long)block,
+ (unsigned long long)block);
+ if(query(_("Do you want to fix the bitmap? (y/n) "))) {
if(gfs2_set_bitmap(sbp, block, block_status))
log_err(_("Unlinked block %llu "
"(0x%llx) bitmap not fixed."
diff --git a/gfs2/fsck/rgrepair.c b/gfs2/fsck/rgrepair.c
index 3517956..957b1d9 100644
--- a/gfs2/fsck/rgrepair.c
+++ b/gfs2/fsck/rgrepair.c
@@ -418,7 +418,7 @@ static int rewrite_rg_block(struct gfs2_sbd *sdp, struct rgrp_list *rg,
*/
int rg_repair(struct gfs2_sbd *sdp, int trust_lvl, int *rg_count)
{
- int error, descrepencies;
+ int error, discrepancies;
osi_list_t expected_rglist;
int calc_rg_count = 0, rgcount_from_index, rg;
osi_list_t *exp, *act; /* expected, actual */
@@ -470,7 +470,7 @@ int rg_repair(struct gfs2_sbd *sdp, int trust_lvl, int *rg_count)
/* we have a large number that are completely wrong, we should */
/* abandon this method of recovery and try a better one. */
/* ------------------------------------------------------------- */
- descrepencies = 0;
+ discrepancies = 0;
for (rg = 0, act = sdp->rglist.next, exp = expected_rglist.next;
act != &sdp->rglist && exp != &expected_rglist;
act = act->next, exp = exp->next, rg++) {
@@ -483,14 +483,14 @@ int rg_repair(struct gfs2_sbd *sdp, int trust_lvl, int *rg_count)
!ri_equal(actual->ri, expected->ri, ri_data0) ||
!ri_equal(actual->ri, expected->ri, ri_data) ||
!ri_equal(actual->ri, expected->ri, ri_bitbytes)) {
- descrepencies++;
+ discrepancies++;
}
}
- if (trust_lvl < distrust && descrepencies > (trust_lvl * 8)) {
+ if (trust_lvl < distrust && discrepancies > (trust_lvl * 8)) {
log_warn( _("Level %d didn't work. Too many descepencies.\n"),
trust_lvl + 1);
log_warn( _("%d out of %d RGs did not match what was expected.\n"),
- descrepencies, rg);
+ discrepancies, rg);
gfs2_rgrp_free(&expected_rglist);
gfs2_rgrp_free(&sdp->rglist);
return -1;
diff --git a/gfs2/libgfs2/libgfs2.h b/gfs2/libgfs2/libgfs2.h
index 951966a..7091a37 100644
--- a/gfs2/libgfs2/libgfs2.h
+++ b/gfs2/libgfs2/libgfs2.h
@@ -257,9 +257,9 @@ struct metapath {
/* bitmap.c */
struct gfs2_bmap {
- uint64_t size;
- uint64_t mapsize;
- unsigned char *map;
+ uint64_t size;
+ uint64_t mapsize;
+ unsigned char *map;
};
/* block_list.c */
14 years, 4 months
gfs2-utils: master - fsck.gfs2: reprocess lost+found and other inode metadata when blocks are added
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/gfs2-utils.git?p=gfs2-utils.git;a=commitd...
Commit: 692fa870a1a810b3c66c8316ffedf1e9ab847ab3
Parent: 5fd378c85cb2d7c88198d6f43c827c3792477719
Author: Bob Peterson <bob(a)ganesha.peterson>
AuthorDate: Fri Jan 22 15:29:19 2010 -0600
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Tue Jan 26 15:09:49 2010 -0600
fsck.gfs2: reprocess lost+found and other inode metadata when blocks are added
On rare occasions, fsck.gfs2 needs to allocate blocks in the file system.
For example, this can happen when new directory leafs are added to
lost+found and when lost+found's hash table needs to be doubled.
While libgfs2 did a stellar job of updating the rgrp bitmap information,
those newly allocated blocks were unfortunately not being properly
accounted for in the fsck.gfs2 blockmap. Therefore, pass5 would
mistakenly mark them as free blocks. Further use of the file
system would often allocate those blocks a second time, creating
a duplicate block reference. That means very bad file system
corruption. This patch fixes the problem by checking for block
count changes in inodes at critical points, and subsequently fixing
up the blockmap using new "alloc_*" helper functions.
rhbz#455300
---
gfs2/fsck/lost_n_found.c | 8 ++++
gfs2/fsck/metawalk.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++
gfs2/fsck/metawalk.h | 1 +
gfs2/fsck/pass2.c | 16 +++++++
gfs2/fsck/pass3.c | 10 +++++
5 files changed, 133 insertions(+), 0 deletions(-)
diff --git a/gfs2/fsck/lost_n_found.c b/gfs2/fsck/lost_n_found.c
index 9c49ee3..d77e951 100644
--- a/gfs2/fsck/lost_n_found.c
+++ b/gfs2/fsck/lost_n_found.c
@@ -29,6 +29,7 @@
int add_inode_to_lf(struct gfs2_inode *ip){
char tmp_name[256];
__be32 inode_type;
+ uint64_t lf_blocks;
struct dir_info *di;
if(!lf_dip) {
@@ -83,6 +84,8 @@ int add_inode_to_lf(struct gfs2_inode *ip){
log_err( _("Trying to add lost+found to itself...skipping"));
return 0;
}
+ lf_blocks = lf_dip->i_di.di_blocks;
+
switch(ip->i_di.di_mode & S_IFMT){
case S_IFDIR:
log_info( _("Adding .. entry pointing to lost+found for "
@@ -165,6 +168,11 @@ int add_inode_to_lf(struct gfs2_inode *ip){
dir_add(lf_dip, tmp_name, strlen(tmp_name), &(ip->i_di.di_num),
inode_type);
+ /* If the lf directory had new blocks added we have to mark them
+ properly in the bitmap so they're not freed. */
+ if (lf_dip->i_di.di_blocks != lf_blocks)
+ reprocess_inode(lf_dip, "lost+found");
+
/* This inode is linked from lost+found */
increment_link(ip->i_di.di_num.no_addr, lf_dip->i_di.di_num.no_addr,
_("from lost+found"));
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 3e7a63c..b5339d2 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -1432,3 +1432,101 @@ int delete_eattr_leaf(struct gfs2_inode *ip, uint64_t block, uint64_t parent,
return delete_blocks(ip, block, NULL, _("extended attribute"),
private);
}
+
+static int alloc_metalist(struct gfs2_inode *ip, uint64_t block,
+ struct gfs2_buffer_head **bh, void *private)
+{
+ uint8_t q;
+ const char *desc = (const char *)private;
+
+ /* No need to range_check here--if it was added, it's in range. */
+ /* We can't check the bitmap here because this function is called
+ after the bitmap has been set but before the blockmap has. */
+ *bh = bread(ip->i_sbd, block);
+ q = block_type(block);
+ if (blockmap_to_bitmap(q) == GFS2_BLKST_FREE) { /* If not marked yet */
+ 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);
+ }
+ return 0;
+}
+
+static int alloc_data(struct gfs2_inode *ip, uint64_t block, void *private)
+{
+ uint8_t q;
+ const char *desc = (const char *)private;
+
+ /* No need to range_check here--if it was added, it's in range. */
+ /* 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) == GFS2_BLKST_FREE) { /* If not marked yet */
+ 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);
+ }
+ return 0;
+}
+
+static int alloc_leaf(struct gfs2_inode *ip, uint64_t block,
+ struct gfs2_buffer_head *bh, void *private)
+{
+ uint8_t q;
+
+ /* No need to range_check here--if it was added, it's in range. */
+ /* 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) == GFS2_BLKST_FREE) /* If not marked yet */
+ fsck_blockmap_set(ip, block, _("newly allocated leaf"),
+ gfs2_leaf_blk);
+ return 0;
+}
+
+struct metawalk_fxns alloc_fxns = {
+ .private = NULL,
+ .check_leaf = alloc_leaf,
+ .check_metalist = alloc_metalist,
+ .check_data = alloc_data,
+ .check_eattr_indir = NULL,
+ .check_eattr_leaf = NULL,
+ .check_dentry = NULL,
+ .check_eattr_entry = NULL,
+ .check_eattr_extentry = NULL,
+ .finish_eattr_indir = NULL,
+};
+
+/*
+ * reprocess_inode - fixes the blockmap to match the bitmap due to an
+ * unexpected block allocation via libgfs2.
+ *
+ * The problem we're trying to overcome here is when a new block must be
+ * added to a dinode because of a write. This will happen when lost+found
+ * needs a new indirect block for its hash table. In that case, the write
+ * causes a new block to be assigned in the bitmap but that block is not yet
+ * accurately reflected in the fsck blockmap. We need to compensate here.
+ *
+ * We can't really use fsck_blockmap_set here because the new block
+ * was already allocated by libgfs2 and therefore it took care of
+ * the rgrp free space variable. fsck_blockmap_set adjusts the free space
+ * in the rgrp according to the change, which has already been done.
+ * So it's only our blockmap that now disagrees with the rgrp bitmap, so we
+ * need to fix only that.
+ */
+void reprocess_inode(struct gfs2_inode *ip, const char *desc)
+{
+ int error;
+
+ alloc_fxns.private = (void *)desc;
+ log_info( _("%s had blocks added; reprocessing its metadata tree "
+ "at height=%d.\n"), desc, ip->i_di.di_height);
+ error = check_metatree(ip, &alloc_fxns);
+ if (error)
+ log_err( _("Error %d reprocessing the %s metadata tree.\n"),
+ error, desc);
+}
diff --git a/gfs2/fsck/metawalk.h b/gfs2/fsck/metawalk.h
index 72c282a..653b512 100644
--- a/gfs2/fsck/metawalk.h
+++ b/gfs2/fsck/metawalk.h
@@ -32,6 +32,7 @@ extern int _fsck_blockmap_set(struct gfs2_inode *ip, uint64_t bblock,
const char *caller, int line);
extern int check_n_fix_bitmap(struct gfs2_sbd *sdp, uint64_t blk,
enum gfs2_mark_block new_blockmap_state);
+extern void reprocess_inode(struct gfs2_inode *ip, const char *desc);
extern struct duptree *dupfind(uint64_t block);
#define is_duplicate(dblock) ((dupfind(dblock)) ? 1 : 0)
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index d82e6cc..4d73c1c 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -551,6 +551,8 @@ static int check_system_dir(struct gfs2_inode *sysinode, const char *dirname,
if(!ds.dotdir) {
log_err( _("No '.' entry found for %s directory.\n"), dirname);
if (query( _("Is it okay to add '.' entry? (y/n) "))) {
+ uint64_t cur_blks = sysinode->i_di.di_blocks;
+
sprintf(tmp_name, ".");
filename_len = strlen(tmp_name); /* no trailing NULL */
if(!(filename = malloc(sizeof(char) * filename_len))) {
@@ -568,6 +570,8 @@ static int check_system_dir(struct gfs2_inode *sysinode, const char *dirname,
log_warn( _("Adding '.' entry\n"));
dir_add(sysinode, filename, filename_len,
&(sysinode->i_di.di_num), DT_DIR);
+ if (cur_blks != sysinode->i_di.di_blocks)
+ reprocess_inode(sysinode, dirname);
/* This system inode is linked to itself via '.' */
increment_link(sysinode->i_di.di_num.no_addr,
sysinode->i_di.di_num.no_addr,
@@ -733,6 +737,8 @@ int pass2(struct gfs2_sbd *sbp)
dirblk, dirblk);
if (query( _("Is it okay to add '.' entry? (y/n) "))) {
+ uint64_t cur_blks;
+
sprintf(tmp_name, ".");
filename_len = strlen(tmp_name); /* no trailing
NULL */
@@ -750,8 +756,18 @@ int pass2(struct gfs2_sbd *sbp)
}
memcpy(filename, tmp_name, filename_len);
+ cur_blks = ip->i_di.di_blocks;
dir_add(ip, filename, filename_len,
&(ip->i_di.di_num), DT_DIR);
+ if (cur_blks != ip->i_di.di_blocks) {
+ char dirname[80];
+
+ sprintf(dirname, _("Directory at %lld "
+ "(0x%llx)"),
+ (unsigned long long)dirblk,
+ (unsigned long long)dirblk);
+ reprocess_inode(ip, dirname);
+ }
/* directory links to itself via '.' */
increment_link(ip->i_di.di_num.no_addr,
ip->i_di.di_num.no_addr,
diff --git a/gfs2/fsck/pass3.c b/gfs2/fsck/pass3.c
index 3f58877..8608678 100644
--- a/gfs2/fsck/pass3.c
+++ b/gfs2/fsck/pass3.c
@@ -22,6 +22,7 @@ static int attach_dotdot_to(struct gfs2_sbd *sbp, uint64_t newdotdot,
char *filename;
int filename_len;
struct gfs2_inode *ip, *pip;
+ uint64_t cur_blks;
ip = fsck_load_inode(sbp, block);
pip = fsck_load_inode(sbp, newdotdot);
@@ -52,7 +53,16 @@ static int attach_dotdot_to(struct gfs2_sbd *sbp, uint64_t newdotdot,
log_warn( _("Unable to remove \"..\" directory entry.\n"));
else
decrement_link(olddotdot, block, _("old \"..\""));
+ cur_blks = ip->i_di.di_blocks;
dir_add(ip, filename, filename_len, &pip->i_di.di_num, DT_DIR);
+ if (cur_blks != ip->i_di.di_blocks) {
+ char dirname[80];
+
+ sprintf(dirname, _("Directory at %lld (0x%llx)"),
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr);
+ reprocess_inode(ip, dirname);
+ }
increment_link(newdotdot, block, _("new \"..\""));
bmodified(ip->i_bh);
fsck_inode_put(&ip);
14 years, 4 months
gfs2-utils: master - lost+found link count and connections were not properly managed
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/gfs2-utils.git?p=gfs2-utils.git;a=commitd...
Commit: 5fd378c85cb2d7c88198d6f43c827c3792477719
Parent: 5fb70beaded92567a8dada5a0224474965336193
Author: Bob Peterson <bob(a)ganesha.peterson>
AuthorDate: Fri Jan 22 15:07:19 2010 -0600
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Tue Jan 26 15:09:49 2010 -0600
lost+found link count and connections were not properly managed
When the lost+found directory was created, function createi in
libgfs2 incremented the di_nlink link count for the root directory,
but fsck.gfs2 did not increment the nlink value in the hash
table. As a result, pass4 doesn't find and fix the discrepancy.
Subsequent runs of fsck.gfs2 detect the problem, though.
This patch adjusts for the new link and keeps everything sane.
In a similar fashion, if the dinode being moved to lost+found
happens to be a directory, the links were not properly adjusted
for that directory's ".." dentry. This patch also takes care of
that so the links don't get off.
rhbz#455300
---
gfs2/fsck/lost_n_found.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 44 insertions(+), 0 deletions(-)
diff --git a/gfs2/fsck/lost_n_found.c b/gfs2/fsck/lost_n_found.c
index ef801f1..9c49ee3 100644
--- a/gfs2/fsck/lost_n_found.c
+++ b/gfs2/fsck/lost_n_found.c
@@ -29,6 +29,7 @@
int add_inode_to_lf(struct gfs2_inode *ip){
char tmp_name[256];
__be32 inode_type;
+ struct dir_info *di;
if(!lf_dip) {
uint8_t q;
@@ -37,6 +38,13 @@ int add_inode_to_lf(struct gfs2_inode *ip){
lf_dip = createi(ip->i_sbd->md.rooti, "lost+found",
S_IFDIR | 0700, 0);
+ /* createi will have incremented the di_nlink link count for
+ the root directory. We must increment the nlink value
+ in the hash table to keep them in sync so that pass4 can
+ detect and fix any discrepancies. */
+ set_link_count(ip->i_sbd->sd_sb.sb_root_dir.no_addr,
+ ip->i_sbd->md.rooti->i_di.di_nlink);
+
q = block_type(lf_dip->i_di.di_num.no_addr);
if(q != gfs2_inode_dir) {
/* This is a new lost+found directory, so set its
@@ -61,6 +69,15 @@ int add_inode_to_lf(struct gfs2_inode *ip){
ip->i_sbd->md.rooti->i_di.di_num.no_addr,
"\"..\"");
}
+ log_info( _("lost+found directory is dinode %lld (0x%llx)\n"),
+ (unsigned long long)lf_dip->i_di.di_num.no_addr,
+ (unsigned long long)lf_dip->i_di.di_num.no_addr);
+ di = dirtree_find(lf_dip->i_di.di_num.no_addr);
+ if (di) {
+ log_info( _("Marking lost+found inode connected\n"));
+ di->checked = 1;
+ di = NULL;
+ }
}
if(ip->i_di.di_num.no_addr == lf_dip->i_di.di_num.no_addr) {
log_err( _("Trying to add lost+found to itself...skipping"));
@@ -73,6 +90,33 @@ int add_inode_to_lf(struct gfs2_inode *ip){
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
+ /* If there's a pre-existing .. directory entry, we have to
+ back out the links. */
+ di = dirtree_find(ip->i_di.di_num.no_addr);
+ if (di && gfs2_check_range(ip->i_sbd, di->dotdot_parent) == 0){
+ struct gfs2_inode *dip;
+
+ log_debug(_("Directory %lld (0x%llx) already had a "
+ "\"..\" link to %lld (0x%llx).\n"),
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)di->dotdot_parent,
+ (unsigned long long)di->dotdot_parent);
+ decrement_link(di->dotdot_parent,
+ ip->i_di.di_num.no_addr,
+ _(".. unlinked, moving to lost+found"));
+ dip = fsck_load_inode(ip->i_sbd, di->dotdot_parent);
+ dip->i_di.di_nlink--;
+ log_debug(_("Decrementing its links to %d\n"),
+ dip->i_di.di_nlink);
+ bmodified(dip->i_bh);
+ fsck_inode_put(&dip);
+ di = NULL;
+ } else
+ log_debug(_("Couldn't find a valid \"..\" entry "
+ "for orphan directory %lld (0x%llx)\n"),
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr);
if(gfs2_dirent_del(ip, "..", 2))
log_warn( _("add_inode_to_lf: Unable to remove "
"\"..\" directory entry.\n"));
14 years, 4 months
gfs2-utils: master - fsck.gfs2: separate check_data function in check_metatree
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/gfs2-utils.git?p=gfs2-utils.git;a=commitd...
Commit: 5fb70beaded92567a8dada5a0224474965336193
Parent: ab799ce87953da7e4791b2d860d8658bf7a4e3a9
Author: Bob Peterson <bob(a)ganesha.peterson>
AuthorDate: Fri Jan 22 14:38:05 2010 -0600
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Tue Jan 26 15:09:48 2010 -0600
fsck.gfs2: separate check_data function in check_metatree
Function check_metatree had a loop for checking data blocks. I broke
this loop into its own function. That serves two purposes: First, it
makes check_metatree smaller and easier to read (it's already big an
unruly). Second, it avoids looping unnecessarily when the caller
has no check_data() function of its own. Net result is faster code.
rhbz#455300
---
gfs2/fsck/metawalk.c | 72 ++++++++++++++++++++++++++++++++++++++------------
1 files changed, 55 insertions(+), 17 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 3d2b8fb..3e7a63c 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -1159,6 +1159,49 @@ fail:
}
/**
+ * check_data - check all data pointers for a given buffer
+ * This does not include "data" blocks that are really
+ * hash table blocks for directories.
+ *
+ * @ip:
+ *
+ * returns: +ENOENT if there are too many bad pointers
+ * -1 if a more serious error occurred.
+ * 0 if no errors occurred
+ * 1 if errors were found and corrected
+ * 2 (ENOENT) is there were too many bad pointers
+ */
+static int check_data(struct gfs2_inode *ip, struct metawalk_fxns *pass,
+ uint64_t *ptr_start, char *ptr_end,
+ uint64_t *blks_checked)
+{
+ int error = 0, rc = 0;
+ uint64_t block, *ptr;
+
+ /* If there isn't much pointer corruption check the pointers */
+ for (ptr = ptr_start ; (char *)ptr < ptr_end && !fsck_abort; ptr++) {
+ if (!*ptr)
+ continue;
+
+ if (skip_this_pass || fsck_abort)
+ return error;
+ block = be64_to_cpu(*ptr);
+ /* It's important that we don't call gfs2_check_range and
+ bypass calling check_data on invalid blocks because that
+ would defeat the rangecheck_block related functions in
+ pass1. Therefore the individual check_data functions
+ should do a range check. */
+ rc = pass->check_data(ip, block, pass->private);
+ if (rc < 0)
+ return rc;
+ if (!error && rc)
+ error = rc;
+ (*blks_checked)++;
+ }
+ return error;
+}
+
+/**
* check_metatree
* @ip:
* @rgd:
@@ -1169,11 +1212,10 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
osi_list_t metalist[GFS2_MAX_META_HEIGHT];
osi_list_t *list;
struct gfs2_buffer_head *bh;
- uint64_t block, *ptr;
uint32_t height = ip->i_di.di_height;
int i, head_size;
uint64_t blks_checked = 0;
- int error;
+ int error, rc;
if (!height && !S_ISDIR(ip->i_di.di_mode))
return 0;
@@ -1229,23 +1271,19 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
}
head_size = sizeof(struct gfs2_dinode);
}
- ptr = (uint64_t *)(bh->b_data + head_size);
- for ( ; (char *)ptr < (bh->b_data + ip->i_sbd->bsize); ptr++) {
- if (!*ptr)
- continue;
-
- block = be64_to_cpu(*ptr);
+ if (pass->check_data)
+ rc = check_data(ip, pass, (uint64_t *)
+ (bh->b_data + head_size),
+ (bh->b_data + ip->i_sbd->bsize),
+ &blks_checked);
+ else
+ rc = 0;
- if(pass->check_data &&
- (pass->check_data(ip, block, pass->private) < 0)) {
- stack;
- return -1;
- }
- blks_checked++;
- if (ip->i_di.di_blocks > COMFORTABLE_BLKS)
- big_file_comfort(ip, blks_checked);
- }
+ if (rc && (!error || rc < 0))
+ error = rc;
+ if (ip->i_di.di_blocks > COMFORTABLE_BLKS)
+ big_file_comfort(ip, blks_checked);
if (bh == ip->i_bh)
osi_list_del(&bh->b_altlist);
else
14 years, 4 months
gfs2-utils: master - fsck.gfs2: metawalk was not checking many directories
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/gfs2-utils.git?p=gfs2-utils.git;a=commitd...
Commit: ab799ce87953da7e4791b2d860d8658bf7a4e3a9
Parent: d9ab45e177bb834b977fa37cf891e3e2777ffa86
Author: Bob Peterson <bob(a)ganesha.peterson>
AuthorDate: Fri Jan 22 14:24:31 2010 -0600
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Tue Jan 26 15:09:48 2010 -0600
fsck.gfs2: metawalk was not checking many directories
The fsck.gfs2 program was not checking the directory hash tables
of many subdirectories. It was checking the leaf blocks, but
it wasn't checking the hash table block pointers if the height
value was equal to 0, which means every directory with a small
number of leaf blocks. That means before, you could have all
kinds of directory corruption and never know it.
rhbz#455300
---
gfs2/fsck/metawalk.c | 70 +++++++++++++++++++++++++++----------------------
1 files changed, 39 insertions(+), 31 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 20abde5..3d2b8fb 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -1072,12 +1072,24 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
uint32_t height = ip->i_di.di_height;
struct gfs2_buffer_head *bh, *nbh, *metabh = ip->i_bh;
osi_list_t *prev_list, *cur_list, *tmp;
- int i, head_size;
+ int i, head_size, iblk_type;
uint64_t *ptr, block;
- int err;
+ int error = 0, err;
osi_list_add(&metabh->b_altlist, &mlp[0]);
+ /* Directories are special. Their 'data' is the hash table, which is
+ basically an indirect block list. Their height is not important
+ because it checks everything through the hash table using
+ "depth" field calculations. However, we still have to check the
+ indirect blocks, even if the height == 1. */
+ if (S_ISDIR(ip->i_di.di_mode)) {
+ height++;
+ iblk_type = GFS2_METATYPE_JD;
+ } else {
+ iblk_type = GFS2_METATYPE_IN;
+ }
+
/* if(<there are no indirect blocks to check>) */
if (height < 2)
return 0;
@@ -1091,7 +1103,7 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
if (i > 1) {
/* if this isn't really a block list skip it */
- if (gfs2_check_meta(bh, GFS2_METATYPE_IN))
+ if (gfs2_check_meta(bh, iblk_type))
continue;
head_size = sizeof(struct gfs2_meta_header);
} else {
@@ -1116,9 +1128,12 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
it gets with "bread". */
if(err < 0) {
stack;
+ error = err;
goto fail;
}
if(err > 0) {
+ if (!error)
+ error = err;
log_debug( _("Skipping block %" PRIu64
" (0x%" PRIx64 ")\n"),
block, block);
@@ -1137,10 +1152,10 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
} /* for all data on the indirect block */
} /* for blocks at that height */
} /* for height */
- return 0;
+ return error;
fail:
free_metalist(ip, mlp);
- return -1;
+ return error;
}
/**
@@ -1158,26 +1173,32 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
uint32_t height = ip->i_di.di_height;
int i, head_size;
uint64_t blks_checked = 0;
- int error = 0;
+ int error;
- if (!height)
- goto end;
+ if (!height && !S_ISDIR(ip->i_di.di_mode))
+ return 0;
for (i = 0; i < GFS2_MAX_META_HEIGHT; i++)
osi_list_init(&metalist[i]);
- /* create metalist for each level */
- if (build_and_check_metalist(ip, &metalist[0], pass)){
+ /* create and check the metadata list for each height */
+ error = build_and_check_metalist(ip, &metalist[0], pass);
+ if (error) {
stack;
- return -1;
+ return error;
}
- /* We don't need to record directory blocks - they will be
- * recorded later...i think... */
- if (S_ISDIR(ip->i_di.di_mode))
- log_debug( _("Directory with height > 0 at %llu (0x%llx)\n"),
- (unsigned long long)ip->i_di.di_num.no_addr,
- (unsigned long long)ip->i_di.di_num.no_addr);
+ /* For directories, we've already checked the "data" blocks which
+ * comprise the directory hash table, so we perform the directory
+ * checks and exit. */
+ if (S_ISDIR(ip->i_di.di_mode)) {
+ free_metalist(ip, &metalist[0]);
+ if (!(ip->i_di.di_flags & GFS2_DIF_EXHASH))
+ return 0;
+ /* check validity of leaf blocks and leaf chains */
+ error = check_leaf_blks(ip, pass);
+ return error;
+ }
/* check data blocks */
list = &metalist[height - 1];
@@ -1238,20 +1259,7 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
(unsigned long long)ip->i_di.di_num.no_addr);
fflush(stdout);
}
-
-end:
- if (S_ISDIR(ip->i_di.di_mode)) {
- /* check validity of leaf blocks and leaf chains */
- if (ip->i_di.di_flags & GFS2_DIF_EXHASH) {
- error = check_leaf_blks(ip, pass);
- if(error < 0)
- return -1;
- if(error > 0)
- return 1;
- }
- }
-
- return 0;
+ return error;
}
/* Checks stuffed inode directories */
14 years, 4 months
gfs2-utils: master - fsck.gfs2: metawalk needs to check for no valid leaf blocks
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/gfs2-utils.git?p=gfs2-utils.git;a=commitd...
Commit: d9ab45e177bb834b977fa37cf891e3e2777ffa86
Parent: e95e10a3f72e345d99eecc014b31b538165bbd6b
Author: Bob Peterson <bob(a)ganesha.peterson>
AuthorDate: Fri Jan 22 13:55:51 2010 -0600
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Tue Jan 26 15:09:48 2010 -0600
fsck.gfs2: metawalk needs to check for no valid leaf blocks
The code that validates directory leaf blocks was failing in rare
cases where the directory had no valid leaf blocks at all.
It would give a good return code and pretend everything was okay
when, in fact, it left corruption out there.
rhbz#455300
---
gfs2/fsck/metawalk.c | 20 +++++++++++++-------
1 files changed, 13 insertions(+), 7 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index b7ab47a..20abde5 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -534,7 +534,7 @@ static int check_leaf_blks(struct gfs2_inode *ip, struct metawalk_fxns *pass)
int error;
struct gfs2_leaf leaf, oldleaf;
uint64_t leaf_no, old_leaf, bad_leaf = -1;
- uint64_t first_leaf_ptr = -1, first_ok_leaf = -1;
+ uint64_t first_ok_leaf;
struct gfs2_buffer_head *lbh;
int lindex;
struct gfs2_sbd *sbp = ip->i_sbd;
@@ -544,21 +544,27 @@ static int check_leaf_blks(struct gfs2_inode *ip, struct metawalk_fxns *pass)
/* Find the first valid leaf pointer in range and use it as our "old"
leaf. That way, bad blocks at the beginning will be overwritten
with the first valid leaf. */
- first_ok_leaf = -1;
+ first_ok_leaf = leaf_no = -1;
for(lindex = 0; lindex < (1 << ip->i_di.di_depth); lindex++) {
- gfs2_get_leaf_nr(ip, lindex, &first_ok_leaf);
- if (first_leaf_ptr == -1)
- first_leaf_ptr = first_ok_leaf;
- if(gfs2_check_range(ip->i_sbd, first_ok_leaf) == 0) {
- lbh = bread(sbp, first_ok_leaf);
+ gfs2_get_leaf_nr(ip, lindex, &leaf_no);
+ if (gfs2_check_range(ip->i_sbd, leaf_no) == 0) {
+ lbh = bread(sbp, leaf_no);
/* Make sure it's really a valid leaf block. */
if (gfs2_check_meta(lbh, GFS2_METATYPE_LF) == 0) {
brelse(lbh);
+ first_ok_leaf = leaf_no;
break;
}
brelse(lbh);
}
}
+ if (first_ok_leaf == -1) { /* no valid leaf found */
+ log_err( _("Directory #%llu (0x%llx) has no valid leaf "
+ "blocks\n"),
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ (unsigned long long)ip->i_di.di_num.no_addr);
+ return 1;
+ }
old_leaf = -1;
memset(&oldleaf, 0, sizeof(oldleaf));
for(lindex = 0; lindex < (1 << ip->i_di.di_depth); lindex++) {
14 years, 4 months
gfs2-utils: master - fsck.gfs2: enforce consistency between bitmap and blockmap
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/gfs2-utils.git?p=gfs2-utils.git;a=commitd...
Commit: e95e10a3f72e345d99eecc014b31b538165bbd6b
Parent: 04e6b40284539557d6db87ffd6d38db477fe7525
Author: Bob Peterson <bob(a)ganesha.peterson>
AuthorDate: Fri Jan 22 13:41:44 2010 -0600
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Tue Jan 26 15:09:48 2010 -0600
fsck.gfs2: enforce consistency between bitmap and blockmap
One of the big problems with fsck.gfs2 was that there was nothing
to enforce that the incore bitmap from the rgrps corresponded
one-to-one with the incore blockmaps. This patch enforces that
by making a central function that sets values into the blockmap
and makes sure the bitmap has the correct corresponding bits.
It also tracks all block references with debug messages so block
map problems may be easily tracked down by running fsck.gfs2 with
-vv. I needed to add some support functions and modified how
the metadata buffers are managed.
rhbz#455300
---
gfs2/fsck/eattr.c | 11 ++-
gfs2/fsck/lost_n_found.c | 4 +-
gfs2/fsck/main.c | 14 ++-
gfs2/fsck/metawalk.c | 216 ++++++++++++++++++++++++++++++++++++++--------
gfs2/fsck/metawalk.h | 8 ++
gfs2/fsck/pass1.c | 196 ++++++++++++++----------------------------
gfs2/fsck/pass1b.c | 23 +++--
gfs2/fsck/pass2.c | 11 ++-
gfs2/fsck/pass3.c | 40 +++++++--
gfs2/fsck/pass4.c | 14 ++--
gfs2/libgfs2/libgfs2.h | 28 ++++++
11 files changed, 360 insertions(+), 205 deletions(-)
diff --git a/gfs2/fsck/eattr.c b/gfs2/fsck/eattr.c
index 26c11f1..e477924 100644
--- a/gfs2/fsck/eattr.c
+++ b/gfs2/fsck/eattr.c
@@ -10,14 +10,15 @@
#include "eattr.h"
#include "metawalk.h"
-static int clear_blk_nodup(struct gfs2_sbd *sbp, uint64_t block)
+static int clear_blk_nodup(struct gfs2_inode *ip, uint64_t block)
{
if(is_duplicate(block)) {
log_debug( _("Not clearing block with marked as a duplicate\n"));
return 1;
}
- gfs2_blockmap_set(bl, block, gfs2_block_free);
+ fsck_blockmap_set(ip, block, _("cleared eattr block"),
+ gfs2_block_free);
return 0;
@@ -27,14 +28,14 @@ int clear_eattr_indir(struct gfs2_inode *ip, uint64_t block,
uint64_t parent, struct gfs2_buffer_head **bh,
void *private)
{
- return clear_blk_nodup(ip->i_sbd, block);
+ return clear_blk_nodup(ip, block);
}
int clear_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
uint64_t parent, struct gfs2_buffer_head **bh,
void *private)
{
- return clear_blk_nodup(ip->i_sbd, block);
+ return clear_blk_nodup(ip, block);
}
int clear_eattr_entry (struct gfs2_inode *ip,
@@ -83,7 +84,7 @@ int clear_eattr_extentry(struct gfs2_inode *ip, uint64_t *ea_data_ptr,
{
uint64_t block = be64_to_cpu(*ea_data_ptr);
- return clear_blk_nodup(ip->i_sbd, block);
+ return clear_blk_nodup(ip, block);
}
diff --git a/gfs2/fsck/lost_n_found.c b/gfs2/fsck/lost_n_found.c
index f9cb556..ef801f1 100644
--- a/gfs2/fsck/lost_n_found.c
+++ b/gfs2/fsck/lost_n_found.c
@@ -14,6 +14,7 @@
#include "libgfs2.h"
#include "lost_n_found.h"
#include "link.h"
+#include "metawalk.h"
#include "util.h"
/* add_inode_to_lf - Add dir entry to lost+found for the inode
@@ -46,7 +47,8 @@ int add_inode_to_lf(struct gfs2_inode *ip){
* directory or just found an old one, and we
* used that instead of the block_type to run
* this */
- gfs2_blockmap_set(bl, lf_dip->i_di.di_num.no_addr,
+ fsck_blockmap_set(ip, lf_dip->i_di.di_num.no_addr,
+ _("lost+found dinode"),
gfs2_inode_dir);
/* root inode links to lost+found */
increment_link(ip->i_sbd->md.rooti->i_di.di_num.no_addr,
diff --git a/gfs2/fsck/main.c b/gfs2/fsck/main.c
index ca81af5..700e80e 100644
--- a/gfs2/fsck/main.c
+++ b/gfs2/fsck/main.c
@@ -17,6 +17,7 @@
#include "libgfs2.h"
#include "fsck.h"
#include "osi_list.h"
+#include "metawalk.h"
#include "util.h"
struct gfs2_options opts = {0};
@@ -170,9 +171,11 @@ static int check_system_inode(struct gfs2_inode *sysinode, const char *filename,
/* bitmap. In that case, don't rebuild the inode. */
/* Just reuse the inode and fix the bitmap. */
if (ds.q == gfs2_block_free) {
- log_info( _("The inode exists but the block is not marked 'in use'; fixing it.\n"));
- gfs2_blockmap_set(bl,sysinode->i_di.di_num.no_addr,
- mark);
+ 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)
dirtree_insert(sysinode->i_di.di_num.no_addr);
@@ -188,8 +191,9 @@ static int check_system_inode(struct gfs2_inode *sysinode, const char *filename,
log_err( _("Invalid or missing %s system inode.\n"), filename);
if (query(_("Create new %s system inode? (y/n) "), filename)) {
builder(sysinode->i_sbd);
- gfs2_blockmap_set(bl, sysinode->i_di.di_num.no_addr,
- mark);
+ fsck_blockmap_set(sysinode,
+ sysinode->i_di.di_num.no_addr,
+ filename, mark);
ds.q = mark;
if (mark == gfs2_inode_dir)
dirtree_insert(sysinode->i_di.di_num.no_addr);
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 0680e9e..b7ab47a 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -8,16 +8,155 @@
#include <sys/stat.h>
#include <unistd.h>
#include <libintl.h>
+#include <ctype.h>
#define _(String) gettext(String)
#include "libgfs2.h"
+#include "osi_tree.h"
#include "fsck.h"
#include "util.h"
#include "metawalk.h"
#include "hash.h"
+#include "inode_hash.h"
#define COMFORTABLE_BLKS 5242880 /* 20GB in 4K blocks */
+/* There are two bitmaps: (1) The "blockmap" that fsck uses to keep track of
+ what block type has been discovered, and (2) The rgrp bitmap. Function
+ gfs2_blockmap_set is used to set the former and gfs2_set_bitmap
+ is used to set the latter. The two must be kept in sync, otherwise
+ 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,
+ enum gfs2_mark_block new_blockmap_state)
+{
+ int old_bitmap_state, new_bitmap_state;
+ struct rgrp_list *rgd;
+
+ rgd = gfs2_blk2rgrpd(sdp, blk);
+
+ old_bitmap_state = gfs2_get_bitmap(sdp, blk, rgd);
+ if (old_bitmap_state < 0) {
+ log_err( _("Block %lld (0x%llx) is not represented in the"
+ "system bitmap; part of an rgrp or superblock.\n"),
+ (unsigned long long)blk, (unsigned long long)blk);
+ return -1;
+ }
+ new_bitmap_state = blockmap_to_bitmap(new_blockmap_state);
+ if (old_bitmap_state != new_bitmap_state) {
+ const char *allocdesc[] = {"free space", "data", "unlinked",
+ "inode", "reserved"};
+
+ log_err( _("Block %llu (0x%llx) seems to be %s, but is "
+ "marked as %s in the bitmap.\n"),
+ (unsigned long long)blk, (unsigned long long)blk,
+ allocdesc[new_bitmap_state],
+ allocdesc[old_bitmap_state]);
+ if(query( _("Okay to 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
+ space in the rgrp. If the old bitmap state was
+ free (and therefore it no longer is) we have to
+ 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(sdp, blk, new_bitmap_state);
+ if (new_bitmap_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) {
+ struct dir_info *dt;
+ struct inode_info *ii;
+
+ dt = dirtree_find(blk);
+ if (dt)
+ dirtree_delete(dt);
+ ii = inodetree_find(blk);
+ if (ii)
+ inodetree_delete(ii);
+ }
+ rgd->rg.rg_free++;
+ gfs2_rgrp_out(&rgd->rg, rgd->bh[0]);
+ } else if (old_bitmap_state == GFS2_BLKST_FREE) {
+ rgd->rg.rg_free--;
+ gfs2_rgrp_out(&rgd->rg, rgd->bh[0]);
+ }
+ log_err( _("The bitmap was fixed.\n"));
+ } else {
+ log_err( _("The bitmap inconsistency was ignored.\n"));
+ }
+ }
+ return 0;
+}
+
+/*
+ * _fsck_blockmap_set - Mark a block in the 4-bit blockmap and the 2-bit
+ * 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,
+ const char *caller, int fline)
+{
+ int error;
+
+ if (print_level >= MSG_DEBUG) {
+ const char *p;
+
+ p = strrchr(caller, '/');
+ if (p)
+ p++;
+ else
+ p = caller;
+ /* I'm circumventing the log levels here on purpose to make the
+ output easier to debug. */
+ if (ip->i_di.di_num.no_addr == bblock) {
+ print_fsck_log(MSG_DEBUG, p, fline,
+ _("%s inode found at block %lld "
+ "(0x%llx): marking as '%s'\n"),
+ btype, (unsigned long long)
+ ip->i_di.di_num.no_addr,
+ (unsigned long long)
+ ip->i_di.di_num.no_addr,
+ block_type_string(mark));
+ } else if (mark == gfs2_bad_block || mark == gfs2_meta_inval) {
+ print_fsck_log(MSG_DEBUG, p, fline,
+ _("inode %lld (0x%llx) references "
+ "%s block %lld (0x%llx): "
+ "marking as '%s'\n"),
+ (unsigned long long)
+ ip->i_di.di_num.no_addr,
+ (unsigned long long)
+ ip->i_di.di_num.no_addr,
+ btype, (unsigned long long)bblock,
+ (unsigned long long)bblock,
+ block_type_string(mark));
+ } else {
+ print_fsck_log(MSG_DEBUG, p, fline,
+ _("inode %lld (0x%llx) references "
+ "%s block %lld (0x%llx): "
+ "marking as '%s'\n"),
+ (unsigned long long)
+ ip->i_di.di_num.no_addr,
+ (unsigned long long)
+ ip->i_di.di_num.no_addr, btype,
+ (unsigned long long)bblock,
+ (unsigned long long)bblock,
+ block_type_string(mark));
+ }
+ }
+
+ /* First, check the rgrp bitmap against what we think it should be.
+ If that fails, it's an invalid block--part of an rgrp. */
+ error = check_n_fix_bitmap(ip->i_sbd, bblock, mark);
+ if (error) {
+ log_err( _("This block is not represented in the bitmap.\n"));
+ return error;
+ }
+
+ error = gfs2_blockmap_set(bl, bblock, mark);
+ return error;
+}
+
struct duptree *dupfind(uint64_t block)
{
struct osi_node *node = dup_blocks.osi_node;
@@ -694,9 +833,10 @@ static int check_eattr_entries(struct gfs2_inode *ip,
/* Endianness doesn't matter
in this case because it's
a single byte. */
- gfs2_blockmap_set(bl,
- ip->i_di.di_eattr,
- gfs2_meta_eattr);
+ fsck_blockmap_set(ip,
+ ip->i_di.di_eattr,
+ _("extended attribute"),
+ gfs2_meta_eattr);
log_err( _("The EA was "
"fixed.\n"));
} else {
@@ -845,10 +985,9 @@ static int check_indirect_eattr(struct gfs2_inode *ip, uint64_t indirect,
pass->private);
}
if (leaf_pointer_errors == leaf_pointers) {
- if (indirect_buf->b_modified)
- gfs2_set_bitmap(sdp, indirect,
- GFS2_BLKST_FREE);
- gfs2_blockmap_set(bl, indirect,
+ fsck_blockmap_set(ip, indirect,
+ _("indirect extended "
+ "attribute"),
gfs2_block_free);
error = 1;
}
@@ -891,6 +1030,29 @@ int check_inode_eattr(struct gfs2_inode *ip, struct metawalk_fxns *pass)
}
/**
+ * free_metalist - free all metadata on a multi-level metadata list
+ */
+static void free_metalist(struct gfs2_inode *ip, osi_list_t *mlp)
+{
+ int i;
+ struct gfs2_buffer_head *nbh;
+
+ for (i = 0; i < GFS2_MAX_META_HEIGHT; i++) {
+ osi_list_t *list;
+
+ list = &mlp[i];
+ while (!osi_list_empty(list)) {
+ nbh = osi_list_entry(list->next,
+ struct gfs2_buffer_head, b_altlist);
+ if (nbh == ip->i_bh)
+ osi_list_del(&nbh->b_altlist);
+ else
+ brelse(nbh);
+ }
+ }
+}
+
+/**
* build_and_check_metalist - check a bunch of indirect blocks
* This includes hash table blocks for directories
* which are technically "data" in the bitmap.
@@ -971,16 +1133,7 @@ static int build_and_check_metalist(struct gfs2_inode *ip, osi_list_t *mlp,
} /* for height */
return 0;
fail:
- for (i = 0; i < GFS2_MAX_META_HEIGHT; i++) {
- osi_list_t *list;
- list = &mlp[i];
- while (!osi_list_empty(list)) {
- nbh = osi_list_entry(list->next,
- struct gfs2_buffer_head, b_altlist);
- brelse(nbh);
- osi_list_del(&nbh->b_altlist);
- }
- }
+ free_metalist(ip, mlp);
return -1;
}
@@ -993,7 +1146,7 @@ fail:
int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
{
osi_list_t metalist[GFS2_MAX_META_HEIGHT];
- osi_list_t *list, *tmp;
+ osi_list_t *list;
struct gfs2_buffer_head *bh;
uint64_t block, *ptr;
uint32_t height = ip->i_di.di_height;
@@ -1025,8 +1178,9 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
if (ip->i_di.di_blocks > COMFORTABLE_BLKS)
last_reported_fblock = -10000000;
- for (tmp = list->next; tmp != list; tmp = tmp->next) {
- bh = osi_list_entry(tmp, struct gfs2_buffer_head, b_altlist);
+ while (error >= 0 && !osi_list_empty(list)) {
+ bh = osi_list_entry(list->next, struct gfs2_buffer_head,
+ b_altlist);
if (height > 1) {
if (gfs2_check_meta(bh, GFS2_METATYPE_IN)) {
@@ -1065,6 +1219,10 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
if (ip->i_di.di_blocks > COMFORTABLE_BLKS)
big_file_comfort(ip, blks_checked);
}
+ if (bh == ip->i_bh)
+ osi_list_del(&bh->b_altlist);
+ else
+ brelse(bh);
}
if (ip->i_di.di_blocks > COMFORTABLE_BLKS) {
log_notice( _("\rLarge file at %lld (0x%llx) - 100 percent "
@@ -1075,22 +1233,6 @@ int check_metatree(struct gfs2_inode *ip, struct metawalk_fxns *pass)
fflush(stdout);
}
- /* free metalists */
- for (i = 0; i < GFS2_MAX_META_HEIGHT; i++)
- {
- list = &metalist[i];
- while (!osi_list_empty(list))
- {
- bh = osi_list_entry(list->next,
- struct gfs2_buffer_head, b_altlist);
- if (bh == ip->i_bh)
- osi_list_del(&bh->b_altlist);
- else
- brelse(bh);
- osi_list_del(&bh->b_altlist);
- }
- }
-
end:
if (S_ISDIR(ip->i_di.di_mode)) {
/* check validity of leaf blocks and leaf chains */
@@ -1207,7 +1349,7 @@ int delete_blocks(struct gfs2_inode *ip, uint64_t 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);
- gfs2_blockmap_set(bl, block, gfs2_block_free);
+ fsck_blockmap_set(ip, block, btype, gfs2_block_free);
gfs2_free_block(ip->i_sbd, block);
}
}
diff --git a/gfs2/fsck/metawalk.h b/gfs2/fsck/metawalk.h
index 9710b01..72c282a 100644
--- a/gfs2/fsck/metawalk.h
+++ b/gfs2/fsck/metawalk.h
@@ -27,10 +27,18 @@ extern int delete_eattr_indir(struct gfs2_inode *ip, uint64_t block,
extern int delete_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
uint64_t parent, struct gfs2_buffer_head **bh,
void *private);
+extern int _fsck_blockmap_set(struct gfs2_inode *ip, uint64_t bblock,
+ const char *btype, enum gfs2_mark_block mark,
+ const char *caller, int line);
+extern int check_n_fix_bitmap(struct gfs2_sbd *sdp, uint64_t blk,
+ enum gfs2_mark_block new_blockmap_state);
extern struct duptree *dupfind(uint64_t block);
#define is_duplicate(dblock) ((dupfind(dblock)) ? 1 : 0)
+#define fsck_blockmap_set(ip, b, bt, m) _fsck_blockmap_set(ip, b, bt, m, \
+ __FILE__, __LINE__)
+
/* metawalk_fxns: function pointers to check various parts of the fs
*
* The functions should return -1 on fatal errors, 1 if the block
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index 3061e12..09c6a77 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -76,12 +76,7 @@ static int leaf(struct gfs2_inode *ip, uint64_t block,
{
struct block_count *bc = (struct block_count *) private;
- log_debug( _("\tDinode %lld (0x%llx) references leaf block #%lld "
- "(0x%llx)\n"),
- (unsigned long long)ip->i_di.di_num.no_addr,
- (unsigned long long)ip->i_di.di_num.no_addr,
- (unsigned long long)block, (unsigned long long)block);
- gfs2_blockmap_set(bl, block, gfs2_leaf_blk);
+ fsck_blockmap_set(ip, block, _("directory leaf"), gfs2_leaf_blk);
bc->indir_count++;
return 0;
}
@@ -97,8 +92,8 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
*bh = NULL;
if (gfs2_check_range(ip->i_sbd, block)){ /* blk outside of FS */
- gfs2_blockmap_set(bl, ip->i_di.di_num.no_addr,
- gfs2_bad_block);
+ fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
+ _("itself"), gfs2_bad_block);
log_debug( _("Bad indirect block pointer (out of range).\n"));
return 1;
@@ -116,7 +111,8 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
log_debug( _("Bad indirect block pointer (points to "
"something that is not an indirect block).\n"));
if(!found_dup) {
- gfs2_blockmap_set(bl, block, gfs2_meta_inval);
+ fsck_blockmap_set(ip, block, _("bad indirect"),
+ gfs2_meta_inval);
brelse(nbh);
return 1;
}
@@ -124,11 +120,9 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
} else /* blk check ok */
*bh = nbh;
- if (!found_dup) {
- log_debug( _("Setting %" PRIu64 " (0x%" PRIx64 ") to indirect "
- "block.\n"), block, block);
- gfs2_blockmap_set(bl, block, gfs2_indir_blk);
- }
+ if (!found_dup)
+ fsck_blockmap_set(ip, block, _("indirect"),
+ gfs2_indir_blk);
bc->indir_count++;
return 0;
@@ -138,7 +132,7 @@ static int check_data(struct gfs2_inode *ip, uint64_t block, void *private)
{
uint8_t q;
struct block_count *bc = (struct block_count *) private;
- int error = 0, btype;
+ int error = 0;
if (gfs2_check_range(ip->i_sbd, block)) {
log_err( _("inode %lld (0x%llx) has a bad data block pointer "
@@ -149,8 +143,9 @@ static int check_data(struct gfs2_inode *ip, uint64_t block, void *private)
/* Mark the owner of this block with the bad_block
* designator so we know to check it for out of range
* blocks later */
- gfs2_blockmap_set(bl, ip->i_di.di_num.no_addr,
- gfs2_bad_block);
+ fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
+ _("bad (out of range) data"),
+ gfs2_bad_block);
return 1;
}
q = block_type(block);
@@ -178,41 +173,7 @@ static int check_data(struct gfs2_inode *ip, uint64_t block, void *private)
gfs2_block_unmark(ip->i_sbd, bl, block, gfs2_meta_inval);
gfs2_dup_set(block);
}
- log_debug( _("Marking block %llu (0x%llx) as data block\n"),
- (unsigned long long)block, (unsigned long long)block);
- gfs2_blockmap_set(bl, block, gfs2_block_used);
-
- /* This is also confusing, so I'll clarify. There are two bitmaps:
- (1) The gfs2_bmap that fsck uses to keep track of what block
- type has been discovered, and (2) The rgrp bitmap. Function
- gfs2_blockmap_set is used to set the former and gfs2_set_bitmap
- is used to set the latter. In this function we need to set both
- because we found a "data" block that could be "meta" in the rgrp
- bitmap. If we don't we could run into the data block again as
- metadata when we're traversing the metadata with gfs2_next_rg_meta
- in func pass1(). If that happens, it will look at the block,
- say "hey this isn't metadata" and mark it incorrectly as an
- invalid metadata block and free it. Ordinarily, fsck will wait
- until pass5 to sync (2) so that it agrees with (1). However, in
- this case, it's better to do it upfront. The duplicate solving
- code in pass1b.c is better at resolving metadata referencing a
- data block than it is at resolving a data block referencing a
- metadata block. */
- btype = gfs2_get_bitmap(ip->i_sbd, block, NULL);
- if (btype != GFS2_BLKST_USED) {
- const char *allocdesc[] = {"free space", "data", "unlinked",
- "metadata", "reserved"};
-
- log_err( _("Block %llu (0x%llx) seems to be data, but is "
- "marked as %s.\n"), (unsigned long long)block,
- (unsigned long long)block, allocdesc[btype]);
- if(query( _("Okay to mark it as 'data'? (y/n)"))) {
- gfs2_set_bitmap(ip->i_sbd, block, GFS2_BLKST_USED);
- log_err( _("The block was reassigned as data.\n"));
- } else {
- log_err( _("The invalid block was ignored.\n"));
- }
- }
+ fsck_blockmap_set(ip, block, _("data"), gfs2_block_used);
bc->data_count++;
return error;
}
@@ -220,11 +181,9 @@ static int check_data(struct gfs2_inode *ip, uint64_t block, void *private)
static int remove_inode_eattr(struct gfs2_inode *ip, struct block_count *bc,
int duplicate)
{
- if (!duplicate) {
- gfs2_set_bitmap(ip->i_sbd, ip->i_di.di_eattr,
- GFS2_BLKST_FREE);
- gfs2_blockmap_set(bl, ip->i_di.di_eattr, gfs2_block_free);
- }
+ if (!duplicate)
+ fsck_blockmap_set(ip, ip->i_di.di_eattr, _("deleted eattr"),
+ gfs2_block_free);
ip->i_di.di_eattr = 0;
bc->ea_count = 0;
ip->i_di.di_blocks = 1 + bc->indir_count + bc->data_count;
@@ -264,8 +223,6 @@ static int ask_remove_inode_eattr(struct gfs2_inode *ip,
static int clear_eas(struct gfs2_inode *ip, struct block_count *bc,
uint64_t block, int duplicate, const char *emsg)
{
- struct gfs2_sbd *sdp = ip->i_sbd;
-
log_err( _("Inode #%llu (0x%llx): %s"),
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr, emsg);
@@ -277,8 +234,8 @@ static int clear_eas(struct gfs2_inode *ip, struct block_count *bc,
log_err( _("The bad extended attribute was "
"removed.\n"));
} else if (!duplicate) {
- gfs2_blockmap_set(bl, block, gfs2_block_free);
- gfs2_set_bitmap(sdp, block, GFS2_BLKST_FREE);
+ fsck_blockmap_set(ip, block, _("removed eattr"),
+ gfs2_block_free);
log_err( _("The bad Extended Attribute was "
"removed.\n"));
}
@@ -343,10 +300,9 @@ static int check_eattr_indir(struct gfs2_inode *ip, uint64_t indirect,
bc->ea_count++;
ret = 1;
} else {
- log_debug( _("Setting #%" PRIu64 " (0x%" PRIx64
- ") to indirect Extended Attribute block\n"),
- indirect, indirect);
- gfs2_blockmap_set(bl, indirect, gfs2_indir_blk);
+ fsck_blockmap_set(ip, indirect,
+ _("indirect Extended Attribute"),
+ gfs2_indir_blk);
bc->ea_count++;
}
return ret;
@@ -428,12 +384,10 @@ static int check_leaf_block(struct gfs2_inode *ip, uint64_t block, int btype,
brelse(leaf_bh);
return 1;
}
- log_debug( _("Setting block #%lld (0x%llx) to eattr block\n"),
- (unsigned long long)block, (unsigned long long)block);
/* Point of confusion: We've got to set the ea block itself to
gfs2_meta_eattr here. Elsewhere we mark the inode with
gfs2_eattr_block meaning it contains an eattr for pass1c. */
- gfs2_blockmap_set(bl, block, gfs2_meta_eattr);
+ fsck_blockmap_set(ip, block, _("Extended Attribute"), gfs2_meta_eattr);
bc->ea_count++;
*bh = leaf_bh;
return 0;
@@ -471,7 +425,9 @@ static int check_extended_leaf_eattr(struct gfs2_inode *ip, uint64_t *data_ptr,
(unsigned long long)ip->i_di.di_eattr,
(unsigned long long)el_blk,
(unsigned long long)el_blk);
- gfs2_blockmap_set(bl, ip->i_di.di_eattr, gfs2_bad_block);
+ fsck_blockmap_set(ip, ip->i_di.di_eattr,
+ _("bad (out of range) Extended Attribute "),
+ gfs2_bad_block);
return 1;
}
error = check_leaf_block(ip, el_blk, GFS2_METATYPE_ED, &bh, private);
@@ -502,7 +458,9 @@ static int check_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)block, (unsigned long long)block);
- gfs2_blockmap_set(bl, ip->i_di.di_eattr, gfs2_bad_block);
+ fsck_blockmap_set(ip, ip->i_di.di_eattr,
+ _("bad (out of range) Extended "
+ "Attribute leaf"), gfs2_bad_block);
return 1;
}
return check_leaf_block(ip, block, GFS2_METATYPE_EA, bh, private);
@@ -554,38 +512,26 @@ static int clear_metalist(struct gfs2_inode *ip, uint64_t block,
{
*bh = NULL;
- if(!is_duplicate(block)) {
- gfs2_blockmap_set(bl, block, gfs2_block_free);
- return 0;
- }
+ if(!is_duplicate(block))
+ fsck_blockmap_set(ip, block, _("cleared metadata"),
+ gfs2_block_free);
return 0;
}
static int clear_data(struct gfs2_inode *ip, uint64_t block, void *private)
{
- if(!is_duplicate(block)) {
- gfs2_blockmap_set(bl, block, gfs2_block_free);
- return 0;
- }
+ if(!is_duplicate(block))
+ fsck_blockmap_set(ip, block, _("cleared data"),
+ gfs2_block_free);
return 0;
-
}
static int clear_leaf(struct gfs2_inode *ip, uint64_t block,
struct gfs2_buffer_head *bh, void *private)
{
- log_crit( _("Clearing leaf #%" PRIu64 " (0x%" PRIx64 ")\n"),
- block, block);
-
- if(!is_duplicate(block)) {
- log_crit( _("Setting leaf #%" PRIu64 " (0x%" PRIx64 ") invalid\n"),
- block, block);
- if(gfs2_blockmap_set(bl, block, gfs2_block_free)) {
- stack;
- return -1;
- }
- return 0;
- }
+ if(!is_duplicate(block))
+ fsck_blockmap_set(ip, block, _("cleared directory leaf"),
+ gfs2_block_free);
return 0;
}
@@ -632,9 +578,8 @@ static int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
switch(ip->i_di.di_mode & S_IFMT) {
case S_IFDIR:
- log_debug( _("Setting %" PRIu64 " (0x%" PRIx64 ") to directory inode.\n"),
- block, block);
- if(gfs2_blockmap_set(bl, block, gfs2_inode_dir)) {
+ if (fsck_blockmap_set(ip, block, _("directory"),
+ gfs2_inode_dir)) {
stack;
fsck_inode_put(&ip);
return -1;
@@ -646,68 +591,60 @@ static int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
}
break;
case S_IFREG:
- log_debug( _("Setting %" PRIu64 " (0x%" PRIx64 ") to file inode.\n"),
- block, block);
- if(gfs2_blockmap_set(bl, block, gfs2_inode_file)) {
+ if (fsck_blockmap_set(ip, block, _("file"),
+ gfs2_inode_file)) {
stack;
fsck_inode_put(&ip);
return -1;
}
break;
case S_IFLNK:
- log_debug( _("Setting %" PRIu64 " (0x%" PRIx64 ") to symlink inode.\n"),
- block, block);
- if(gfs2_blockmap_set(bl, block, gfs2_inode_lnk)) {
+ if (fsck_blockmap_set(ip, block, _("symlink"),
+ gfs2_inode_lnk)) {
stack;
fsck_inode_put(&ip);
return -1;
}
break;
case S_IFBLK:
- log_debug( _("Setting %" PRIu64 " (0x%" PRIx64 ") to block dev inode.\n"),
- block, block);
- if(gfs2_blockmap_set(bl, block, gfs2_inode_blk)) {
+ if (fsck_blockmap_set(ip, block, _("block device"),
+ gfs2_inode_blk)) {
stack;
fsck_inode_put(&ip);
return -1;
}
break;
case S_IFCHR:
- log_debug( _("Setting %" PRIu64 " (0x%" PRIx64 ") to char dev inode.\n"),
- block, block);
- if(gfs2_blockmap_set(bl, block, gfs2_inode_chr)) {
+ if (fsck_blockmap_set(ip, block, _("character device"),
+ gfs2_inode_chr)) {
stack;
fsck_inode_put(&ip);
return -1;
}
break;
case S_IFIFO:
- log_debug( _("Setting %" PRIu64 " (0x%" PRIx64 ") to fifo inode.\n"),
- block, block);
- if(gfs2_blockmap_set(bl, block, gfs2_inode_fifo)) {
+ if (fsck_blockmap_set(ip, block, _("fifo"),
+ gfs2_inode_fifo)) {
stack;
fsck_inode_put(&ip);
return -1;
}
break;
case S_IFSOCK:
- log_debug( _("Setting %" PRIu64 " (0x%" PRIx64 ") to socket inode.\n"),
- block, block);
- if(gfs2_blockmap_set(bl, block, gfs2_inode_sock)) {
+ if (fsck_blockmap_set(ip, block, _("socket"),
+ gfs2_inode_sock)) {
stack;
fsck_inode_put(&ip);
return -1;
}
break;
default:
- log_debug( _("Setting %" PRIu64 " (0x%" PRIx64 ") to invalid.\n"),
- block, block);
- if(gfs2_blockmap_set(bl, block, gfs2_meta_inval)) {
+ if (fsck_blockmap_set(ip, block, _("invalid mode"),
+ gfs2_meta_inval)) {
stack;
fsck_inode_put(&ip);
return -1;
}
- gfs2_set_bitmap(sdp, block, GFS2_BLKST_FREE);
fsck_inode_put(&ip);
return 0;
}
@@ -726,14 +663,12 @@ static int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
(unsigned long long)ip->i_di.di_num.no_addr,
ip->i_di.di_depth,
(1 >> (ip->i_di.di_size/sizeof(uint64_t))));
- /* once implemented, remove continue statement */
- log_warn( _("Marking inode invalid\n"));
- if(gfs2_blockmap_set(bl, block, gfs2_meta_inval)) {
+ if(fsck_blockmap_set(ip, block, _("bad depth"),
+ gfs2_meta_inval)) {
stack;
fsck_inode_put(&ip);
return -1;
}
- gfs2_set_bitmap(sdp, block, GFS2_BLKST_FREE);
fsck_inode_put(&ip);
return 0;
}
@@ -752,9 +687,8 @@ static int handle_di(struct gfs2_sbd *sdp, struct gfs2_buffer_head *bh,
(unsigned long long)ip->i_di.di_num.no_addr);
/* FIXME: Must set all leaves invalid as well */
check_metatree(ip, &invalidate_metatree);
- gfs2_blockmap_set(bl, ip->i_di.di_num.no_addr,
- gfs2_meta_inval);
- gfs2_set_bitmap(sdp, ip->i_di.di_num.no_addr, GFS2_BLKST_FREE);
+ fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
+ _("corrupt"), gfs2_meta_inval);
fsck_inode_put(&ip);
return 0;
}
@@ -880,16 +814,14 @@ int pass1(struct gfs2_sbd *sbp)
"%llu (0x%llx)\n"),
(unsigned long long)block,
(unsigned long long)block);
- if(query( _("Okay to free the invalid block? "
- "(y/n)"))) {
- gfs2_set_bitmap(sbp, block,
- GFS2_BLKST_FREE);
- log_err( _("The invalid block was "
- "freed.\n"));
- } else {
- log_err( _("The invalid block was "
- "ignored.\n"));
+ if (gfs2_blockmap_set(bl, block,
+ gfs2_block_free)) {
+ stack;
+ brelse(bh);
+ return FSCK_ERROR;
}
+ check_n_fix_bitmap(sbp, block,
+ gfs2_block_free);
} else if (handle_di(sbp, bh, block) < 0) {
stack;
brelse(bh);
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index dc655c8..32512fd 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -167,8 +167,8 @@ static int clear_dup_metalist(struct gfs2_inode *ip, uint64_t block,
dh->id->parent);
/* Setting the block to invalid means the inode is
* cleared in pass2 */
- gfs2_blockmap_set(bl, ip->i_di.di_num.no_addr,
- gfs2_meta_inval);
+ fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
+ _("inode with duplicate"), gfs2_meta_inval);
}
return 0;
}
@@ -199,7 +199,8 @@ static int clear_dup_eattr_indir(struct gfs2_inode *ip, uint64_t block,
log_err( _("Inode %s is in directory %" PRIu64 " (0x%" PRIx64 ")\n"),
dh->id->name ? dh->id->name : "",
dh->id->parent, dh->id->parent);
- gfs2_blockmap_set(bl, ip->i_di.di_eattr, gfs2_meta_inval);
+ fsck_blockmap_set(ip, ip->i_di.di_eattr,
+ _("indirect eattr"), gfs2_meta_inval);
}
return 0;
@@ -225,7 +226,8 @@ static int clear_dup_eattr_leaf(struct gfs2_inode *ip, uint64_t block,
dh->id->name ? dh->id->name : "",
dh->id->parent, dh->id->parent);
/* mark the main eattr block invalid */
- gfs2_blockmap_set(bl, ip->i_di.di_eattr, gfs2_meta_inval);
+ fsck_blockmap_set(ip, ip->i_di.di_eattr,
+ _("indirect eattr leaf"), gfs2_meta_inval);
}
return 0;
@@ -295,7 +297,8 @@ static int clear_eattr_extentry(struct gfs2_inode *ip, uint64_t *ea_data_ptr,
dh->id->name ? dh->id->name : "",
dh->id->parent, dh->id->parent);
/* mark the main eattr block invalid */
- gfs2_blockmap_set(bl, ip->i_di.di_eattr, gfs2_meta_inval);
+ fsck_blockmap_set(ip, ip->i_di.di_eattr,
+ _("extended eattr leaf"), gfs2_meta_inval);
}
return 0;
@@ -417,9 +420,9 @@ static int handle_dup_blk(struct gfs2_sbd *sbp, struct duptree *b)
inodetree_delete(ii);
/* Setting the block to invalid means the inode
is cleared in pass2 */
- gfs2_blockmap_set(bl, ip->i_di.di_num.no_addr,
- gfs2_meta_inval);
- bmodified(ip->i_bh);
+ fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
+ _("inode with bad duplicate"),
+ gfs2_meta_inval);
fsck_inode_put(&ip);
} else {
log_warn( _("The bad inode was not cleared."));
@@ -463,8 +466,8 @@ static int handle_dup_blk(struct gfs2_sbd *sbp, struct duptree *b)
if(!id->ea_only)
check_metatree(ip, &clear_dup_fxns);
- gfs2_blockmap_set(bl, ip->i_di.di_num.no_addr,
- gfs2_meta_inval);
+ fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
+ _("inode with duplicate"), gfs2_meta_inval);
fsck_inode_put(&ip); /* out, brelse, free */
dh.ref_inode_count--;
if(dh.ref_inode_count == 1)
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index 18a7d10..d82e6cc 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -214,7 +214,8 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
log_err( _("Directory entry not fixed.\n"));
goto dentry_is_valid;
}
- gfs2_blockmap_set(bl, ip->i_di.di_num.no_addr,
+ fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
+ _("corrupt directory entry"),
gfs2_meta_inval);
log_err( _("Bad directory entry deleted.\n"));
return 1;
@@ -263,7 +264,8 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
check_metatree(entry_ip, &pass2_fxns_delete);
if (entry_ip != ip)
fsck_inode_put(&entry_ip);
- gfs2_blockmap_set(bl, entryblock, gfs2_block_free);
+ fsck_blockmap_set(ip, entryblock,
+ _("bad directory entry"), gfs2_block_free);
goto nuke_dentry;
}
if(q < gfs2_inode_dir || q > gfs2_inode_sock) {
@@ -539,7 +541,8 @@ static int check_system_dir(struct gfs2_inode *sysinode, const char *dirname,
return -1;
}
if (error > 0)
- gfs2_blockmap_set(bl, iblock, gfs2_meta_inval);
+ fsck_blockmap_set(sysinode, iblock, dirname,
+ gfs2_meta_inval);
if(check_inode_eattr(sysinode, &pass2_fxns)) {
stack;
@@ -719,6 +722,8 @@ int pass2(struct gfs2_sbd *sbp)
} else
log_err( _("Directory entry to invalid inode remains.\n"));
}
+ /* Can't use fsck_blockmap_set here because we don't
+ have an inode in memory. */
gfs2_blockmap_set(bl, dirblk, gfs2_meta_inval);
}
ip = fsck_load_inode(sbp, dirblk);
diff --git a/gfs2/fsck/pass3.c b/gfs2/fsck/pass3.c
index 0e8f40b..3f58877 100644
--- a/gfs2/fsck/pass3.c
+++ b/gfs2/fsck/pass3.c
@@ -203,9 +203,20 @@ int pass3(struct gfs2_sbd *sbp)
log_err( _("Found unlinked directory containing bad block\n"));
if(query(
_("Clear unlinked directory with bad blocks? (y/n) "))) {
+ log_warn( _("inode %lld (0x%llx) is "
+ "now marked as free\n"),
+ (unsigned long long)
+ di->dinode,
+ (unsigned long long)
+ di->dinode);
+ /* Can't use fsck_blockmap_set
+ because we don't have ip */
gfs2_blockmap_set(bl,
- di->dinode,
- gfs2_block_free);
+ di->dinode,
+ gfs2_block_free);
+ check_n_fix_bitmap(sbp,
+ di->dinode,
+ gfs2_block_free);
break;
} else
log_err( _("Unlinked directory with bad block remains\n"));
@@ -218,9 +229,25 @@ int pass3(struct gfs2_sbd *sbp)
q != gfs2_inode_fifo &&
q != gfs2_inode_sock) {
log_err( _("Unlinked block marked as inode not an inode\n"));
+ if(!query(_("Clear the unlinked block?"
+ " (y/n) "))) {
+ log_err( _("The block was not "
+ "cleared\n"));
+ break;
+ }
+ log_warn( _("inode %lld (0x%llx) is now "
+ "marked as free\n"),
+ (unsigned long long)
+ di->dinode,
+ (unsigned long long)
+ di->dinode);
+ /* Can't use fsck_blockmap_set
+ because we don't have ip */
gfs2_blockmap_set(bl, di->dinode,
gfs2_block_free);
- log_err( _("Cleared\n"));
+ check_n_fix_bitmap(sbp, di->dinode,
+ gfs2_block_free);
+ log_err( _("The block was cleared\n"));
break;
}
@@ -232,9 +259,10 @@ int pass3(struct gfs2_sbd *sbp)
if(!ip->i_di.di_size && !ip->i_di.di_eattr){
log_err( _("Unlinked directory has zero size.\n"));
if(query( _("Remove zero-size unlinked directory? (y/n) "))) {
- gfs2_blockmap_set(bl,
- di->dinode,
- gfs2_block_free);
+ fsck_blockmap_set(ip,
+ di->dinode,
+ _("zero-sized unlinked inode"),
+ gfs2_block_free);
fsck_inode_put(&ip);
break;
} else {
diff --git a/gfs2/fsck/pass4.c b/gfs2/fsck/pass4.c
index 78fd6c6..47a1eaa 100644
--- a/gfs2/fsck/pass4.c
+++ b/gfs2/fsck/pass4.c
@@ -72,10 +72,10 @@ static int scan_inode_list(struct gfs2_sbd *sbp) {
check_inode_eattr(ip,
&pass4_fxns_delete);
check_metatree(ip, &pass4_fxns_delete);
- bmodified(ip->i_bh);
- fsck_inode_put(&ip);
- gfs2_blockmap_set(bl, ii->inode,
+ fsck_blockmap_set(ip, ii->inode,
+ _("bad unlinked"),
gfs2_block_free);
+ fsck_inode_put(&ip);
continue;
} else
log_err( _("Unlinked inode with bad blocks not cleared\n"));
@@ -97,9 +97,10 @@ static int scan_inode_list(struct gfs2_sbd *sbp) {
check_inode_eattr(ip,
&pass4_fxns_delete);
check_metatree(ip, &pass4_fxns_delete);
- bmodified(ip->i_bh);
- gfs2_blockmap_set(bl, ii->inode,
+ fsck_blockmap_set(ip, ii->inode,
+ _("invalid unlinked"),
gfs2_block_free);
+ fsck_inode_put(&ip);
log_err( _("The inode was deleted\n"));
} else {
log_err( _("The inode was not "
@@ -116,7 +117,8 @@ static int scan_inode_list(struct gfs2_sbd *sbp) {
if(!ip->i_di.di_size && !ip->i_di.di_eattr){
log_err( _("Unlinked inode has zero size\n"));
if(query( _("Clear zero-size unlinked inode? (y/n) "))) {
- gfs2_blockmap_set(bl, ii->inode,
+ fsck_blockmap_set(ip, ii->inode,
+ _("unlinked zero-length"),
gfs2_block_free);
fsck_inode_put(&ip);
continue;
diff --git a/gfs2/libgfs2/libgfs2.h b/gfs2/libgfs2/libgfs2.h
index 3a6c61e..951966a 100644
--- a/gfs2/libgfs2/libgfs2.h
+++ b/gfs2/libgfs2/libgfs2.h
@@ -313,6 +313,34 @@ static const inline char *block_type_string(uint8_t 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)
+{
+ static int bitmap_states[16] = {
+ GFS2_BLKST_FREE,
+ GFS2_BLKST_USED,
+ GFS2_BLKST_USED,
+ GFS2_BLKST_DINODE,
+ GFS2_BLKST_DINODE,
+
+ GFS2_BLKST_DINODE,
+ GFS2_BLKST_DINODE,
+ GFS2_BLKST_DINODE,
+ GFS2_BLKST_DINODE,
+ GFS2_BLKST_DINODE,
+
+ GFS2_BLKST_FREE,
+ GFS2_BLKST_FREE,
+ GFS2_BLKST_USED,
+ GFS2_BLKST_USED,
+ GFS2_BLKST_USED,
+
+ GFS2_BLKST_USED
+ };
+ return bitmap_states[m];
+}
+
extern struct gfs2_bmap *gfs2_bmap_create(struct gfs2_sbd *sdp, uint64_t size,
uint64_t *addl_mem_needed);
extern struct special_blocks *blockfind(struct special_blocks *blist, uint64_t num);
14 years, 4 months
gfs2-utils: master - fsck.gfs2: Enforce consistent behavior in directory processing
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/gfs2-utils.git?p=gfs2-utils.git;a=commitd...
Commit: 04e6b40284539557d6db87ffd6d38db477fe7525
Parent: 15ab396220635427dacc678160246ec8d19d8624
Author: Bob Peterson <bob(a)ganesha.peterson>
AuthorDate: Fri Jan 22 09:18:48 2010 -0600
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Tue Jan 26 15:09:47 2010 -0600
fsck.gfs2: Enforce consistent behavior in directory processing
In pass2, all directory entries are checked and validated by a huge,
confusing, hard-to-debug function called check_dentry. However,
when problems were found, there was inconsistent behavior regarding
the keeping and accounting for valid directories or deleting invalid
directories. But either a directory entry is good or it's not. If
it is invalid, no matter what the problem is, it should be treated
the same as all the other bad entries. If the directory is good,
or if fsck.gfs2 is instructed to ignore the problem, it should be
treated the same as all other good entries. To that end, this patch
introduces two centralized labels (dentry_is_valid and nuke_dentry).
Function check_dentry is simplified and its behavior made consistent
by introducing several gotos (oh, the shame) to those labels.
rhbz#455300
---
gfs2/fsck/pass2.c | 330 ++++++++++++++++++++++------------------------------
1 files changed, 140 insertions(+), 190 deletions(-)
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index 184014c..18a7d10 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -182,41 +182,6 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
entryblock = de->de_inum.no_addr;
/* Start of checks */
- if (de->de_rec_len < GFS2_DIRENT_SIZE(de->de_name_len)){
- log_err( _("Dir entry with bad record or name length\n"
- "\tRecord length = %u\n"
- "\tName length = %u\n"),
- de->de_rec_len,
- de->de_name_len);
- gfs2_blockmap_set(bl, ip->i_di.di_num.no_addr,
- gfs2_meta_inval);
- return 1;
- /* FIXME: should probably delete the entry here at the
- * very least - maybe look at attempting to fix it */
- }
-
- calculated_hash = gfs2_disk_hash(filename, de->de_name_len);
- if (de->de_hash != calculated_hash){
- log_err( _("Dir entry with bad hash or name length\n"
- "\tHash found = %u (0x%x)\n"
- "\tFilename = %s\n"), de->de_hash, de->de_hash,
- filename);
- log_err( _("\tName length found = %u\n"
- "\tHash expected = %u (0x%x)\n"),
- de->de_name_len, calculated_hash, calculated_hash);
- if(query( _("Fix directory hash for %s? (y/n) "),
- filename)) {
- de->de_hash = calculated_hash;
- gfs2_dirent_out(de, (char *)dent);
- log_err( _("Directory entry hash for %s fixed.\n"), filename);
- }
- else {
- log_err( _("Directory entry hash for %s not fixed.\n"), filename);
- return 1;
- }
- }
- /* FIXME: This should probably go to the top of the fxn, and
- * references to filename should be replaced with tmp_name */
memset(tmp_name, 0, MAX_FILENAME);
if(de->de_name_len < MAX_FILENAME)
strncpy(tmp_name, filename, de->de_name_len);
@@ -228,11 +193,9 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
"%lld (0x%llx) is out of range\n"),
tmp_name, (unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
- if(query( _("Clear directory entry tp out of range block? (y/n) "))) {
- log_err( _("Clearing %s\n"), tmp_name);
- dirent2_del(ip, bh, prev_de, dent);
- bmodified(bh);
- return 1;
+ if(query( _("Clear directory entry to out of range block? "
+ "(y/n) "))) {
+ goto nuke_dentry;
} else {
log_err( _("Directory entry to out of range block remains\n"));
(*count)++;
@@ -242,6 +205,43 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
return 0;
}
}
+
+ if (de->de_rec_len < GFS2_DIRENT_SIZE(de->de_name_len)) {
+ log_err( _("Dir entry with bad record or name length\n"
+ "\tRecord length = %u\n\tName length = %u\n"),
+ de->de_rec_len, de->de_name_len);
+ if(!query( _("Clear the directory entry? (y/n) "))) {
+ log_err( _("Directory entry not fixed.\n"));
+ goto dentry_is_valid;
+ }
+ gfs2_blockmap_set(bl, ip->i_di.di_num.no_addr,
+ gfs2_meta_inval);
+ log_err( _("Bad directory entry deleted.\n"));
+ return 1;
+ }
+
+ calculated_hash = gfs2_disk_hash(tmp_name, de->de_name_len);
+ if (de->de_hash != calculated_hash){
+ log_err( _("Dir entry with bad hash or name length\n"
+ "\tHash found = %u (0x%x)\n"
+ "\tFilename = %s\n"),
+ de->de_hash, de->de_hash, tmp_name);
+ log_err( _("\tName length found = %u\n"
+ "\tHash expected = %u (0x%x)\n"),
+ de->de_name_len, calculated_hash, calculated_hash);
+ if(!query( _("Fix directory hash for %s? (y/n) "),
+ tmp_name)) {
+ log_err( _("Directory entry hash for %s not "
+ "fixed.\n"), tmp_name);
+ goto dentry_is_valid;
+ }
+ de->de_hash = calculated_hash;
+ gfs2_dirent_out(de, (char *)dent);
+ bmodified(bh);
+ log_err( _("Directory entry hash for %s fixed.\n"),
+ tmp_name);
+ }
+
q = block_type(entryblock);
/* Get the status of the directory inode */
if(q == gfs2_bad_block) {
@@ -250,25 +250,21 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
/* Handle bad blocks */
log_err( _("Found a bad directory entry: %s\n"), filename);
- if(query( _("Delete inode containing bad blocks? (y/n)"))) {
- entry_ip = fsck_load_inode(sbp, entryblock);
- check_inode_eattr(entry_ip, &pass2_fxns_delete);
- check_metatree(entry_ip, &pass2_fxns_delete);
- bmodified(entry_ip->i_bh);
- fsck_inode_put(&entry_ip);
- dirent2_del(ip, bh, prev_de, dent);
- gfs2_blockmap_set(bl, entryblock, gfs2_block_free);
- bmodified(bh);
- log_warn( _("The inode containing bad blocks was "
- "deleted.\n"));
- return 1;
- } else {
+ if(!query( _("Delete inode containing bad blocks? (y/n)"))) {
log_warn( _("Entry to inode containing bad blocks remains\n"));
- (*count)++;
- ds->entry_count++;
- return 0;
+ goto dentry_is_valid;
}
+ if (ip->i_di.di_num.no_addr == entryblock)
+ entry_ip = ip;
+ else
+ entry_ip = fsck_load_inode(sbp, entryblock);
+ check_inode_eattr(entry_ip, &pass2_fxns_delete);
+ check_metatree(entry_ip, &pass2_fxns_delete);
+ if (entry_ip != ip)
+ fsck_inode_put(&entry_ip);
+ gfs2_blockmap_set(bl, entryblock, gfs2_block_free);
+ goto nuke_dentry;
}
if(q < gfs2_inode_dir || q > gfs2_inode_sock) {
log_err( _("Directory entry '%s' referencing inode %llu "
@@ -282,41 +278,29 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
_("previously marked invalid") :
_("is not an inode"));
- if(query( _("Clear directory entry to non-inode block? "
- "(y/n) "))) {
- struct gfs2_buffer_head *bhi;
-
- dirent2_del(ip, bh, prev_de, dent);
- bmodified(bh);
- log_warn( _("Directory entry '%s' cleared\n"), tmp_name);
- /* If it was previously marked invalid (i.e. known
- to be bad, not just a free block, etc.) then
- delete any metadata it holds. If not, return. */
- if (q != gfs2_meta_inval)
- return 1;
-
- /* Now try to clear the dinode, if it is an dinode */
- bhi = bread(sbp, entryblock);
- error = gfs2_check_meta(bhi, GFS2_METATYPE_DI);
- bmodified(bhi);
- brelse(bhi);
- if (error)
- return 1; /* not a dinode: nothing to delete */
-
- entry_ip = fsck_load_inode(sbp, entryblock);
- check_inode_eattr(entry_ip, &pass2_fxns_delete);
- check_metatree(entry_ip, &pass2_fxns_delete);
- bmodified(entry_ip->i_bh);
- fsck_inode_put(&entry_ip);
- gfs2_blockmap_set(bl, entryblock, gfs2_block_free);
-
- return 1;
- } else {
+ if(!query( _("Clear directory entry to non-inode block? "
+ "(y/n) "))) {
log_err( _("Directory entry to non-inode block remains\n"));
- (*count)++;
- ds->entry_count++;
- return 0;
+ goto dentry_is_valid;
}
+
+ /* Don't decrement the link here: Here in pass2, we increment
+ only when we know it's okay.
+ decrement_link(ip->i_di.di_num.no_addr); */
+ /* If it was previously marked invalid (i.e. known
+ to be bad, not just a free block, etc.) then the temptation
+ would be to delete any metadata it holds. The trouble is:
+ if it's invalid, we may or _may_not_ have traversed its
+ metadata tree, and therefore may or may not have marked the
+ blocks it points to as a metadata type, or as a duplicate.
+ If there is really a duplicate reference, but we didn't
+ process the metadata tree because it's invalid, some other
+ inode has a reference to the metadata block, in which case
+ freeing it would do more harm than good. IOW we cannot
+ count on "delete_block_if_notdup" knowing whether it's
+ really a duplicate block if we never traversed the metadata
+ tree for the invalid inode. */
+ goto nuke_dentry;
}
error = check_file_type(de->de_type, q);
@@ -340,22 +324,18 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
(unsigned long long)entryblock,
(unsigned long long)entryblock,
block_type_string(q));
- if(query( _("Clear stale directory entry? (y/n) "))) {
+ if(!query( _("Clear stale directory entry? (y/n) "))) {
+ log_err( _("Stale directory entry remains\n"));
+ goto dentry_is_valid;
+ }
+ if (ip->i_di.di_num.no_addr == entryblock)
+ entry_ip = ip;
+ else
entry_ip = fsck_load_inode(sbp, entryblock);
check_inode_eattr(entry_ip, &clear_eattrs);
if (entry_ip != ip)
fsck_inode_put(&entry_ip);
-
- dirent2_del(ip, bh, prev_de, dent);
- bmodified(bh);
- log_err( _("Stale directory entry deleted\n"));
- return 1;
- } else {
- log_err( _("Stale directory entry remains\n"));
- (*count)++;
- ds->entry_count++;
- return 0;
- }
+ goto nuke_dentry;
}
if(!strcmp(".", tmp_name)) {
@@ -366,26 +346,20 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
" (0x%llx)\n"),
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
- if(query( _("Clear duplicate '.' entry? (y/n) "))) {
- entry_ip = fsck_load_inode(sbp, entryblock);
- check_inode_eattr(entry_ip, &clear_eattrs);
- fsck_inode_put(&entry_ip);
-
- dirent2_del(ip, bh, prev_de, dent);
- bmodified(bh);
- return 1;
- } else {
+ if(!query( _("Clear duplicate '.' entry? (y/n) "))) {
log_err( _("Duplicate '.' entry remains\n"));
/* FIXME: Should we continue on here
- * and check the rest of the '.'
- * entry? */
- increment_link(entryblock,
- ip->i_di.di_num.no_addr,
- _("valid reference"));
- (*count)++;
- ds->entry_count++;
- return 0;
+ * and check the rest of the '.' entry? */
+ goto dentry_is_valid;
}
+ if (ip->i_di.di_num.no_addr == entryblock)
+ entry_ip = ip;
+ else
+ entry_ip = fsck_load_inode(sbp, entryblock);
+ check_inode_eattr(entry_ip, &clear_eattrs);
+ if (entry_ip != ip)
+ fsck_inode_put(&entry_ip);
+ goto nuke_dentry;
}
/* GFS2 does not rely on '.' being in a certain
@@ -403,35 +377,24 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
(unsigned long long)entryblock,
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
- if(query( _("Remove '.' reference? (y/n) "))) {
- entry_ip = fsck_load_inode(sbp, entryblock);
- check_inode_eattr(entry_ip, &clear_eattrs);
- fsck_inode_put(&entry_ip);
-
- dirent2_del(ip, bh, prev_de, dent);
- bmodified(bh);
- return 1;
-
- } else {
+ if(!query( _("Remove '.' reference? (y/n) "))) {
log_err( _("Invalid '.' reference remains\n"));
/* Not setting ds->dotdir here since
* this '.' entry is invalid */
- increment_link(entryblock,
- ip->i_di.di_num.no_addr,
- _("valid reference"));
- (*count)++;
- ds->entry_count++;
- return 0;
+ goto dentry_is_valid;
}
+ if (ip->i_di.di_num.no_addr == entryblock)
+ entry_ip = ip;
+ else
+ entry_ip = fsck_load_inode(sbp, entryblock);
+ check_inode_eattr(entry_ip, &clear_eattrs);
+ if (entry_ip != ip)
+ fsck_inode_put(&entry_ip);
+ goto nuke_dentry;
}
ds->dotdir = 1;
- increment_link(entryblock, ip->i_di.di_num.no_addr,
- _("valid reference"));
- (*count)++;
- ds->entry_count++;
-
- return 0;
+ goto dentry_is_valid;
}
if(!strcmp("..", tmp_name)) {
log_debug( _("Found .. dentry\n"));
@@ -440,27 +403,23 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
"(0x%llx)\n"),
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
- if(query( _("Clear duplicate '..' entry? (y/n) "))) {
-
- entry_ip = fsck_load_inode(sbp, entryblock);
- check_inode_eattr(entry_ip, &clear_eattrs);
- fsck_inode_put(&entry_ip);
-
- dirent2_del(ip, bh, prev_de, dent);
- bmodified(bh);
- return 1;
- } else {
+ if(!query( _("Clear duplicate '..' entry? (y/n) "))) {
log_err( _("Duplicate '..' entry remains\n"));
/* FIXME: Should we continue on here
* and check the rest of the '..'
* entry? */
- increment_link(entryblock,
- ip->i_di.di_num.no_addr,
- _("valid reference"));
- (*count)++;
- ds->entry_count++;
- return 0;
+ goto dentry_is_valid;
}
+
+ if (ip->i_di.di_num.no_addr == entryblock)
+ entry_ip = ip;
+ else
+ entry_ip = fsck_load_inode(sbp, entryblock);
+ check_inode_eattr(entry_ip, &clear_eattrs);
+ if (entry_ip != ip)
+ fsck_inode_put(&entry_ip);
+
+ goto nuke_dentry;
}
if(q != gfs2_inode_dir) {
@@ -468,24 +427,19 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
"pointing to something that's not a directory"),
(unsigned long long)ip->i_di.di_num.no_addr,
(unsigned long long)ip->i_di.di_num.no_addr);
- if(query( _("Clear bad '..' directory entry? (y/n) "))) {
+ if(!query( _("Clear bad '..' directory entry? (y/n) "))) {
+ log_err( _("Bad '..' directory entry remains\n"));
+ goto dentry_is_valid;
+ }
+ if (ip->i_di.di_num.no_addr == entryblock)
+ entry_ip = ip;
+ else
entry_ip = fsck_load_inode(sbp, entryblock);
check_inode_eattr(entry_ip, &clear_eattrs);
if (entry_ip != ip)
fsck_inode_put(&entry_ip);
- dirent2_del(ip, bh, prev_de, dent);
- bmodified(bh);
- return 1;
- } else {
- log_err( _("Bad '..' directory entry remains\n"));
- increment_link(entryblock,
- ip->i_di.di_num.no_addr,
- _("valid reference"));
- (*count)++;
- ds->entry_count++;
- return 0;
- }
+ goto nuke_dentry;
}
/* GFS2 does not rely on '..' being in a certain location */
@@ -498,21 +452,16 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
}
ds->dotdotdir = 1;
- increment_link(entryblock, ip->i_di.di_num.no_addr,
- _("valid reference"));
- (*count)++;
- ds->entry_count++;
- return 0;
+ goto dentry_is_valid;
}
/* After this point we're only concerned with directories */
if(q != gfs2_inode_dir) {
- log_debug( _("Found non-dir inode dentry\n"));
- increment_link(entryblock, ip->i_di.di_num.no_addr,
- _("valid reference"));
- (*count)++;
- ds->entry_count++;
- return 0;
+ log_debug( _("Found non-dir inode dentry pointing to %lld "
+ "(0x%llx)\n"),
+ (unsigned long long)entryblock,
+ (unsigned long long)entryblock);
+ goto dentry_is_valid;
}
/*log_debug( _("Found plain directory dentry\n"));*/
@@ -521,28 +470,29 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
log_err( _("%s: Hard link to block %" PRIu64" (0x%" PRIx64
") detected.\n"), tmp_name, entryblock, entryblock);
- if(query( _("Clear hard link to directory? (y/n) "))) {
- bmodified(bh);
- dirent2_del(ip, bh, prev_de, dent);
- log_warn( _("Directory entry %s cleared\n"), filename);
-
- return 1;
- } else {
+ if(query( _("Clear hard link to directory? (y/n) ")))
+ goto nuke_dentry;
+ else {
log_err( _("Hard link to directory remains\n"));
- (*count)++;
- ds->entry_count++;
- return 0;
+ goto dentry_is_valid;
}
} else if (error < 0) {
stack;
return -1;
}
+dentry_is_valid:
+ /* This directory inode links to this inode via this dentry */
increment_link(entryblock, ip->i_di.di_num.no_addr,
_("valid reference"));
(*count)++;
ds->entry_count++;
/* End of checks */
return 0;
+
+nuke_dentry:
+ dirent2_del(ip, bh, prev_de, dent);
+ log_err( _("Bad directory entry '%s' cleared.\n"), tmp_name);
+ return 1;
}
14 years, 4 months
gfs2-utils: master - fsck.gfs2: link.c should log why it's making a change for debugging
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/gfs2-utils.git?p=gfs2-utils.git;a=commitd...
Commit: 15ab396220635427dacc678160246ec8d19d8624
Parent: 1bb9a56fe54da70b7439de72fd87dd16c5f4fd18
Author: Bob Peterson <bob(a)ganesha.peterson>
AuthorDate: Fri Jan 22 09:01:15 2010 -0600
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Tue Jan 26 15:09:47 2010 -0600
fsck.gfs2: link.c should log why it's making a change for debugging
This patch helps in debugging directory link problems by logging
the dinode and the reason why the directory link count is being
incremented or decremented.
rhbz#455300
---
gfs2/fsck/link.c | 31 +++++++++++++++++++++++--------
gfs2/fsck/link.h | 6 ++++--
gfs2/fsck/lost_n_found.c | 22 ++++++++++++++++------
gfs2/fsck/pass2.c | 40 ++++++++++++++++++++++++++++------------
gfs2/fsck/pass3.c | 4 ++--
5 files changed, 73 insertions(+), 30 deletions(-)
diff --git a/gfs2/fsck/link.c b/gfs2/fsck/link.c
index a6b0780..0996fa9 100644
--- a/gfs2/fsck/link.c
+++ b/gfs2/fsck/link.c
@@ -29,21 +29,28 @@ int set_link_count(uint64_t inode_no, uint32_t count)
return 0;
}
-int increment_link(struct gfs2_sbd *sbp, uint64_t inode_no)
+int increment_link(uint64_t inode_no, uint64_t referenced_from,
+ const char *why)
{
struct inode_info *ii = NULL;
ii = inodetree_find(inode_no);
/* If the list has entries, look for one that matches
* inode_no */
- if(ii) {
+ if (ii) {
ii->counted_links++;
- log_debug( _("Incremented counted links to %u for %"PRIu64" (0x%"
- PRIx64 ")\n"), ii->counted_links, inode_no, inode_no);
+ log_debug( _("Directory %lld (0x%llx) incremented counted "
+ "links to %u for %"PRIu64" (0x%" PRIx64 ") "
+ "via %s\n"),
+ (unsigned long long)referenced_from,
+ (unsigned long long)referenced_from,
+ ii->counted_links, inode_no, inode_no, why);
return 0;
}
- log_debug( _("No match found when incrementing link for %" PRIu64
- " (0x%" PRIx64 ")!\n"), inode_no, inode_no);
+ log_debug( _("Ref: %lld (0x%llx) No match found when incrementing "
+ "link for %" PRIu64 " (0x%" PRIx64 ")!\n"),
+ (unsigned long long)referenced_from,
+ (unsigned long long)referenced_from, inode_no, inode_no);
/* If no match was found, add a new entry and set its
* counted links to 1 */
ii = inodetree_insert(inode_no);
@@ -54,16 +61,24 @@ int increment_link(struct gfs2_sbd *sbp, uint64_t inode_no)
return 0;
}
-int decrement_link(struct gfs2_sbd *sbp, uint64_t inode_no)
+int decrement_link(uint64_t inode_no, uint64_t referenced_from,
+ const char *why)
{
struct inode_info *ii = NULL;
ii = inodetree_find(inode_no);
/* If the list has entries, look for one that matches
* inode_no */
- log_err( _("Decrementing %"PRIu64" (0x%" PRIx64 ")\n"), inode_no, inode_no);
+ log_err( _("Decrementing %"PRIu64" (0x%" PRIx64 ") to %d\n"),
+ inode_no, inode_no, ii->counted_links);
if(ii) {
ii->counted_links--;
+ log_debug( _("Directory %lld (0x%llx) decremented counted "
+ "links to %u for %"PRIu64" (0x%" PRIx64 ") "
+ "via %s\n"),
+ (unsigned long long)referenced_from,
+ (unsigned long long)referenced_from,
+ ii->counted_links, inode_no, inode_no, why);
return 0;
}
log_debug( _("No match found when decrementing link for %" PRIu64
diff --git a/gfs2/fsck/link.h b/gfs2/fsck/link.h
index 7446b4a..f890575 100644
--- a/gfs2/fsck/link.h
+++ b/gfs2/fsck/link.h
@@ -2,7 +2,9 @@
#define _LINK_H
int set_link_count(uint64_t inode_no, uint32_t count);
-int increment_link(struct gfs2_sbd *sbp, uint64_t inode_no);
-int decrement_link(struct gfs2_sbd *sbp, uint64_t inode_no);
+int increment_link(uint64_t inode_no, uint64_t referenced_from,
+ const char *why);
+int decrement_link(uint64_t inode_no, uint64_t referenced_from,
+ const char *why);
#endif /* _LINK_H */
diff --git a/gfs2/fsck/lost_n_found.c b/gfs2/fsck/lost_n_found.c
index 417ddd7..f9cb556 100644
--- a/gfs2/fsck/lost_n_found.c
+++ b/gfs2/fsck/lost_n_found.c
@@ -48,10 +48,16 @@ int add_inode_to_lf(struct gfs2_inode *ip){
* this */
gfs2_blockmap_set(bl, lf_dip->i_di.di_num.no_addr,
gfs2_inode_dir);
- increment_link(ip->i_sbd,
- ip->i_sbd->md.rooti->i_di.di_num.no_addr);
- increment_link(ip->i_sbd, lf_dip->i_di.di_num.no_addr);
- increment_link(ip->i_sbd, lf_dip->i_di.di_num.no_addr);
+ /* root inode links to lost+found */
+ increment_link(ip->i_sbd->md.rooti->i_di.di_num.no_addr,
+ lf_dip->i_di.di_num.no_addr, _("root"));
+ /* lost+found link for '.' from itself */
+ increment_link(lf_dip->i_di.di_num.no_addr,
+ lf_dip->i_di.di_num.no_addr, "\".\"");
+ /* lost+found link for '..' back to root */
+ increment_link(lf_dip->i_di.di_num.no_addr,
+ ip->i_sbd->md.rooti->i_di.di_num.no_addr,
+ "\"..\"");
}
}
if(ip->i_di.di_num.no_addr == lf_dip->i_di.di_num.no_addr) {
@@ -113,9 +119,13 @@ int add_inode_to_lf(struct gfs2_inode *ip){
dir_add(lf_dip, tmp_name, strlen(tmp_name), &(ip->i_di.di_num),
inode_type);
- increment_link(ip->i_sbd, ip->i_di.di_num.no_addr);
+ /* This inode is linked from lost+found */
+ increment_link(ip->i_di.di_num.no_addr, lf_dip->i_di.di_num.no_addr,
+ _("from lost+found"));
+ /* If it's a directory, lost+found is back-linked to it via .. */
if(S_ISDIR(ip->i_di.di_mode))
- increment_link(ip->i_sbd, lf_dip->i_di.di_num.no_addr);
+ increment_link(lf_dip->i_di.di_num.no_addr,
+ ip->i_di.di_mode, _("to lost+found"));
log_notice( _("Added inode #%llu to lost+found dir\n"),
(unsigned long long)ip->i_di.di_num.no_addr);
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index c4e5d17..184014c 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -379,7 +379,9 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
/* FIXME: Should we continue on here
* and check the rest of the '.'
* entry? */
- increment_link(sbp, entryblock);
+ increment_link(entryblock,
+ ip->i_di.di_num.no_addr,
+ _("valid reference"));
(*count)++;
ds->entry_count++;
return 0;
@@ -414,7 +416,9 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
log_err( _("Invalid '.' reference remains\n"));
/* Not setting ds->dotdir here since
* this '.' entry is invalid */
- increment_link(sbp, entryblock);
+ increment_link(entryblock,
+ ip->i_di.di_num.no_addr,
+ _("valid reference"));
(*count)++;
ds->entry_count++;
return 0;
@@ -422,7 +426,8 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
}
ds->dotdir = 1;
- increment_link(sbp, entryblock);
+ increment_link(entryblock, ip->i_di.di_num.no_addr,
+ _("valid reference"));
(*count)++;
ds->entry_count++;
@@ -449,7 +454,9 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
/* FIXME: Should we continue on here
* and check the rest of the '..'
* entry? */
- increment_link(sbp, entryblock);
+ increment_link(entryblock,
+ ip->i_di.di_num.no_addr,
+ _("valid reference"));
(*count)++;
ds->entry_count++;
return 0;
@@ -472,7 +479,9 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
return 1;
} else {
log_err( _("Bad '..' directory entry remains\n"));
- increment_link(sbp, entryblock);
+ increment_link(entryblock,
+ ip->i_di.di_num.no_addr,
+ _("valid reference"));
(*count)++;
ds->entry_count++;
return 0;
@@ -489,7 +498,8 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
}
ds->dotdotdir = 1;
- increment_link(sbp, entryblock);
+ increment_link(entryblock, ip->i_di.di_num.no_addr,
+ _("valid reference"));
(*count)++;
ds->entry_count++;
return 0;
@@ -498,7 +508,8 @@ 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) {
log_debug( _("Found non-dir inode dentry\n"));
- increment_link(sbp, entryblock);
+ increment_link(entryblock, ip->i_di.di_num.no_addr,
+ _("valid reference"));
(*count)++;
ds->entry_count++;
return 0;
@@ -526,7 +537,8 @@ static int check_dentry(struct gfs2_inode *ip, struct gfs2_dirent *dent,
stack;
return -1;
}
- increment_link(sbp, entryblock);
+ increment_link(entryblock, ip->i_di.di_num.no_addr,
+ _("valid reference"));
(*count)++;
ds->entry_count++;
/* End of checks */
@@ -603,8 +615,10 @@ static int check_system_dir(struct gfs2_inode *sysinode, const char *dirname,
log_warn( _("Adding '.' entry\n"));
dir_add(sysinode, filename, filename_len,
&(sysinode->i_di.di_num), DT_DIR);
- increment_link(sysinode->i_sbd,
- sysinode->i_di.di_num.no_addr);
+ /* This system inode is linked to itself via '.' */
+ increment_link(sysinode->i_di.di_num.no_addr,
+ sysinode->i_di.di_num.no_addr,
+ "sysinode \".\"");
ds.entry_count++;
free(filename);
} else
@@ -783,8 +797,10 @@ int pass2(struct gfs2_sbd *sbp)
dir_add(ip, filename, filename_len,
&(ip->i_di.di_num), DT_DIR);
- increment_link(ip->i_sbd,
- ip->i_di.di_num.no_addr);
+ /* directory links to itself via '.' */
+ increment_link(ip->i_di.di_num.no_addr,
+ ip->i_di.di_num.no_addr,
+ _("\". (itself)\""));
ds.entry_count++;
free(filename);
log_err( _("The directory was fixed.\n"));
diff --git a/gfs2/fsck/pass3.c b/gfs2/fsck/pass3.c
index ab01b39..0e8f40b 100644
--- a/gfs2/fsck/pass3.c
+++ b/gfs2/fsck/pass3.c
@@ -51,9 +51,9 @@ static int attach_dotdot_to(struct gfs2_sbd *sbp, uint64_t newdotdot,
if(gfs2_dirent_del(ip, filename, filename_len))
log_warn( _("Unable to remove \"..\" directory entry.\n"));
else
- decrement_link(sbp, olddotdot);
+ decrement_link(olddotdot, block, _("old \"..\""));
dir_add(ip, filename, filename_len, &pip->i_di.di_num, DT_DIR);
- increment_link(sbp, newdotdot);
+ increment_link(newdotdot, block, _("new \"..\""));
bmodified(ip->i_bh);
fsck_inode_put(&ip);
fsck_inode_put(&pip);
14 years, 4 months
gfs2-utils: master - libgfs2: Get rid of useless constants
by Bob Peterson
Gitweb: http://git.fedorahosted.org/git/gfs2-utils.git?p=gfs2-utils.git;a=commitd...
Commit: 1bb9a56fe54da70b7439de72fd87dd16c5f4fd18
Parent: 9f97dc7deaead8a0983c5566a00b3845f003472a
Author: Bob Peterson <bob(a)ganesha.peterson>
AuthorDate: Fri Jan 22 08:38:59 2010 -0600
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Tue Jan 26 15:09:47 2010 -0600
libgfs2: Get rid of useless constants
This patch eliminates a bunch of constants relating to block type.
They were not used except by subsequent declares, so they only
served to confuse things. It was one more thing that had to be
kept in sync.
rhbz#455300
---
gfs2/fsck/util.c | 12 -------
gfs2/libgfs2/libgfs2.h | 81 ++++++++++++++++++++++++++++--------------------
2 files changed, 47 insertions(+), 46 deletions(-)
diff --git a/gfs2/fsck/util.c b/gfs2/fsck/util.c
index f24f76e..f667527 100644
--- a/gfs2/fsck/util.c
+++ b/gfs2/fsck/util.c
@@ -81,18 +81,6 @@ void warm_fuzzy_stuff(uint64_t block)
}
}
-const char *block_type_string(uint8_t q)
-{
- const char *blktyp[] = {"free", "used", "indirect data", "inode",
- "file", "symlink", "block dev", "char dev",
- "fifo", "socket", "dir leaf", "journ data",
- "other meta", "eattribute", "unused",
- "invalid"};
- if (q < 16)
- return (blktyp[q]);
- return blktyp[15];
-}
-
/* fsck_query: Same as gfs2_query except it adjusts errors_found and
errors_corrected. */
int fsck_query(const char *format, ...)
diff --git a/gfs2/libgfs2/libgfs2.h b/gfs2/libgfs2/libgfs2.h
index 4fbc4e1..3a6c61e 100644
--- a/gfs2/libgfs2/libgfs2.h
+++ b/gfs2/libgfs2/libgfs2.h
@@ -263,43 +263,56 @@ struct gfs2_bmap {
};
/* block_list.c */
-#define FREE (0x0) /* 0000 */
-#define BLOCK_IN_USE (0x1) /* 0001 */
-#define DIR_INDIR_BLK (0x2) /* 0010 */
-#define DIR_INODE (0x3) /* 0011 */
-#define FILE_INODE (0x4) /* 0100 */
-#define LNK_INODE (0x5)
-#define BLK_INODE (0x6)
-#define CHR_INODE (0x7)
-#define FIFO_INODE (0x8)
-#define SOCK_INODE (0x9)
-#define DIR_LEAF_INODE (0xA) /* 1010 */
-#define JOURNAL_BLK (0xB) /* 1011 */
-#define OTHER_META (0xC) /* 1100 */
-#define EATTR_META (0xD) /* 1101 */
-#define BAD_BLOCK (0xE) /* 1110 */
-#define INVALID_META (0xF) /* 1111 */
-
-/* Must be kept in sync with mark_to_bitmap array in block_list.c */
+
enum gfs2_mark_block {
- gfs2_block_free = FREE,
- gfs2_block_used = BLOCK_IN_USE,
- gfs2_indir_blk = DIR_INDIR_BLK,
- gfs2_inode_dir = DIR_INODE,
- gfs2_inode_file = FILE_INODE,
- gfs2_inode_lnk = LNK_INODE,
- gfs2_inode_blk = BLK_INODE,
- gfs2_inode_chr = CHR_INODE,
- gfs2_inode_fifo = FIFO_INODE,
- gfs2_inode_sock = SOCK_INODE,
- gfs2_leaf_blk = DIR_LEAF_INODE,
- gfs2_journal_blk = JOURNAL_BLK,
- gfs2_meta_other = OTHER_META,
- gfs2_meta_eattr = EATTR_META,
- gfs2_bad_block = BAD_BLOCK, /* Contains at least one bad block */
- gfs2_meta_inval = INVALID_META,
+ gfs2_block_free = (0x0),
+ gfs2_block_used = (0x1),
+ gfs2_indir_blk = (0x2),
+ gfs2_inode_dir = (0x3),
+ gfs2_inode_file = (0x4),
+
+ gfs2_inode_lnk = (0x5),
+ gfs2_inode_blk = (0x6),
+ gfs2_inode_chr = (0x7),
+ gfs2_inode_fifo = (0x8),
+ gfs2_inode_sock = (0x9),
+
+ gfs2_journal_blk = (0xa),
+ gfs2_meta_inval = (0xb),
+ gfs2_leaf_blk = (0xc),
+ gfs2_meta_other = (0xd),
+ 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 data",
+ "directory",
+ "file",
+
+ "symlink",
+ "block device",
+ "char device",
+ "fifo",
+ "socket",
+
+ "journaled data",
+ "invalid meta",
+ "dir leaf",
+ "other metadata",
+ "eattribute",
+
+ "bad"};
+ if (q < 16)
+ return (blktyp[q]);
+ return blktyp[15];
+}
+
extern struct gfs2_bmap *gfs2_bmap_create(struct gfs2_sbd *sdp, uint64_t size,
uint64_t *addl_mem_needed);
extern struct special_blocks *blockfind(struct special_blocks *blist, uint64_t num);
14 years, 4 months