aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruenba@redhat.com>2017-12-08 15:11:39 -0500
committerBob Peterson <rpeterso@redhat.com>2018-01-17 08:35:50 -0500
commitc3ce5aa9b02dd912e381237e7f98d591d7358cdc (patch)
tree97db1b1f8a04435798d5c369ed2271d8921c7943
parente8b43fe0c1e035a135be7ca3791d465fcb1b501e (diff)
gfs2: Fix metadata read-ahead during truncate
The metadata read-ahead algorithm broke when switching from recursive to non-recursive delete: the current algorithm reads ahead blocks at height N - 1 while deallocating the blocks at hight N. However, deallocating the blocks at height N requires a complete walk of the metadata tree, not only down to height N - 1. Consequently, all blocks below height N - 1 will be accessed without read-ahead. Fix this by issuing read-aheads as early as possible, after each metapath lookup. Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com> Signed-off-by: Bob Peterson <rpeterso@redhat.com>
-rw-r--r--fs/gfs2/bmap.c42
1 files changed, 25 insertions, 17 deletions
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
index 1110aa9f6f31..e983b5872679 100644
--- a/fs/gfs2/bmap.c
+++ b/fs/gfs2/bmap.c
@@ -279,14 +279,17 @@ 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, 282static void gfs2_metapath_ra(struct gfs2_glock *gl, struct metapath *mp,
283 const struct buffer_head *bh, const __be64 *pos) 283 unsigned int height)
284{ 284{
285 struct buffer_head *rabh; 285 struct buffer_head *bh = mp->mp_bh[height];
286 const __be64 *pos = metapointer(height, mp);
286 const __be64 *endp = (const __be64 *)(bh->b_data + bh->b_size); 287 const __be64 *endp = (const __be64 *)(bh->b_data + bh->b_size);
287 const __be64 *t; 288 const __be64 *t;
288 289
289 for (t = pos; t < endp; t++) { 290 for (t = pos; t < endp; t++) {
291 struct buffer_head *rabh;
292
290 if (!*t) 293 if (!*t)
291 continue; 294 continue;
292 295
@@ -353,12 +356,13 @@ static int lookup_metapath(struct gfs2_inode *ip, struct metapath *mp)
353 * 356 *
354 * Similar to lookup_metapath, but does lookups for a range of heights 357 * Similar to lookup_metapath, but does lookups for a range of heights
355 * 358 *
356 * Returns: error 359 * Returns: error or the number of buffers filled
357 */ 360 */
358 361
359static int fillup_metapath(struct gfs2_inode *ip, struct metapath *mp, int h) 362static int fillup_metapath(struct gfs2_inode *ip, struct metapath *mp, int h)
360{ 363{
361 unsigned int x = 0; 364 unsigned int x = 0;
365 int ret;
362 366
363 if (h) { 367 if (h) {
364 /* find the first buffer we need to look up. */ 368 /* find the first buffer we need to look up. */
@@ -367,7 +371,10 @@ static int fillup_metapath(struct gfs2_inode *ip, struct metapath *mp, int h)
367 break; 371 break;
368 } 372 }
369 } 373 }
370 return __fillup_metapath(ip, mp, x, h); 374 ret = __fillup_metapath(ip, mp, x, h);
375 if (ret)
376 return ret;
377 return mp->mp_aheight - x - 1;
371} 378}
372 379
373static inline void release_metapath(struct metapath *mp) 380static inline void release_metapath(struct metapath *mp)
@@ -1309,7 +1316,6 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 newsize)
1309 u32 btotal = 0; 1316 u32 btotal = 0;
1310 int ret, state; 1317 int ret, state;
1311 int mp_h; /* metapath buffers are read in to this height */ 1318 int mp_h; /* metapath buffers are read in to this height */
1312 sector_t last_ra = 0;
1313 u64 prev_bnr = 0; 1319 u64 prev_bnr = 0;
1314 bool preserve1; /* need to preserve the first meta pointer? */ 1320 bool preserve1; /* need to preserve the first meta pointer? */
1315 1321
@@ -1331,6 +1337,11 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 newsize)
1331 ret = lookup_metapath(ip, &mp); 1337 ret = lookup_metapath(ip, &mp);
1332 if (ret) 1338 if (ret)
1333 goto out_metapath; 1339 goto out_metapath;
1340
1341 /* issue read-ahead on metadata */
1342 for (mp_h = 0; mp_h < mp.mp_aheight - 1; mp_h++)
1343 gfs2_metapath_ra(ip->i_gl, &mp, mp_h);
1344
1334 if (mp.mp_aheight == ip->i_height) 1345 if (mp.mp_aheight == ip->i_height)
1335 state = DEALLOC_MP_FULL; /* We have a complete metapath */ 1346 state = DEALLOC_MP_FULL; /* We have a complete metapath */
1336 else 1347 else
@@ -1352,16 +1363,6 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 newsize)
1352 /* Truncate a full metapath at the given strip height. 1363 /* Truncate a full metapath at the given strip height.
1353 * Note that strip_h == mp_h in order to be in this state. */ 1364 * Note that strip_h == mp_h in order to be in this state. */
1354 case DEALLOC_MP_FULL: 1365 case DEALLOC_MP_FULL:
1355 if (mp_h > 0) { /* issue read-ahead on metadata */
1356 __be64 *top;
1357
1358 bh = mp.mp_bh[mp_h - 1];
1359 if (bh->b_blocknr != last_ra) {
1360 last_ra = bh->b_blocknr;
1361 top = metaptr1(mp_h - 1, &mp);
1362 gfs2_metapath_ra(ip->i_gl, bh, top);
1363 }
1364 }
1365 /* If we're truncating to a non-zero size and the mp is 1366 /* If we're truncating to a non-zero size and the mp is
1366 at the beginning of file for the strip height, we 1367 at the beginning of file for the strip height, we
1367 need to preserve the first metadata pointer. */ 1368 need to preserve the first metadata pointer. */
@@ -1427,9 +1428,16 @@ static int trunc_dealloc(struct gfs2_inode *ip, u64 newsize)
1427 case DEALLOC_FILL_MP: 1428 case DEALLOC_FILL_MP:
1428 /* Fill the buffers out to the current height. */ 1429 /* Fill the buffers out to the current height. */
1429 ret = fillup_metapath(ip, &mp, mp_h); 1430 ret = fillup_metapath(ip, &mp, mp_h);
1430 if (ret) 1431 if (ret < 0)
1431 goto out; 1432 goto out;
1432 1433
1434 /* issue read-ahead on metadata */
1435 if (mp.mp_aheight > 1) {
1436 for (; ret > 1; ret--)
1437 gfs2_metapath_ra(ip->i_gl, &mp,
1438 mp.mp_aheight - ret);
1439 }
1440
1433 /* If buffers found for the entire strip height */ 1441 /* If buffers found for the entire strip height */
1434 if (mp.mp_aheight - 1 == strip_h) { 1442 if (mp.mp_aheight - 1 == strip_h) {
1435 state = DEALLOC_MP_FULL; 1443 state = DEALLOC_MP_FULL;