summaryrefslogtreecommitdiffstats
path: root/e2fsck/pass1.c
diff options
context:
space:
mode:
Diffstat (limited to 'e2fsck/pass1.c')
-rw-r--r--e2fsck/pass1.c104
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,
&quota_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