gfs2: Generalize truncate code
Pull the code for computing the range of metapointers to iterate out of gfs2_metapath_ra (for readahead), sweep_bh_for_rgrps (for deallocating metapointers within a block), and trunc_dealloc (for walking the metadata tree). In sweep_bh_for_rgrps, move the code for looking up the resource group descriptor of the current resource group out of the inner loop. The metatype check moves to trunc_dealloc. Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com> Signed-off-by: Bob Peterson <rpeterso@redhat.com>
This commit is contained in:
parent
bdba0d5ec1
commit
5cf26b1e88
122
fs/gfs2/bmap.c
122
fs/gfs2/bmap.c
|
@ -279,15 +279,11 @@ static inline __be64 *metapointer(unsigned int height, const struct metapath *mp
|
|||
return p + mp->mp_list[height];
|
||||
}
|
||||
|
||||
static void gfs2_metapath_ra(struct gfs2_glock *gl, struct metapath *mp,
|
||||
unsigned int height)
|
||||
static void gfs2_metapath_ra(struct gfs2_glock *gl, __be64 *start, __be64 *end)
|
||||
{
|
||||
struct buffer_head *bh = mp->mp_bh[height];
|
||||
const __be64 *pos = metapointer(height, mp);
|
||||
const __be64 *endp = (const __be64 *)(bh->b_data + bh->b_size);
|
||||
const __be64 *t;
|
||||
|
||||
for (t = pos; t < endp; t++) {
|
||||
for (t = start; t < end; t++) {
|
||||
struct buffer_head *rabh;
|
||||
|
||||
if (!*t)
|
||||
|
@ -1077,10 +1073,11 @@ out:
|
|||
* sweep_bh_for_rgrps - find an rgrp in a meta buffer and free blocks therein
|
||||
* @ip: inode
|
||||
* @rg_gh: holder of resource group glock
|
||||
* @mp: current metapath fully populated with buffers
|
||||
* @bh: buffer head to sweep
|
||||
* @start: starting point in bh
|
||||
* @end: end point in bh
|
||||
* @meta: true if bh points to metadata (rather than data)
|
||||
* @btotal: place to keep count of total blocks freed
|
||||
* @hgt: height we're processing
|
||||
* @keep_start: preserve the first meta pointer
|
||||
*
|
||||
* We sweep a metadata buffer (provided by the metapath) for blocks we need to
|
||||
* free, and free them all. However, we do it one rgrp at a time. If this
|
||||
|
@ -1095,47 +1092,46 @@ out:
|
|||
* *btotal has the total number of blocks freed
|
||||
*/
|
||||
static int sweep_bh_for_rgrps(struct gfs2_inode *ip, struct gfs2_holder *rd_gh,
|
||||
const struct metapath *mp, u32 *btotal, int hgt,
|
||||
bool keep_start)
|
||||
struct buffer_head *bh, __be64 *start, __be64 *end,
|
||||
bool meta, u32 *btotal)
|
||||
{
|
||||
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
|
||||
struct gfs2_rgrpd *rgd;
|
||||
struct gfs2_trans *tr;
|
||||
struct buffer_head *bh = mp->mp_bh[hgt];
|
||||
__be64 *top, *bottom, *p;
|
||||
__be64 *p;
|
||||
int blks_outside_rgrp;
|
||||
u64 bn, bstart, isize_blks;
|
||||
s64 blen; /* needs to be s64 or gfs2_add_inode_blocks breaks */
|
||||
int meta = ((hgt != ip->i_height - 1) ? 1 : 0);
|
||||
int ret = 0;
|
||||
bool buf_in_tr = false; /* buffer was added to transaction */
|
||||
|
||||
if (gfs2_metatype_check(sdp, bh,
|
||||
(hgt ? GFS2_METATYPE_IN : GFS2_METATYPE_DI)))
|
||||
return -EIO;
|
||||
|
||||
more_rgrps:
|
||||
rgd = NULL;
|
||||
if (gfs2_holder_initialized(rd_gh)) {
|
||||
rgd = gfs2_glock2rgrp(rd_gh->gh_gl);
|
||||
gfs2_assert_withdraw(sdp,
|
||||
gfs2_glock_is_locked_by_me(rd_gh->gh_gl));
|
||||
}
|
||||
blks_outside_rgrp = 0;
|
||||
bstart = 0;
|
||||
blen = 0;
|
||||
top = metapointer(hgt, mp); /* first ptr from metapath */
|
||||
/* If we're keeping some data at the truncation point, we've got to
|
||||
preserve the metadata tree by adding 1 to the starting metapath. */
|
||||
if (keep_start)
|
||||
top++;
|
||||
|
||||
bottom = (__be64 *)(bh->b_data + bh->b_size);
|
||||
|
||||
for (p = top; p < bottom; p++) {
|
||||
for (p = start; p < end; p++) {
|
||||
if (!*p)
|
||||
continue;
|
||||
bn = be64_to_cpu(*p);
|
||||
if (gfs2_holder_initialized(rd_gh)) {
|
||||
rgd = gfs2_glock2rgrp(rd_gh->gh_gl);
|
||||
gfs2_assert_withdraw(sdp,
|
||||
gfs2_glock_is_locked_by_me(rd_gh->gh_gl));
|
||||
|
||||
if (rgd) {
|
||||
if (!rgrp_contains_block(rgd, bn)) {
|
||||
blks_outside_rgrp++;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
rgd = gfs2_blk2rgrpd(sdp, bn, true);
|
||||
if (unlikely(!rgd)) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
ret = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE,
|
||||
0, rd_gh);
|
||||
if (ret)
|
||||
|
@ -1147,11 +1143,6 @@ more_rgrps:
|
|||
gfs2_rs_deltree(&ip->i_res);
|
||||
}
|
||||
|
||||
if (!rgrp_contains_block(rgd, bn)) {
|
||||
blks_outside_rgrp++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* The size of our transactions will be unknown until we
|
||||
actually process all the metadata blocks that relate to
|
||||
the rgrp. So we estimate. We know it can't be more than
|
||||
|
@ -1170,7 +1161,7 @@ more_rgrps:
|
|||
jblocks_rqsted += isize_blks;
|
||||
revokes = jblocks_rqsted;
|
||||
if (meta)
|
||||
revokes += hptrs(sdp, hgt);
|
||||
revokes += end - start;
|
||||
else if (ip->i_depth)
|
||||
revokes += sdp->sd_inptrs;
|
||||
ret = gfs2_trans_begin(sdp, jblocks_rqsted, revokes);
|
||||
|
@ -1228,7 +1219,11 @@ out_unlock:
|
|||
outside the rgrp we just processed,
|
||||
do it all over again. */
|
||||
if (current->journal_info) {
|
||||
struct buffer_head *dibh = mp->mp_bh[0];
|
||||
struct buffer_head *dibh;
|
||||
|
||||
ret = gfs2_meta_inode_buffer(ip, &dibh);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* Every transaction boundary, we rewrite the dinode
|
||||
to keep its di_blocks current in case of failure. */
|
||||
|
@ -1236,6 +1231,7 @@ out_unlock:
|
|||
current_time(&ip->i_inode);
|
||||
gfs2_trans_add_meta(ip->i_gl, dibh);
|
||||
gfs2_dinode_out(ip, dibh->b_data);
|
||||
brelse(dibh);
|
||||
up_write(&ip->i_rw_mutex);
|
||||
gfs2_trans_end(sdp);
|
||||
}
|
||||
|
@ -1295,6 +1291,23 @@ static bool mp_eq_to_hgt(struct metapath *mp, __u16 *list, unsigned int h)
|
|||
return true;
|
||||
}
|
||||
|
||||
static inline void
|
||||
metapointer_range(struct metapath *mp, int height,
|
||||
__u16 *start_list, unsigned int start_aligned,
|
||||
__be64 **start, __be64 **end)
|
||||
{
|
||||
struct buffer_head *bh = mp->mp_bh[height];
|
||||
__be64 *first;
|
||||
|
||||
first = metaptr1(height, mp);
|
||||
*start = first;
|
||||
if (mp_eq_to_hgt(mp, start_list, height)) {
|
||||
bool keep_start = height < start_aligned;
|
||||
*start = first + start_list[height] + keep_start;
|
||||
}
|
||||
*end = (__be64 *)(bh->b_data + bh->b_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* trunc_dealloc - truncate a file down to a desired size
|
||||
* @ip: inode to truncate
|
||||
|
@ -1321,7 +1334,7 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 newsize)
|
|||
int ret, state;
|
||||
int mp_h; /* metapath buffers are read in to this height */
|
||||
u64 prev_bnr = 0;
|
||||
bool keep_start; /* need to preserve the first meta pointer? */
|
||||
__be64 *start, *end;
|
||||
|
||||
memset(&mp, 0, sizeof(mp));
|
||||
find_metapath(sdp, lblock, &mp, ip->i_height);
|
||||
|
@ -1352,8 +1365,11 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 newsize)
|
|||
goto out_metapath;
|
||||
|
||||
/* issue read-ahead on metadata */
|
||||
for (mp_h = 0; mp_h < mp.mp_aheight - 1; mp_h++)
|
||||
gfs2_metapath_ra(ip->i_gl, &mp, mp_h);
|
||||
for (mp_h = 0; mp_h < mp.mp_aheight - 1; mp_h++) {
|
||||
metapointer_range(&mp, mp_h, start_list, start_aligned,
|
||||
&start, &end);
|
||||
gfs2_metapath_ra(ip->i_gl, start, end);
|
||||
}
|
||||
|
||||
if (mp.mp_aheight == ip->i_height)
|
||||
state = DEALLOC_MP_FULL; /* We have a complete metapath */
|
||||
|
@ -1388,11 +1404,20 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 newsize)
|
|||
}
|
||||
prev_bnr = bh->b_blocknr;
|
||||
|
||||
keep_start = mp_h < start_aligned &&
|
||||
mp_eq_to_hgt(&mp, start_list, mp_h);
|
||||
if (gfs2_metatype_check(sdp, bh,
|
||||
(mp_h ? GFS2_METATYPE_IN :
|
||||
GFS2_METATYPE_DI))) {
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
metapointer_range(&mp, mp_h, start_list, start_aligned,
|
||||
&start, &end);
|
||||
ret = sweep_bh_for_rgrps(ip, &rd_gh, mp.mp_bh[mp_h],
|
||||
start, end,
|
||||
mp_h != ip->i_height - 1,
|
||||
&btotal);
|
||||
|
||||
ret = sweep_bh_for_rgrps(ip, &rd_gh, &mp, &btotal,
|
||||
mp_h, keep_start);
|
||||
/* If we hit an error or just swept dinode buffer,
|
||||
just exit. */
|
||||
if (ret || !mp_h) {
|
||||
|
@ -1446,9 +1471,12 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 newsize)
|
|||
|
||||
/* issue read-ahead on metadata */
|
||||
if (mp.mp_aheight > 1) {
|
||||
for (; ret > 1; ret--)
|
||||
gfs2_metapath_ra(ip->i_gl, &mp,
|
||||
mp.mp_aheight - ret);
|
||||
for (; ret > 1; ret--) {
|
||||
metapointer_range(&mp, mp.mp_aheight - ret,
|
||||
start_list, start_aligned,
|
||||
&start, &end);
|
||||
gfs2_metapath_ra(ip->i_gl, start, end);
|
||||
}
|
||||
}
|
||||
|
||||
/* If buffers found for the entire strip height */
|
||||
|
|
Loading…
Reference in New Issue