[Ocfs2-tools-devel] [PATCH] fsck.ocfs2: detect and break chain loop
Xue jiufei
xuejiufei at huawei.com
Fri Dec 21 23:09:53 PST 2012
We have encontered a global_bitmap chain loop. There is a previous
discussion on this issue:
https://oss.oracle.com/pipermail/ocfs2-tools-devel/2010-March/002785.html.
Based on previous discussion, we make another patch to detect and break
chain loop in fsck.ocfs2. It has been tested and run correctly.
Signed-off-by: xuejiufei <xuejiufei at huawei.com>
---
fsck.ocfs2/pass0.c | 171 ++++++++++++++++++++++++++++++++++++++++++++++-----
1 files changed, 154 insertions(+), 17 deletions(-)
diff --git a/fsck.ocfs2/pass0.c b/fsck.ocfs2/pass0.c
index 0f6f14c..e6b21cf 100644
--- a/fsck.ocfs2/pass0.c
+++ b/fsck.ocfs2/pass0.c
@@ -665,6 +665,92 @@ out:
return ret;
}
+static errcode_t get_group_desc_next(o2fsck_state *ost, uint64_t blkno,
+ char *buf, uint64_t *next)
+{
+ struct ocfs2_group_desc *gd;
+ errcode_t ret = 0;
+
+ ret = ocfs2_read_group_desc(ost->ost_fs, blkno, buf);
+ if (ret)
+ return ret;
+
+ gd = (struct ocfs2_group_desc *)buf;
+ *next = gd->bg_next_group;
+
+ return ret;
+}
+
+static errcode_t break_chain_loop(o2fsck_state *ost, struct ocfs2_chain_rec *chain,
+ char *buf1, int *looped)
+{
+ char *buf;
+ uint64_t blkno = chain->c_blkno;
+ uint64_t slow_blkno, fast_blkno, prev_blkno, next = 0;
+ errcode_t ret = 0;
+
+ ret = ocfs2_malloc_block(ost->ost_fs->fs_io, &buf);
+ if (ret)
+ goto out;
+
+ slow_blkno = blkno;
+ fast_blkno = blkno;
+ prev_blkno = blkno;
+
+ while (1) {
+ if (fast_blkno && ((ret = get_group_desc_next(ost, fast_blkno, buf,
+ &next)) == 0) && next) {
+ fast_blkno = next;
+ ret = get_group_desc_next(ost, fast_blkno, buf, &next);
+ if (ret)
+ goto out;
+ fast_blkno = next;
+ }
+ else
+ break;
+
+ prev_blkno = slow_blkno;
+ ret = get_group_desc_next(ost, slow_blkno, buf, &next);
+ if (ret)
+ goto out;
+ slow_blkno = next;
+
+ if (fast_blkno == slow_blkno) {
+ *looped = 1;
+ break;
+ }
+ }
+
+ if (*looped) {
+ fast_blkno = blkno;
+
+ while (fast_blkno != slow_blkno) {
+ prev_blkno = slow_blkno;
+ ret = get_group_desc_next(ost, slow_blkno, buf, &next);
+ if (ret)
+ goto out;
+ slow_blkno = next;
+
+ ret = get_group_desc_next(ost, fast_blkno, buf, &next);
+ if (ret)
+ goto out;
+ fast_blkno = next;
+ }
+
+ ret = ocfs2_read_group_desc(ost->ost_fs, prev_blkno, buf);
+ if (ret)
+ goto out;
+
+ memcpy(buf1, buf, ost->ost_fs->fs_blocksize);
+ }
+
+out:
+ if (buf)
+ ocfs2_free(&buf);
+
+ return ret;
+}
+
/* this takes a slightly ridiculous number of arguments :/ */
static errcode_t check_chain(o2fsck_state *ost,
struct ocfs2_dinode *di,
@@ -675,19 +761,40 @@ static errcode_t check_chain(o2fsck_state *ost,
char *pre_cache_buf,
int *chain_changed,
ocfs2_bitmap *allowed,
- ocfs2_bitmap *forbidden)
+ ocfs2_bitmap *forbidden,
+ unsigned int max_chain_len)
{
struct ocfs2_group_desc *bg1 = (struct ocfs2_group_desc *)buf1;
struct ocfs2_group_desc *bg2 = (struct ocfs2_group_desc *)buf2;
uint64_t blkno;
errcode_t ret = 0;
- int depth = 0, clear_ref = 0;
+ int depth, clear_ref, looped;
int blocks_per_group = ocfs2_clusters_to_blocks(ost->ost_fs,
cs->cs_cpg);
+ ocfs2_bitmap *tmp = NULL;
verbosef("free %u total %u blkno %"PRIu64"\n", chain->c_free,
chain->c_total, (uint64_t)chain->c_blkno);
+ ret = ocfs2_block_bitmap_new(ost->ost_fs, "temporal group descriptors", &tmp);
+ if (ret) {
+ com_err(whoami, ret, "while allocating temporal descs "
+ "bitmap");
+ goto out;
+ }
+
+re_check:
+ depth = 0;
+ clear_ref = 0;
+ looped = 0;
+ cs->cs_free_bits = 0;
+ cs->cs_total_bits = 0;
+
+ for (blkno = ost->ost_fs->fs_first_cg_blkno;
+ !ocfs2_bitmap_find_next_set(tmp, blkno, &blkno);
+ blkno++)
+ o2fsck_bitmap_clear(tmp, blkno, NULL);
+
while(1) {
/* fetch the next reference */
if (depth == 0)
@@ -700,18 +807,9 @@ static errcode_t check_chain(o2fsck_state *ost,
* to the next group, implying that we've just
* decided that bg1 is valid. */
blkno = bg1->bg_blkno;
- if (allowed) {
- int was_set;
- ocfs2_bitmap_test(allowed, blkno, &was_set);
- if (was_set) {
- o2fsck_bitmap_clear(allowed, blkno,
- &was_set);
- mark_group_used(ost, cs, bg1->bg_blkno,
- allowed != NULL, bg1);
- } else if (forbidden)
- o2fsck_bitmap_set(forbidden, blkno,
- &was_set);
- } else
+ if (allowed || forbidden)
+ o2fsck_bitmap_set(tmp, blkno, NULL);
+ else
mark_group_used(ost, cs, bg1->bg_blkno,
allowed != NULL, bg1);
blkno = bg1->bg_next_group;
@@ -721,6 +819,17 @@ static errcode_t check_chain(o2fsck_state *ost,
if (blkno == 0)
break;
+ /* there exists a loop */
+ else if ((depth + 1) > max_chain_len) {
+ ret = break_chain_loop(ost, chain, buf1, &looped);
+ if (ret == 0 && looped) {
+ clear_ref = 1;
+ break;
+ }
+ else if (ret)
+ break;
+ }
+
/* is it even feasible? */
if (ocfs2_block_out_of_range(ost->ost_fs, blkno)) {
if (prompt(ost, PY, PR_CHAIN_LINK_RANGE,
@@ -826,6 +935,13 @@ static errcode_t check_chain(o2fsck_state *ost,
ost->ost_saw_error = 1;
}
}
+ /*
+ * If there exists a loop, cs_total_bits and cs_free_bits may
+ * be incorrect, we should recheck the chain
+ */
+ if (ret == 0 && looped) {
+ goto re_check;
+ }
}
if (cs->cs_total_bits != chain->c_total ||
@@ -845,7 +961,24 @@ static errcode_t check_chain(o2fsck_state *ost,
}
}
+ if (allowed) {
+ int was_set;
+ for (blkno = ost->ost_fs->fs_first_cg_blkno;
+ !ocfs2_bitmap_find_next_set(tmp, blkno, &blkno);
+ blkno++) {
+ ocfs2_bitmap_test(allowed, blkno, &was_set);
+ if (was_set) {
+ o2fsck_bitmap_clear(allowed, blkno,
+ &was_set);
+ mark_group_used(ost, cs, blkno, allowed !=NULL, NULL);
+ } else if (forbidden)
+ o2fsck_bitmap_set(forbidden, blkno, &was_set);
+ }
+ }
+
out:
+ if (tmp)
+ ocfs2_bitmap_free(tmp);
return ret;
}
@@ -866,6 +999,7 @@ static errcode_t verify_chain_alloc(o2fsck_state *ost,
int changed = 0, trust_next_free = 1;
errcode_t ret = 0;
uint64_t chain_bytes;
+ unsigned int num_gds, max_chain_len;
if (memcmp(di->i_signature, OCFS2_INODE_SIGNATURE,
strlen(OCFS2_INODE_SIGNATURE))) {
@@ -895,9 +1029,12 @@ static errcode_t verify_chain_alloc(o2fsck_state *ost,
/* XXX should we check suballoc_node? */
cl = &di->id2.i_chain;
+ num_gds = (di->i_clusters + cl->cl_cpg) / cl->cl_cpg;
+ max_chain_len = (num_gds + cl->cl_count) / cl->cl_count;
- verbosef("cl cpg %u bpc %u count %u next %u\n",
- cl->cl_cpg, cl->cl_bpc, cl->cl_count, cl->cl_next_free_rec);
+ verbosef("cl cpg %u bpc %u count %u next %u, gds %u, max chain length %u\n",
+ cl->cl_cpg, cl->cl_bpc, cl->cl_count, cl->cl_next_free_rec,
+ num_gds, max_chain_len);
max_count = ocfs2_chain_recs_per_inode(ost->ost_fs->fs_blocksize);
@@ -966,7 +1103,7 @@ static errcode_t verify_chain_alloc(o2fsck_state *ost,
.cs_cpg = cl->cl_cpg,
};
ret = check_chain(ost, di, &cs, cr, buf1, buf2, pre_cache_buf,
- &changed, allowed, forbidden);
+ &changed, allowed, forbidden, max_chain_len);
/* XXX what? not checking ret? */
if (cr->c_blkno != 0) {
--
1.7.8.6
More information about the Ocfs2-tools-devel
mailing list