summaryrefslogtreecommitdiffstats
path: root/e2fsck/pass4.c
diff options
context:
space:
mode:
Diffstat (limited to 'e2fsck/pass4.c')
-rw-r--r--e2fsck/pass4.c53
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) {