diff --git a/0001-fswreck-Create-a-loop-in-group-chains.patch b/0001-fswreck-Create-a-loop-in-group-chains.patch new file mode 100644 index 0000000..a3faf51 --- /dev/null +++ b/0001-fswreck-Create-a-loop-in-group-chains.patch @@ -0,0 +1,68 @@ +From 57a0a528f35d2b540d4ed533b6274586056664ce Mon Sep 17 00:00:00 2001 +From: Goldwyn Rodrigues +Date: Thu, 20 Sep 2012 19:39:17 -0500 +Subject: [PATCH 1/2] fswreck: Create a loop in group chains + +--- + fswreck/corrupt.c | 3 +++ + fswreck/group.c | 6 ++++++ + fswreck/include/fsck_type.h | 1 + + fswreck/main.c | 2 ++ + 4 files changed, 12 insertions(+) + +Index: ocfs2-tools/fswreck/corrupt.c +=================================================================== +--- ocfs2-tools.orig/fswreck/corrupt.c 2012-08-24 10:02:19.000000000 -0500 ++++ ocfs2-tools/fswreck/corrupt.c 2012-09-25 11:12:35.000000000 -0500 +@@ -331,6 +331,9 @@ void corrupt_group_desc(ocfs2_filesys *f + case GROUP_FREE_BITS: + func = mess_up_group_minor; + break; ++ case GROUP_CHAIN_LOOP: ++ func = mess_up_group_minor; ++ break; + case GROUP_GEN: + func = mess_up_group_gen; + break; +Index: ocfs2-tools/fswreck/group.c +=================================================================== +--- ocfs2-tools.orig/fswreck/group.c 2012-08-24 10:02:19.000000000 -0500 ++++ ocfs2-tools/fswreck/group.c 2012-09-25 11:12:35.000000000 -0500 +@@ -176,6 +176,12 @@ static void damage_group_desc(ocfs2_file + bg->bg_chain, (bg->bg_chain + 10)); + bg->bg_chain += 10; + break; ++ case GROUP_CHAIN_LOOP: ++ fprintf(stdout, "Corrput GROUP_LOOP: " ++ "change group next from %"PRIu64" to %"PRIu64"\n", ++ bg->bg_next_group, cr->c_blkno); ++ bg->bg_next_group = cpu_to_le64(cr->c_blkno); ++ break; + case GROUP_FREE_BITS: + fprintf(stdout, "Corrput GROUP_FREE_BITS: " + "change group free bits from %u to %u\n", +Index: ocfs2-tools/fswreck/include/fsck_type.h +=================================================================== +--- ocfs2-tools.orig/fswreck/include/fsck_type.h 2012-08-24 10:02:19.000000000 -0500 ++++ ocfs2-tools/fswreck/include/fsck_type.h 2012-09-25 11:12:35.000000000 -0500 +@@ -57,6 +57,7 @@ enum fsck_type + GROUP_BLKNO, + GROUP_CHAIN, + GROUP_FREE_BITS, ++ GROUP_CHAIN_LOOP, + CHAIN_COUNT, + CHAIN_NEXT_FREE, + CHAIN_EMPTY, +Index: ocfs2-tools/fswreck/main.c +=================================================================== +--- ocfs2-tools.orig/fswreck/main.c 2012-08-24 10:02:19.000000000 -0500 ++++ ocfs2-tools/fswreck/main.c 2012-09-25 11:12:35.000000000 -0500 +@@ -102,6 +102,8 @@ static struct prompt_code prompt_codes[N + "Corrupt chain group's blkno"), + define_prompt_code(GROUP_CHAIN, corrupt_group_desc, "", 1, + "Corrupt chain group's chain where it was in"), ++ define_prompt_code(GROUP_CHAIN_LOOP, corrupt_group_desc, "", 1, ++ "Corrupt group's chain to form a loop"), + define_prompt_code(GROUP_FREE_BITS, corrupt_group_desc, "", 1, + "Corrupt chain group's free bits"), + define_prompt_code(CHAIN_COUNT, corrupt_sys_file, "", 1, diff --git a/0002-Break-a-chain-loop-in-group-desc.patch b/0002-Break-a-chain-loop-in-group-desc.patch new file mode 100644 index 0000000..3ebbc2a --- /dev/null +++ b/0002-Break-a-chain-loop-in-group-desc.patch @@ -0,0 +1,156 @@ +From 16f191550058a768935cab2fe575c48e64eba334 Mon Sep 17 00:00:00 2001 +From: Goldwyn Rodrigues +Date: Thu, 20 Sep 2012 20:12:14 -0500 +Subject: [PATCH 2/2] Break a chain loop in group desc + +This patch detects and 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 exiting block +numbers. +--- + fsck.ocfs2/fsck.ocfs2.checks.8.in | 9 ++++++ + fsck.ocfs2/pass0.c | 61 ++++++++++++++++++++++++++++++++++--- + include/ocfs2-kernel/ocfs2_fs.h | 2 +- + 3 files changed, 67 insertions(+), 5 deletions(-) + +Index: ocfs2-tools/fsck.ocfs2/fsck.ocfs2.checks.8.in +=================================================================== +--- ocfs2-tools.orig/fsck.ocfs2/fsck.ocfs2.checks.8.in 2012-09-25 11:12:57.000000000 -0500 ++++ ocfs2-tools/fsck.ocfs2/fsck.ocfs2.checks.8.in 2012-09-25 11:13:03.000000000 -0500 +@@ -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 "GROUP_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 +Index: ocfs2-tools/fsck.ocfs2/pass0.c +=================================================================== +--- ocfs2-tools.orig/fsck.ocfs2/pass0.c 2012-09-25 11:12:57.000000000 -0500 ++++ ocfs2-tools/fsck.ocfs2/pass0.c 2012-09-25 11:13:03.000000000 -0500 +@@ -666,6 +666,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; ibg_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, +@@ -675,7 +715,8 @@ static errcode_t check_chain(o2fsck_stat + char *buf2, + 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; +@@ -792,6 +833,14 @@ static errcode_t check_chain(o2fsck_stat + /* 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_GROUP_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 +@@ -854,6 +903,7 @@ static errcode_t verify_chain_alloc(o2fs + 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))) { +@@ -883,9 +933,12 @@ static errcode_t verify_chain_alloc(o2fs + /* 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); + +@@ -948,7 +1001,7 @@ static errcode_t verify_chain_alloc(o2fs + .cs_cpg = cl->cl_cpg, + }; + ret = check_chain(ost, di, &cs, cr, buf1, buf2, &changed, +- allowed, forbidden); ++ allowed, forbidden, max_chain_len); + /* XXX what? not checking ret? */ + + if (cr->c_blkno != 0) { +Index: ocfs2-tools/include/ocfs2-kernel/ocfs2_fs.h +=================================================================== +--- ocfs2-tools.orig/include/ocfs2-kernel/ocfs2_fs.h 2012-09-25 11:12:57.000000000 -0500 ++++ ocfs2-tools/include/ocfs2-kernel/ocfs2_fs.h 2012-09-25 11:13:03.000000000 -0500 +@@ -1685,7 +1685,7 @@ static inline int ocfs2_sprintf_system_i + } + + static inline void ocfs2_set_de_type(struct ocfs2_dir_entry *de, +- umode_t mode) ++ unsigned short mode) + { + de->file_type = ocfs2_type_by_mode[(mode & S_IFMT)>>S_SHIFT]; + } diff --git a/ocfs2-tools.changes b/ocfs2-tools.changes index 986659d..a5cd5fa 100644 --- a/ocfs2-tools.changes +++ b/ocfs2-tools.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Tue Sep 25 11:24:55 CDT 2012 - rgoldwyn@suse.de + +- Fix infinite loop while checking for group desc chains + (bnc#781122) + ------------------------------------------------------------------- Fri Aug 24 12:12:32 CDT 2012 - rgoldwyn@suse.de diff --git a/ocfs2-tools.spec b/ocfs2-tools.spec index 8fc146e..dbdd87f 100644 --- a/ocfs2-tools.spec +++ b/ocfs2-tools.spec @@ -52,6 +52,8 @@ Patch204: dont-use-var-lock-subsys.patch Patch205: ocfs2-tools-kernel33.patch Patch206: ocfs2-tools-resource.patch Patch207: fix-indexed-dirs.patch +Patch208: 0001-fswreck-Create-a-loop-in-group-chains.patch +Patch209: 0002-Break-a-chain-loop-in-group-desc.patch Url: http://oss.oracle.com/projects/ocfs2-tools/ Requires: /sbin/chkconfig Requires: e2fsprogs @@ -129,6 +131,8 @@ managing the file system. %patch205 -p1 %patch206 -p1 %patch207 -p1 +%patch208 -p1 +%patch209 -p1 %build export CFLAGS="${CFLAGS} ${RPM_OPT_FLAGS}"