All of lore.kernel.org
 help / color / mirror / Atom feed
From: Tahsin Erdogan <tahsin@google.com>
To: Andreas Dilger <adilger@dilger.ca>,
	"Darrick J . Wong" <darrick.wong@oracle.com>,
	Theodore Ts'o <tytso@mit.edu>,
	linux-ext4@vger.kernel.org
Cc: Tahsin Erdogan <tahsin@google.com>
Subject: [PATCH 06/12] e2fsck: update i_blocks accounting for ea_inode feature
Date: Mon, 26 Jun 2017 06:43:42 -0700	[thread overview]
Message-ID: <20170626134348.1240-6-tahsin@google.com> (raw)
In-Reply-To: <20170626134348.1240-1-tahsin@google.com>

With ea_inode feature, i_blocks include the disk space used by
referenced xattr inodes. Make e2fsck aware of that.

Signed-off-by: Tahsin Erdogan <tahsin@google.com>
---
 e2fsck/e2fsck.c |   4 ++
 e2fsck/e2fsck.h |   5 +++
 e2fsck/pass1.c  | 124 +++++++++++++++++++++++++++++++++++++++++---------------
 3 files changed, 100 insertions(+), 33 deletions(-)

diff --git a/e2fsck/e2fsck.c b/e2fsck/e2fsck.c
index 0f9da46a5a12..e0f449ee2047 100644
--- a/e2fsck/e2fsck.c
+++ b/e2fsck/e2fsck.c
@@ -98,6 +98,10 @@ errcode_t e2fsck_reset_context(e2fsck_t ctx)
 		ea_refcount_free(ctx->refcount_extra);
 		ctx->refcount_extra = 0;
 	}
+	if (ctx->ea_block_quota) {
+		ea_refcount_free(ctx->ea_block_quota);
+		ctx->ea_block_quota = 0;
+	}
 	if (ctx->block_dup_map) {
 		ext2fs_free_block_bitmap(ctx->block_dup_map);
 		ctx->block_dup_map = 0;
diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h
index f9285d01978c..79eeda9fbafb 100644
--- a/e2fsck/e2fsck.h
+++ b/e2fsck/e2fsck.h
@@ -269,6 +269,11 @@ struct e2fsck_struct {
 	ext2_refcount_t	refcount;
 	ext2_refcount_t refcount_extra;
 
+	/*
+	 * Quota blocks to be charged for each ea block.
+	 */
+	ext2_refcount_t ea_block_quota;
+
 	/*
 	 * Array of flags indicating whether an inode bitmap, block
 	 * bitmap, or inode table is invalid
diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
index 9ee2c5e89a61..cc88a7d05cef 100644
--- a/e2fsck/pass1.c
+++ b/e2fsck/pass1.c
@@ -66,7 +66,7 @@ static int process_bad_block(ext2_filsys fs, blk64_t *block_nr,
 			     e2_blkcnt_t blockcnt, blk64_t ref_blk,
 			     int ref_offset, void *priv_data);
 static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
-			 char *block_buf);
+			 char *block_buf, blk64_t ea_ibody_quota_blocks);
 static void mark_table_blocks(e2fsck_t ctx);
 static void alloc_bb_map(e2fsck_t ctx);
 static void alloc_imagic_map(e2fsck_t ctx);
@@ -103,6 +103,7 @@ struct process_block_struct {
 
 struct process_inode_block {
 	ext2_ino_t ino;
+	blk64_t ea_ibody_quota_blocks;
 	struct ext2_inode_large inode;
 };
 
@@ -351,13 +352,25 @@ static void mark_inode_ea_map(e2fsck_t ctx, struct problem_context *pctx,
 	ext2fs_mark_inode_bitmap2(ctx->inode_ea_map, ino);
 }
 
+/*
+ * 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)
+				      struct problem_context *pctx,
+				      blk64_t *quota_blocks)
 {
 	struct ext2_inode inode;
 	__u32 hash;
@@ -380,11 +393,15 @@ static problem_t check_large_ea_inode(e2fsck_t ctx,
 		fatal_error(ctx, 0);
 	}
 
-	if (hash != entry->e_hash) {
+	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) {
-
+		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.
 			 */
@@ -411,7 +428,8 @@ static problem_t check_large_ea_inode(e2fsck_t ctx,
 	return 0;
 }
 
-static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx)
+static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx,
+			      blk64_t *ea_ibody_quota_blocks)
 {
 	struct ext2_super_block *sb = ctx->fs->super;
 	struct ext2_inode_large *inode;
@@ -420,6 +438,9 @@ static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx)
 	unsigned int storage_size, remain;
 	problem_t problem = 0;
 	region_t region = 0;
