X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=e2fsck%2Fpass1.c;h=799158ea059f13d8b1e6d47e21ee5751151abedc;hb=d37026ea07a6abcb0bbff8d97e58b47e8089df8e;hp=23d2e99f7dd74dc92ed59a7eaa8885255decfcfa;hpb=25f291c9b32d8017e6969c72a75e37d354c0570b;p=tools%2Fe2fsprogs.git diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c index 23d2e99..799158e 100644 --- a/e2fsck/pass1.c +++ b/e2fsck/pass1.c @@ -102,7 +102,7 @@ struct process_block_struct { struct process_inode_block { ext2_ino_t ino; - struct ext2_inode inode; + struct ext2_inode_large inode; }; struct scan_callback_struct { @@ -181,7 +181,6 @@ int e2fsck_pass1_check_symlink(ext2_filsys fs, ext2_ino_t ino, ext2_extent_handle_t handle; struct ext2_extent_info info; struct ext2fs_extent extent; - int encrypted = 0; if ((inode->i_size_high || inode->i_size == 0) || (inode->i_flags & EXT2_INDEX_FL)) @@ -449,6 +448,21 @@ fix: EXT2_INODE_SIZE(sb), "pass1"); } +static int check_inode_extra_negative_epoch(__u32 xtime, __u32 extra) { + return (xtime & (1 << 31)) != 0 && + (extra & EXT4_EPOCH_MASK) == EXT4_EPOCH_MASK; +} + +#define CHECK_INODE_EXTRA_NEGATIVE_EPOCH(inode, xtime) \ + check_inode_extra_negative_epoch(inode->i_##xtime, \ + inode->i_##xtime##_extra) + +/* When today's date is earlier than 2242, we assume that atimes, + * ctimes, crtimes, and mtimes with years in the range 2310..2378 are + * actually pre-1970 dates mis-encoded. + */ +#define EXT4_EXTRA_NEGATIVE_DATE_CUTOFF 2 * (1LL << 32) + static void check_inode_extra_space(e2fsck_t ctx, struct problem_context *pctx) { struct ext2_super_block *sb = ctx->fs->super; @@ -483,12 +497,42 @@ 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) { /* it seems inode has an extended attribute(s) in body */ check_ea_in_inode(ctx, pctx); } + + /* + * If the inode's extended atime (ctime, crtime, mtime) is stored in + * the old, invalid format, repair it. + */ + if (sizeof(time_t) > 4 && ctx->now < EXT4_EXTRA_NEGATIVE_DATE_CUTOFF && + (CHECK_INODE_EXTRA_NEGATIVE_EPOCH(inode, atime) || + CHECK_INODE_EXTRA_NEGATIVE_EPOCH(inode, ctime) || + CHECK_INODE_EXTRA_NEGATIVE_EPOCH(inode, crtime) || + CHECK_INODE_EXTRA_NEGATIVE_EPOCH(inode, mtime))) { + + if (!fix_problem(ctx, PR_1_EA_TIME_OUT_OF_RANGE, pctx)) + return; + + if (CHECK_INODE_EXTRA_NEGATIVE_EPOCH(inode, atime)) + inode->i_atime_extra &= ~EXT4_EPOCH_MASK; + if (CHECK_INODE_EXTRA_NEGATIVE_EPOCH(inode, ctime)) + inode->i_ctime_extra &= ~EXT4_EPOCH_MASK; + if (CHECK_INODE_EXTRA_NEGATIVE_EPOCH(inode, crtime)) + inode->i_crtime_extra &= ~EXT4_EPOCH_MASK; + if (CHECK_INODE_EXTRA_NEGATIVE_EPOCH(inode, mtime)) + inode->i_mtime_extra &= ~EXT4_EPOCH_MASK; + e2fsck_write_inode_full(ctx, pctx->ino, pctx->inode, + EXT2_INODE_SIZE(sb), "pass1"); + } + } /* @@ -541,14 +585,12 @@ static void check_is_really_dir(e2fsck_t ctx, struct problem_context *pctx, * data. If it's true, we will treat it as a directory. */ - extent_fs = (ctx->fs->super->s_feature_incompat & - EXT3_FEATURE_INCOMPAT_EXTENTS); - inlinedata_fs = (ctx->fs->super->s_feature_incompat & - EXT4_FEATURE_INCOMPAT_INLINE_DATA); + extent_fs = ext2fs_has_feature_extents(ctx->fs->super); + inlinedata_fs = ext2fs_has_feature_inline_data(ctx->fs->super); if (inlinedata_fs && (inode->i_flags & EXT4_INLINE_DATA_FL)) { size_t size; __u32 dotdot; - unsigned int rec_len; + unsigned int rec_len2; struct ext2_dir_entry de; if (ext2fs_inline_data_size(ctx->fs, pctx->ino, &size)) @@ -569,14 +611,14 @@ static void check_is_really_dir(e2fsck_t ctx, struct problem_context *pctx, dotdot = ext2fs_le32_to_cpu(dotdot); de.inode = ext2fs_le32_to_cpu(de.inode); de.rec_len = ext2fs_le16_to_cpu(de.rec_len); - ext2fs_get_rec_len(ctx->fs, &de, &rec_len); + ext2fs_get_rec_len(ctx->fs, &de, &rec_len2); if (dotdot >= ctx->fs->super->s_inodes_count || (dotdot < EXT2_FIRST_INO(ctx->fs->super) && dotdot != EXT2_ROOT_INO) || de.inode >= ctx->fs->super->s_inodes_count || (de.inode < EXT2_FIRST_INO(ctx->fs->super) && de.inode != 0) || - rec_len > EXT4_MIN_INLINE_DATA_SIZE - + rec_len2 > EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DATA_DOTDOT_SIZE) return; /* device files never have a "system.data" entry */ @@ -831,10 +873,8 @@ static int fix_inline_data_extents_file(e2fsck_t ctx, int dirty = 0; /* Both feature flags not set? Just run the regular checks */ - if (!EXT2_HAS_INCOMPAT_FEATURE(fs->super, - EXT3_FEATURE_INCOMPAT_EXTENTS) && - !EXT2_HAS_INCOMPAT_FEATURE(fs->super, - EXT4_FEATURE_INCOMPAT_INLINE_DATA)) + if (!ext2fs_has_feature_extents(fs->super) && + !ext2fs_has_feature_inline_data(fs->super)) return 0; /* Clear both flags if it's a special file */ @@ -955,6 +995,41 @@ out: } } +/* + * Check if the passed ino is one of the used superblock quota inodes. + * + * Before the quota inodes were journaled, older superblock quota inodes + * were just regular files in the filesystem and not reserved inodes. This + * checks if the passed ino is one of the s_*_quota_inum superblock fields, + * which may not always be the same as the EXT4_*_QUOTA_INO fields. + */ +static int quota_inum_is_super(struct ext2_super_block *sb, ext2_ino_t ino) +{ + enum quota_type qtype; + + for (qtype = 0; qtype < MAXQUOTAS; qtype++) + if (*quota_sb_inump(sb, qtype) == ino) + return 1; + + return 0; +} + +/* + * Check if the passed ino is one of the reserved quota inodes. + * This checks if the inode number is one of the reserved EXT4_*_QUOTA_INO + * inodes. These inodes may or may not be in use by the quota feature. + */ +static int quota_inum_is_reserved(ext2_filsys fs, ext2_ino_t ino) +{ + enum quota_type qtype; + + for (qtype = 0; qtype < MAXQUOTAS; qtype++) + if (quota_type2inum(qtype, fs->super) == ino) + return 1; + + return 0; +} + void e2fsck_pass1(e2fsck_t ctx) { int i; @@ -993,7 +1068,7 @@ void e2fsck_pass1(e2fsck_t ctx) if (!(ctx->options & E2F_OPT_PREEN)) fix_problem(ctx, PR_1_PASS_HEADER, &pctx); - if ((fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) && + if (ext2fs_has_feature_dir_index(fs->super) && !(ctx->options & E2F_OPT_NO)) { if (ext2fs_u32_list_create(&ctx->dirs_to_hash, 50)) ctx->dirs_to_hash = 0; @@ -1014,10 +1089,9 @@ void e2fsck_pass1(e2fsck_t ctx) } #undef EXT2_BPP - imagic_fs = (sb->s_feature_compat & EXT2_FEATURE_COMPAT_IMAGIC_INODES); - extent_fs = (sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS); - inlinedata_fs = (sb->s_feature_incompat & - EXT4_FEATURE_INCOMPAT_INLINE_DATA); + imagic_fs = ext2fs_has_feature_imagic_inodes(sb); + extent_fs = ext2fs_has_feature_extents(sb); + inlinedata_fs = ext2fs_has_feature_inline_data(sb); /* * Allocate bitmaps structures @@ -1151,7 +1225,7 @@ void e2fsck_pass1(e2fsck_t ctx) fs->super->s_mkfs_time < fs->super->s_inodes_count)) low_dtime_check = 0; - if ((fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_MMP) && + if (ext2fs_has_feature_mmp(fs->super) && fs->super->s_mmp_block > fs->super->s_first_data_block && fs->super->s_mmp_block < ext2fs_blocks_count(fs->super)) ext2fs_mark_block_bitmap2(ctx->block_found_map, @@ -1172,7 +1246,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 @@ -1264,8 +1338,7 @@ void e2fsck_pass1(e2fsck_t ctx) pctx.errcode = ext2fs_inline_data_size(fs, ino, &size); if (!pctx.errcode && size && fix_problem(ctx, PR_1_INLINE_DATA_FEATURE, &pctx)) { - sb->s_feature_incompat |= - EXT4_FEATURE_INCOMPAT_INLINE_DATA; + ext2fs_set_feature_inline_data(sb); ext2fs_mark_super_dirty(fs); inlinedata_fs = 1; } else if (fix_problem(ctx, PR_1_INLINE_DATA_SET, &pctx)) { @@ -1354,7 +1427,7 @@ void e2fsck_pass1(e2fsck_t ctx) if ((ext2fs_extent_header_verify(inode->i_block, sizeof(inode->i_block)) == 0) && fix_problem(ctx, PR_1_EXTENT_FEATURE, &pctx)) { - sb->s_feature_incompat |= EXT3_FEATURE_INCOMPAT_EXTENTS; + ext2fs_set_feature_extents(sb); ext2fs_mark_super_dirty(fs); extent_fs = 1; } else if (fix_problem(ctx, PR_1_EXTENTS_SET, &pctx)) { @@ -1505,13 +1578,10 @@ void e2fsck_pass1(e2fsck_t ctx) inode_size, "pass1"); failed_csum = 0; } - } else if ((ino == EXT4_USR_QUOTA_INO) || - (ino == EXT4_GRP_QUOTA_INO)) { + } else if (quota_inum_is_reserved(fs, ino)) { ext2fs_mark_inode_bitmap2(ctx->inode_used_map, ino); - if ((fs->super->s_feature_ro_compat & - EXT4_FEATURE_RO_COMPAT_QUOTA) && - ((fs->super->s_usr_quota_inum == ino) || - (fs->super->s_grp_quota_inum == ino))) { + if (ext2fs_has_feature_quota(fs->super) && + quota_inum_is_super(fs->super, ino)) { if (!LINUX_S_ISREG(inode->i_mode) && fix_problem(ctx, PR_1_QUOTA_BAD_MODE, &pctx)) { @@ -1640,13 +1710,11 @@ void e2fsck_pass1(e2fsck_t ctx) (LINUX_S_ISDIR(inode->i_mode) && inode->i_dir_acl)) mark_inode_bad(ctx, ino); if ((fs->super->s_creator_os == EXT2_OS_LINUX) && - !(fs->super->s_feature_incompat & - EXT4_FEATURE_INCOMPAT_64BIT) && + !ext2fs_has_feature_64bit(fs->super) && inode->osd2.linux2.l_i_file_acl_high != 0) mark_inode_bad(ctx, ino); if ((fs->super->s_creator_os == EXT2_OS_LINUX) && - !(fs->super->s_feature_ro_compat & - EXT4_FEATURE_RO_COMPAT_HUGE_FILE) && + !ext2fs_has_feature_huge_file(fs->super) && (inode->osd2.linux2.l_i_blocks_hi != 0)) mark_inode_bad(ctx, ino); if (inode->i_flags & EXT2_IMAGIC_FL) { @@ -1747,7 +1815,8 @@ void e2fsck_pass1(e2fsck_t ctx) inode->i_block[EXT2_TIND_BLOCK] || ext2fs_file_acl_block(fs, inode))) { inodes_to_process[process_inode_count].ino = ino; - inodes_to_process[process_inode_count].inode = *inode; + inodes_to_process[process_inode_count].inode = + *(struct ext2_inode_large *)inode; process_inode_count++; } else check_blocks(ctx, &pctx, block_buf); @@ -1857,6 +1926,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 @@ -1908,7 +1979,8 @@ static void process_inodes(e2fsck_t ctx, char *block_buf) sizeof(struct process_inode_block), process_inode_cmp); clear_problem_context(&pctx); for (i=0; i < process_inode_count; i++) { - pctx.inode = ctx->stashed_inode = &inodes_to_process[i].inode; + pctx.inode = ctx->stashed_inode = + (struct ext2_inode *) &inodes_to_process[i].inode; pctx.ino = ctx->stashed_ino = inodes_to_process[i].ino; #if 0 @@ -1946,8 +2018,8 @@ static EXT2_QSORT_TYPE process_inode_cmp(const void *a, const void *b) * inodes, so it's OK to pass NULL to * ext2fs_file_acl_block() here. */ - ret = ext2fs_file_acl_block(0, &(ib_a->inode)) - - ext2fs_file_acl_block(0, &(ib_b->inode)); + ret = ext2fs_file_acl_block(0, ext2fs_const_inode(&ib_a->inode)) - + ext2fs_file_acl_block(0, ext2fs_const_inode(&ib_b->inode)); if (ret == 0) ret = ib_a->ino - ib_b->ino; return ret; @@ -2155,7 +2227,7 @@ static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx, * Or if the extended attribute block is an invalid block, * then the inode is also corrupted. */ - if (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_EXT_ATTR) || + if (!ext2fs_has_feature_xattr(fs->super) || (blk < fs->super->s_first_data_block) || (blk >= ext2fs_blocks_count(fs->super))) { mark_inode_bad(ctx, ino); @@ -2349,7 +2421,7 @@ static int handle_htree(e2fsck_t ctx, struct problem_context *pctx, if ((!LINUX_S_ISDIR(inode->i_mode) && fix_problem(ctx, PR_1_HTREE_NODIR, pctx)) || - (!(fs->super->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) && + (!ext2fs_has_feature_dir_index(fs->super) && fix_problem(ctx, PR_1_HTREE_SET, pctx))) return 1; @@ -2830,7 +2902,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)) @@ -2983,10 +3068,8 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx, pctx->ino = ino; pctx->errcode = 0; - extent_fs = (ctx->fs->super->s_feature_incompat & - EXT3_FEATURE_INCOMPAT_EXTENTS); - inlinedata_fs = (ctx->fs->super->s_feature_incompat & - EXT4_FEATURE_INCOMPAT_INLINE_DATA); + extent_fs = ext2fs_has_feature_extents(ctx->fs->super); + inlinedata_fs = ext2fs_has_feature_inline_data(ctx->fs->super); if (check_ext_attr(ctx, pctx, block_buf)) { if (ctx->flags & E2F_FLAG_SIGNAL_MASK) @@ -3080,14 +3163,15 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx, } } - if (ino == EXT2_ROOT_INO || ino >= EXT2_FIRST_INODE(ctx->fs->super)) { - quota_data_add(ctx->qctx, inode, ino, - pb.num_blocks * fs->blocksize); - quota_data_inodes(ctx->qctx, inode, ino, +1); + if (ino != quota_type2inum(PRJQUOTA, fs->super) && + (ino == EXT2_ROOT_INO || ino >= EXT2_FIRST_INODE(ctx->fs->super))) { + quota_data_add(ctx->qctx, (struct ext2_inode_large *) inode, + ino, pb.num_blocks * fs->blocksize); + quota_data_inodes(ctx->qctx, (struct ext2_inode_large *) inode, + ino, +1); } - if (!(fs->super->s_feature_ro_compat & - EXT4_FEATURE_RO_COMPAT_HUGE_FILE) || + if (!ext2fs_has_feature_huge_file(fs->super) || !(inode->i_flags & EXT4_HUGE_FILE_FL)) pb.num_blocks *= (fs->blocksize / 512); pb.num_blocks *= EXT2FS_CLUSTER_RATIO(fs); @@ -3171,8 +3255,7 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx, ctx->large_files++; if ((fs->super->s_creator_os == EXT2_OS_LINUX) && ((pb.num_blocks != ext2fs_inode_i_blocks(fs, inode)) || - ((fs->super->s_feature_ro_compat & - EXT4_FEATURE_RO_COMPAT_HUGE_FILE) && + (ext2fs_has_feature_huge_file(fs->super) && (inode->i_flags & EXT4_HUGE_FILE_FL) && (inode->osd2.linux2.l_i_blocks_hi != 0)))) { pctx->num = pb.num_blocks; @@ -3189,8 +3272,7 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx, * a block mapped file, so rebuild it as an extent file. We can skip * symlinks because they're never rewritten. */ - if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super, - EXT4_FEATURE_RO_COMPAT_BIGALLOC) && + if (ext2fs_has_feature_bigalloc(fs->super) && (LINUX_S_ISREG(inode->i_mode) || LINUX_S_ISDIR(inode->i_mode)) && ext2fs_inode_data_blocks2(fs, inode) > 0 && (ino == EXT2_ROOT_INO || ino >= EXT2_FIRST_INO(fs->super)) && @@ -3656,8 +3738,7 @@ static void new_table_block(e2fsck_t ctx, blk64_t first_block, dgrp_t group, * within the flex_bg, and if that fails then try finding the * space anywhere in the filesystem. */ - is_flexbg = EXT2_HAS_INCOMPAT_FEATURE(fs->super, - EXT4_FEATURE_INCOMPAT_FLEX_BG); + is_flexbg = ext2fs_has_feature_flex_bg(fs->super); if (is_flexbg) { flexbg_size = 1 << fs->super->s_log_groups_per_flex; flexbg = group / flexbg_size;