diff options
Diffstat (limited to '')
-rw-r--r-- | e2fsck/pass4.c | 53 |
1 files changed, 35 insertions, 18 deletions
diff --git a/e2fsck/pass4.c b/e2fsck/pass4.c index d2dda02..cf0cf7c 100644 --- a/e2fsck/pass4.c +++ b/e2fsck/pass4.c @@ -96,9 +96,10 @@ static int disconnect_inode(e2fsck_t ctx, ext2_ino_t i, ext2_ino_t *last_ino, * an xattr inode at all. Return immediately if EA_INODE flag is not set. */ static void check_ea_inode(e2fsck_t ctx, ext2_ino_t i, ext2_ino_t *last_ino, - struct ext2_inode_large *inode, __u16 *link_counted) + struct ext2_inode_large *inode, __u16 *link_counted, + ea_value_t actual_refs) { - __u64 actual_refs = 0; + struct problem_context pctx; __u64 ref_count; if (*last_ino != i) { @@ -107,13 +108,26 @@ static void check_ea_inode(e2fsck_t ctx, ext2_ino_t i, ext2_ino_t *last_ino, "pass4: check_ea_inode"); *last_ino = i; } - if (!(inode->i_flags & EXT4_EA_INODE_FL)) - return; - if (ctx->ea_inode_refs) - ea_refcount_fetch(ctx->ea_inode_refs, i, &actual_refs); - if (!actual_refs) + clear_problem_context(&pctx); + pctx.ino = i; + pctx.inode = EXT2_INODE(inode); + + /* No references to the inode from xattrs? */ + if (actual_refs == EA_INODE_NO_REFS) { + /* + * No references from directory hierarchy either? Inode will + * will get attached to lost+found so clear EA_INODE_FL. + * Otherwise this is likely a spuriously set flag so clear it. + */ + if (*link_counted == 0 || + fix_problem(ctx, PR_4_EA_INODE_SPURIOUS_FLAG, &pctx)) { + /* Clear EA_INODE_FL (likely a normal file) */ + inode->i_flags &= ~EXT4_EA_INODE_FL; + e2fsck_write_inode(ctx, i, EXT2_INODE(inode), "pass4"); + } return; + } /* * There are some attribute references, link_counted is now considered @@ -127,10 +141,6 @@ static void check_ea_inode(e2fsck_t ctx, ext2_ino_t i, ext2_ino_t *last_ino, * However, their i_ctime and i_atime should be the same. */ if (ref_count != actual_refs && inode->i_ctime != inode->i_atime) { - struct problem_context pctx; - - clear_problem_context(&pctx); - pctx.ino = i; pctx.num = ref_count; pctx.num2 = actual_refs; if (fix_problem(ctx, PR_4_EA_INODE_REF_COUNT, &pctx)) { @@ -188,6 +198,7 @@ void e2fsck_pass4(e2fsck_t ctx) /* Protect loop from wrap-around if s_inodes_count maxed */ for (i = 1; i <= fs->super->s_inodes_count && i > 0; i++) { ext2_ino_t last_ino = 0; + ea_value_t ea_refs; int isdir; if (ctx->flags & E2F_FLAG_SIGNAL_MASK) @@ -211,13 +222,19 @@ void e2fsck_pass4(e2fsck_t ctx) ext2fs_icount_fetch(ctx->inode_link_info, i, &link_count); ext2fs_icount_fetch(ctx->inode_count, i, &link_counted); - if (link_counted == 0) { - /* - * link_counted is expected to be 0 for an ea_inode. - * check_ea_inode() will update link_counted if - * necessary. - */ - check_ea_inode(ctx, i, &last_ino, inode, &link_counted); + if (ctx->ea_inode_refs) { + ea_refcount_fetch(ctx->ea_inode_refs, i, &ea_refs); + if (ea_refs) { + /* + * Final consolidation of EA inodes. We either + * decide the inode is fine and set link_counted + * to one, or we decide this is actually a + * normal file and clear EA_INODE flag, or + * decide the inode should just be deleted. + */ + check_ea_inode(ctx, i, &last_ino, inode, + &link_counted, ea_refs); + } } if (link_counted == 0) { |