cluster-devel.redhat.com archive mirror
 help / color / mirror / Atom feed
From: Andreas Gruenbacher <agruenba@redhat.com>
To: cluster-devel.redhat.com
Subject: [Cluster-devel] [PATCH 8/8] gfs2: Get rid of gfs2_write_calc_reserv in gfs2_iomap_begin_write
Date: Tue, 28 Aug 2018 23:47:31 +0200	[thread overview]
Message-ID: <20180828214731.15199-9-agruenba@redhat.com> (raw)
In-Reply-To: <20180828214731.15199-1-agruenba@redhat.com>

Compute the number of blocks to allocate in gfs2_compute_alloc_size.
This allows to get rid of gfs2_write_calc_reserv in
gfs2_iomap_begin_write.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
---
 fs/gfs2/bmap.c | 113 +++++++++++++++++++++++++++++++------------------
 1 file changed, 71 insertions(+), 42 deletions(-)

diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index 66ecc4439e77..0ccabf925afd 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -32,14 +32,15 @@
 #include "trace_gfs2.h"
 
 /* This doesn't need to be that large as max 64 bit pointers in a 4k
- * block is 512, so __u16 is fine for that. It saves stack space to
+ * block is 512, so u16 is fine for that. It saves stack space to
  * keep it small.
  */
 struct metapath {
 	struct buffer_head *mp_bh[GFS2_MAX_META_HEIGHT];
-	__u16 mp_list[GFS2_MAX_META_HEIGHT];
-	int mp_fheight; /* find_metapath height */
-	int mp_aheight; /* actual height (lookup height) */
+	u16 mp_list[GFS2_MAX_META_HEIGHT];
+	u16 mp_data_blocks, mp_ind_blocks;
+	u8 mp_fheight; /* find_metapath height */
+	u8 mp_aheight; /* actual height (lookup height) */
 };
 
 static int punch_hole(struct gfs2_inode *ip, u64 offset, u64 length);
@@ -647,8 +648,7 @@ static int gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap,
 	struct gfs2_sbd *sdp = GFS2_SB(inode);
 	struct buffer_head *dibh = mp->mp_bh[0];
 	u64 bn;
-	unsigned n, i, blks, alloced = 0, iblks = 0;
-	size_t dblks = iomap->length >> inode->i_blkbits;
+	unsigned n, i, blks, alloced = 0;
 	const unsigned end_of_metadata = mp->mp_fheight - 1;
 	int ret;
 	enum alloc_state state;
@@ -657,7 +657,7 @@ static int gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap,
 
 	BUG_ON(mp->mp_aheight < 1);
 	BUG_ON(dibh == NULL);
-	BUG_ON(dblks < 1);
+	BUG_ON(mp->mp_data_blocks < 1);
 
 	gfs2_trans_add_meta(ip->i_gl, dibh);
 
@@ -668,32 +668,18 @@ static int gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap,
 		state = ALLOC_DATA;
 	} else {
 		/* Need to allocate indirect blocks */
-		iblks = mp->mp_fheight - mp->mp_aheight;
-		/*
-		 * If the height doesn't increase or the inode doesn't contain
-		 * any pointers, we can go straight to extending the tree down.
-		 */
 		if (mp->mp_fheight == ip->i_height || !contains_data) {
 			/* Extend tree down */
 			state = ALLOC_GROW_DEPTH;
 		} else {
 			/* Build up tree height */
 			state = ALLOC_GROW_HEIGHT;
-			iblks += mp->mp_fheight - ip->i_height;
-			if (mp->mp_list[0] == 0) {
-				/*
-				 * The metapath for growing the height and the
-				 * metapath for the new allocation start with
-				 * the same block; only allocate it once.
-				 */
-				iblks--;
-			}
 		}
 	}
 
 	/* start of the second part of the function (state machine) */
 
-	blks = dblks + iblks;
+	blks = mp->mp_data_blocks + mp->mp_ind_blocks;
 	i = mp->mp_aheight;
 	do {
 		n = blks - alloced;
@@ -763,12 +749,13 @@ static int gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap,
 				break;
 		/* Tree complete, adding data blocks */
 		case ALLOC_DATA:
-			BUG_ON(n > dblks);
+			BUG_ON(n > mp->mp_data_blocks);
 			BUG_ON(mp->mp_bh[end_of_metadata] == NULL);
 			gfs2_trans_add_meta(ip->i_gl, mp->mp_bh[end_of_metadata]);
-			dblks = n;
 			ptr = metapointer(end_of_metadata, mp);
 			iomap->addr = bn << inode->i_blkbits;
+			iomap->length = (u64)n << inode->i_blkbits;
+			iomap->type = IOMAP_MAPPED;
 			iomap->flags |= IOMAP_F_MERGED | IOMAP_F_NEW;
 			while (n-- > 0)
 				*ptr++ = cpu_to_be64(bn++);
@@ -776,8 +763,6 @@ static int gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap,
 		}
 	} while (iomap->addr == IOMAP_NULL_ADDR);
 
