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 ...@@ -279,15 +279,11 @@ static inline __be64 *metapointer(unsigned int height, const struct metapath *mp
return p + mp->mp_list[height]; return p + mp->mp_list[height];
} }
static void gfs2_metapath_ra(struct gfs2_glock *gl, struct metapath *mp, static void gfs2_metapath_ra(struct gfs2_glock *gl, __be64 *start, __be64 *end)
unsigned int height)
{ {
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; const __be64 *t;
for (t = pos; t < endp; t++) { for (t = start; t < end; t++) {
struct buffer_head *rabh; struct buffer_head *rabh;
if (!*t) if (!*t)
...@@ -1077,10 +1073,11 @@ static int trunc_start(struct inode *inode, u64 newsize) ...@@ -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 * sweep_bh_for_rgrps - find an rgrp in a meta buffer and free blocks therein
* @ip: inode * @ip: inode
* @rg_gh: holder of resource group glock * @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 * @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 * 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 * 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) ...@@ -1095,47 +1092,46 @@ static int trunc_start(struct inode *inode, u64 newsize)
* *btotal has the total number of blocks freed * *btotal has the total number of blocks freed
*/ */
static int sweep_bh_for_rgrps(struct gfs2_inode *ip, struct gfs2_holder *rd_gh, static int sweep_bh_for_rgrps(struct gfs2_inode *ip, struct gfs2_holder *rd_gh,
const struct metapath *mp, u32 *btotal, int hgt, struct buffer_head *bh, __be64 *start, __be64 *end,
bool keep_start) bool meta, u32 *btotal)
{ {
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
struct gfs2_rgrpd *rgd; struct gfs2_rgrpd *rgd;
struct gfs2_trans *tr; struct gfs2_trans *tr;
struct buffer_head *bh = mp->mp_bh[hgt]; __be64 *p;
__be64 *top, *bottom, *p;
int blks_outside_rgrp; int blks_outside_rgrp;
u64 bn, bstart, isize_blks; u64 bn, bstart, isize_blks;
s64 blen; /* needs to be s64 or gfs2_add_inode_blocks breaks */ s64 blen; /* needs to be s64 or gfs2_add_inode_blocks breaks */
int meta = ((hgt != ip->i_height - 1) ? 1 : 0);
int ret = 0; int ret = 0;
bool buf_in_tr = false; /* buffer was added to transaction */ 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: 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; blks_outside_rgrp = 0;
bstart = 0; bstart = 0;
blen = 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) if (!*p)
continue; continue;
bn = be64_to_cpu(*p); bn = be64_to_cpu(*p);
if (gfs2_holder_initialized(rd_gh)) {
rgd = gfs2_glock2rgrp(rd_gh->gh_gl); if (rgd) {
gfs2_assert_withdraw(sdp, if (!rgrp_contains_block(rgd, bn)) {
gfs2_glock_is_locked_by_me(rd_gh->gh_gl)); blks_outside_rgrp++;
continue;
}
} else { } else {
rgd = gfs2_blk2rgrpd(sdp, bn, true); rgd = gfs2_blk2rgrpd(sdp, bn, true);
if (unlikely(!rgd)) {
ret = -EIO;
goto out;
}
ret = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, ret = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE,
0, rd_gh); 0, rd_gh);
if (ret) if (ret)
...@@ -1147,11 +1143,6 @@ static int sweep_bh_for_rgrps(struct gfs2_inode *ip, struct gfs2_holder *rd_gh, ...@@ -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); 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 /* The size of our transactions will be unknown until we
actually process all the metadata blocks that relate to actually process all the metadata blocks that relate to
the rgrp. So we estimate. We know it can't be more than 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, ...@@ -1170,7 +1161,7 @@ static int sweep_bh_for_rgrps(struct gfs2_inode *ip, struct gfs2_holder *rd_gh,
jblocks_rqsted += isize_blks; jblocks_rqsted += isize_blks;
revokes = jblocks_rqsted; revokes = jblocks_rqsted;
if (meta) if (meta)
revokes += hptrs(sdp, hgt); revokes += end - start;
else if (ip->i_depth) else if (ip->i_depth)
revokes += sdp->sd_inptrs; revokes += sdp->sd_inptrs;
ret = gfs2_trans_begin(sdp, jblocks_rqsted, revokes); 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, ...@@ -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, outside the rgrp we just processed,
do it all over again. */ do it all over again. */
if (current->journal_info) { 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 /* Every transaction boundary, we rewrite the dinode
to keep its di_blocks current in case of failure. */ 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, ...@@ -1236,6 +1231,7 @@ static int sweep_bh_for_rgrps(struct gfs2_inode *ip, struct gfs2_holder *rd_gh,
current_time(&ip->i_inode); current_time(&ip->i_inode);
gfs2_trans_add_meta(ip->i_gl, dibh); gfs2_trans_add_meta(ip->i_gl, dibh);
gfs2_dinode_out(ip, dibh->b_data); gfs2_dinode_out(ip, dibh->b_data);
brelse(dibh);
up_write(&ip->i_rw_mutex); up_write(&ip->i_rw_mutex);
gfs2_trans_end(sdp); gfs2_trans_end(sdp);
} }
...@@ -1295,6 +1291,23 @@ static bool mp_eq_to_hgt(struct metapath *mp, __u16 *list, unsigned int h) ...@@ -1295,6 +1291,23 @@ static bool mp_eq_to_hgt(struct metapath *mp, __u16 *list, unsigned int h)
return true; 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 * trunc_dealloc - truncate a file down to a desired size
* @ip: inode to truncate * @ip: inode to truncate
...@@ -1321,7 +1334,7 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 newsize) ...@@ -1321,7 +1334,7 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 newsize)
int ret, state; int ret, state;
int mp_h; /* metapath buffers are read in to this height */ int mp_h; /* metapath buffers are read in to this height */
u64 prev_bnr = 0; u64 prev_bnr = 0;
bool keep_start; /* need to preserve the first meta pointer? */ __be64 *start, *end;
memset(&mp, 0, sizeof(mp)); memset(&mp, 0, sizeof(mp));
find_metapath(sdp, lblock, &mp, ip->i_height); find_metapath(sdp, lblock, &mp, ip->i_height);
...@@ -1352,8 +1365,11 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 newsize) ...@@ -1352,8 +1365,11 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 newsize)
goto out_metapath; goto out_metapath;
/* issue read-ahead on metadata */ /* issue read-ahead on metadata */
for (mp_h = 0; mp_h < mp.mp_aheight - 1; mp_h++) for (mp_h = 0; mp_h < mp.mp_aheight - 1; mp_h++) {
gfs2_metapath_ra(ip->i_gl, &mp, 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) if (mp.mp_aheight == ip->i_height)
state = DEALLOC_MP_FULL; /* We have a complete metapath */ state = DEALLOC_MP_FULL; /* We have a complete metapath */
...@@ -1388,11 +1404,20 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 newsize) ...@@ -1388,11 +1404,20 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 newsize)
} }
prev_bnr = bh->b_blocknr; prev_bnr = bh->b_blocknr;
keep_start = mp_h < start_aligned && if (gfs2_metatype_check(sdp, bh,
mp_eq_to_hgt(&mp, start_list, mp_h); (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, /* If we hit an error or just swept dinode buffer,
just exit. */ just exit. */
if (ret || !mp_h) { if (ret || !mp_h) {
...@@ -1446,9 +1471,12 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 newsize) ...@@ -1446,9 +1471,12 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 newsize)
/* issue read-ahead on metadata */ /* issue read-ahead on metadata */
if (mp.mp_aheight > 1) { if (mp.mp_aheight > 1) {
for (; ret > 1; ret--) for (; ret > 1; ret--) {
gfs2_metapath_ra(ip->i_gl, &mp, metapointer_range(&mp, mp.mp_aheight - ret,
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 */ /* 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