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
next prev 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).