aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruenba@redhat.com>2017-12-11 06:49:55 -0500
committerAndreas Gruenbacher <agruenba@redhat.com>2018-01-18 15:15:37 -0500
commit5cf26b1e88c9eef76a1e8bdedbad48db925bbdd5 (patch)
tree29e9d9ba8e64035cdfa04b4c6ceaa7e957a51ec5
parentbdba0d5ec13ed48420a4f85a69317c963c0de67e (diff)
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>
-rw-r--r--fs/gfs2/bmap.c122
1 files changed, 75 insertions, 47 deletions
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index c4a297e87512..8fd42ae026dd 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -279,15 +279,11 @@ static inline __be64 *metapointer(unsigned int height, const struct metapath *mp
279 return p + mp->mp_list[height]; 279 return p + mp->mp_list[height];
280} 280}
281 281
282static void gfs2_metapath_ra(struct gfs2_glock *gl, struct metapath *mp, 282static void gfs2_metapath_ra(struct gfs2_glock *gl, __be64 *start, __be64 *end)
283 unsigned int height)
284{ 283{
285 struct buffer_head *bh = mp->mp_bh[height];
286 const __be64 *pos = metapointer(height, mp);
287 const __be64 *endp = (const __be64 *)(bh->b_data + bh->b_size);
288 const __be64 *t; 284 const __be64 *t;
289 285
290 for (t = pos; t < endp; t++) { 286 for (t = start; t < end; t++) {
291 struct buffer_head *rabh; 287 struct buffer_head *rabh;
292 288
293 if (!*t) 289 if (!*t)
@@ -1077,10 +1073,11 @@ out:
1077 * sweep_bh_for_rgrps - find an rgrp in a meta buffer and free blocks therein 1073 * sweep_bh_for_rgrps - find an rgrp in a meta buffer and free blocks therein
1078 * @ip: inode 1074 * @ip: inode
1079 * @rg_gh: holder of resource group glock 1075 * @rg_gh: holder of resource group glock
1080 * @mp: current metapath fully populated with buffers 1076 * @bh: buffer head to sweep
1077 * @start: starting point in bh
1078 * @end: end point in bh
1079 * @meta: true if bh points to metadata (rather than data)
1081 * @btotal: place to keep count of total blocks freed 1080 * @btotal: place to keep count of total blocks freed
1082 * @hgt: height we're processing
1083 * @keep_start: preserve the first meta pointer
1084 * 1081 *
1085 * We sweep a metadata buffer (provided by the metapath) for blocks we need to 1082 * We sweep a metadata buffer (provided by the metapath) for blocks we need to
1086 * free, and free them all. However, we do it one rgrp at a time. If this 1083 * free, and free them all. However, we do it one rgrp at a time. If this
@@ -1095,47 +1092,46 @@ out:
1095 * *btotal has the total number of blocks freed 1092 * *btotal has the total number of blocks freed
1096 */ 1093 */
1097static int sweep_bh_for_rgrps(struct gfs2_inode *ip, struct gfs2_holder *rd_gh, 1094static int sweep_bh_for_rgrps(struct gfs2_inode *ip, struct gfs2_holder *rd_gh,
1098 const struct metapath *mp, u32 *btotal, int hgt, 1095 struct buffer_head *bh, __be64 *start, __be64 *end,
1099 bool keep_start) 1096 bool meta, u32 *btotal)
1100{ 1097{
1101 struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); 1098 struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
1102 struct gfs2_rgrpd *rgd; 1099 struct gfs2_rgrpd *rgd;
1103 struct gfs2_trans *tr; 1100 struct gfs2_trans *tr;
1104 struct buffer_head *bh = mp->mp_bh[hgt]; 1101 __be64 *p;
1105 __be64 *top, *bottom, *p;
1106 int blks_outside_rgrp; 1102 int blks_outside_rgrp;
1107 u64 bn, bstart, isize_blks; 1103 u64 bn, bstart, isize_blks;
1108 s64 blen; /* needs to be s64 or gfs2_add_inode_blocks breaks */ 1104 s64 blen; /* needs to be s64 or gfs2_add_inode_blocks breaks */
1109 int meta = ((hgt != ip->i_height - 1) ? 1 : 0);
1110 int ret = 0; 1105 int ret = 0;
1111 bool buf_in_tr = false; /* buffer was added to transaction */ 1106 bool buf_in_tr = false; /* buffer was added to transaction */
1112 1107
1113 if (gfs2_metatype_check(sdp, bh,
1114 (hgt ? GFS2_METATYPE_IN : GFS2_METATYPE_DI)))
1115 return -EIO;
1116
1117more_rgrps: 1108more_rgrps:
1109 rgd = NULL;
1110 if (gfs2_holder_initialized(rd_gh)) {
1111 rgd = gfs2_glock2rgrp(rd_gh->gh_gl);
1112 gfs2_assert_withdraw(sdp,
1113 gfs2_glock_is_locked_by_me(rd_gh->gh_gl));
1114 }
1118 blks_outside_rgrp = 0; 1115 blks_outside_rgrp = 0;
1119 bstart = 0; 1116 bstart = 0;
1120 blen = 0; 1117 blen = 0;
1121 top = metapointer(hgt, mp); /* first ptr from metapath */
1122 /* If we're keeping some data at the truncation point, we've got to
1123 preserve the metadata tree by adding 1 to the starting metapath. */
1124 if (keep_start)
1125 top++;
1126
1127 bottom = (__be64 *)(bh->b_data + bh->b_size);
1128 1118
1129 for (p = top; p < bottom; p++) { 1119 for (p = start; p < end; p++) {
1130 if (!*p) 1120 if (!*p)
1131 continue; 1121 continue;
1132 bn = be64_to_cpu(*p); 1122 bn = be64_to_cpu(*p);
1133 if (gfs2_holder_initialized(rd_gh)) { 1123
1134 rgd = gfs2_glock2rgrp(rd_gh->gh_gl); 1124 if (rgd) {
1135 gfs2_assert_withdraw(sdp, 1125 if (!rgrp_contains_block(rgd, bn)) {
1136 gfs2_glock_is_locked_by_me(rd_gh->gh_gl)); 1126 blks_outside_rgrp++;
1127 continue;
1128 }
1137 } else { 1129 } else {
1138 rgd = gfs2_blk2rgrpd(sdp, bn, true); 1130 rgd = gfs2_blk2rgrpd(sdp, bn, true);
1131 if (unlikely(!rgd)) {
1132 ret = -EIO;
1133 goto out;
1134 }
1139 ret = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 1135 ret = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE,
1140 0, rd_gh); 1136 0, rd_gh);
1141 if (ret) 1137 if (ret)
@@ -1147,11 +1143,6 @@ more_rgrps:
1147 gfs2_rs_deltree(&ip->i_res); 1143 gfs2_rs_deltree(&ip->i_res);
1148 } 1144 }
1149 1145
1150 if (!rgrp_contains_block(rgd, bn)) {
1151 blks_outside_rgrp++;
1152 continue;
1153 }
1154
1155 /* The size of our transactions will be unknown until we 1146 /* The size of our transactions will be unknown until we
1156 actually process all the metadata blocks that relate to 1147 actually process all the metadata blocks that relate to
1157 the rgrp. So we estimate. We know it can't be more than 1148 the rgrp. So we estimate. We know it can't be more than
@@ -1170,7 +1161,7 @@ more_rgrps:
1170 jblocks_rqsted += isize_blks; 1161 jblocks_rqsted += isize_blks;
1171 revokes = jblocks_rqsted; 1162 revokes = jblocks_rqsted;
1172 if (meta) 1163 if (meta)
1173 revokes += hptrs(sdp, hgt); 1164 revokes += end - start;
1174 else if (ip->i_depth) 1165 else if (ip->i_depth)
1175 revokes += sdp->sd_inptrs; 1166 revokes += sdp->sd_inptrs;
1176 ret = gfs2_trans_begin(sdp, jblocks_rqsted, revokes); 1167 ret = gfs2_trans_begin(sdp, jblocks_rqsted, revokes);
@@ -1228,7 +1219,11 @@ out_unlock:
1228 outside the rgrp we just processed, 1219 outside the rgrp we just processed,
1229 do it all over again. */ 1220 do it all over again. */
1230 if (current->journal_info) { 1221 if (current->journal_info) {
1231 struct buffer_head *dibh = mp->mp_bh[0]; 1222 struct buffer_head *dibh;
1223
1224 ret = gfs2_meta_inode_buffer(ip, &dibh);
1225 if (ret)
1226 goto out;
1232 1227
1233 /* Every transaction boundary, we rewrite the dinode 1228 /* Every transaction boundary, we rewrite the dinode
1234 to keep its di_blocks current in case of failure. */ 1229 to keep its di_blocks current in case of failure. */
@@ -1236,6 +1231,7 @@ out_unlock:
1236 current_time(&ip->i_inode); 1231 current_time(&ip->i_inode);
1237 gfs2_trans_add_meta(ip->i_gl, dibh); 1232 gfs2_trans_add_meta(ip->i_gl, dibh);
1238 gfs2_dinode_out(ip, dibh->b_data); 1233 gfs2_dinode_out(ip, dibh->b_data);
1234 brelse(dibh);
1239 up_write(&ip->i_rw_mutex); 1235 up_write(&ip->i_rw_mutex);
1240 gfs2_trans_end(sdp); 1236 gfs2_trans_end(sdp);
1241 } 1237 }
@@ -1295,6 +1291,23 @@ static bool mp_eq_to_hgt(struct metapath *mp, __u16 *list, unsigned int h)
1295 return true; 1291 return true;
1296} 1292}
1297 1293
1294static inline void
1295metapointer_range(struct metapath *mp, int height,
1296 __u16 *start_list, unsigned int start_aligned,
1297 __be64 **start, __be64 **end)
1298{
1299 struct buffer_head *bh = mp->mp_bh[height];
1300 __be64 *first;
1301
1302 first = metaptr1(height, mp);
1303 *start = first;
1304 if (mp_eq_to_hgt(mp, start_list, height)) {
1305 bool keep_start = height < start_aligned;
1306 *start = first + start_list[height] + keep_start;
1307 }
1308 *end = (__be64 *)(bh->b_data + bh->b_size);
1309}
1310
1298/** 1311/**
1299 * trunc_dealloc - truncate a file down to a desired size 1312 * trunc_dealloc - truncate a file down to a desired size
1300 * @ip: inode to truncate 1313 * @ip: inode to truncate
@@ -1321,7 +1334,7 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 newsize)
1321 int ret, state; 1334 int ret, state;
1322 int mp_h; /* metapath buffers are read in to this height */ 1335 int mp_h; /* metapath buffers are read in to this height */
1323 u64 prev_bnr = 0; 1336 u64 prev_bnr = 0;
1324 bool keep_start; /* need to preserve the first meta pointer? */ 1337 __be64 *start, *end;
1325 1338
1326 memset(&mp, 0, sizeof(mp)); 1339 memset(&mp, 0, sizeof(mp));
1327 find_metapath(sdp, lblock, &mp, ip->i_height); 1340 find_metapath(sdp, lblock, &mp, ip->i_height);
@@ -1352,8 +1365,11 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 newsize)
1352 goto out_metapath; 1365 goto out_metapath;
1353 1366
1354 /* issue read-ahead on metadata */ 1367 /* issue read-ahead on metadata */
1355 for (mp_h = 0; mp_h < mp.mp_aheight - 1; mp_h++) 1368 for (mp_h = 0; mp_h < mp.mp_aheight - 1; mp_h++) {
1356 gfs2_metapath_ra(ip->i_gl, &mp, mp_h); 1369 metapointer_range(&mp, mp_h, start_list, start_aligned,
1370 &start, &end);
1371 gfs2_metapath_ra(ip->i_gl, start, end);
1372 }
1357 1373
1358 if (mp.mp_aheight == ip->i_height) 1374 if (mp.mp_aheight == ip->i_height)
1359 state = DEALLOC_MP_FULL; /* We have a complete metapath */ 1375 state = DEALLOC_MP_FULL; /* We have a complete metapath */
@@ -1388,11 +1404,20 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 newsize)
1388 } 1404 }
1389 prev_bnr = bh->b_blocknr; 1405 prev_bnr = bh->b_blocknr;
1390 1406
1391 keep_start = mp_h < start_aligned && 1407 if (gfs2_metatype_check(sdp, bh,
1392 mp_eq_to_hgt(&mp, start_list, mp_h); 1408 (mp_h ? GFS2_METATYPE_IN :
1409 GFS2_METATYPE_DI))) {
1410 ret = -EIO;
1411 goto out;
1412 }
1413
1414 metapointer_range(&mp, mp_h, start_list, start_aligned,
1415 &start, &end);
1416 ret = sweep_bh_for_rgrps(ip, &rd_gh, mp.mp_bh[mp_h],
1417 start, end,
1418 mp_h != ip->i_height - 1,
1419 &btotal);
1393 1420
1394 ret = sweep_bh_for_rgrps(ip, &rd_gh, &mp, &btotal,
1395 mp_h, keep_start);
1396 /* If we hit an error or just swept dinode buffer, 1421 /* If we hit an error or just swept dinode buffer,
1397 just exit. */ 1422 just exit. */
1398 if (ret || !mp_h) { 1423 if (ret || !mp_h) {
@@ -1446,9 +1471,12 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 newsize)
1446 1471
1447 /* issue read-ahead on metadata */ 1472 /* issue read-ahead on metadata */
1448 if (mp.mp_aheight > 1) { 1473 if (mp.mp_aheight > 1) {
1449 for (; ret > 1; ret--) 1474 for (; ret > 1; ret--) {
1450 gfs2_metapath_ra(ip->i_gl, &mp, 1475 metapointer_range(&mp, mp.mp_aheight - ret,
1451 mp.mp_aheight - ret); 1476 start_list, start_aligned,
1477 &start, &end);
1478 gfs2_metapath_ra(ip->i_gl, start, end);
1479 }
1452 } 1480 }
1453 1481
1454 /* If buffers found for the entire strip height */ 1482 /* If buffers found for the entire strip height */