Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=68922b8444c39…
Commit: 68922b8444c39c78a79b9f62062e60adfaa5f1ea
Parent: 088b93612bafef494994e2dc116e4ae64f442585
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Fri Jan 6 14:19:09 2012 -0600
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri Apr 5 06:25:00 2013 -0700
fsck.gfs2: Print step 2 duplicate debug msg first
In testing fsck.gfs2 I noticed that when duplicates were resolved,
the "step 2" debug message was printed after step 2 was actually
done. That's misleading, so this patch changes it.
rhbz#877150
---
gfs2/fsck/pass1b.c | 8 ++++----
1 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index b296c54..f2922b6 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -657,15 +657,15 @@ static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *b)
* directory inode referencing a data block as a leaf block.
*/
if (!last_reference) {
- last_reference = resolve_dup_references(sdp, b,
- &b->ref_inode_list,
- &dh, 0,
- acceptable_ref);
log_debug( _("----------------------------------------------\n"
"Step 2: Eliminate references to block %llu "
"(0x%llx) that need the wrong block type.\n"),
(unsigned long long)b->block,
(unsigned long long)b->block);
+ last_reference = resolve_dup_references(sdp, b,
+ &b->ref_inode_list,
+ &dh, 0,
+ acceptable_ref);
}
/* Step 3 - We have multiple dinodes referencing it as the correct
* type. Just blast one of them.
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=f1918c89c393a…
Commit: f1918c89c393ac3ba79704d9cdb3948993d05c2a
Parent: bd252744f5297a2a2d38baa32cf21acf802fbc83
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Fri Jan 6 14:14:29 2012 -0600
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri Apr 5 06:25:00 2013 -0700
fsck.gfs2: system dinodes take priority over user dinodes
In testing fsck.gfs2 I noticed some incorrect behavior: If a block
was referenced incorrectly by two dinodes, fsck deleted which
ever reference it found first. Therefore, if a system dinode
and a user dinode referenced the same block, fsck.gfs2 could
mistakenly delete the system dinode. For example, a journal could
get deleted because a user dinode improperly referenced one of its
blocks. This patch gives priority to system dinodes when resolving
duplicates.
rhbz#877150
---
gfs2/fsck/pass1b.c | 9 ++++++++-
gfs2/fsck/util.c | 14 ++++++++++++--
2 files changed, 20 insertions(+), 3 deletions(-)
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index 6106d51..b296c54 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -498,7 +498,14 @@ static int resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *b,
continue; /* don't delete the dinode */
}
}
-
+ /* If this reference is from a system inode, for example, if
+ it's data or metadata inside a journal, the reference
+ should take priority over user dinodes that reference the
+ block. */
+ if (!found_good_ref && fsck_system_inode(sdp, id->block_no)) {
+ found_good_ref = 1;
+ continue; /* don't delete the dinode */
+ }
log_warn( _("Inode %s (%lld/0x%llx) references block "
"%llu (0x%llx) as '%s', but the block is "
"really %s.\n"),
diff --git a/gfs2/fsck/util.c b/gfs2/fsck/util.c
index f9260f6..84cecec 100644
--- a/gfs2/fsck/util.c
+++ b/gfs2/fsck/util.c
@@ -296,8 +296,18 @@ int add_duplicate_ref(struct gfs2_inode *ip, uint64_t block,
inode reference list otherwise put it on the normal list. */
if (!inode_valid || q == gfs2_inode_invalid)
osi_list_add_prev(&id->list, &dt->ref_invinode_list);
- else
- osi_list_add_prev(&id->list, &dt->ref_inode_list);
+ else {
+ /* If this is a system dinode, we want the duplicate
+ processing to find it first. That way references
+ from inside journals, et al, will take priority.
+ We don't want to delete journals in favor of dinodes
+ that reference a block inside a journal. */
+ if (fsck_system_inode(ip->i_sbd, id->block_no))
+ osi_list_add(&id->list, &dt->ref_inode_list);
+ else
+ osi_list_add_prev(&id->list,
+ &dt->ref_inode_list);
+ }
}
id->reftypecount[reftype]++;
id->dup_count++;
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=bd252744f5297…
Commit: bd252744f5297a2a2d38baa32cf21acf802fbc83
Parent: 96652b11c13dec9672162211d0c98bb7ec6b46b5
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Fri Jan 6 14:11:11 2012 -0600
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri Apr 5 06:25:00 2013 -0700
fsck.gfs2: Increment link count reporting wrong dinode
The output from fsck.gfs2 was wrong when it reported about a
link count change for lost+found. This patch fixes the message
so it reports the correct dinode block number.
rhbz#877150
---
gfs2/fsck/lost_n_found.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/gfs2/fsck/lost_n_found.c b/gfs2/fsck/lost_n_found.c
index fd3b689..b762f09 100644
--- a/gfs2/fsck/lost_n_found.c
+++ b/gfs2/fsck/lost_n_found.c
@@ -210,7 +210,7 @@ int add_inode_to_lf(struct gfs2_inode *ip){
/* If it's a directory, lost+found is back-linked to it via .. */
if (S_ISDIR(ip->i_di.di_mode))
incr_link_count(lf_dip->i_di.di_num.no_addr,
- ip->i_di.di_mode, _("to lost+found"));
+ ip->i_di.di_num.no_addr, _("to lost+found"));
log_notice( _("Added inode #%llu (0x%llx) to lost+found\n"),
(unsigned long long)ip->i_di.di_num.no_addr,
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=96652b11c13de…
Commit: 96652b11c13dec9672162211d0c98bb7ec6b46b5
Parent: b68d265afaa6120cfb7eb4450af2c3739e6d9d75
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Fri Jan 6 14:06:09 2012 -0600
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri Apr 5 06:25:00 2013 -0700
fsck.gfs2: Shorten debug output
This patch considerably shortens the debug output of fsck.gfs2 by
doing a few things. First, if fsck is just reporting the setting
of block types, it abbreviates the output by just listing other
blocks in parenthesis. Second, some of the key debug messages now give
only the block number in hexadecimal rather than both decimal and hex.
In one fsck.gfs2 run I did, it reduced the output from 32GB to 6.7GB.
rhbz#877150
---
gfs2/fsck/link.c | 38 ++++++++++++---------------
gfs2/fsck/metawalk.c | 69 ++++++++++++++++++++++++++++++++-----------------
gfs2/fsck/pass2.c | 6 ++--
3 files changed, 65 insertions(+), 48 deletions(-)
diff --git a/gfs2/fsck/link.c b/gfs2/fsck/link.c
index 4bb9aff..047ef05 100644
--- a/gfs2/fsck/link.c
+++ b/gfs2/fsck/link.c
@@ -48,22 +48,20 @@ int incr_link_count(uint64_t inode_no, uint64_t referenced_from,
struct inode_info *ii = NULL;
ii = inodetree_find(inode_no);
- /* If the list has entries, look for one that matches
- * inode_no */
+ /* If the list has entries, look for one that matches inode_no */
if (ii) {
ii->counted_links++;
- log_debug( _("Directory %lld (0x%llx) incremented counted "
- "links to %u for %"PRIu64" (0x%" PRIx64 ") "
- "via %s\n"),
+ log_debug( _("Dir (0x%llx) incremented counted "
+ "links to %u for (0x%llx) via %s\n"),
(unsigned long long)referenced_from,
- (unsigned long long)referenced_from,
- ii->counted_links, inode_no, inode_no, why);
+ ii->counted_links, (unsigned long long)inode_no,
+ why);
return 0;
}
- log_debug( _("Ref: %lld (0x%llx) No match found when incrementing "
- "link for %" PRIu64 " (0x%" PRIx64 ")!\n"),
+ log_debug( _("Ref: (0x%llx) No match found when incrementing "
+ "link for (0x%llx)!\n"),
(unsigned long long)referenced_from,
- (unsigned long long)referenced_from, inode_no, inode_no);
+ (unsigned long long)inode_no);
/* If no match was found, add a new entry and set its
* counted links to 1 */
ii = inodetree_insert(inode_no);
@@ -84,24 +82,22 @@ int decr_link_count(uint64_t inode_no, uint64_t referenced_from,
* inode_no */
if (ii) {
if (!ii->counted_links) {
- log_debug( _("Directory %lld (0x%llx)'s link to "
- " %"PRIu64" (0x%" PRIx64 ") via %s is zero!\n"),
- (unsigned long long)referenced_from,
+ log_debug( _("Dir (0x%llx)'s link to "
+ "(0x%llx) via %s is zero!\n"),
(unsigned long long)referenced_from,
- inode_no, inode_no, why);
+ (unsigned long long)inode_no, why);
return 0;
}
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,
+ log_debug( _("Dir (0x%llx) decremented counted "
+ "links to %u for (0x%llx) via %s\n"),
(unsigned long long)referenced_from,
- ii->counted_links, inode_no, inode_no, why);
+ ii->counted_links, (unsigned long long)inode_no,
+ why);
return 0;
}
- log_debug( _("No match found when decrementing link for %" PRIu64
- " (0x%" PRIx64 ")!\n"), inode_no, inode_no);
+ log_debug( _("No match found when decrementing link for (0x%llx)!\n"),
+ (unsigned long long)inode_no);
return -1;
}
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 4dd021f..a580867 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -111,36 +111,57 @@ int _fsck_blockmap_set(struct gfs2_inode *ip, uint64_t bblock,
const char *caller, int fline)
{
int error;
+ static int prev_ino_addr = 0;
+ static enum gfs2_mark_block prev_mark = 0;
+ static int prevcount = 0;
if (print_level >= MSG_DEBUG) {
+ if ((ip->i_di.di_num.no_addr == prev_ino_addr) &&
+ (mark == prev_mark)) {
+ log_info("(0x%llx) ", (unsigned long long)bblock);
+ prevcount++;
+ if (prevcount > 10) {
+ log_info("\n");
+ prevcount = 0;
+ }
/* 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, caller, fline,
- _("%s inode found at block "
- "0x%llx: marking as '%s'\n"),
- btype, (unsigned long long)
- ip->i_di.di_num.no_addr,
- block_type_string(mark));
+ } else if (ip->i_di.di_num.no_addr == bblock) {
+ if (prevcount) {
+ log_info("\n");
+ prevcount = 0;
+ }
+ printf( _("(%s:%d) %s inode found at block "
+ "(0x%llx): marking as '%s'\n"), caller, fline,
+ btype,
+ (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, caller, fline,
- _("inode 0x%llx references "
- "%s block 0x%llx: "
- "marking as '%s'\n"),
- (unsigned long long)
- ip->i_di.di_num.no_addr,
- btype, (unsigned long long)bblock,
- block_type_string(mark));
+ if (prevcount) {
+ log_info("\n");
+ prevcount = 0;
+ }
+ printf( _("(%s:%d) inode (0x%llx) references %s block"
+ " (0x%llx): marking as '%s'\n"),
+ caller, fline,
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ btype, (unsigned long long)bblock,
+ block_type_string(mark));
} else {
- print_fsck_log(MSG_DEBUG, caller, fline,
- _("inode 0x%llx references "
- "%s block 0x%llx: "
- "marking as '%s'\n"),
- (unsigned long long)
- ip->i_di.di_num.no_addr, btype,
- (unsigned long long)bblock,
- block_type_string(mark));
+ if (prevcount) {
+ log_info("\n");
+ prevcount = 0;
+ }
+ printf( _("(%s:%d) inode (0x%llx) references %s block"
+ " (0x%llx): marking as '%s'\n"),
+ caller, fline,
+ (unsigned long long)ip->i_di.di_num.no_addr,
+ btype, (unsigned long long)bblock,
+ block_type_string(mark));
}
+ prev_ino_addr = ip->i_di.di_num.no_addr;
+ prev_mark = mark;
}
/* First, check the rgrp bitmap against what we think it should be.
@@ -679,7 +700,7 @@ static int check_leaf_blks(struct gfs2_inode *ip, struct metawalk_fxns *pass)
if (!leaf.lf_next || error)
break;
leaf_no = leaf.lf_next;
- log_debug( _("Leaf chain 0x%llx detected.\n"),
+ log_debug( _("Leaf chain (0x%llx) detected.\n"),
(unsigned long long)leaf_no);
} while (1); /* while we have chained leaf blocks */
} /* for every leaf block */
diff --git a/gfs2/fsck/pass2.c b/gfs2/fsck/pass2.c
index 71f305f..33eb2d4 100644
--- a/gfs2/fsck/pass2.c
+++ b/gfs2/fsck/pass2.c
@@ -82,7 +82,7 @@ static int set_dotdot_dir(struct gfs2_sbd *sdp, uint64_t childblock,
}
if (di->dinode != childblock) {
log_debug("'..' doesn't point to what we found: childblock "
- "0x%llx != dinode 0x%llx\n",
+ "(0x%llx) != dinode (0x%llx)\n",
(unsigned long long)childblock,
(unsigned long long)di->dinode);
return -1;
@@ -99,8 +99,8 @@ static int set_dotdot_dir(struct gfs2_sbd *sdp, uint64_t childblock,
(unsigned long long)di->dotdot_parent);
return -1;
}
- log_debug("Setting '..' for directory block 0x%llx to parent 0x%llx\n",
- (unsigned long long)childblock,
+ log_debug("Setting '..' for directory block (0x%llx) to parent "
+ "(0x%llx)\n", (unsigned long long)childblock,
(unsigned long long)parentblock);
di->dotdot_parent = parentblock;
return 0;
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=b68d265afaa61…
Commit: b68d265afaa6120cfb7eb4450af2c3739e6d9d75
Parent: 304bce8e5d34fae0aea3d2438b65ba163001a806
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Fri Jan 6 13:55:38 2012 -0600
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri Apr 5 06:25:00 2013 -0700
libgfs2: Make rebuild functions not re-read ip
Before this patch, the libgfs2 rebuild functions in structures.c
were not consistent about reading in the gfs2_inode in-core struct.
Some of the functions did and some didn't. The previous patch to
make fsck.gfs2 operate on gfs1 introduced a problem because the code
was changed to re-read the inum and statfs files if they were rebuilt.
But since the functions already did the read, it was a double-read.
A double-read is a bad thing because inode writes are now done on
the last inode put, and the double-read messed up the counter.
(Number of inode gets should match puts). This patch makes all the
build functions consistent: they all put the inode after building,
except for root and master which have no parent inodes.
There was also a minor problem whereby leaf searches were getting
the number of entries from the directory buffer rather than from
the dinode itself. (The buffer may be out of date, but the dinode
should always be current). So there were circumstances where you
could add a new dirent to "master" but the count of entries was not
correct in the buffer, which caused the search to stop prematurely.
rhbz#877150
---
gfs2/convert/gfs2_convert.c | 3 +++
gfs2/fsck/initialize.c | 5 +++++
gfs2/libgfs2/fs_ops.c | 10 +++++-----
gfs2/libgfs2/structures.c | 4 ++--
gfs2/mkfs/main_mkfs.c | 2 ++
5 files changed, 17 insertions(+), 7 deletions(-)
diff --git a/gfs2/convert/gfs2_convert.c b/gfs2/convert/gfs2_convert.c
index b9e034c..d887838 100644
--- a/gfs2/convert/gfs2_convert.c
+++ b/gfs2/convert/gfs2_convert.c
@@ -2154,9 +2154,12 @@ int main(int argc, char **argv)
build_per_node(&sb2);
/* Create the empty inode number file */
build_inum(&sb2); /* Does not do inode_put */
+ gfs2_lookupi(sb2.master_dir, "inum", 4, &sb2.md.inum);
/* Create the statfs file */
build_statfs(&sb2); /* Does not do inode_put */
+ gfs2_lookupi(sb2.master_dir, "statfs", 6, &sb2.md.statfs);
+ do_init_statfs(&sb2);
/* Create the resource group index file */
build_rindex(&sb2);
/* Create the quota file */
diff --git a/gfs2/fsck/initialize.c b/gfs2/fsck/initialize.c
index 1db4ce6..150c586 100644
--- a/gfs2/fsck/initialize.c
+++ b/gfs2/fsck/initialize.c
@@ -380,6 +380,7 @@ static int rebuild_master(struct gfs2_sbd *sdp)
IF2DT(S_IFREG | 0600));
} else {
build_inum(sdp);
+ gfs2_lookupi(sdp->master_dir, "inum", 4, &sdp->md.inum);
}
if (fix_md.statfs) {
@@ -389,6 +390,7 @@ static int rebuild_master(struct gfs2_sbd *sdp)
IF2DT(S_IFREG | 0600));
} else {
build_statfs(sdp);
+ gfs2_lookupi(sdp->master_dir, "statfs", 6, &sdp->md.statfs);
}
if (fix_md.riinode) {
@@ -410,6 +412,8 @@ static int rebuild_master(struct gfs2_sbd *sdp)
}
log_err(_("Master directory rebuilt.\n"));
+ inode_put(&sdp->md.inum);
+ inode_put(&sdp->md.statfs);
inode_put(&sdp->master_dir);
return 0;
}
@@ -583,6 +587,7 @@ static int init_system_inodes(struct gfs2_sbd *sdp)
"valid statfs file; aborting.\n"));
return FSCK_ERROR;
}
+ do_init_statfs(sdp);
}
buf = malloc(sdp->md.statfs->i_di.di_size);
// FIXME: handle failed malloc
diff --git a/gfs2/libgfs2/fs_ops.c b/gfs2/libgfs2/fs_ops.c
index 6579d6f..0691956 100644
--- a/gfs2/libgfs2/fs_ops.c
+++ b/gfs2/libgfs2/fs_ops.c
@@ -1207,6 +1207,7 @@ static void dir_l_add(struct gfs2_inode *dip, const char *filename, int len,
dent->de_hash = cpu_to_be32(dent->de_hash);
dent->de_type = cpu_to_be16(type);
memcpy((char *)(dent + 1), filename, len);
+ bmodified(dip->i_bh);
}
void dir_add(struct gfs2_inode *dip, const char *filename, int len,
@@ -1356,10 +1357,9 @@ static int leaf_search(struct gfs2_inode *dip, struct gfs2_buffer_head *bh,
if (type == IS_LEAF){
struct gfs2_leaf *leaf = (struct gfs2_leaf *)bh->b_data;
entries = be16_to_cpu(leaf->lf_entries);
- } else if (type == IS_DINODE) {
- struct gfs2_dinode *dinode = (struct gfs2_dinode *)bh->b_data;
- entries = be32_to_cpu(dinode->di_entries);
- } else
+ } else if (type == IS_DINODE)
+ entries = dip->i_di.di_entries;
+ else
return -1;
hash = gfs2_disk_hash(filename, len);
@@ -1372,7 +1372,7 @@ static int leaf_search(struct gfs2_inode *dip, struct gfs2_buffer_head *bh,
if (be32_to_cpu(dent->de_hash) == hash &&
gfs2_filecmp(filename, (char *)(dent + 1),
- be16_to_cpu(dent->de_name_len))){
+ be16_to_cpu(dent->de_name_len))) {
*dent_out = dent;
if (dent_prev)
*dent_prev = prev;
diff --git a/gfs2/libgfs2/structures.c b/gfs2/libgfs2/structures.c
index 2a09214..b7851e8 100644
--- a/gfs2/libgfs2/structures.c
+++ b/gfs2/libgfs2/structures.c
@@ -297,7 +297,7 @@ int build_inum(struct gfs2_sbd *sdp)
gfs2_dinode_print(&ip->i_di);
}
- sdp->md.inum = ip;
+ inode_put(&ip);
return 0;
}
@@ -313,7 +313,7 @@ int build_statfs(struct gfs2_sbd *sdp)
gfs2_dinode_print(&ip->i_di);
}
- sdp->md.statfs = ip;
+ inode_put(&ip);
return 0;
}
diff --git a/gfs2/mkfs/main_mkfs.c b/gfs2/mkfs/main_mkfs.c
index 35d10ea..bfe6c45 100644
--- a/gfs2/mkfs/main_mkfs.c
+++ b/gfs2/mkfs/main_mkfs.c
@@ -422,7 +422,9 @@ main_mkfs(int argc, char *argv[])
build_jindex(sdp);
build_per_node(sdp);
build_inum(sdp);
+ gfs2_lookupi(sdp->master_dir, "inum", 4, &sdp->md.inum);
build_statfs(sdp);
+ gfs2_lookupi(sdp->master_dir, "statfs", 6, &sdp->md.statfs);
build_rindex(sdp);
build_quota(sdp);
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=f7bd730c35b34…
Commit: f7bd730c35b34d89d4e38d37d0148fb05997b596
Parent: 5fb6299352820a1809019915513585a2c09e9501
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Wed Aug 17 10:33:07 2011 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri Apr 5 06:25:00 2013 -0700
fsck.gfs2: Remove bad inodes from duplicate tree
The problem was that if an inode was determined to be "bad" (lots of
corruption) and its metadata blocks were invalidated in pass1, the
"bad" block for the inode was set as "data" in the bitmap. Later,
that caused duplicate reference processing (pass1b) to not remove the
block from the inode tree inside function check_n_fix_bitmap when the
bad block was freed. Later still, in pass4, that caused the now
deleted inode to be processed again, at which time it would reprocess
the inode's metadata and free all blocks, including blocks that were
duplicate-referenced by other inodes. In other words, pass4 freed
blocks out from under valid references when it should not have. This
patch changes the bitmap type for "bad" blocks from "data" to
"inode". That causes function check_n_fix_bitmap to try to remove the
bad block from the inode tree, so pass4 never processes it by mistake.
This patch also changes a few debug messages to make them shorter so
that the output files aren't as big to search through.
rhbz#877150
---
gfs2/fsck/metawalk.c | 20 ++++++--------------
gfs2/fsck/pass1.c | 8 ++++++--
2 files changed, 12 insertions(+), 16 deletions(-)
diff --git a/gfs2/fsck/metawalk.c b/gfs2/fsck/metawalk.c
index 1c06253..b7fff1c 100644
--- a/gfs2/fsck/metawalk.c
+++ b/gfs2/fsck/metawalk.c
@@ -117,36 +117,28 @@ int _fsck_blockmap_set(struct gfs2_inode *ip, uint64_t bblock,
output easier to debug. */
if (ip->i_di.di_num.no_addr == bblock) {
print_fsck_log(MSG_DEBUG, caller, fline,
- _("%s inode found at block %lld "
- "(0x%llx): marking as '%s'\n"),
+ _("%s inode found at block "
+ "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, caller, fline,
- _("inode %lld (0x%llx) references "
- "%s block %lld (0x%llx): "
+ _("inode 0x%llx references "
+ "%s block 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, caller, fline,
- _("inode %lld (0x%llx) references "
- "%s block %lld (0x%llx): "
+ _("inode 0x%llx references "
+ "%s block 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));
}
}
diff --git a/gfs2/fsck/pass1.c b/gfs2/fsck/pass1.c
index f92e29e..35c716f 100644
--- a/gfs2/fsck/pass1.c
+++ b/gfs2/fsck/pass1.c
@@ -387,8 +387,12 @@ static int check_metalist(struct gfs2_inode *ip, uint64_t block,
*bh = NULL;
if (!valid_block(ip->i_sbd, block)) { /* blk outside of FS */
+ /* The bad dinode should be invalidated later due to
+ "unrecoverable" errors. The inode itself should be
+ set "free" and removed from the inodetree by
+ undo_check_metalist. */
fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
- _("itself"), gfs2_bad_block);
+ _("bad block referencing"), gfs2_bad_block);
log_debug( _("Bad indirect block (invalid/out of range) "
"found in inode %lld (0x%llx).\n"),
(unsigned long long)ip->i_di.di_num.no_addr,
@@ -461,7 +465,7 @@ static int undo_check_metalist(struct gfs2_inode *ip, uint64_t block,
if (!valid_block(ip->i_sbd, block)) { /* blk outside of FS */
fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
- _("itself"), gfs2_block_free);
+ _("bad block referencing"), gfs2_block_free);
return 1;
}
if (S_ISDIR(ip->i_di.di_mode) && h == ip->i_di.di_height)
Gitweb: http://git.fedorahosted.org/git/?p=cluster.git;a=commitdiff;h=5fb6299352820…
Commit: 5fb6299352820a1809019915513585a2c09e9501
Parent: 1323d19acf8bfebd71050fa68431be073487f97f
Author: Bob Peterson <rpeterso(a)redhat.com>
AuthorDate: Thu Aug 11 12:25:38 2011 -0500
Committer: Bob Peterson <rpeterso(a)redhat.com>
CommitterDate: Fri Apr 5 06:25:00 2013 -0700
fsck.gfs2: four-step duplicate elimination process
This patch reforms the duplicate block reference processing by
introducing a new four-step duplicate elimination process.
Step 1. Delete inodes that reference the block and were previously
marked invalid.
Step 2. Delete inodes that reference the block as the wrong block
type. (Data block referenced as metadata, or vise versa)
Step 3. Delete inodes until we're down to a single reference.
Step 4. Fix the block type to be according to the remaining reference.
rhbz#877150
---
gfs2/fsck/pass1b.c | 280 ++++++++++++++++++++++++++++++++++++----------------
1 files changed, 196 insertions(+), 84 deletions(-)
diff --git a/gfs2/fsck/pass1b.c b/gfs2/fsck/pass1b.c
index 443daf5..5dd7579 100644
--- a/gfs2/fsck/pass1b.c
+++ b/gfs2/fsck/pass1b.c
@@ -28,6 +28,10 @@
#include "metawalk.h"
#include "inode_hash.h"
+const char *reftype_str[ref_types + 1] = {"data", "metadata",
+ "extended attribute",
+ "unimportant"};
+
struct fxn_info {
uint64_t block;
int found;
@@ -381,25 +385,38 @@ static int find_block_ref(struct gfs2_sbd *sdp, uint64_t inode)
return error;
}
+/* get_ref_type - figure out if all duplicate references from this inode
+ are the same type, and if so, return the type. */
+static enum dup_ref_type get_ref_type(struct inode_with_dups *id)
+{
+ if (id->reftypecount[ref_as_ea] &&
+ !id->reftypecount[ref_as_data] &&
+ !id->reftypecount[ref_as_meta])
+ return ref_as_ea;
+ if (!id->reftypecount[ref_as_ea] &&
+ id->reftypecount[ref_as_data] &&
+ !id->reftypecount[ref_as_meta])
+ return ref_as_data;
+ if (!id->reftypecount[ref_as_ea] &&
+ !id->reftypecount[ref_as_data] &&
+ id->reftypecount[ref_as_meta])
+ return ref_as_meta;
+ return ref_types; /* multiple references */
+}
+
static void log_inode_reference(struct duptree *b, osi_list_t *tmp, int inval)
{
char reftypestring[32];
struct inode_with_dups *id;
id = osi_list_entry(tmp, struct inode_with_dups, list);
- if (id->dup_count == 1) {
- if (id->reftypecount[ref_as_data])
- strcpy(reftypestring, "as data");
- else if (id->reftypecount[ref_as_meta])
- strcpy(reftypestring, "as metadata");
- else
- strcpy(reftypestring, "as extended attribute");
- } else {
+ if (id->dup_count == 1)
+ sprintf(reftypestring, "as %s", reftype_str[get_ref_type(id)]);
+ else
sprintf(reftypestring, "%d/%d/%d",
id->reftypecount[ref_as_data],
id->reftypecount[ref_as_meta],
id->reftypecount[ref_as_ea]);
- }
if (inval)
log_warn( _("Invalid "));
log_warn( _("Inode %s (%lld/0x%llx) has %d reference(s) to "
@@ -409,10 +426,22 @@ static void log_inode_reference(struct duptree *b, osi_list_t *tmp, int inval)
(unsigned long long)b->block,
(unsigned long long)b->block, reftypestring);
}
-
-static int clear_a_reference(struct gfs2_sbd *sdp, struct duptree *b,
- osi_list_t *ref_list, struct dup_handler *dh,
- int inval)
+/*
+ * resolve_dup_references - resolve all but the last dinode that has a
+ * duplicate reference to a given block.
+ *
+ * @sdp - pointer to the superblock structure
+ * @b - pointer to the duplicate reference rbtree to use
+ * @ref_list - list of duplicate references to be resolved (invalid or valid)
+ * @dh - duplicate handler
+ * inval - The references on this ref_list are invalid. We prefer to delete
+ * these first before resorting to deleting valid dinodes.
+ * acceptable_ref - Delete dinodes that reference the given block as anything
+ * _but_ this type. Try to save references as this type.
+ */
+static int resolve_dup_references(struct gfs2_sbd *sdp, struct duptree *b,
+ osi_list_t *ref_list, struct dup_handler *dh,
+ int inval, int acceptable_ref)
{
struct gfs2_inode *ip;
struct inode_with_dups *id;
@@ -428,26 +457,74 @@ static int clear_a_reference(struct gfs2_sbd *sdp, struct duptree *b,
.check_eattr_entry = clear_eattr_entry,
.check_eattr_extentry = clear_eattr_extentry,
};
+ enum dup_ref_type this_ref;
+ struct inode_info *ii;
+ int found_good_ref = 0;
osi_list_foreach_safe(tmp, ref_list, x) {
id = osi_list_entry(tmp, struct inode_with_dups, list);
dh->b = b;
dh->id = id;
+
if (dh->ref_inode_count == 1) /* down to the last reference */
return 1;
- if (!(query( _("Okay to clear %s inode %lld (0x%llx)? (y/n) "),
+
+ this_ref = get_ref_type(id);
+ if (inval)
+ log_warn( _("Invalid "));
+ /* FIXME: If we already found an acceptable reference to this
+ * block, we should really duplicate the block and fix all
+ * references to it in this inode. Unfortunately, we would
+ * have to traverse the entire metadata tree to do that. */
+ if (acceptable_ref != ref_types && /* If we're nuking all but
+ an acceptable reference
+ type and */
+ this_ref == acceptable_ref && /* this ref is acceptable */
+ !found_good_ref) { /* We haven't found a good reference */
+ uint8_t q;
+
+ /* If this is an invalid inode, but not on the invalid
+ list, it's better to delete it. */
+ q = block_type(id->block_no);
+ if (q != gfs2_inode_invalid) {
+ found_good_ref = 1;
+ continue; /* don't delete the dinode */
+ }
+ }
+
+ log_warn( _("Inode %s (%lld/0x%llx) references block "
+ "%llu (0x%llx) as '%s', but the block is "
+ "really %s.\n"),
+ id->name, (unsigned long long)id->block_no,
+ (unsigned long long)id->block_no,
+ (unsigned long long)b->block,
+ (unsigned long long)b->block,
+ reftype_str[this_ref],
+ reftype_str[acceptable_ref]);
+ if (!(query( _("Okay to delete %s inode %lld (0x%llx)? "
+ "(y/n) "),
(inval ? _("invalidated") : ""),
(unsigned long long)id->block_no,
(unsigned long long)id->block_no))) {
- log_warn( _("The bad inode was not cleared...\n"));
+ log_warn( _("The bad inode was not cleared."));
+ /* delete the list entry so we don't leak memory but
+ leave the reference count. If the decrement the
+ ref count, we could get down to 1 and the dinode
+ would be changed without a 'Yes' answer. */
+ /* (dh->ref_inode_count)--;*/
+ dup_listent_delete(id);
continue;
}
log_warn( _("Clearing inode %lld (0x%llx)...\n"),
(unsigned long long)id->block_no,
(unsigned long long)id->block_no);
+
+ ip = fsck_load_inode(sdp, id->block_no);
+ ii = inodetree_find(ip->i_di.di_num.no_addr);
+ if (ii)
+ inodetree_delete(ii);
clear_dup_fxns.private = (void *) dh;
/* Clear the EAs for the inode first */
- ip = fsck_load_inode(sdp, id->block_no);
check_inode_eattr(ip, &clear_dup_fxns);
/* If the dup wasn't only in the EA, clear the inode */
if (id->reftypecount[ref_as_data] ||
@@ -455,13 +532,14 @@ static int clear_a_reference(struct gfs2_sbd *sdp, struct duptree *b,
check_metatree(ip, &clear_dup_fxns);
fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
- _("bad"), gfs2_inode_invalid);
+ _("duplicate referencing bad"),
+ gfs2_inode_invalid);
fsck_inode_put(&ip); /* out, brelse, free */
(dh->ref_inode_count)--;
- /* Inode is marked invalid and is removed in pass2 */
/* FIXME: other option should be to duplicate the
* block for each duplicate and point the metadata at
* the cloned blocks */
+ dup_listent_delete(id);
}
if (dh->ref_inode_count == 1) /* down to the last reference */
return 1;
@@ -474,19 +552,56 @@ static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *b)
osi_list_t *tmp;
struct inode_with_dups *id;
struct dup_handler dh = {0};
- int last_reference, ref_in_invalid_inode = 0;
+ int last_reference = 0;
+ struct gfs2_buffer_head *bh;
+ uint32_t cmagic, ctype;
+ enum dup_ref_type acceptable_ref;
+ /* Count the duplicate references, both valid and invalid */
osi_list_foreach(tmp, &b->ref_invinode_list) {
id = osi_list_entry(tmp, struct inode_with_dups, list);
dh.ref_inode_count++;
dh.ref_count += id->dup_count;
- ref_in_invalid_inode = 1;
}
osi_list_foreach(tmp, &b->ref_inode_list) {
id = osi_list_entry(tmp, struct inode_with_dups, list);
dh.ref_inode_count++;
dh.ref_count += id->dup_count;
}
+
+ /* Log the duplicate references */
+ log_notice( _("Block %llu (0x%llx) has %d inodes referencing it"
+ " for a total of %d duplicate references:\n"),
+ (unsigned long long)b->block, (unsigned long long)b->block,
+ dh.ref_inode_count, dh.ref_count);
+
+ osi_list_foreach(tmp, &b->ref_invinode_list)
+ log_inode_reference(b, tmp, 1);
+ osi_list_foreach(tmp, &b->ref_inode_list)
+ log_inode_reference(b, tmp, 0);
+
+ /* Figure out the block type to see if we can eliminate references
+ to a different type. In other words, if the duplicate block looks
+ like metadata, we can delete dinodes that reference it as data.
+ If the block doesn't look like metadata, we can eliminate any
+ references to it as metadata. Dinodes with such references are
+ clearly corrupt and need to be deleted.
+ And if we're left with a single reference, problem solved. */
+ bh = bread(sdp, b->block);
+ cmagic = ((struct gfs2_meta_header *)(bh->b_data))->mh_magic;
+ ctype = ((struct gfs2_meta_header *)(bh->b_data))->mh_type;
+ brelse(bh);
+
+ if (be32_to_cpu(cmagic) == GFS2_MAGIC &&
+ (be32_to_cpu(ctype) == GFS2_METATYPE_EA ||
+ be32_to_cpu(ctype) == GFS2_METATYPE_ED))
+ acceptable_ref = ref_as_ea;
+ else if (be32_to_cpu(cmagic) == GFS2_MAGIC &&
+ be32_to_cpu(ctype) <= GFS2_METATYPE_QC)
+ acceptable_ref = ref_as_meta;
+ else
+ acceptable_ref = ref_as_data;
+
/* A single reference to the block implies a possible situation where
a data pointer points to a metadata block. In other words, the
duplicate reference in the file system is (1) Metadata block X and
@@ -500,75 +615,71 @@ static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *b)
invalidated for other reasons, such as bad pointers. So we need to
make sure at this point that any inode deletes reverse out any
duplicate reference before we get to this point. */
- if (dh.ref_count == 1) {
- struct gfs2_buffer_head *bh;
- uint32_t cmagic;
-
- bh = bread(sdp, b->block);
- cmagic = ((struct gfs2_meta_header *)(bh->b_data))->mh_magic;
- brelse(bh);
- if (be32_to_cpu(cmagic) == GFS2_MAGIC) {
- if (ref_in_invalid_inode)
- tmp = b->ref_invinode_list.next;
- else
- tmp = b->ref_inode_list.next;
- id = osi_list_entry(tmp, struct inode_with_dups, list);
- log_warn( _("Inode %s (%lld/0x%llx) has a reference to"
- " data block %llu (0x%llx), "
- "but the block is really metadata.\n"),
- id->name, (unsigned long long)id->block_no,
- (unsigned long long)id->block_no,
- (unsigned long long)b->block,
- (unsigned long long)b->block);
- if (query( _("Clear the inode? (y/n) "))) {
- struct inode_info *ii;
-
- log_warn( _("Clearing inode %lld (0x%llx)...\n"),
- (unsigned long long)id->block_no,
- (unsigned long long)id->block_no);
- ip = fsck_load_inode(sdp, id->block_no);
- ii = inodetree_find(ip->i_di.di_num.no_addr);
- if (ii)
- inodetree_delete(ii);
- /* Setting the block to invalid means the inode
- is cleared in pass2 */
- fsck_blockmap_set(ip, ip->i_di.di_num.no_addr,
- _("inode with bad duplicate"),
- gfs2_inode_invalid);
- fsck_inode_put(&ip);
- } else {
- log_warn( _("The bad inode was not cleared."));
- }
- return 0;
- }
- /* The other references may have been discredited due to
- invalid metadata or something. Use the last remaining. */
- log_notice( _("Block %llu (0x%llx) has only one remaining "
- "reference.\n"),
+ if (dh.ref_count == 1)
+ last_reference = 1;
+
+ /* Step 1 - eliminate references from inodes that are not valid.
+ * This may be because they were deleted due to corruption.
+ * All block types are unacceptable, so we use ref_types.
+ */
+ if (!last_reference) {
+ log_debug( _("----------------------------------------------\n"
+ "Step 1: Eliminate references to block %llu "
+ "(0x%llx) that were previously marked "
+ "invalid.\n"),
+ (unsigned long long)b->block,
+ (unsigned long long)b->block);
+ last_reference = resolve_dup_references(sdp, b,
+ &b->ref_invinode_list,
+ &dh, 1, ref_types);
+ }
+ /* Step 2 - eliminate reference from inodes that reference it as the
+ * wrong type. For example, a data file referencing it as
+ * a data block, but it's really a metadata block. Or a
+ * directory inode referencing a data block as a leaf block.
+ */
+ if (!last_reference) {
+ last_reference = resolve_dup_references(sdp, b,
+ &b->ref_inode_list,
+ &dh, 0,
+ acceptable_ref);
+ log_debug( _("----------------------------------------------\n"
+ "Step 2: Eliminate references to block %llu "
+ "(0x%llx) that need the wrong block type.\n"),
+ (unsigned long long)b->block,
+ (unsigned long long)b->block);
+ }
+ /* Step 3 - We have multiple dinodes referencing it as the correct
+ * type. Just blast one of them.
+ * All block types are fair game, so we use ref_types.
+ */
+ if (!last_reference) {
+ log_debug( _("----------------------------------------------\n"
+ "Step 3: Choose one reference to block %llu "
+ "(0x%llx) to keep.\n"),
+ (unsigned long long)b->block,
+ (unsigned long long)b->block);
+ last_reference = resolve_dup_references(sdp, b,
+ &b->ref_inode_list,
+ &dh, 0, ref_types);
+ }
+ /* Now fix the block type of the block in question. */
+ if (osi_list_empty(&b->ref_inode_list)) {
+ log_notice( _("Block %llu (0x%llx) has no more references; "
+ "Marking as 'free'.\n"),
(unsigned long long)b->block,
(unsigned long long)b->block);
+ gfs2_blockmap_set(bl, b->block, gfs2_block_free);
+ check_n_fix_bitmap(sdp, b->block, gfs2_block_free);
return 0;
}
-
- log_notice( _("Block %llu (0x%llx) has %d inodes referencing it"
- " for a total of %d duplicate references\n"),
- (unsigned long long)b->block, (unsigned long long)b->block,
- dh.ref_inode_count, dh.ref_count);
-
- osi_list_foreach(tmp, &b->ref_invinode_list)
- log_inode_reference(b, tmp, 1);
- osi_list_foreach(tmp, &b->ref_inode_list)
- log_inode_reference(b, tmp, 0);
-
- last_reference = clear_a_reference(sdp, b, &b->ref_invinode_list,
- &dh, 1);
- if (!last_reference)
- last_reference = clear_a_reference(sdp, b, &b->ref_inode_list,
- &dh, 0);
-
- if (last_reference && !osi_list_empty(&b->ref_inode_list)) {
+ if (last_reference) {
uint8_t q;
+ log_notice( _("Block %llu (0x%llx) has only one remaining "
+ "reference.\n"),
+ (unsigned long long)b->block,
+ (unsigned long long)b->block);
/* If we're down to a single reference (and not all references
deleted, which may be the case of an inode that has only
itself and a reference), we need to reset the block type
@@ -576,7 +687,8 @@ static int handle_dup_blk(struct gfs2_sbd *sdp, struct duptree *b)
in the list, not the structure's place holder. */
tmp = (&b->ref_inode_list)->next;
id = osi_list_entry(tmp, struct inode_with_dups, list);
- log_debug( _("Resetting the type based on the remaining "
+ log_debug( _("----------------------------------------------\n"
+ "Step 4. Set block type based on the remaining "
"reference in inode %lld (0x%llx).\n"),
(unsigned long long)id->block_no,
(unsigned long long)id->block_no);