diff --git a/e2fsck/e2fsck.c b/e2fsck/e2fsck.c index dd8150be..6fb2f40a 100644 --- a/e2fsck/e2fsck.c +++ b/e2fsck/e2fsck.c @@ -209,8 +209,6 @@ static pass_t e2fsck_passes[] = { e2fsck_pass1, e2fsck_pass1e, e2fsck_pass2, e2fsck_pass3, e2fsck_pass4, e2fsck_pass5, 0 }; -#define E2F_FLAG_RUN_RETURN (E2F_FLAG_SIGNAL_MASK|E2F_FLAG_RESTART) - int e2fsck_run(e2fsck_t ctx) { int i; diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h index 48d4a29d..33b43476 100644 --- a/e2fsck/e2fsck.h +++ b/e2fsck/e2fsck.h @@ -175,10 +175,10 @@ struct resource_track { */ #define E2F_FLAG_ABORT 0x0001 /* Abort signaled */ #define E2F_FLAG_CANCEL 0x0002 /* Cancel signaled */ -#define E2F_FLAG_SIGNAL_MASK 0x0003 +#define E2F_FLAG_SIGNAL_MASK (E2F_FLAG_ABORT | E2F_FLAG_CANCEL) #define E2F_FLAG_RESTART 0x0004 /* Restart signaled */ +#define E2F_FLAG_RUN_RETURN (E2F_FLAG_SIGNAL_MASK | E2F_FLAG_RESTART) #define E2F_FLAG_RESTART_LATER 0x0008 /* Restart after all iterations done */ - #define E2F_FLAG_SETJMP_OK 0x0010 /* Setjmp valid for abort */ #define E2F_FLAG_PROG_BAR 0x0020 /* Progress bar on screen */ diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c index 0a8e23ec..5a8d4a19 100644 --- a/e2fsck/pass1.c +++ b/e2fsck/pass1.c @@ -482,6 +482,10 @@ static void check_inode_extra_space(e2fsck_t ctx, struct problem_context *pctx) return; } + /* check if there is no place for an EA header */ + if (inode->i_extra_isize >= max - sizeof(__u32)) + return; + eamagic = (__u32 *) (((char *) inode) + EXT2_GOOD_OLD_INODE_SIZE + inode->i_extra_isize); if (*eamagic == EXT2_EXT_ATTR_MAGIC) { @@ -1166,7 +1170,7 @@ void e2fsck_pass1(e2fsck_t ctx) pass1_readahead(ctx, &ra_group, &ino_threshold); ehandler_operation(old_op); if (ctx->flags & E2F_FLAG_SIGNAL_MASK) - return; + goto endit; if (pctx.errcode == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) { /* * If badblocks says badblocks is bad, offer to clear @@ -1847,6 +1851,8 @@ endit: if ((ctx->flags & E2F_FLAG_SIGNAL_MASK) == 0) print_resource_track(ctx, _("Pass 1"), &rtrack, ctx->fs->io); + else + ctx->invalid_bitmaps++; } #undef FINISH_INODE_LOOP @@ -2820,7 +2826,20 @@ static void check_blocks_extents(e2fsck_t ctx, struct problem_context *pctx, ext2_ino_t ino = pctx->ino; errcode_t retval; blk64_t eof_lblk; + struct ext3_extent_header *eh; + /* Check for a proper extent header... */ + eh = (struct ext3_extent_header *) &inode->i_block[0]; + retval = ext2fs_extent_header_verify(eh, sizeof(inode->i_block)); + if (retval) { + if (fix_problem(ctx, PR_1_MISSING_EXTENT_HEADER, pctx)) + e2fsck_clear_inode(ctx, ino, inode, 0, + "check_blocks_extents"); + pctx->errcode = 0; + return; + } + + /* ...since this function doesn't fail if i_block is zeroed. */ pctx->errcode = ext2fs_extent_open2(fs, ino, inode, &ehandle); if (pctx->errcode) { if (fix_problem(ctx, PR_1_READ_EXTENT, pctx)) diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c index 532b0ebd..6a7215ad 100644 --- a/e2fsck/pass2.c +++ b/e2fsck/pass2.c @@ -161,14 +161,14 @@ void e2fsck_pass2(e2fsck_t ctx) check_dir_func = cd.ra_entries ? check_dir_block2 : check_dir_block; cd.pctx.errcode = ext2fs_dblist_iterate2(fs->dblist, check_dir_func, &cd); - if (ctx->flags & E2F_FLAG_SIGNAL_MASK || ctx->flags & E2F_FLAG_RESTART) - return; - if (ctx->flags & E2F_FLAG_RESTART_LATER) { ctx->flags |= E2F_FLAG_RESTART; - return; + ctx->flags &= ~E2F_FLAG_RESTART_LATER; } + if (ctx->flags & E2F_FLAG_RUN_RETURN) + return; + if (cd.pctx.errcode) { fix_problem(ctx, PR_2_DBLIST_ITERATE, &cd.pctx); ctx->flags |= E2F_FLAG_ABORT; @@ -922,7 +922,7 @@ static int check_dir_block(ext2_filsys fs, ibuf = buf = cd->buf; ctx = cd->ctx; - if (ctx->flags & E2F_FLAG_SIGNAL_MASK || ctx->flags & E2F_FLAG_RESTART) + if (ctx->flags & E2F_FLAG_RUN_RETURN) return DIRENT_ABORT; if (ctx->progress && (ctx->progress)(ctx, 2, cd->count++, cd->max)) diff --git a/e2fsck/problem.c b/e2fsck/problem.c index f761ec98..a7da94dc 100644 --- a/e2fsck/problem.c +++ b/e2fsck/problem.c @@ -1114,6 +1114,11 @@ static struct e2fsck_problem problem_table[] = { N_("@i %i on bigalloc @f cannot be @b mapped. "), PROMPT_FIX, 0 }, + /* Inode has corrupt extent header */ + { PR_1_MISSING_EXTENT_HEADER, + N_("@i %i has corrupt @x header. "), + PROMPT_CLEAR_INODE, 0 }, + /* Pass 1b errors */ /* Pass 1B: Rescan for duplicate/bad blocks */ diff --git a/e2fsck/problem.h b/e2fsck/problem.h index 2ff0f5ef..3b92e411 100644 --- a/e2fsck/problem.h +++ b/e2fsck/problem.h @@ -651,6 +651,9 @@ struct problem_context { /* bigalloc fs cannot have blockmap files */ #define PR_1_NO_BIGALLOC_BLOCKMAP_FILES 0x010080 +/* Missing extent header */ +#define PR_1_MISSING_EXTENT_HEADER 0x010081 + /* * Pass 1b errors */ diff --git a/e2fsck/rehash.c b/e2fsck/rehash.c index 15d3dd93..1285adb0 100644 --- a/e2fsck/rehash.c +++ b/e2fsck/rehash.c @@ -71,6 +71,8 @@ int e2fsck_dir_will_be_rehashed(e2fsck_t ctx, ext2_ino_t ino) return ext2fs_u32_list_test(ctx->dirs_to_hash, ino); } +#undef REHASH_DEBUG + struct fill_dir_struct { char *buf; struct ext2_inode *inode; @@ -684,8 +686,8 @@ static errcode_t calculate_tree(ext2_filsys fs, struct write_dir_struct { struct out_dir *outdir; errcode_t err; + ext2_ino_t ino; e2fsck_t ctx; - blk64_t cleared; ext2_ino_t dir; }; @@ -703,10 +705,15 @@ static int write_dir_block(ext2_filsys fs, blk64_t blk; char *dir, *buf = 0; - if (*block_nr == 0) - return 0; - if (blockcnt < 0) +#ifdef REHASH_DEBUG + printf("%u: write_dir_block %lld:%lld", wd->ino, blockcnt, *block_nr); +#endif + if ((*block_nr == 0) || (blockcnt < 0)) { +#ifdef REHASH_DEBUG + printf(" - skip\n"); +#endif return 0; + } if (blockcnt < wd->outdir->num) dir = wd->outdir->buf + (blockcnt * fs->blocksize); else if (wd->ctx->lost_and_found == wd->dir) { @@ -717,26 +724,20 @@ static int write_dir_block(ext2_filsys fs, dir = buf; wd->outdir->num++; } else { - /* We don't need this block, so release it */ - e2fsck_read_bitmaps(wd->ctx); - blk = *block_nr; - /* - * In theory, we only release blocks from the end of the - * directory file, so it's fine to clobber a whole cluster at - * once. - */ - if (blk % EXT2FS_CLUSTER_RATIO(fs) == 0) { - ext2fs_block_alloc_stats2(fs, blk, -1); - wd->cleared++; - } - *block_nr = 0; - return BLOCK_CHANGED; + /* Don't free blocks at the end of the directory, they + * will be truncated by the caller. */ +#ifdef REHASH_DEBUG + printf(" - not freed\n"); +#endif + return 0; } - wd->err = ext2fs_write_dir_block4(fs, *block_nr, dir, 0, wd->dir); if (buf) ext2fs_free_mem(&buf); +#ifdef REHASH_DEBUG + printf(" - write (%d)\n", wd->err); +#endif if (wd->err) return BLOCK_ABORT; return 0; @@ -756,11 +757,11 @@ static errcode_t write_directory(e2fsck_t ctx, ext2_filsys fs, wd.outdir = outdir; wd.err = 0; + wd.ino = ino; wd.ctx = ctx; - wd.cleared = 0; wd.dir = ino; - retval = ext2fs_block_iterate3(fs, ino, 0, 0, + retval = ext2fs_block_iterate3(fs, ino, 0, NULL, write_dir_block, &wd); if (retval) return retval; @@ -772,14 +773,17 @@ static errcode_t write_directory(e2fsck_t ctx, ext2_filsys fs, inode->i_flags &= ~EXT2_INDEX_FL; else inode->i_flags |= EXT2_INDEX_FL; - retval = ext2fs_inode_size_set(fs, inode, - outdir->num * fs->blocksize); +#ifdef REHASH_DEBUG + printf("%u: set inode size to %u blocks = %u bytes\n", + ino, outdir->num, outdir->num * fs->blocksize); +#endif + retval = ext2fs_inode_size_set(fs, inode, (ext2_off64_t)outdir->num * + fs->blocksize); if (retval) return retval; - ext2fs_iblk_sub_blocks(fs, inode, wd.cleared); - e2fsck_write_inode(ctx, ino, inode, "rehash_dir"); - return 0; + /* ext2fs_punch() calls ext2fs_write_inode() which writes the size */ + return ext2fs_punch(fs, ino, inode, NULL, outdir->num, ~0ULL); } errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino, @@ -789,12 +793,9 @@ errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino, errcode_t retval; struct ext2_inode inode; char *dir_buf = 0; - struct fill_dir_struct fd; - struct out_dir outdir; + struct fill_dir_struct fd = { NULL }; + struct out_dir outdir = { 0 }; - outdir.max = outdir.num = 0; - outdir.buf = 0; - outdir.hashes = 0; e2fsck_read_inode(ctx, ino, &inode, "rehash_dir"); if (ext2fs_has_feature_inline_data(fs->super) && @@ -802,24 +803,19 @@ errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino, return 0; retval = ENOMEM; - fd.harray = 0; dir_buf = malloc(inode.i_size); if (!dir_buf) goto errout; fd.max_array = inode.i_size / 32; - fd.num_array = 0; fd.harray = malloc(fd.max_array * sizeof(struct hash_entry)); if (!fd.harray) goto errout; + fd.ino = ino; fd.ctx = ctx; fd.buf = dir_buf; fd.inode = &inode; - fd.ino = ino; - fd.err = 0; - fd.dir_size = 0; - fd.compress = 0; fd.dir = ino; if (!ext2fs_has_feature_dir_index(fs->super) || (inode.i_size / fs->blocksize) < 2) diff --git a/e2fsck/unix.c b/e2fsck/unix.c index bb25f291..51bcd69d 100644 --- a/e2fsck/unix.c +++ b/e2fsck/unix.c @@ -1819,8 +1819,15 @@ print_unsupp_features: } no_journal: - if (ctx->qctx) { + if (run_result & E2F_FLAG_ABORT) { + fatal_error(ctx, _("aborted")); + } else if (run_result & E2F_FLAG_CANCEL) { + log_out(ctx, _("%s: e2fsck canceled.\n"), ctx->device_name ? + ctx->device_name : ctx->filesystem_name); + exit_value |= FSCK_CANCELED; + } else if (ctx->qctx && !ctx->invalid_bitmaps) { int i, needs_writeout; + for (i = 0; i < MAXQUOTAS; i++) { if (qtype != -1 && qtype != i) continue; @@ -1847,18 +1854,13 @@ no_journal: ext2fs_close_free(&ctx->fs); goto restart; } - if (run_result & E2F_FLAG_ABORT) - fatal_error(ctx, _("aborted")); #ifdef MTRACE mtrace_print("Cleanup"); #endif was_changed = ext2fs_test_changed(fs); - if (run_result & E2F_FLAG_CANCEL) { - log_out(ctx, _("%s: e2fsck canceled.\n"), ctx->device_name ? - ctx->device_name : ctx->filesystem_name); - exit_value |= FSCK_CANCELED; - } else if (!(ctx->options & E2F_OPT_READONLY)) { + if (!(ctx->flags & E2F_FLAG_RUN_RETURN) && + !(ctx->options & E2F_OPT_READONLY)) { if (ext2fs_test_valid(fs)) { if (!(sb->s_state & EXT2_VALID_FS)) exit_value |= FSCK_NONDESTRUCT; diff --git a/lib/ext2fs/punch.c b/lib/ext2fs/punch.c index db4aa191..85f45d4b 100644 --- a/lib/ext2fs/punch.c +++ b/lib/ext2fs/punch.c @@ -48,7 +48,7 @@ static int check_zero_block(char *buf, int blocksize) */ static errcode_t ind_punch(ext2_filsys fs, struct ext2_inode *inode, char *block_buf, blk_t *p, int level, - blk_t start, blk_t count, int max) + blk64_t start, blk64_t count, int max) { errcode_t retval; blk_t b; @@ -57,11 +57,11 @@ static errcode_t ind_punch(ext2_filsys fs, struct ext2_inode *inode, int freed = 0; #ifdef PUNCH_DEBUG - printf("Entering ind_punch, level %d, start %u, count %u, " + printf("Entering ind_punch, level %d, start %llu, count %llu, " "max %d\n", level, start, count, max); #endif - incr = 1ULL << ((EXT2_BLOCK_SIZE_BITS(fs->super)-2)*level); - for (i=0, offset=0; i < max; i++, p++, offset += incr) { + incr = 1ULL << ((EXT2_BLOCK_SIZE_BITS(fs->super) - 2) * level); + for (i = 0, offset = 0; i < max; i++, p++, offset += incr) { if (offset >= start + count) break; if (*p == 0 || (offset+incr) <= start) @@ -101,8 +101,9 @@ static errcode_t ind_punch(ext2_filsys fs, struct ext2_inode *inode, return ext2fs_iblk_sub_blocks(fs, inode, freed); } +#define BLK_T_MAX ((blk_t)~0ULL) static errcode_t ext2fs_punch_ind(ext2_filsys fs, struct ext2_inode *inode, - char *block_buf, blk_t start, blk_t count) + char *block_buf, blk64_t start, blk64_t end) { errcode_t retval; char *buf = 0; @@ -111,6 +112,15 @@ static errcode_t ext2fs_punch_ind(ext2_filsys fs, struct ext2_inode *inode, blk_t *bp = inode->i_block; blk_t addr_per_block; blk64_t max = EXT2_NDIR_BLOCKS; + blk_t count; + + /* Check start/end don't overflow the 2^32-1 indirect block limit */ + if (start > BLK_T_MAX) + return 0; + if (end >= BLK_T_MAX || end - start + 1 >= BLK_T_MAX) + count = BLK_T_MAX - start; + else + count = end - start + 1; if (!block_buf) { retval = ext2fs_get_array(3, fs->blocksize, &buf); @@ -119,11 +129,11 @@ static errcode_t ext2fs_punch_ind(ext2_filsys fs, struct ext2_inode *inode, block_buf = buf; } - addr_per_block = (blk_t) fs->blocksize >> 2; + addr_per_block = (blk_t)fs->blocksize >> 2; for (level = 0; level < 4; level++, max *= (blk64_t)addr_per_block) { #ifdef PUNCH_DEBUG - printf("Main loop level %d, start %u count %u " + printf("Main loop level %d, start %llu count %u " "max %llu num %d\n", level, start, count, max, num); #endif if (start < max) { @@ -150,6 +160,7 @@ errout: ext2fs_free_mem(&buf); return retval; } +#undef BLK_T_MAX #ifdef PUNCH_DEBUG @@ -460,8 +471,8 @@ static errcode_t ext2fs_punch_inline_data(ext2_filsys fs, ext2_ino_t ino, } /* - * Deallocate all logical blocks starting at start to end, inclusive. - * If end is ~0, then this is effectively truncate. + * Deallocate all logical _blocks_ starting at start to end, inclusive. + * If end is ~0ULL, then this is effectively truncate. */ errcode_t ext2fs_punch(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode, @@ -485,19 +496,14 @@ errcode_t ext2fs_punch(ext2_filsys fs, ext2_ino_t ino, return ext2fs_punch_inline_data(fs, ino, inode, start, end); else if (inode->i_flags & EXT4_EXTENTS_FL) retval = ext2fs_punch_extent(fs, ino, inode, start, end); - else { - blk_t count; - - if (start > ~0U) - return 0; - if (end > ~0U) - end = ~0U; - count = ((end - start + 1) < ~0U) ? (end - start + 1) : ~0U; - retval = ext2fs_punch_ind(fs, inode, block_buf, - (blk_t) start, count); - } + else + retval = ext2fs_punch_ind(fs, inode, block_buf, start, end); if (retval) return retval; +#ifdef PUNCH_DEBUG + printf("%u: write inode size now %u blocks %u\n", + ino, inode->i_size, inode->i_blocks); +#endif return ext2fs_write_inode(fs, ino, inode); } diff --git a/lib/ext2fs/tst_badblocks.c b/lib/ext2fs/tst_badblocks.c index 3b39ef13..c685f33c 100644 --- a/lib/ext2fs/tst_badblocks.c +++ b/lib/ext2fs/tst_badblocks.c @@ -30,11 +30,11 @@ #define DEL_BLK 0x0002 blk_t test1[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0 }; -blk_t test2[] = { 11, 10, 9, 8, 7, 6, 5, 4, 3, 3, 2, 1 }; +blk_t test2[] = { 11, 10, 9, 8, 7, 6, 5, 4, 3, 3, 2, 1, 0 }; blk_t test3[] = { 3, 1, 4, 5, 9, 2, 7, 10, 5, 6, 10, 8, 0 }; blk_t test4[] = { 20, 50, 12, 17, 13, 2, 66, 23, 56, 0 }; blk_t test4a[] = { - 20, 1, + 20, 1, 50, 1, 3, 0, 17, 1, diff --git a/misc/chattr.1.in b/misc/chattr.1.in index 33ef9a20..1d6b057a 100644 --- a/misc/chattr.1.in +++ b/misc/chattr.1.in @@ -93,7 +93,7 @@ set on new or empty files. If it is set on a file which already has data blocks, it is undefined when the blocks assigned to the file will be fully stable. If the 'C' flag is set on a directory, it will have no effect on the directory, but new files created in that directory will -the No_COW attribute.) +have the No_COW attribute set.) .PP A file with the 'd' attribute set is not candidate for backup when the .BR dump (8) diff --git a/misc/tune2fs.c b/misc/tune2fs.c index 8bde640d..4d573996 100644 --- a/misc/tune2fs.c +++ b/misc/tune2fs.c @@ -3070,6 +3070,18 @@ retry_open: ext_mount_opts); free(ext_mount_opts); } + + /* Warn if file system needs recovery and it is opened for writing. */ + if ((open_flag & EXT2_FLAG_RW) && !(mount_flags & EXT2_MF_MOUNTED) && + (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) && + (sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER)) { + fprintf(stderr, +_("Warning: The journal is dirty. You may wish to replay the journal like:\n\n" + "\te2fsck -E journal_only %s\n\n" + "then rerun this command. Otherwise, any changes made may be overwritten\n" + "by journal recovery.\n"), device_name); + } + free(device_name); remove_error_table(&et_ext2_error_table); diff --git a/tests/f_extent_htree/expect.1 b/tests/f_extent_htree/expect.1 new file mode 100644 index 00000000..223ca697 --- /dev/null +++ b/tests/f_extent_htree/expect.1 @@ -0,0 +1,29 @@ +Pass 1: Checking inodes, blocks, and sizes +Pass 2: Checking directory structure +Pass 3: Checking directory connectivity +Pass 3A: Optimizing directories +Pass 4: Checking reference counts +Pass 5: Checking group summary information + +test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** + + 352 inodes used (41.12%, out of 856) + 0 non-contiguous files (0.0%) + 1 non-contiguous directory (0.3%) + # of inodes with ind/dind/tind blocks: 0/0/0 + Extent depth histogram: 342/1 + 586 blocks used (68.94%, out of 850) + 0 bad blocks + 0 large files + + 340 regular files + 3 directories + 0 character device files + 0 block device files + 0 fifos + 0 links + 0 symbolic links (0 fast symbolic links) + 0 sockets +------------ + 343 files +Exit status is 1 diff --git a/tests/f_extent_htree/expect.2 b/tests/f_extent_htree/expect.2 new file mode 100644 index 00000000..860b491e --- /dev/null +++ b/tests/f_extent_htree/expect.2 @@ -0,0 +1,7 @@ +Pass 1: Checking inodes, blocks, and sizes +Pass 2: Checking directory structure +Pass 3: Checking directory connectivity +Pass 4: Checking reference counts +Pass 5: Checking group summary information +test_filesys: 352/856 files (0.3% non-contiguous), 586/850 blocks +Exit status is 0 diff --git a/tests/f_extent_htree/image.gz b/tests/f_extent_htree/image.gz new file mode 100644 index 00000000..284207ef Binary files /dev/null and b/tests/f_extent_htree/image.gz differ diff --git a/tests/f_extent_htree/name b/tests/f_extent_htree/name new file mode 100644 index 00000000..fc3812d5 --- /dev/null +++ b/tests/f_extent_htree/name @@ -0,0 +1 @@ +htree extent compression diff --git a/tests/f_extent_htree/script b/tests/f_extent_htree/script new file mode 100644 index 00000000..60854c65 --- /dev/null +++ b/tests/f_extent_htree/script @@ -0,0 +1,69 @@ +#!/bin/bash + +FSCK_OPT="-fyvD" +. $cmd_dir/run_e2fsck + +exit $? +# This script depends on "mke2fs -d", which is only in master and not maint, +# to populate the file directory tree poorly (namely that there are no +# contiguous blocks in the directory leaf and the extent tree is large). + +# Once the "mke2fs -d" option is available on the "maint" branch, the +# above few lines should be deleted, along with the "image.gz" file. + +TMPDIR=${TMPDIR:-"/tmp"} +OUT=$test_name.log + +FSCK_OPT="-fyvD" +SKIP_GUNZIP="true" + +NAMELEN=250 +SRC=$TMPDIR/$test_name.tmp +SUB=subdir +BASE=$SRC/$SUB/$(yes | tr -d '\n' | dd bs=$NAMELEN count=1 2> /dev/null) +TMPFILE=${TMPFILE:-"$TMPDIR/image"} +BSIZE=1024 + +> $OUT +mkdir -p $SRC/$SUB +# calculate the number of files needed to create the directory extent tree +# deep enough to exceed the in-inode index and spill into an index block. +# +# dirents per block * extents per block * (index blocks > i_blocks) +NUM=$(((BSIZE / (NAMELEN + 8)) * (BSIZE / 12) * 2)) +# Create source files. Unfortunately hard links will be copied as links, +# and blocks with only NULs will be turned into holes. +if [ ! -f $BASE.1 ]; then + for N in $(seq $NUM); do + echo "foo" > $BASE.$N + done >> $OUT +fi + +# make filesystem with enough inodes and blocks to hold all the test files +> $TMPFILE +NUM=$((NUM * 5 / 3)) +echo "mke2fs -b $BSIZE -O dir_index,extent -d$SRC -N$NUM $TMPFILE $NUM" >> $OUT +$MKE2FS -b $BSIZE -O dir_index,extent -d$SRC -N$NUM $TMPFILE $NUM >> $OUT 2>&1 +rm -r $SRC + +# Run e2fsck to convert dir to htree before deleting the files, as mke2fs +# doesn't do this. Run second e2fsck to verify there is no corruption yet. +( + EXP1=$test_dir/expect.pre.1 + EXP2=$test_dir/expect.pre.2 + OUT1=$test_name.pre.1.log + OUT2=$test_name.pre.2.log + DESCRIPTION="$(cat $test_dir/name) setup" + . $cmd_dir/run_e2fsck +) + +# generate a list of filenames for debugfs to delete, one from each leaf block +DELETE_LIST=$TMPDIR/delete.$$ +$DEBUGFS -c -R "htree subdir" $TMPFILE 2>> $OUT | + grep -A2 "Reading directory block" | + awk '/yyyyy/ { print "rm '$SUB'/"$4 }' > $DELETE_LIST +$DEBUGFS -w -f $DELETE_LIST $TMPFILE >> $OUT 2>&1 +rm $DELETE_LIST +cp $TMPFILE $TMPFILE.sav + +. $cmd_dir/run_e2fsck diff --git a/tests/f_extents/expect.1 b/tests/f_extents/expect.1 index e9d9e5b3..da65f949 100644 --- a/tests/f_extents/expect.1 +++ b/tests/f_extents/expect.1 @@ -27,8 +27,7 @@ Inode 17 extent tree (at level 1) could be shorter. Fix? yes Inode 17, i_blocks is 32, should be 0. Fix? yes -Error while reading over extent tree in inode 18: Corrupt extent header -Clear inode? yes +Inode 18 has corrupt extent header. Clear inode? yes Inode 18, i_blocks is 2, should be 0. Fix? yes diff --git a/tests/f_h_badnode/expect.1 b/tests/f_h_badnode/expect.1 index ce2adb3f..95b1cee8 100644 --- a/tests/f_h_badnode/expect.1 +++ b/tests/f_h_badnode/expect.1 @@ -14,5 +14,5 @@ Pass 4: Checking reference counts Pass 5: Checking group summary information test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** -test_filesys: 47730/100192 files (0.0% non-contiguous), 13551/31745 blocks +test_filesys: 47730/100192 files (0.0% non-contiguous), 13550/31745 blocks Exit status is 1 diff --git a/tests/f_h_badnode/expect.2 b/tests/f_h_badnode/expect.2 index b9dadb73..65985d14 100644 --- a/tests/f_h_badnode/expect.2 +++ b/tests/f_h_badnode/expect.2 @@ -3,5 +3,5 @@ Pass 2: Checking directory structure Pass 3: Checking directory connectivity Pass 4: Checking reference counts Pass 5: Checking group summary information -test_filesys: 47730/100192 files (0.0% non-contiguous), 13551/31745 blocks +test_filesys: 47730/100192 files (0.0% non-contiguous), 13550/31745 blocks Exit status is 0 diff --git a/tests/f_zeroed_ext_header/expect.1 b/tests/f_zeroed_ext_header/expect.1 new file mode 100644 index 00000000..2613e9ff --- /dev/null +++ b/tests/f_zeroed_ext_header/expect.1 @@ -0,0 +1,22 @@ +Pass 1: Checking inodes, blocks, and sizes +Inode 12 has corrupt extent header. Clear inode? yes + +Pass 2: Checking directory structure +Entry 'testa' in / (2) has deleted/unused inode 12. Clear? yes + +Pass 3: Checking directory connectivity +Pass 4: Checking reference counts +Pass 5: Checking group summary information +Inode bitmap differences: -12 +Fix? yes + +Free inodes count wrong for group #0 (115, counted=116). +Fix? yes + +Free inodes count wrong (115, counted=116). +Fix? yes + + +test_filesys: ***** FILE SYSTEM WAS MODIFIED ***** +test_filesys: 12/128 files (0.0% non-contiguous), 15/256 blocks +Exit status is 1 diff --git a/tests/f_zeroed_ext_header/expect.2 b/tests/f_zeroed_ext_header/expect.2 new file mode 100644 index 00000000..177288fb --- /dev/null +++ b/tests/f_zeroed_ext_header/expect.2 @@ -0,0 +1,7 @@ +Pass 1: Checking inodes, blocks, and sizes +Pass 2: Checking directory structure +Pass 3: Checking directory connectivity +Pass 4: Checking reference counts +Pass 5: Checking group summary information +test_filesys: 12/128 files (0.0% non-contiguous), 15/256 blocks +Exit status is 0 diff --git a/tests/f_zeroed_ext_header/image.gz b/tests/f_zeroed_ext_header/image.gz new file mode 100644 index 00000000..67a43341 Binary files /dev/null and b/tests/f_zeroed_ext_header/image.gz differ diff --git a/tests/f_zeroed_ext_header/name b/tests/f_zeroed_ext_header/name new file mode 100644 index 00000000..31394cf5 --- /dev/null +++ b/tests/f_zeroed_ext_header/name @@ -0,0 +1 @@ +zap inode with zeroed extent header