+	blk64_t quota_blocks = 0;
+
+	*ea_ibody_quota_blocks = 0;
 
 	inode = (struct ext2_inode_large *) pctx->inode;
 	storage_size = EXT2_INODE_SIZE(ctx->fs->super) - EXT2_GOOD_OLD_INODE_SIZE -
@@ -496,11 +517,15 @@ static void check_ea_in_inode(e2fsck_t ctx, struct problem_context *pctx)
 				goto fix;
 			}
 		} else {
-			problem = check_large_ea_inode(ctx, entry, pctx);
+			blk64_t entry_quota_blocks;
+
+			problem = check_large_ea_inode(ctx, entry, pctx,
+						       &entry_quota_blocks);
 			if (problem != 0)
 				goto fix;
 
 			mark_inode_ea_map(ctx, pctx, entry->e_value_inum);
+			quota_blocks += entry_quota_blocks;
 		}
 
 		/* If EA value is stored in external inode then it does not
@@ -523,8 +548,10 @@ fix:
 	 * it seems like a corruption. it's very unlikely we could repair
 	 * EA(s) in automatic fashion -bzzz
 	 */
-	if (problem == 0 || !fix_problem(ctx, problem, pctx))
+	if (problem == 0 || !fix_problem(ctx, problem, pctx)) {
+		*ea_ibody_quota_blocks = quota_blocks;
 		return;
+	}
 
 	/* simply remove all possible EA(s) */
 	*((__u32 *)header) = 0UL;
