Skip to content

Commit 75d893d

Browse files
author
Darrick J. Wong
committed
xfs: speed up rmap lookups by using non-overlapped lookups when possible
Reverse mapping on a reflink-capable filesystem has some pretty high overhead when performing file operations. This is because the rmap records for logically and physically adjacent extents might not be adjacent in the rmap index due to data block sharing. As a result, we use expensive overlapped-interval btree search, which walks every record that overlaps with the supplied key in the hopes of finding the record. However, profiling data shows that when the index contains a record that is an exact match for a query key, the non-overlapped btree search function can find the record much faster than the overlapped version. Try the non-overlapped lookup first, which will make scrub run much faster. Signed-off-by: Darrick J. Wong <[email protected]> Reviewed-by: Dave Chinner <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]>
1 parent 5b7ca8b commit 75d893d

File tree

1 file changed

+38
-14
lines changed

1 file changed

+38
-14
lines changed

fs/xfs/libxfs/xfs_rmap.c

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -367,7 +367,6 @@ xfs_rmap_lookup_le_range_helper(
367367
return 0;
368368

369369
*info->irec = *rec;
370-
*info->stat = 1;
371370
return -ECANCELED;
372371
}
373372

@@ -388,6 +387,7 @@ xfs_rmap_lookup_le_range(
388387
int *stat)
389388
{
390389
struct xfs_find_left_neighbor_info info;
390+
int found = 0;
391391
int error;
392392

393393
info.high.rm_startblock = bno;
@@ -400,20 +400,44 @@ xfs_rmap_lookup_le_range(
400400
info.high.rm_blockcount = 0;
401401
*stat = 0;
402402
info.irec = irec;
403-
info.stat = stat;
404403

405-
trace_xfs_rmap_lookup_le_range(cur->bc_mp,
406-
cur->bc_ag.pag->pag_agno, bno, 0, owner, offset, flags);
407-
error = xfs_rmap_query_range(cur, &info.high, &info.high,
408-
xfs_rmap_lookup_le_range_helper, &info);
409-
if (error == -ECANCELED)
410-
error = 0;
411-
if (*stat)
412-
trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
413-
cur->bc_ag.pag->pag_agno, irec->rm_startblock,
414-
irec->rm_blockcount, irec->rm_owner,
415-
irec->rm_offset, irec->rm_flags);
416-
return error;
404+
trace_xfs_rmap_lookup_le_range(cur->bc_mp, cur->bc_ag.pag->pag_agno,
405+
bno, 0, owner, offset, flags);
406+
407+
/*
408+
* Historically, we always used the range query to walk every reverse
409+
* mapping that could possibly overlap the key that the caller asked
410+
* for, and filter out the ones that don't. That is very slow when
411+
* there are a lot of records.
412+
*
413+
* However, there are two scenarios where the classic btree search can
414+
* produce correct results -- if the index contains a record that is an
415+
* exact match for the lookup key; and if there are no other records
416+
* between the record we want and the key we supplied.
417+
*
418+
* As an optimization, try a non-overlapped lookup first. This makes
419+
* scrub run much faster on most filesystems because bmbt records are
420+
* usually an exact match for rmap records. If we don't find what we
421+
* want, we fall back to the overlapped query.
422+
*/
423+
error = xfs_rmap_lookup_le(cur, bno, owner, offset, flags, irec,
424+
&found);
425+
if (error)
426+
return error;
427+
if (found)
428+
error = xfs_rmap_lookup_le_range_helper(cur, irec, &info);
429+
if (!error)
430+
error = xfs_rmap_query_range(cur, &info.high, &info.high,
431+
xfs_rmap_lookup_le_range_helper, &info);
432+
if (error != -ECANCELED)
433+
return error;
434+
435+
*stat = 1;
436+
trace_xfs_rmap_lookup_le_range_result(cur->bc_mp,
437+
cur->bc_ag.pag->pag_agno, irec->rm_startblock,
438+
irec->rm_blockcount, irec->rm_owner, irec->rm_offset,
439+
irec->rm_flags);
440+
return 0;
417441
}
418442

419443
/*

0 commit comments

Comments
 (0)