From: Theodore Ts'o Date: Mon, 30 Nov 2015 23:16:36 +0000 (-0500) Subject: Merge branch 'maint' into next X-Git-Tag: v1.43-WIP-2016-03-15~41 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=94676ef2b30d80c11008f0e13c77029e286bd0d7;p=thirdparty%2Fe2fsprogs.git Merge branch 'maint' into next --- 94676ef2b30d80c11008f0e13c77029e286bd0d7 diff --cc e2fsck/e2fsck.c index dd8150be6,2002dc00a..6fb2f40a3 --- a/e2fsck/e2fsck.c +++ b/e2fsck/e2fsck.c @@@ -206,11 -200,9 +206,9 @@@ void e2fsck_free_context(e2fsck_t ctx typedef void (*pass_t)(e2fsck_t ctx); static pass_t e2fsck_passes[] = { - e2fsck_pass1, e2fsck_pass2, e2fsck_pass3, e2fsck_pass4, - e2fsck_pass5, 0 }; + 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 --cc e2fsck/pass1.c index 0a8e23ece,2370bb0e7..5a8d4a198 --- a/e2fsck/pass1.c +++ b/e2fsck/pass1.c @@@ -1162,43 -768,10 +1166,43 @@@ void e2fsck_pass1(e2fsck_t ctx old_op = ehandler_operation(_("getting next inode from scan")); pctx.errcode = ext2fs_get_next_inode_full(scan, &ino, inode, inode_size); + if (ino > ino_threshold) + 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 + * the list, update the in-core bb list, and restart + * the inode scan. + */ + if (ino == EXT2_BAD_INO && + fix_problem(ctx, PR_1_BADBLOCKS_IN_BADBLOCKS, + &pctx)) { + errcode_t err; + + e2fsck_clear_inode(ctx, ino, inode, 0, "pass1"); + ext2fs_badblocks_list_free(ctx->fs->badblocks); + ctx->fs->badblocks = NULL; + err = ext2fs_read_bb_inode(ctx->fs, + &ctx->fs->badblocks); + if (err) { + fix_problem(ctx, PR_1_ISCAN_ERROR, + &pctx); + ctx->flags |= E2F_FLAG_ABORT; + goto endit; + } + err = ext2fs_inode_scan_goto_blockgroup(scan, + 0); + if (err) { + fix_problem(ctx, PR_1_ISCAN_ERROR, + &pctx); + ctx->flags |= E2F_FLAG_ABORT; + goto endit; + } + continue; + } if (!ctx->inode_bb_map) alloc_bb_map(ctx); ext2fs_mark_inode_bitmap2(ctx->inode_bb_map, ino); @@@ -1839,16 -1279,11 +1843,18 @@@ endit if (inode) ext2fs_free_mem(&inode); + /* + * The l+f inode may have been cleared, so zap it now and + * later passes will recalculate it if necessary + */ + ctx->lost_and_found = 0; + 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 /* * When the inode_scan routines call this callback at the end of the diff --cc e2fsck/pass2.c index 532b0ebd9,b8f7e33a4..6a7215add --- a/e2fsck/pass2.c +++ b/e2fsck/pass2.c @@@ -155,20 -143,19 +155,20 @@@ void e2fsck_pass2(e2fsck_t ctx if (ctx->progress) (void) (ctx->progress)(ctx, 2, 0, cd.max); - if (fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) + if (ext2fs_has_feature_dir_index(fs->super)) ext2fs_dblist_sort2(fs->dblist, special_dir_block_cmp); - cd.pctx.errcode = ext2fs_dblist_iterate2(fs->dblist, check_dir_block, + 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; @@@ -910,19 -734,12 +910,19 @@@ static int check_dir_block(ext2_filsys struct problem_context pctx; int dups_found = 0; int ret; + int dx_csum_size = 0, de_csum_size = 0; + int failed_csum = 0; + int is_leaf = 1; + size_t inline_data_size = 0; + int filetype = 0; + int encrypted = 0; + size_t max_block_size; cd = (struct check_dir_struct *) priv_data; - buf = cd->buf; + 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 --cc e2fsck/problem.c index f761ec98f,e78314817..a7da94dc1 --- a/e2fsck/problem.c +++ b/e2fsck/problem.c @@@ -1053,67 -987,11 +1053,72 @@@ static struct e2fsck_problem problem_ta N_("@i %i logical @b %b (physical @b %c) violates cluster allocation rules.\nWill fix in pass 1B.\n"), PROMPT_NONE, 0 }, + /* Inode has INLINE_DATA_FL flag but extended attribute not found */ + { PR_1_INLINE_DATA_NO_ATTR, + N_("@i %i has INLINE_DATA_FL flag but @a not found. "), + PROMPT_TRUNCATE, 0 }, + + /* Extents/inlinedata flag set on a device or socket inode */ + { PR_1_SPECIAL_EXTENTS_IDATA, + N_("Special (@v/socket/fifo) file (@i %i) has extents\n" + "or inline-data flag set. "), + PROMPT_CLEAR, PR_PREEN_OK | PR_PREEN_NO | PR_NO_OK }, + + /* Inode has extent header but inline data flag is set */ + { PR_1_CLEAR_INLINE_DATA_FOR_EXTENT, + N_("@i %i has @x header but inline data flag is set.\n"), + PROMPT_FIX, 0 }, + + /* Inode seems to have inline data but extent flag is set */ + { PR_1_CLEAR_EXTENT_FOR_INLINE_DATA, + N_("@i %i seems to have inline data but @x flag is set.\n"), + PROMPT_FIX, 0 }, + + /* Inode seems to have block map but inline data and extent flags set */ + { PR_1_CLEAR_EXTENT_INLINE_DATA_FLAGS, + N_("@i %i seems to have @b map but inline data and @x flags set.\n"), + PROMPT_FIX, 0 }, + + /* Inode has inline data and extent flags but i_block contains junk */ + { PR_1_CLEAR_EXTENT_INLINE_DATA_INODE, + N_("@i %i has inline data and @x flags set but i_block contains junk.\n"), + PROMPT_CLEAR_INODE, 0 }, + + /* Bad block list says the bad block list inode is bad */ + { PR_1_BADBLOCKS_IN_BADBLOCKS, + N_("Bad block list says the bad block list @i is bad. "), + PROMPT_CLEAR_INODE, 0 }, + + /* Error allocating extent region allocation structure */ + { PR_1_EXTENT_ALLOC_REGION_ABORT, + N_("@A @x region allocation structure. "), + PROMPT_NONE, PR_FATAL}, + + /* Inode has a duplicate extent mapping */ + { PR_1_EXTENT_COLLISION, + N_("@i %i has a duplicate @x mapping\n\t(logical @b %c, @n physical @b %b, len %N)\n"), + PROMPT_CLEAR, 0 }, + + /* Error allocating memory for encrypted directory list */ + { PR_1_ALLOCATE_ENCRYPTED_DIRLIST, + N_("@A memory for encrypted @d list\n"), + PROMPT_NONE, PR_FATAL }, + + /* Inode extent tree could be more shallow */ + { PR_1_EXTENT_BAD_MAX_DEPTH, + N_("@i %i @x tree could be more shallow (%b; could be <= %c)\n"), + PROMPT_FIX, PR_NO_OK | PR_PREEN_NO | PR_PREEN_OK }, + + /* Inode extent tree could be more shallow */ + { PR_1_NO_BIGALLOC_BLOCKMAP_FILES, + 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 --cc e2fsck/rehash.c index 15d3dd937,52d99a3cc..1285adb0e --- a/e2fsck/rehash.c +++ b/e2fsck/rehash.c @@@ -52,25 -52,8 +52,27 @@@ #include "e2fsck.h" #include "problem.h" +/* Schedule a dir to be rebuilt during pass 3A. */ +void e2fsck_rehash_dir_later(e2fsck_t ctx, ext2_ino_t ino) +{ + if (!ctx->dirs_to_hash) + ext2fs_u32_list_create(&ctx->dirs_to_hash, 50); + if (ctx->dirs_to_hash) + ext2fs_u32_list_add(ctx->dirs_to_hash, ino); +} + +/* Ask if a dir will be rebuilt during pass 3A. */ +int e2fsck_dir_will_be_rehashed(e2fsck_t ctx, ext2_ino_t ino) +{ + if (ctx->options & E2F_OPT_COMPRESS_DIRS) + return 1; + if (!ctx->dirs_to_hash) + return 0; + return ext2fs_u32_list_test(ctx->dirs_to_hash, ino); +} + + #undef REHASH_DEBUG + struct fill_dir_struct { char *buf; struct ext2_inode *inode; @@@ -684,9 -628,8 +686,9 @@@ static errcode_t calculate_tree(ext2_fi 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; }; /* @@@ -701,42 -644,37 +703,41 @@@ static int write_dir_block(ext2_filsys { struct write_dir_struct *wd = (struct write_dir_struct *) priv_data; blk64_t blk; - char *dir; + 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) { ++ if ((*block_nr == 0) || (blockcnt < 0)) { + #ifdef REHASH_DEBUG + printf(" - skip\n"); + #endif return 0; + } - /* Don't free blocks at the end of the directory, they will be - * truncated by the caller. */ - if (blockcnt >= wd->outdir->num) { + if (blockcnt < wd->outdir->num) + dir = wd->outdir->buf + (blockcnt * fs->blocksize); + else if (wd->ctx->lost_and_found == wd->dir) { + /* Don't release any extra directory blocks for lost+found */ + wd->err = ext2fs_new_dir_block(fs, 0, 0, &buf); + if (wd->err) + return BLOCK_ABORT; + 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; } - - if (blockcnt < 0) { -#ifdef REHASH_DEBUG - printf(" - skip\n"); -#endif - return 0; - } + wd->err = ext2fs_write_dir_block4(fs, *block_nr, dir, 0, wd->dir); + if (buf) + ext2fs_free_mem(&buf); - dir = wd->outdir->buf + (blockcnt * fs->blocksize); - wd->err = ext2fs_write_dir_block3(fs, *block_nr, dir, 0); + #ifdef REHASH_DEBUG + printf(" - write (%d)\n", wd->err); + #endif if (wd->err) return BLOCK_ABORT; return 0; @@@ -756,53 -694,46 +757,52 @@@ static errcode_t write_directory(e2fsck 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; if (wd.err) return wd.err; - e2fsck_read_inode(ctx, ino, &inode, "rehash_dir"); + e2fsck_read_inode(ctx, ino, inode, "rehash_dir"); if (compress) - inode.i_flags &= ~EXT2_INDEX_FL; + inode->i_flags &= ~EXT2_INDEX_FL; else - inode.i_flags |= EXT2_INDEX_FL; + 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 * ++ 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); ++ return ext2fs_punch(fs, ino, inode, NULL, outdir->num, ~0ULL); } -errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino) +errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino, + struct problem_context *pctx) { ext2_filsys fs = ctx->fs; 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) && + (inode.i_flags & EXT4_INLINE_DATA_FL)) + return 0; + retval = ENOMEM; - fd.harray = 0; dir_buf = malloc(inode.i_size); if (!dir_buf) goto errout; @@@ -816,12 -747,7 +816,8 @@@ fd.ctx = ctx; fd.buf = dir_buf; fd.inode = &inode; - fd.ino = ino; - fd.err = 0; - fd.dir_size = 0; - fd.compress = 0; - if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) || + fd.dir = ino; + if (!ext2fs_has_feature_dir_index(fs->super) || (inode.i_size / fs->blocksize) < 2) fd.compress = 1; fd.parent = 0; diff --cc lib/ext2fs/punch.c index db4aa1915,62ddd50aa..85f45d4bc --- a/lib/ext2fs/punch.c +++ b/lib/ext2fs/punch.c @@@ -433,35 -439,10 +444,35 @@@ errout ext2fs_extent_free(handle); return retval; } + +static errcode_t ext2fs_punch_inline_data(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode, + blk64_t start, + blk64_t end EXT2FS_ATTR((unused))) +{ + errcode_t retval; + + /* + * In libext2fs ext2fs_punch is based on block unit. So that + * means that if start > 0 we don't need to do nothing. Due + * to this we will remove all inline data in ext2fs_punch() + * now. + */ + if (start > 0) + return 0; + + memset((char *)inode->i_block, 0, EXT4_MIN_INLINE_DATA_SIZE); + inode->i_size = 0; + retval = ext2fs_write_inode(fs, ino, inode); + if (retval) + return retval; + + return ext2fs_inline_data_ea_remove(fs, 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, @@@ -481,21 -462,10 +492,12 @@@ return retval; inode = &inode_buf; } - if (inode->i_flags & EXT4_EXTENTS_FL) + if (inode->i_flags & EXT4_INLINE_DATA_FL) + 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; diff --cc tests/f_extents/expect.1 index e9d9e5b3f,882c321b6..da65f9496 --- a/tests/f_extents/expect.1 +++ b/tests/f_extents/expect.1 @@@ -23,12 -15,9 +23,11 @@@ Inode 17 has an invalid exten (logical block 0, invalid physical block 22011707397135, len 15) Clear? yes +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