@@ -547,13 +574,16 @@ static int check_inode_extra_negative_epoch(__u32 xtime, __u32 extra) {
  */
 #define EXT4_EXTRA_NEGATIVE_DATE_CUTOFF 2 * (1LL << 32)
 
-static void check_inode_extra_space(e2fsck_t ctx, struct problem_context *pctx)
+static void check_inode_extra_space(e2fsck_t ctx, struct problem_context *pctx,
+				    blk64_t *ea_ibody_quota_blocks)
 {
 	struct ext2_super_block *sb = ctx->fs->super;
 	struct ext2_inode_large *inode;
 	__u32 *eamagic;
 	int min, max;
 
+	*ea_ibody_quota_blocks = 0;
+
 	inode = (struct ext2_inode_large *) pctx->inode;
 	if (EXT2_INODE_SIZE(sb) == EXT2_GOOD_OLD_INODE_SIZE) {
 		/* this isn't large inode. so, nothing to check */
@@ -592,7 +622,7 @@ static void check_inode_extra_space(e2fsck_t ctx, struct problem_context *pctx)
 			inode->i_extra_isize);
 	if (*eamagic == EXT2_EXT_ATTR_MAGIC) {
 		/* it seems inode has an extended attribute(s) in body */
-		check_ea_in_inode(ctx, pctx);
+		check_ea_in_inode(ctx, pctx, ea_ibody_quota_blocks);
 	}
 
 	/*
@@ -1150,6 +1180,7 @@ void e2fsck_pass1(e2fsck_t ctx)
 	int		failed_csum = 0;
 	ext2_ino_t	ino_threshold = 0;
 	dgrp_t		ra_group = 0;
+	blk64_t		ea_ibody_quota_blocks;
 
 	init_resource_track(&rtrack, ctx->fs->io);
 	clear_problem_context(&pctx);
@@ -1695,7 +1726,7 @@ void e2fsck_pass1(e2fsck_t ctx)
 							   "pass1");
 					failed_csum = 0;
 				}
-				check_blocks(ctx, &pctx, block_buf);
+				check_blocks(ctx, &pctx, block_buf, 0);
 				FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum);
 				continue;
 			}
@@ -1722,7 +1753,7 @@ void e2fsck_pass1(e2fsck_t ctx)
 							"pass1");
 					failed_csum = 0;
 				}
-				check_blocks(ctx, &pctx, block_buf);
+				check_blocks(ctx, &pctx, block_buf, 0);
 				FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum);
 				continue;
 			}
@@ -1760,7 +1791,7 @@ void e2fsck_pass1(e2fsck_t ctx)
 					failed_csum = 0;
 				}
 			}
-			check_blocks(ctx, &pctx, block_buf);
+			check_blocks(ctx, &pctx, block_buf, 0);
 			FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum);
 			continue;
 		}
@@ -1825,7 +1856,7 @@ void e2fsck_pass1(e2fsck_t ctx)
 			}
 		}
 
-		check_inode_extra_space(ctx, &pctx);
+		check_inode_extra_space(ctx, &pctx, &ea_ibody_quota_blocks);
 		check_is_really_dir(ctx, &pctx, block_buf);
 
 		/*
@@ -1872,7 +1903,8 @@ void e2fsck_pass1(e2fsck_t ctx)
 				continue;
 			} else if (ext2fs_inode_data_blocks(fs, inode) == 0) {
 				ctx->fs_fast_symlinks_count++;
-				check_blocks(ctx, &pctx, block_buf);
+				check_blocks(ctx, &pctx, block_buf,
+					     ea_ibody_quota_blocks);
 				FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum);
 				continue;
 			}
@@ -1906,17 +1938,19 @@ void e2fsck_pass1(e2fsck_t ctx)
 		     inode->i_block[EXT2_DIND_BLOCK] ||
 		     inode->i_block[EXT2_TIND_BLOCK] ||
 		     ext2fs_file_acl_block(fs, inode))) {
-			struct ext2_inode_large *ip;
+			struct process_inode_block *itp;
 
-			inodes_to_process[process_inode_count].ino = ino;
-			ip = &inodes_to_process[process_inode_count].inode;
+			itp = &inodes_to_process[process_inode_count];
+			itp->ino = ino;
+			itp->ea_ibody_quota_blocks = ea_ibody_quota_blocks;
 			if (inode_size < sizeof(struct ext2_inode_large))
-				memcpy(ip, inode, inode_size);
+				memcpy(&itp->inode, inode, inode_size);
 			else
-				memcpy(ip, inode, sizeof(*ip));
+				memcpy(&itp->inode, inode, sizeof(itp->inode));
 			process_inode_count++;
 		} else
-			check_blocks(ctx, &pctx, block_buf);
+			check_blocks(ctx, &pctx, block_buf,
+				     ea_ibody_quota_blocks);
 
 		FINISH_INODE_LOOP(ctx, ino, &pctx, failed_csum);
 
@@ -2086,7 +2120,8 @@ static void process_inodes(e2fsck_t ctx, char *block_buf)
 		sprintf(buf, _("reading indirect blocks of inode %u"),
 			pctx.ino);
 		ehandler_operation(buf);
-		check_blocks(ctx, &pctx, block_buf);
+		check_blocks(ctx, &pctx, block_buf,
+			     inodes_to_process[i].ea_ibody_quota_blocks);
 		if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
 			break;
 	}
@@ -2306,7 +2341,7 @@ static void adjust_extattr_refcount(e2fsck_t ctx, ext2_refcount_t refcount,
  * Handle processing the extended attribute blocks
  */
 static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
-			   char *block_buf)
+			   char *block_buf, blk64_t *ea_block_quota_blocks)
 {
 	ext2_filsys fs = ctx->fs;
 	ext2_ino_t	ino = pctx->ino;
@@ -2315,7 +2350,7 @@ static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
 	char *		end;
 	struct ext2_ext_attr_header *header;
 	struct ext2_ext_attr_entry *entry;
-	int		count;
+	blk64_t		quota_blocks = EXT2FS_C2B(fs, 1);
 	region_t	region = 0;
 	int		failed_csum = 0;
 
@@ -2369,6 +2404,12 @@ static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
 
 	/* Have we seen this EA block before? */
 	if (ext2fs_fast_test_block_bitmap2(ctx->block_ea_map, blk)) {
+		if (ctx->ea_block_quota)
+			ea_refcount_fetch(ctx->ea_block_quota, blk,
+					  ea_block_quota_blocks);
+		else
+			*ea_block_quota_blocks = 0;
+
 		if (ea_refcount_decrement(ctx->refcount, blk, 0) == 0)
 			return 1;
 		/* Ooops, this EA was referenced more than it stated */
@@ -2477,13 +2518,17 @@ static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
 			}
 		} else {
 			problem_t problem;
+			blk64_t entry_quota_blocks;
 
-			problem = check_large_ea_inode(ctx, entry, pctx);
+			problem = check_large_ea_inode(ctx, entry, pctx,
+						       &entry_quota_blocks);
 			if (problem == 0)
 				mark_inode_ea_map(ctx, pctx,
 						  entry->e_value_inum);
 			else if (fix_problem(ctx, problem, pctx))
 				goto clear_extattr;
+
+			quota_blocks += entry_quota_blocks;
 		}
 
 		entry = EXT2_EXT_ATTR_NEXT(entry);
@@ -2506,9 +2551,21 @@ static int check_ext_attr(e2fsck_t ctx, struct problem_context *pctx,
 			return 0;
 	}
 
-	count = header->h_refcount - 1;
-	if (count)
-		ea_refcount_store(ctx->refcount, blk, count);
+	*ea_block_quota_blocks = quota_blocks;
+	if (quota_blocks) {
+		if (!ctx->ea_block_quota) {
+			pctx->errcode = ea_refcount_create(0,
+							&ctx->ea_block_quota);
+			if (pctx->errcode) {
+				pctx->num = 3;
+				fix_problem(ctx, PR_1_ALLOCATE_REFCOUNT, pctx);
+				ctx->flags |= E2F_FLAG_ABORT;
+				return 0;
+			}
+		}
+		ea_refcount_store(ctx->ea_block_quota, blk, quota_blocks);
+	}
+	ea_refcount_store(ctx->refcount, blk, header->h_refcount - 1);
 	mark_block_used(ctx, blk);
 	ext2fs_fast_mark_block_bitmap2(ctx->block_ea_map, blk);
 	return 1;
