diff options
Diffstat (limited to 'e2fsck/pass1.c')
-rw-r--r-- | e2fsck/pass1.c | 104 |
1 files changed, 83 insertions, 21 deletions
diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c index a341c72..eb73922 100644 --- a/e2fsck/pass1.c +++ b/e2fsck/pass1.c @@ -387,34 +387,71 @@ static problem_t check_large_ea_inode(e2fsck_t ctx, return 0; } +static int alloc_ea_inode_refs(e2fsck_t ctx, struct problem_context *pctx) +{ + pctx->errcode = ea_refcount_create(0, &ctx->ea_inode_refs); + if (pctx->errcode) { + pctx->num = 4; + fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx); + ctx->flags |= E2F_FLAG_ABORT; + return 0; + } + return 1; +} + static void inc_ea_inode_refs(e2fsck_t ctx, struct problem_context *pctx, struct ext2_ext_attr_entry *first, void *end) { struct ext2_ext_attr_entry *entry = first; struct ext2_ext_attr_entry *np = EXT2_EXT_ATTR_NEXT(entry); + ea_value_t refs; while ((void *) entry < end && (void *) np < end && !EXT2_EXT_IS_LAST_ENTRY(entry)) { if (!entry->e_value_inum) goto next; - if (!ctx->ea_inode_refs) { - pctx->errcode = ea_refcount_create(0, - &ctx->ea_inode_refs); - if (pctx->errcode) { - pctx->num = 4; - fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx); - ctx->flags |= E2F_FLAG_ABORT; - return; - } - } - ea_refcount_increment(ctx->ea_inode_refs, entry->e_value_inum, - 0); + if (!ctx->ea_inode_refs && !alloc_ea_inode_refs(ctx, pctx)) + return; + ea_refcount_fetch(ctx->ea_inode_refs, entry->e_value_inum, + &refs); + if (refs == EA_INODE_NO_REFS) + refs = 1; + else + refs += 1; + ea_refcount_store(ctx->ea_inode_refs, entry->e_value_inum, refs); next: entry = np; np = EXT2_EXT_ATTR_NEXT(entry); } } +/* + * Make sure inode is tracked as EA inode. We use special EA_INODE_NO_REFS + * value if we didn't find any xattrs referencing this inode yet. + */ +static int track_ea_inode(e2fsck_t ctx, struct problem_context *pctx, + ext2_ino_t ino) +{ + ea_value_t refs; + + if (!ctx->ea_inode_refs && !alloc_ea_inode_refs(ctx, pctx)) + return 0; + + ea_refcount_fetch(ctx->ea_inode_refs, ino, &refs); + if (refs > 0) + return 1; + + pctx->errcode = ea_refcount_store(ctx->ea_inode_refs, ino, + EA_INODE_NO_REFS); + if (pctx->errcode) { + pctx->num = 5; + fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx); + ctx->flags |= E2F_FLAG_ABORT; + return 0; + } + return 1; +} + static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx, struct ea_quota *ea_ibody_quota) { @@ -510,6 +547,12 @@ static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx, } else { blk64_t quota_blocks; + if (!ext2fs_has_feature_ea_inode(sb) && + fix_problem(ctx, PR_1_EA_INODE_FEATURE, pctx)) { + ext2fs_set_feature_ea_inode(sb); + ext2fs_mark_super_dirty(ctx->fs); + } + problem = check_large_ea_inode(ctx, entry, pctx, "a_blocks); if (problem != 0) @@ -1181,6 +1224,7 @@ void e2fsck_pass1(e2fsck_t ctx) ext2_ino_t ino_threshold = 0; dgrp_t ra_group = 0; struct ea_quota ea_ibody_quota; + time_t tm; init_resource_track(&rtrack, ctx->fs->io); clear_problem_context(&pctx); @@ -1357,12 +1401,13 @@ void e2fsck_pass1(e2fsck_t ctx) if (ctx->progress && ((ctx->progress)(ctx, 1, 0, ctx->fs->group_desc_count))) goto endit; - if ((fs->super->s_wtime && - fs->super->s_wtime < fs->super->s_inodes_count) || - (fs->super->s_mtime && - fs->super->s_mtime < fs->super->s_inodes_count) || - (fs->super->s_mkfs_time && - fs->super->s_mkfs_time < fs->super->s_inodes_count)) + + if (((tm = ext2fs_get_tstamp(fs->super, s_wtime)) && + tm < fs->super->s_inodes_count) || + ((tm = ext2fs_get_tstamp(fs->super, s_mtime)) && + tm < fs->super->s_inodes_count) || + ((tm = ext2fs_get_tstamp(fs->super, s_mkfs_time)) && + tm < fs->super->s_inodes_count)) low_dtime_check = 0; if (ext2fs_has_feature_mmp(fs->super) && @@ -1481,7 +1526,7 @@ void e2fsck_pass1(e2fsck_t ctx) if (!inode->i_dtime && inode->i_mode) { if (fix_problem(ctx, PR_1_ZERO_DTIME, &pctx)) { - inode->i_dtime = ctx->now; + ext2fs_set_dtime(fs, inode); e2fsck_write_inode(ctx, ino, inode, "pass1"); failed_csum = 0; @@ -1500,6 +1545,17 @@ void e2fsck_pass1(e2fsck_t ctx) e2fsck_write_inode(ctx, ino, inode, "pass1"); } + if (inode->i_flags & EXT4_EA_INODE_FL) { + if (!LINUX_S_ISREG(inode->i_mode) && + fix_problem(ctx, PR_1_EA_INODE_NONREG, &pctx)) { + inode->i_flags &= ~EXT4_EA_INODE_FL; + e2fsck_write_inode(ctx, ino, inode, "pass1"); + } + if (inode->i_flags & EXT4_EA_INODE_FL) + if (!track_ea_inode(ctx, &pctx, ino)) + continue; + } + /* Conflicting inlinedata/extents inode flags? */ if ((inode->i_flags & EXT4_INLINE_DATA_FL) && (inode->i_flags & EXT4_EXTENTS_FL)) { @@ -2076,7 +2132,7 @@ void e2fsck_pass1(e2fsck_t ctx) if (!pctx.errcode) { e2fsck_read_inode(ctx, EXT2_RESIZE_INO, inode, "recreate inode"); - inode->i_mtime = ctx->now; + ext2fs_inode_xtime_set(inode, i_mtime, ctx->now); e2fsck_write_inode(ctx, EXT2_RESIZE_INO, inode, "recreate inode"); } @@ -2620,6 +2676,12 @@ static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx, problem_t problem; blk64_t entry_quota_blocks; + if (!ext2fs_has_feature_ea_inode(fs->super) && + fix_problem(ctx, PR_1_EA_INODE_FEATURE, pctx)) { + ext2fs_set_feature_ea_inode(fs->super); + ext2fs_mark_super_dirty(fs); + } + problem = check_large_ea_inode(ctx, entry, pctx, &entry_quota_blocks); if (problem && fix_problem(ctx, problem, pctx)) @@ -2791,7 +2853,7 @@ void e2fsck_clear_inode(e2fsck_t ctx, ext2_ino_t ino, inode->i_flags = 0; inode->i_links_count = 0; ext2fs_icount_store(ctx->inode_link_info, ino, 0); - inode->i_dtime = ctx->now; + ext2fs_set_dtime(ctx->fs, inode); /* * If a special inode has such rotten block mappings that we |