[Ocfs2-tools-devel] [PATCH 2/2] looped chain - Break loop in fsck
Goldwyn Rodrigues
rgoldwyn at gmail.com
Tue Mar 2 15:29:17 PST 2010
Detects a loop by checking hops against the theoretical limit of
number of chains in a chain_rec. If a loop is found, it breaks it by
storing the block numbers, and comparing with existing block numbers.
Signed-off-by: Goldwyn Rodrigues <rgoldwyn at suse.de>
Acked-by: Mark Fasheh <mfasheh at suse.com>
---
diff --git a/fsck.ocfs2/fsck.ocfs2.checks.8.in b/fsck.ocfs2/fsck.ocfs2.checks.8.in
index 05561ae..798a1e4 100644
--- a/fsck.ocfs2/fsck.ocfs2.checks.8.in
+++ b/fsck.ocfs2/fsck.ocfs2.checks.8.in
@@ -202,6 +202,15 @@ valid in its bitmap.
Answering yes decreases the number of recorded free bits so that it equals
the total number of bits in the group descriptor's bitmap.
+.SS "CHAIN_LOOP"
+A chain may loop if the next field of the group descriptor points to one of
+the previous group descriptors in the chain. This causes the ocfs2 code, both
+user space and kernel module to loop forever.
+
+Answering yes breaks the loop at an optimum location so that all the existing
+group descriptors are in the chain. However, it cannot re-connect stray group
+descriptors and must rely on the rest of the fsck code to fix it.
+
.SS "CHAIN_COUNT"
The chain list embedded in an inode is limited by the block size and the
number of bytes consumed by the rest of the inode. A chain list header was
diff --git a/fsck.ocfs2/pass0.c b/fsck.ocfs2/pass0.c
index a32bd18..1b59cc1 100644
--- a/fsck.ocfs2/pass0.c
+++ b/fsck.ocfs2/pass0.c
@@ -455,6 +455,46 @@ out:
return ret;
}
+static errcode_t break_loop(o2fsck_state *ost, struct ocfs2_chain_rec *chain,
+ unsigned int max_depth)
+{
+ uint64_t *list;
+ int i;
+ unsigned int depth = 0;
+ uint64_t blkno = chain->c_blkno;
+ char *buf;
+ struct ocfs2_group_desc *gd;
+ errcode_t ret = ocfs2_malloc0(sizeof(uint64_t) * max_depth, &list);
+ if (ret)
+ goto out;
+ ret = ocfs2_malloc_block(ost->ost_fs->fs_io, &buf);
+ if (ret)
+ goto out;
+ gd = (struct ocfs2_group_desc *)buf;
+
+ while (blkno && (depth<=max_depth)) {
+ list[depth++] = blkno;
+ ret = ocfs2_read_group_desc(ost->ost_fs, blkno, buf);
+ if (ret)
+ goto out;
+ blkno = gd->bg_next_group;
+ for (i=0; i<depth; i++)
+ if (list[i]==blkno) {
+ gd->bg_next_group = 0;
+ verbosef("Breaking gd loop %"PRIu64"\n", blkno);
+ ret = ocfs2_write_group_desc(ost->ost_fs,
+ blkno, buf);
+ goto out;
+ }
+ }
+out:
+ if (list)
+ ocfs2_free(&list);
+ 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,
@@ -465,7 +505,8 @@ 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_depth)
{
struct ocfs2_group_desc *bg1 = (struct ocfs2_group_desc *)buf1;
struct ocfs2_group_desc *bg2 = (struct ocfs2_group_desc *)buf2;
@@ -593,6 +634,14 @@ static errcode_t check_chain(o2fsck_state *ost,
/* the loop will now start by reading bg1->next_group */
memcpy(buf1, buf2, ost->ost_fs->fs_blocksize);
depth++;
+ if (depth > max_depth) {
+ if (prompt(ost, PY, PR_CHAIN_LOOP,
+ "Loop detected in chain %d at block %"PRIu64
+ ". Break the loop?",cs->cs_chain_no,
+ (uint64_t) chain->c_blkno))
+ ret = break_loop(ost, chain, max_depth);
+ break;
+ }
}
/* we hit the premature end of a chain.. clear the last
@@ -656,6 +705,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))) {
@@ -685,9 +735,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_ch_len %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);
@@ -756,7 +809,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) {
More information about the Ocfs2-tools-devel
mailing list