@@ -3162,7 +3219,7 @@ err:
  * blocks used by that inode.
  */
 static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
-			 char *block_buf)
+			 char *block_buf, blk64_t ea_ibody_quota_blocks)
 {
 	ext2_filsys fs = ctx->fs;
 	struct process_block_struct pb;
@@ -3173,9 +3230,10 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
 	int		extent_fs;
 	int		inlinedata_fs;
 	__u64		size;
+	blk64_t		ea_block_quota_blocks = 0;
 
 	pb.ino = ino;
-	pb.num_blocks = 0;
+	pb.num_blocks = EXT2FS_B2C(ctx->fs, ea_ibody_quota_blocks);
 	pb.last_block = ~0;
 	pb.last_init_lblock = -1;
 	pb.last_db_block = -1;
@@ -3198,10 +3256,10 @@ static void check_blocks(e2fsck_t ctx, struct problem_context *pctx,
 	extent_fs = ext2fs_has_feature_extents(ctx->fs->super);
 	inlinedata_fs = ext2fs_has_feature_inline_data(ctx->fs->super);
 
-	if (check_ext_attr(ctx, pctx, block_buf)) {
+	if (check_ext_attr(ctx, pctx, block_buf, &ea_block_quota_blocks)) {
 		if (ctx->flags & E2F_FLAG_SIGNAL_MASK)
 			goto out;
-		pb.num_blocks++;
+		pb.num_blocks += EXT2FS_B2C(ctx->fs, ea_block_quota_blocks);
 	}
 
 	if (inlinedata_fs && (inode->i_flags & EXT4_INLINE_DATA_FL))
-- 
2.13.1.611.g7e3b11ae1-goog

  parent reply	other threads:[~2017-06-26 13:44 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-06-26 13:43 [PATCH 01/12] e2fsck: add support for large xattrs in external inodes Tahsin Erdogan
2017-06-26 13:43 ` [PATCH 02/12] tune2fs: do not allow disabling ea_inode feature Tahsin Erdogan
2017-06-26 13:43 ` [PATCH 03/12] e2fsck: ea_inode hash validation Tahsin Erdogan
2017-06-26 21:21   ` Andreas Dilger
2017-06-28  1:41     ` [PATCH v2 " Tahsin Erdogan
2017-06-28  1:47       ` Tahsin Erdogan
2017-06-26 13:43 ` [PATCH 04/12] e2fsck: do not early terminate extra space check Tahsin Erdogan
2017-06-26 21:23   ` Andreas Dilger
2017-06-26 23:57     ` Tahsin Erdogan
2017-06-26 13:43 ` [PATCH 05/12] e2fsck: generalize ea_refcount Tahsin Erdogan
2017-06-26 13:43 ` Tahsin Erdogan [this message]
2017-06-26 21:36   ` [PATCH 06/12] e2fsck: update i_blocks accounting for ea_inode feature Andreas Dilger
2017-06-27 11:37     ` Tahsin Erdogan
2017-06-30  1:39       ` Tahsin Erdogan
2017-06-26 13:43 ` [PATCH 07/12] e2fsck: track ea_inode references Tahsin Erdogan
2017-06-26 21:45   ` Andreas Dilger
2017-06-27  1:25     ` Tahsin Erdogan
2017-06-27 18:43       ` Andreas Dilger
2017-06-28  1:26         ` Tahsin Erdogan
2017-06-26 13:43 ` [PATCH 08/12] e2fsck: add test for ea_inode feature Tahsin Erdogan
2017-06-26 13:43 ` [PATCH 09/12] tune2fs: update ea_inode hashes when fs uuid changes Tahsin Erdogan
2017-06-26 13:43 ` [PATCH 10/12] fuse2fs: refuse to mount fs with ea_inode feature Tahsin Erdogan
2017-06-26 13:43 ` [PATCH 11/12] mke2fs: ea_inode is not supported for hurd Tahsin Erdogan
2017-06-26 13:43 ` [PATCH 12/12] resize2fs: moving xattr inodes is not supported Tahsin Erdogan
2017-07-05  4:04 ` [PATCH 01/12] e2fsck: add support for large xattrs in external inodes Theodore Ts'o

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170626134348.1240-6-tahsin@google.com \
    --to=tahsin@google.com \
    --cc=adilger@dilger.ca \
    --cc=darrick.wong@oracle.com \
    --cc=linux-ext4@vger.kernel.org \
    --cc=tytso@mit.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.