Commit 5cf26b1e authored by Andreas Gruenbacher's avatar Andreas Gruenbacher

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: default avatarAndreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: default avatarBob Peterson <rpeterso@redhat.com>
parent bdba0d5e
......@@ -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 @@ static int trunc_start(struct inode *inode, u64 newsize)
* 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 @@ static int trunc_start(struct inode *inode, u64 newsize)
* *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 @@ static int sweep_bh_for_rgrps(struct gfs2_inode *ip, struct gfs2_holder *rd_gh,
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 @@ static int sweep_bh_for_rgrps(struct gfs2_inode *ip, struct gfs2_holder *rd_gh,
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 @@ static int sweep_bh_for_rgrps(struct gfs2_inode *ip, struct gfs2_holder *rd_gh,
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 @@ static int sweep_bh_for_rgrps(struct gfs2_inode *ip, struct gfs2_holder *rd_gh,
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 */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment