+/*
+ * For a given size, calculate how many blocks would be charged towards quota.
+ */
+static blk64_t size_to_quota_blocks(ext2_filsys fs, size_t size)
+{
+ blk64_t clusters;
+
+ clusters = DIV_ROUND_UP(size, fs->blocksize << fs->cluster_ratio_bits);
+ return EXT2FS_C2B(fs, clusters);
+}
+
+/*
+ * Check validity of EA inode. Return 0 if EA inode is valid, otherwise return
+ * the problem code.
+ */
+static problem_t check_large_ea_inode(e2fsck_t ctx,
+ struct ext2_ext_attr_entry *entry,
+ struct problem_context *pctx,
+ blk64_t *quota_blocks)
+{
+ struct ext2_inode inode;
+ __u32 hash;
+ errcode_t retval;
+
+ /* Check if inode is within valid range */
+ if ((entry->e_value_inum < EXT2_FIRST_INODE(ctx->fs->super)) ||
+ (entry->e_value_inum > ctx->fs->super->s_inodes_count)) {
+ pctx->num = entry->e_value_inum;
+ return PR_1_ATTR_VALUE_EA_INODE;
+ }
+
+ e2fsck_read_inode(ctx, entry->e_value_inum, &inode, "pass1");
+
+ retval = ext2fs_ext_attr_hash_entry2(ctx->fs, entry, NULL, &hash);
+ if (retval) {
+ com_err("check_large_ea_inode", retval,
+ _("while hashing entry with e_value_inum = %u"),
+ entry->e_value_inum);
+ fatal_error(ctx, 0);
+ }
+
+ if (hash == entry->e_hash) {
+ *quota_blocks = size_to_quota_blocks(ctx->fs,
+ entry->e_value_size);
+ } else {
+ /* This might be an old Lustre-style ea_inode reference. */
+ if (inode.i_mtime == pctx->ino &&
+ inode.i_generation == pctx->inode->i_generation) {
+ *quota_blocks = 0;
+ } else {
+ /* If target inode is also missing EA_INODE flag,
+ * this is likely to be a bad reference.
+ */
+ if (!(inode.i_flags & EXT4_EA_INODE_FL)) {
+ pctx->num = entry->e_value_inum;
+ return PR_1_ATTR_VALUE_EA_INODE;
+ } else {
+ pctx->num = entry->e_hash;
+ return PR_1_ATTR_HASH;
+ }
+ }
+ }
+
+ if (!(inode.i_flags & EXT4_EA_INODE_FL)) {
+ pctx->num = entry->e_value_inum;
+ if (fix_problem(ctx, PR_1_ATTR_SET_EA_INODE_FL, pctx)) {
+ inode.i_flags |= EXT4_EA_INODE_FL;
+ ext2fs_write_inode(ctx->fs, entry->e_value_inum,
+ &inode);
+ } else {
+ return PR_1_ATTR_NO_EA_INODE_FL;
+ }
+ }
+ return 0;
+}
+
+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;
+
+ for (entry = first;
+ (void *)entry < end && !EXT2_EXT_IS_LAST_ENTRY(entry);
+ entry = EXT2_EXT_ATTR_NEXT(entry)) {
+ if (!entry->e_value_inum)
+ continue;
+ 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);
+ }
+}
+
+static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx,
+ struct ea_quota *ea_ibody_quota)