2024-05-06 17:41:46

by Jan Kara

[permalink] [raw]
Subject: [PATCH 0/3] e2fsck: expand checking of EA inode

Hello,

customer has reported that his filesystem was reporting errors from
ext4_iget() about inode with EA_INODE_FL but e2fsck was considering the
filesystem as clean. Indeed the EA inode checking in e2fsck is weak and
lets through several cases of corruption related to EA inodes. This series
adds more strict checking of EA inodes and adds e2fsck tests for them.

Honza


2024-05-06 17:41:50

by Jan Kara

[permalink] [raw]
Subject: [PATCH 1/3] e2fsck: add more checks for ea inode consistency

Currently checking of EA inodes was rather weak. Add several more
consistency checks.

1) Check that EA inode is a regular file.
2) Check that EA_INODE feature is set if the filesystem has EA inodes.
3) Make sure that no EA inode is referenced from directory hierarchy.

Signed-off-by: Jan Kara <[email protected]>
---
e2fsck/e2fsck.h | 6 ++++
e2fsck/pass1.c | 84 +++++++++++++++++++++++++++++++++++++++++-------
e2fsck/pass2.c | 15 +++++++++
e2fsck/pass4.c | 53 +++++++++++++++++++-----------
e2fsck/problem.c | 18 +++++++++++
e2fsck/problem.h | 12 +++++++
6 files changed, 158 insertions(+), 30 deletions(-)

diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h
index 55738fdc1d19..ae1273dc00af 100644
--- a/e2fsck/e2fsck.h
+++ b/e2fsck/e2fsck.h
@@ -533,6 +533,12 @@ extern struct dx_dir_info *e2fsck_dx_dir_info_iter(e2fsck_t ctx,
typedef __u64 ea_key_t;
typedef __u64 ea_value_t;

+/*
+ * Special refcount value we use for inodes which have EA_INODE flag set but we
+ * do not yet know about any references.
+ */
+#define EA_INODE_NO_REFS (~(ea_value_t)0)
+
extern errcode_t ea_refcount_create(size_t size, ext2_refcount_t *ret);
extern void ea_refcount_free(ext2_refcount_t refcount);
extern errcode_t ea_refcount_fetch(ext2_refcount_t refcount, ea_key_t ea_key,
diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index 8b6238e8434c..eb73922d3e2c 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)
@@ -1502,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)) {
@@ -2622,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))
diff --git a/e2fsck/pass2.c b/e2fsck/pass2.c
index 08ab40fa8ba1..036c0022d38a 100644
--- a/e2fsck/pass2.c
+++ b/e2fsck/pass2.c
@@ -1501,6 +1501,21 @@ skip_checksum:
problem = PR_2_NULL_NAME;
}

