diff options
author | Andreas Gruenbacher <agruenba@redhat.com> | 2017-12-11 06:49:55 -0500 |
---|---|---|
committer | Andreas Gruenbacher <agruenba@redhat.com> | 2018-01-18 15:15:37 -0500 |
commit | 5cf26b1e88c9eef76a1e8bdedbad48db925bbdd5 (patch) | |
tree | 29e9d9ba8e64035cdfa04b4c6ceaa7e957a51ec5 | |
parent | bdba0d5ec13ed48420a4f85a69317c963c0de67e (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.c | 122 |
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 | ||
282 | static void gfs2_metapath_ra(struct gfs2_glock *gl, struct metapath *mp, | 282 | static 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 | */ |
1097 | static int sweep_bh_for_rgrps(struct gfs2_inode *ip, struct gfs2_holder *rd_gh, | 1094 | static 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 | |||
1117 | more_rgrps: | 1108 | more_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 | ||
1294 | static inline void | ||
1295 | metapointer_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 */ |