-	iomap->type = IOMAP_MAPPED;
-	iomap->length = (u64)dblks << inode->i_blkbits;
 	ip->i_height = mp->mp_fheight;
 	gfs2_add_inode_blocks(&ip->i_inode, alloced);
 	gfs2_dinode_out(ip, dibh->b_data);
@@ -793,16 +778,19 @@ static int gfs2_iomap_alloc(struct inode *inode, struct iomap *iomap,
  * @inode: The inode
  * @mp: The metapath
  * @iomap: The iomap
+ * @contains_data: False if the inode is known empty
  *
  * Compute the maximum size of the next allocation at @mp.
  */
 static void gfs2_compute_alloc_size(struct inode *inode, struct metapath *mp,
-				    struct iomap *iomap)
+				    struct iomap *iomap, bool contains_data)
 {
 	struct gfs2_inode *ip = GFS2_I(inode);
 	struct gfs2_sbd *sdp = GFS2_SB(inode);
 	u64 len = iomap->length >> inode->i_blkbits;
 
+	mp->mp_data_blocks = 0;
+	mp->mp_ind_blocks = 0;
 	if (gfs2_is_stuffed(ip) || mp->mp_fheight != mp->mp_aheight) {
 		unsigned int maxlen;
 
@@ -811,9 +799,43 @@ static void gfs2_compute_alloc_size(struct inode *inode, struct metapath *mp,
 		if (gfs2_inode_contains_data(inode)) {
 			if (iomap->offset == 0)
 				maxlen = 1;
+			else if (gfs2_is_stuffed(ip))
+				mp->mp_data_blocks++;
 		}
 		if (len > maxlen)
 			len = maxlen;
+
+		if (mp->mp_fheight != mp->mp_aheight) {
+			unsigned int h;
+
+			/* Fill out the metadata tree to its full height. */
+			mp->mp_ind_blocks += mp->mp_fheight - mp->mp_aheight;
+
+			/*
+			 * When growing the height, going from height 0 to 1
+			 * requires no indirect blocks.  Going any further
+			 * requires one indirect block for each level.
+			 */
+			h = max_t(unsigned int, ip->i_height, 1);
+			if (mp->mp_fheight > h && contains_data) {
+				mp->mp_ind_blocks += mp->mp_fheight - h;
+				/*
+				 * If the metapath for growing the height and
+				 * the metapath for the new allocation start
+				 * with the same block, we only need to account
+				 * for that block once.
+				 *
+				 * (This kind of overlap is possible because
+				 * indirect blocks contain more pointers than
+				 * the inode.  When we grow the height, a write
+				 * that would have gone beyond the last pointer
+				 * in the inode may still go into the first
+				 * indirect block.)
+				 */
+				if (mp->mp_list[0] == 0)
+					mp->mp_ind_blocks--;
+			}
+		}
 	} else {
 		const __be64 *first, *ptr, *end;
 
@@ -827,6 +849,7 @@ static void gfs2_compute_alloc_size(struct inode *inode, struct metapath *mp,
 		}
 		len = ptr - first;
 	}
+	mp->mp_data_blocks += len;
 	iomap->length = len << inode->i_blkbits;
 }
 
@@ -1014,7 +1037,7 @@ static int gfs2_iomap_begin_write(struct inode *inode, loff_t pos,
 	struct metapath mp = { .mp_aheight = 1, };
 	struct gfs2_inode *ip = GFS2_I(inode);
 	struct gfs2_sbd *sdp = GFS2_SB(inode);
-	unsigned int data_blocks = 0, ind_blocks = 0, rblocks;
+	unsigned int rblocks;
 	bool contains_data, unstuff, alloc_required;
 	int ret;
 
@@ -1034,15 +1057,11 @@ static int gfs2_iomap_begin_write(struct inode *inode, loff_t pos,
 	alloc_required = unstuff || iomap->type == IOMAP_HOLE;
 
 	if (iomap->type == IOMAP_HOLE)
-		gfs2_compute_alloc_size(inode, &mp, iomap);
-
-	if (alloc_required || gfs2_is_jdata(ip))
-		gfs2_write_calc_reserv(ip, iomap->length, &data_blocks,
-				       &ind_blocks);
+		gfs2_compute_alloc_size(inode, &mp, iomap, contains_data);
 
 	if (alloc_required) {
 		struct gfs2_alloc_parms ap = {
-			.target = data_blocks + ind_blocks
+			.target = mp.mp_data_blocks + mp.mp_ind_blocks
 		};
 
 		ret = gfs2_quota_lock_check(ip, &ap);
@@ -1054,15 +1073,16 @@ static int gfs2_iomap_begin_write(struct inode *inode, loff_t pos,
 			goto out_qunlock;
 	}
 
-	rblocks = RES_DINODE + ind_blocks;
+	rblocks = RES_DINODE + mp.mp_ind_blocks;
 	if (gfs2_is_jdata(ip))
-		rblocks += data_blocks;
-	if (ind_blocks || data_blocks)
+		rblocks += mp.mp_data_blocks;
+	if (mp.mp_ind_blocks || mp.mp_data_blocks)
 		rblocks += RES_STATFS + RES_QUOTA;
 	if (inode == sdp->sd_rindex)
 		rblocks += 2 * RES_STATFS;
 	if (alloc_required)
-		rblocks += gfs2_rg_blocks(ip, data_blocks + ind_blocks);
+		rblocks += gfs2_rg_blocks(ip, mp.mp_data_blocks +
+					      mp.mp_ind_blocks);
 
 	ret = gfs2_trans_begin(sdp, rblocks, iomap->length >> inode->i_blkbits);
 	if (ret)
@@ -1074,6 +1094,10 @@ static int gfs2_iomap_begin_write(struct inode *inode, loff_t pos,
 		ret = __gfs2_unstuff_dinode(ip, NULL, dibh, contains_data);
 		if (ret)
 			goto out_trans_end;
+		if (contains_data) {
+			BUG_ON(mp.mp_data_blocks < 1);
+			mp.mp_data_blocks--;
+		}
 		release_metapath(&mp);
 		brelse(iomap->private);
 		iomap->private = NULL;
@@ -1234,9 +1258,12 @@ int gfs2_block_map(struct inode *inode, sector_t lblock,
 	if (create) {
 		ret = gfs2_iomap_get(inode, pos, length, IOMAP_WRITE, &iomap, &mp);
 		if (!ret && iomap.type == IOMAP_HOLE) {
-			gfs2_compute_alloc_size(inode, &mp, &iomap);
+			bool contains_data = gfs2_inode_contains_data(inode);
+
+			gfs2_compute_alloc_size(inode, &mp, &iomap,
+						contains_data);
 			ret = gfs2_iomap_alloc(inode, &iomap, IOMAP_WRITE, &mp,
-					       gfs2_inode_contains_data(inode));
+					       contains_data);
 		}
 		release_metapath(&mp);
 	} else {
@@ -1467,9 +1494,11 @@ int gfs2_iomap_get_alloc(struct inode *inode, loff_t pos, loff_t length,
 
 	ret = gfs2_iomap_get(inode, pos, length, IOMAP_WRITE, iomap, &mp);
 	if (!ret && iomap->type == IOMAP_HOLE) {
-		gfs2_compute_alloc_size(inode, &mp, iomap);
+		bool contains_data = gfs2_inode_contains_data(inode);
+
+		gfs2_compute_alloc_size(inode, &mp, iomap, contains_data);
 		ret = gfs2_iomap_alloc(inode, iomap, IOMAP_WRITE, &mp,
-				       gfs2_inode_contains_data(inode));
+				       contains_data);
 	}
 	release_metapath(&mp);
 	return ret;
-- 
2.17.1



  parent reply	other threads:[~2018-08-28 21:47 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-08-28 21:47 [Cluster-devel] [PATCH 0/8] Get rid of gfs2_write_calc_reserv in gfs2_iomap_begin_write Andreas Gruenbacher
2018-08-28 21:47 ` [Cluster-devel] [PATCH 1/8] gfs2: Don't depend on mp_aheight in clone_metapath Andreas Gruenbacher
2018-08-28 21:47 ` [Cluster-devel] [PATCH 2/8] gfs2: Split gfs2_indirect_init Andreas Gruenbacher
2018-08-28 21:47 ` [Cluster-devel] [PATCH 3/8] gfs2: Move empty inode check out of gfs2_unstuff_dinode Andreas Gruenbacher
2018-08-28 21:47 ` [Cluster-devel] [PATCH 4/8] gfs2: Don't create unnecessary indirect blocks Andreas Gruenbacher
2018-08-28 21:47 ` [Cluster-devel] [PATCH 5/8] gfs2: Improve gfs2_alloc_size for stuffed files Andreas Gruenbacher
2018-08-28 21:47 ` [Cluster-devel] [PATCH 6/8] gfs2: Rename size to len in gfs2_alloc_size Andreas Gruenbacher
2018-08-28 21:47 ` [Cluster-devel] [PATCH 7/8] gfs2: Move gfs2_alloc_size out of gfs2_iomap_get Andreas Gruenbacher
2018-08-28 21:47 ` Andreas Gruenbacher [this message]
2018-08-29 10:12 ` [Cluster-devel] [PATCH 0/8] Get rid of gfs2_write_calc_reserv in gfs2_iomap_begin_write Steven Whitehouse

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=20180828214731.15199-9-agruenba@redhat.com \
    --to=agruenba@redhat.com \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).