+ /*
+ * Check if inode was tracked as EA inode and has actual
+ * references from xattrs. In that case dir entry is likely
+ * bogus and we want to clear it. The case of EA inode without
+ * references from xattrs will be handled in pass 4.
+ */
+ if (!problem && ctx->ea_inode_refs) {
+ ea_value_t refs;
+
+ ea_refcount_fetch(ctx->ea_inode_refs, dirent->inode,
+ &refs);
+ if (refs && refs != EA_INODE_NO_REFS)
+ problem = PR_2_EA_INODE_DIR_LINK;
+ }
+
if (problem) {
if (fix_problem(ctx, problem, &cd->pctx)) {
dirent->inode = 0;
diff --git a/e2fsck/pass4.c b/e2fsck/pass4.c
index d2dda02a94b8..cf0cf7c47582 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) {
diff --git a/e2fsck/problem.c b/e2fsck/problem.c
index 207ebbb34ec8..e433281fab4b 100644
--- a/e2fsck/problem.c
+++ b/e2fsck/problem.c
@@ -1309,6 +1309,16 @@ static struct e2fsck_problem problem_table[] = {
N_("Orphan file @i %i is not in use, but contains data. "),
PROMPT_CLEAR, PR_PREEN_OK },

+ /* EA_INODE flag set on a non-regular file */
+ { PR_1_EA_INODE_NONREG,
+ N_("@i %i has the ea_inode flag set but is not a regular file. "),
+ PROMPT_CLEAR_FLAG, 0, 0, 0, 0 },
+
+ /* EA_INODE present but the file system is missing the ea_inode feature */
+ { PR_1_EA_INODE_FEATURE,
+ N_("@i %i references EA inode but @S is missing EA_INODE feature\n"),
+ PROMPT_FIX, PR_PREEN_OK, 0, 0, 0 },
+
/* Pass 1b errors */

/* Pass 1B: Rescan for duplicate/bad blocks */
@@ -1860,6 +1870,10 @@ static struct e2fsck_problem problem_table[] = {
N_("Duplicate filename @E found. "),
PROMPT_CLEAR, 0, 0, 0, 0 },

+ /* Directory filename is null */
+ { PR_2_EA_INODE_DIR_LINK,
+ N_("@E references EA @i %Di.\n"),
+ PROMPT_CLEAR, 0, 0, 0, 0 },

/* Pass 3 errors */

@@ -2102,6 +2116,10 @@ static struct e2fsck_problem problem_table[] = {
N_("@d @i %i ref count set to overflow but could be exact value %N. "),
PROMPT_FIX, PR_PREEN_OK, 0, 0, 0 },

+ { PR_4_EA_INODE_SPURIOUS_FLAG,
+ N_("Regular @f @i %i has EA_INODE flag set. "),
+ PROMPT_CLEAR, PR_PREEN_OK, 0, 0, 0 },
+
/* Pass 5 errors */

/* Pass 5: Checking group summary information */
diff --git a/e2fsck/problem.h b/e2fsck/problem.h
index b47b0c630c67..ef15b8c84358 100644
--- a/e2fsck/problem.h
+++ b/e2fsck/problem.h
@@ -734,6 +734,12 @@ struct problem_context {
/* Orphan file inode is not in use, but contains data */
#define PR_1_ORPHAN_FILE_NOT_CLEAR 0x010090

+/* Inode has EA_INODE_FL set but is not a regular file */
+#define PR_1_EA_INODE_NONREG 0x010091
+
+/* Inode references EA inode but ea_inode feature is not enabled */
+#define PR_1_EA_INODE_FEATURE 0x010092
+
/*
* Pass 1b errors
*/
@@ -1061,6 +1067,9 @@ struct problem_context {
/* Non-unique filename found, but can't rename */
#define PR_2_NON_UNIQUE_FILE_NO_RENAME 0x020054

+/* EA inode referenced from directory */
+#define PR_2_EA_INODE_DIR_LINK 0x020055
+
/*
* Pass 3 errors
*/
@@ -1203,6 +1212,9 @@ struct problem_context {
/* Directory ref count set to overflow but it doesn't have to be */
#define PR_4_DIR_OVERFLOW_REF_COUNT 0x040007

+/* EA_INODE_FL set on normal file linked from directory hierarchy */
+#define PR_4_EA_INODE_SPURIOUS_FLAG 0x040008
+
/*
* Pass 5 errors
*/
--
2.35.3


2024-05-06 17:41:51

by Jan Kara

[permalink] [raw]
Subject: [PATCH 2/3] e2fsck: add tests for EA inodes

Add tests exercising EA inodes and testing various types of corruption.

Signed-off-by: Jan Kara <[email protected]>
---
tests/f_ea_inode_dir_ref/expect.1 | 12 ++++++++++
tests/f_ea_inode_dir_ref/expect.2 | 7 ++++++
tests/f_ea_inode_dir_ref/image.gz | Bin 0 -> 1822 bytes
tests/f_ea_inode_dir_ref/name | 1 +
tests/f_ea_inode_disconnected/expect.1 | 23 ++++++++++++++++++++
tests/f_ea_inode_disconnected/expect.2 | 7 ++++++
tests/f_ea_inode_disconnected/image | Bin 0 -> 1048576 bytes
tests/f_ea_inode_disconnected/image.gz | Bin 0 -> 1779 bytes
tests/f_ea_inode_disconnected/name | 1 +
tests/f_ea_inode_no_feature/expect.1 | 12 ++++++++++
tests/f_ea_inode_no_feature/expect.2 | 7 ++++++
tests/f_ea_inode_no_feature/image.gz | Bin 0 -> 1817 bytes
tests/f_ea_inode_no_feature/name | 1 +
tests/f_ea_inode_spurious_flag_dir/expect.1 | 11 ++++++++++
tests/f_ea_inode_spurious_flag_dir/expect.2 | 7 ++++++
tests/f_ea_inode_spurious_flag_dir/image | Bin 0 -> 1048576 bytes
tests/f_ea_inode_spurious_flag_dir/image.gz | Bin 0 -> 1598 bytes
tests/f_ea_inode_spurious_flag_dir/name | 1 +
18 files changed, 90 insertions(+)
create mode 100644 tests/f_ea_inode_dir_ref/expect.1
create mode 100644 tests/f_ea_inode_dir_ref/expect.2
create mode 100644 tests/f_ea_inode_dir_ref/image.gz
create mode 100644 tests/f_ea_inode_dir_ref/name
create mode 100644 tests/f_ea_inode_disconnected/expect.1
create mode 100644 tests/f_ea_inode_disconnected/expect.2
create mode 100644 tests/f_ea_inode_disconnected/image
create mode 100644 tests/f_ea_inode_disconnected/image.gz
create mode 100644 tests/f_ea_inode_disconnected/name
create mode 100644 tests/f_ea_inode_no_feature/expect.1
create mode 100644 tests/f_ea_inode_no_feature/expect.2
create mode 100644 tests/f_ea_inode_no_feature/image.gz
create mode 100644 tests/f_ea_inode_no_feature/name
create mode 100644 tests/f_ea_inode_spurious_flag_dir/expect.1
create mode 100644 tests/f_ea_inode_spurious_flag_dir/expect.2
create mode 100644 tests/f_ea_inode_spurious_flag_dir/image
create mode 100644 tests/f_ea_inode_spurious_flag_dir/image.gz
create mode 100644 tests/f_ea_inode_spurious_flag_dir/name

diff --git a/tests/f_ea_inode_dir_ref/expect.1 b/tests/f_ea_inode_dir_ref/expect.1
new file mode 100644
index 000000000000..fa6a872b8bf7
--- /dev/null
+++ b/tests/f_ea_inode_dir_ref/expect.1
@@ -0,0 +1,12 @@
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Entry 'xlink' in / (2) references EA inode 13.
+Clear? yes
+
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 13/128 files (0.0% non-contiguous), 63/1024 blocks
+Exit status is 1
diff --git a/tests/f_ea_inode_dir_ref/expect.2 b/tests/f_ea_inode_dir_ref/expect.2
new file mode 100644
index 000000000000..24d059a300a9
--- /dev/null
+++ b/tests/f_ea_inode_dir_ref/expect.2
@@ -0,0 +1,7 @@
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 13/128 files (0.0% non-contiguous), 63/1024 blocks
+Exit status is 0
diff --git a/tests/f_ea_inode_dir_ref/image.gz b/tests/f_ea_inode_dir_ref/image.gz
new file mode 100644
index 0000000000000000000000000000000000000000..483cc725ee29f2ba26c3cff2571741d1e0c0da49
GIT binary patch
literal 1822
zcmb2|=3tQjWs%0f{PwPIMvSWr!-tz^-5;y9MkR^bN*v7En9K7-h}Ci7jG!ak8X|8O
z%CEb!#M7`dWQrLptF32|kbazw+?Pems|2J3Z7N@_Tq+p2Ix~<ftiN>bP2Ze-S;@gh
zSHJ&mtu)TRcYE&toFDwo5ucnGy0UC!XF0#<y&4kCp}bM=?EZzT125H{kA1P)@0gI&
z+HYr;2L0W4tn%=k*SFIBe<giQ&E{bK_}Bb@!MmIH<tlc4UAu2S-~R3I&ulwdXj7As
zQSx<j<oEvY^L3vteYZdVrsDIFm!Ea#*KhuMFsQ<&<V@UdqvBFIbMNp!n!1<o%UD<E
zeM^|B`?Iy^wDgO$dty4j-rZ;;67;XXr6`JL(b-(v_@0)xyVrlc<-2}fRc-Df76u4d
zw>-?c%;Znx>Z`Lh@z}>PZ_+%j@`ht+QTZC_w?#X5@BS#e?_7W;KVN@O-detXURjQ>
z?@#4&=q^>h+T5&v?AxyhKeMBs4>mh9M^58^;C3YD-?wisU;e&z_|TvEnORTlKm4Ei
zX@CB&i_3$4f48ZwSC~BIzyH6Ymnm7N>ovrF@*h?Gzi`JBdy(mX+8<5&9}x3NzRUZc
zbK%K)4LzWwsr`S(hNP8ucfXL)=y~<wL!HJJ=0E8X8#MOZ@jP)V5{-WP^Ry+@Qw$6a
zap7sdRu!kNJvQgg&M@WJ+w1+0I2UtN>wO7by?JTj(v|;go(SA>(v;Jl?)`Gx{-yiA
zh4$U8w`*BvQ2FGoeOb+fQ$KDTdARk@pW@s9Gv9H1s!9(AlE12=f#j~__;(ym683WZ
zwr9_JU;iI;W5cQM_e$r!4whf~b^ZU1KWkm1{x941yiZ|$`TH}nj&apxKz2)T=Ksr^
z@BCXY^KRAk+^>%x{q;Yd6WM$3d+@*ae{<^YM?L@Feq6fr*7siB8~>*|EsfjW`sID0
z_VmL|KmSYX&$0e>x9G2O{*s^mbM9GQ+*z2%KjWDH*Q>iviAO(9E3VC{-D-I3!{ceO
z?QyrQt$v;2W!vl#_5bqkc@<A`(yip9jsEMNeperzv@^XmS?2ZsAOD{Isy@Hu=XSgK
zw_Y00kgi|H3lBOhjO|TdYA%1tIse7y{I!T{t;d4n^G{2PU{N?KG#Ub<AuuRIp!JJ*
Mr-_~x1A_nq05M9++yDRo

literal 0
HcmV?d00001

diff --git a/tests/f_ea_inode_dir_ref/name b/tests/f_ea_inode_dir_ref/name
new file mode 100644
index 000000000000..e43cd69502f8
--- /dev/null
+++ b/tests/f_ea_inode_dir_ref/name
@@ -0,0 +1 @@
+true ea inode referenced from a directory
diff --git a/tests/f_ea_inode_disconnected/expect.1 b/tests/f_ea_inode_disconnected/expect.1
new file mode 100644
index 000000000000..afc77aea6d11
--- /dev/null
+++ b/tests/f_ea_inode_disconnected/expect.1
@@ -0,0 +1,23 @@
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Unattached inode 13
+Connect to /lost+found? yes
+
+Inode 13 ref count is 2, should be 1. Fix? yes
+
+Pass 5: Checking group summary information
+Inode bitmap differences: -12
+Fix? yes
+
+Free inodes count wrong for group #0 (115, counted=116).
+Fix? yes
+
+Free inodes count wrong (115, counted=116).
+Fix? yes
+
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 12/128 files (0.0% non-contiguous), 63/1024 blocks
+Exit status is 1
diff --git a/tests/f_ea_inode_disconnected/expect.2 b/tests/f_ea_inode_disconnected/expect.2
new file mode 100644
index 000000000000..a67f9445048c
--- /dev/null
+++ b/tests/f_ea_inode_disconnected/expect.2
@@ -0,0 +1,7 @@
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 12/128 files (0.0% non-contiguous), 63/1024 blocks
+Exit status is 0
diff --git a/tests/f_ea_inode_disconnected/image b/tests/f_ea_inode_disconnected/image
new file mode 100644
index 0000000000000000000000000000000000000000..f24547c26f63603cdf8918d3b42d518d8e31504a
GIT binary patch
literal 1048576
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
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
y0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FoIU0)GK&7lxGp

literal 0
HcmV?d00001

diff --git a/tests/f_ea_inode_disconnected/image.gz b/tests/f_ea_inode_disconnected/image.gz
new file mode 100644
index 0000000000000000000000000000000000000000..f440f2052f48dc0489c8d209fb050d96665facff
GIT binary patch
literal 1779
zcmb2|=3q!-uuNlMetXw9BgU11{lm@voX2WSQ=(k?pCxR)Va8Sz$?CXpM$pl2jVYI$
z?PD(1Et%yK#UkzK=znR>k?sl&xi5><Z8>_msy;qhxwI-^wdYEaD{`-`HqSOS^vzXJ
z46fZDKg0a}+3MeEWz+u~w6uyd1%yn_4CYO=2)jI0;8;>@RK-Du<x5`Ao0n^{Jc)DR
z)v8ZHD{Et)?^yhM*S?+2Zfoq;w-y-OtH0d;eBQ6O^VGA}o7dU>`nJzFTD<@9zr*gw
z!vE!6`}_LlW_i2chxLtb$6J4W`*WWE{+mVlnl>`Oo}Y`IIkR4Vb*jR@snasnA3L`2
z>N}mytM>)uRj{|eK7T#A)?Md&>y-Z+1N<gCZdqCWV)Mogx!1SG?f$s*vi|zB8jK8J
z(C|8QtKS}>e>q#Drs~}F-`0?G%CP0{!VtNh()9f?ax!oJw7rj68fRx>WwvjrrB&e*
zhm8MW?_PWPzl`|2)A@YLOudGy0-OK*{U~0x|GN0Ung3^cssBIlKm1hv<K67?{=e&=
zME+);x#W+1)yGTfneqP?Mm&-4^8UAQ2QDf*@gHMDQs&*QFC;X2p1pWcr?G|kPx_1v
z8hh?2ru_7Y5Q%#yu&G8(hfBYlBXXb3e@k|VM}Xvs*Qb0I-_*^%`us}Y)>kiY)zzxx
ztx|k5GuLEx@zUaDm+It-IQA|S+5Yvu_sdQDmu}l9`pve;uBFkS^iA*S+xLA_iyl3>
zxb@GU;@kfN-w8hX`s~;p<rA-0uifcB;riO&Mg0mbC&M47t%%xN^-sSwI;`UT-0PP1
zf9q!bcaw{{5w_%KepNI`+qGPfhIz3&-31Q4-11K{D(i1J-}ddV?|m!#_-lFnx-~~W
zSZn^TwvPkq`D1@A?tksY{g0oteZ6a%5LLgd>ffqQtx+*K_hi2Bi;<tc%0BmA<&Pit
zK7JGrPv^<}=l|XI>w%lRFDsJD>i(_Y{`#!<y87y*oy9Y2=Sci~@NVg?_VY`=$KRg&
z?Q;5sxBGYV!vhBk!@S8$=jF|LFK5o%8gZ@lTyT8;DN7A3>PCe|Ltr!n24x6vz0|)a
L>@2~+Aiw|sY0a}*

literal 0
HcmV?d00001

diff --git a/tests/f_ea_inode_disconnected/name b/tests/f_ea_inode_disconnected/name
new file mode 100644
index 000000000000..ce04192e8777
--- /dev/null
+++ b/tests/f_ea_inode_disconnected/name
@@ -0,0 +1 @@
+ea inode that is not connected anywhere
diff --git a/tests/f_ea_inode_no_feature/expect.1 b/tests/f_ea_inode_no_feature/expect.1
new file mode 100644
index 000000000000..f6a232bfc8f3
--- /dev/null
+++ b/tests/f_ea_inode_no_feature/expect.1
@@ -0,0 +1,12 @@
+Pass 1: Checking inodes, blocks, and sizes
+Inode 12 references EA inode but superblock is missing EA_INODE feature
+Fix? yes
+
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 13/128 files (0.0% non-contiguous), 63/1024 blocks
+Exit status is 1
diff --git a/tests/f_ea_inode_no_feature/expect.2 b/tests/f_ea_inode_no_feature/expect.2
new file mode 100644
index 000000000000..24d059a300a9
--- /dev/null
+++ b/tests/f_ea_inode_no_feature/expect.2
@@ -0,0 +1,7 @@
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 13/128 files (0.0% non-contiguous), 63/1024 blocks
+Exit status is 0
diff --git a/tests/f_ea_inode_no_feature/image.gz b/tests/f_ea_inode_no_feature/image.gz
new file mode 100644
index 0000000000000000000000000000000000000000..596d69a1c990ee5b79c7e2b291904fe5a5aab4b3
GIT binary patch
literal 1817
zcmb2|=3oeZYmvsl{PwPIMvSWr!-vY*zEYDpf|5jSXEa|;x-D@cRg|SQ!Anp-XkiBb
z-vZZP6SIUe18<3lyz!hgS)N^AjKAvQWVx1Q9917f1fo`T+?plgeel)Bb@^qR&EmIS
zZ1MT}w=VJCnc3gVp4&_RJ1j75k3hpBsqXe7j=z<rH-!!r#HDY}e~~$*;{N5!Q(tw9
zYhM+}+PYjX{p)YFWsfVJKbOumR-d}ZDwHcR|KGpY^)}nzUjIEWr+RPE!w1p3&*jXL
zKi>SCzelIuEc@TLS2z3T{eSp;W#e_fId=Dd-MlXS{`{fE3$vfyy1Fv^bA+btPycNm
z^_K77M87;J6#aqw>9X(N%#YuHd*b!(PoEq*e%i};6&jvcoB#fIjYZDAy1m!eRsVdV
zy;@k60Rjq?x8Ay_{IEZ2?X^iMKQ>BD@X_=?v~I%Gs?WPF>P@YxmcIY+HJ|L#TIa*c
z(yN^pvwv&(RsM8eR_0m0(D)nQV<tUiir}o&t1r(=xc%^)f%*UCQBpto|I{D-v%co{
z2jPu>qi5~4pWt!k|MB{re=>7U*K3IV<UgwVf8mZN_9D~&v_G2kKOp9le3$n>=facq
z8hSuUQ|teX4M{8S8o!s(=y`SFLY~GJ+dt_M8#MM@@jP)U5{+K^^Ry+@D+~+{QQ^zA
zuBJt<HB{fW=9<U#@|PR`1n?yuFIgHjSF=}J_v>@T_6u^G{@f^3?cV-Z^;@Z4@tcF6
z6~DA}I_Lkf`w*v-y!bJD_~+05x!;ekRQ7oNW7ieIC10N|1Cph`*If~8F(}iq|1$M7
z_x1leceb7Rey^(e^<?=YU-LgqyjklS^<T|=d7r{s^Y<RIj#1Xzfb5pZh5s*azwvLq
z$h$Sy-+q1k=db^DpUA#{<w^hE|4AvkpY{Cz@8eRXcfR+YyZJwL;o`XM?LXcZTCZ!d
z{QO^io^AP)-$#G7$M=4gx8Iw(r#iQoU*dTG*R8v~#BYB(`)qCH>+Y?UJodRacK!cw
zZsNr0|56P;ANgv(?|o<cxw7M*FS35Vzv0Ed?WX$W`h`7<o8|BAj;Q}X)8hZO^d###
zwzD5+=fXn{3uA}mk>|6IrB@$IuiExB)i=ZD>(^;h92v2w92FW3fzc2cj3E%<QO{%{
Lm3D)HL4W}Oi~P*4

literal 0
HcmV?d00001

diff --git a/tests/f_ea_inode_no_feature/name b/tests/f_ea_inode_no_feature/name
new file mode 100644
index 000000000000..b357afb47c6b
--- /dev/null
+++ b/tests/f_ea_inode_no_feature/name
@@ -0,0 +1 @@
+inode with ea inode but EA_INODE feature is not set
diff --git a/tests/f_ea_inode_spurious_flag_dir/expect.1 b/tests/f_ea_inode_spurious_flag_dir/expect.1
new file mode 100644
index 000000000000..19999ab79306
--- /dev/null
+++ b/tests/f_ea_inode_spurious_flag_dir/expect.1
@@ -0,0 +1,11 @@
+Pass 1: Checking inodes, blocks, and sizes
+Inode 2 has the ea_inode flag set but is not a regular file. Clear flag? yes
+
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+
+test_filesys: ***** FILE SYSTEM WAS MODIFIED *****
+test_filesys: 11/128 files (0.0% non-contiguous), 58/1024 blocks
+Exit status is 1
diff --git a/tests/f_ea_inode_spurious_flag_dir/expect.2 b/tests/f_ea_inode_spurious_flag_dir/expect.2
new file mode 100644
index 000000000000..a35477094496
--- /dev/null
+++ b/tests/f_ea_inode_spurious_flag_dir/expect.2
@@ -0,0 +1,7 @@
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 11/128 files (0.0% non-contiguous), 58/1024 blocks
+Exit status is 0
diff --git a/tests/f_ea_inode_spurious_flag_dir/image b/tests/f_ea_inode_spurious_flag_dir/image
new file mode 100644
index 0000000000000000000000000000000000000000..f323b6131cec7d37d5864ef02ea0f24de090a8fe
GIT binary patch
literal 1048576
zcmeI*O^8iV902h1K77oWg%XL)upuNGYBtI&SSTe*B8oH{UkfH1F&1`g$U;hF{WdmM
zN|J0)R^(%CF;ZB&&Uw${#$am9yz$QO)S3J7&OPV;fA{{+yv3clAt(e0<SH<l0<VWK
z5EqYXA&kUjCGBgM{<sqBXk4W7xELG`p(u8Js5INPwp*XIkDHe^<HlfIJeVEAk=XyS
zo2U04yuNL2<Ho{UXEq*R);i)}|D5y34i`2aKHq<L>(YCB7JXi{=E?j@*c|%49nly|
zasAuUAK}_2<(}(t=koH7E?8gF1u^6n!oH7(KK90-m&Cd%)<?CGP)(CTEZY}cdO8w%
zt~EEt`SIe;&7I@ywu=A(0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBo5fIv~4
ztA;N{QN(9|I#5RA$O-`h9TKR<r0)xr>e{$$tyimS<3@Uh?{%%Wdi2D}Q>%whj2u7Q
zf!V>31PDxtKz#1??ZAeWeJRh&`Twrg%Ks@DRHp<8%m{&$|NU<+G@p6@+?ntGGs3}1
z5Xey=<^O@P9hXz=@;}ErK+HJ{$p4(LzSwgYkpH>g0pibDK>p`^^~IjMfc($>4iJCN
z0`foSt1tH41>}G3cYyeF7LflrUwyIXE+GGNzXQadvw-~1`Ra>3cY$*L=WZc>0t5&U
zAds6t@zX0aI`n7Ah9y9t0|L3tcj6^LfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FqeB2sFk9hud|!&iBcc=^E+x
z<Gde=pVdQX$DWq0*0tvQ&_kHp-0b~SNzJ~ON?c3tPM%D;P=wGQF0Lr|@nih*-tJsK
z*XYi;CK}b%-ifyC&UUZXb!S`?jjHGDL|aZ>yV3Kp?{)S1uk&9e%%9}2+x~L=v)gI@
z+qApfET{SJ&H8fW`K@1>>@U#&oNQ=I=L5Ju6we{f!@uT#H7stP-uT~t;{T5fsZOSB
zx{>mK>C18-Ipu#jZtDaH5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PIJbfm%GR^ltlEvCfWl
zPORyzuRXCU1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
r2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7rc>Z6Uy%fq

literal 0
HcmV?d00001

diff --git a/tests/f_ea_inode_spurious_flag_dir/image.gz b/tests/f_ea_inode_spurious_flag_dir/image.gz
new file mode 100644
index 0000000000000000000000000000000000000000..af19132ce100fc006c8b83832683dbf2bcab6b53
GIT binary patch
literal 1598
zcmb2|=3uD*Z;{5p{PwPYhi{+^`-l6#56}20=4G5>maM)kvt`z#q=QbHfs+<ZId*72
z>*U@u5fM=e+?o@=-o6o`=~<?s{V6@yaFapy^}X+TZFw$z;CuJ{v(@uG)$eNG&-?wV
z`d;jw>zxdzvR18lCHVT&vqaq_rF`wV>^xgfUwM;OT$N*^bh>Q+>MecQ`P*x&?moKN
zyK&FX{RWRb{{1_iH|JjYhg;uV&%XX^em=)y->362zUTSBe>0c2xm%xp`@!A4%*M=z
z`=^B@6`Q1eFO56?-e`)wR`HkXpU)k<U%Tl@TQGk^eA&l?r|0e46FYJG)xan9N~?~h
zOt`)A%b~}eFZTZ0d);n#ZE|?I8z%z<{PCIQ8}`_FTIyDn<?~N9q^zpskPckg_aygs
z<yI@BOaFN9pN@+E`l564@@qZwXIRu}oczP^hq1Tg`s-`!vvm6OKmT8L?VSCG|5~5y
zzr3n>ZT{Xk^WEP@m##nZGwxNctkC-(p!bRYsp|iLI9$}#ne_|{Vm7UxcE;mxeaeFB
zOJ}U0Zi7+>`c0M}KW0BQZ|>)dPxI!!{CzL)<mz8B*W<I-w##f>75aVedXe_pu+DE%
zFFzOl@Hi5X6Lan6^|R;gx1LOUCAg$?ss2}vOI3!ms#r3=&hxcx>R4G^X&SY@-ui!N
z(n*{9)xZ6}+3yTJQ$PD#$+xMQ|Ejl|0oCuaxvzhr{?4?uE8PVO*YEf*IrsIy<x;1k
z-!2OK`}MDX^0qU_m%VoV$3DOO+f>c}s18Qu9k{=K+VrH{>#UWLGp5hWSpVzR?4kfv
bC8NC25Eu=C!5acoF1d$inN4J15MTfRZKqU&

literal 0
HcmV?d00001

diff --git a/tests/f_ea_inode_spurious_flag_dir/name b/tests/f_ea_inode_spurious_flag_dir/name
new file mode 100644
index 000000000000..8ae52ccf02f8
--- /dev/null
+++ b/tests/f_ea_inode_spurious_flag_dir/name
@@ -0,0 +1 @@
+ea inode flag set on a directory
--
2.35.3


2024-05-09 15:01:32

by Theodore Ts'o

[permalink] [raw]
Subject: Re: [PATCH 0/3] e2fsck: expand checking of EA inode


On Mon, 06 May 2024 19:41:16 +0200, Jan Kara wrote:
> customer has reported that his filesystem was reporting errors from
> ext4_iget() about inode with EA_INODE_FL but e2fsck was considering the
> filesystem as clean. Indeed the EA inode checking in e2fsck is weak and
> lets through several cases of corruption related to EA inodes. This series
> adds more strict checking of EA inodes and adds e2fsck tests for them.
>
> Honza
>
> [...]

Applied, thanks!

[1/3] e2fsck: add more checks for ea inode consistency
commit: 849a9e6e133a903db7b005854ec58b35dc947150
[2/3] e2fsck: add tests for EA inodes
commit: eb01b6e22a44a26668c9f8645ca1889d67a643c1
[3/3] e2fsck: fix golden output of several tests
commit: 7b2e837bf0eacb5c12396e994b4c7979f576019a

Best regards,
--
Theodore Ts'o <[email protected]>