Skip to content

Commit 4a200a0

Browse files
author
Darrick J. Wong
committed
xfs: implement masked btree key comparisons for _has_records scans
For keyspace fullness scans, we want to be able to mask off the parts of the key that we don't care about. For most btree types we /do/ want the full keyspace, but for checking that a given space usage also has a full complement of rmapbt records (even if different/multiple owners) we need this masking so that we only track sparseness of rm_startblock, not the whole keyspace (which is extremely sparse). Augment the ->diff_two_keys and ->keys_contiguous helpers to take a third union xfs_btree_key argument, and wire up xfs_rmap_has_records to pass this through. This third "mask" argument should contain a nonzero value in each structure field that should be used in the key comparisons done during the scan. Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Dave Chinner <dchinner@redhat.com>
1 parent 6abc7ae commit 4a200a0

10 files changed

Lines changed: 142 additions & 40 deletions

fs/xfs/libxfs/xfs_alloc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3764,7 +3764,7 @@ xfs_alloc_has_records(
37643764
memset(&high, 0xFF, sizeof(high));
37653765
high.a.ar_startblock = bno + len - 1;
37663766

3767-
return xfs_btree_has_records(cur, &low, &high, outcome);
3767+
return xfs_btree_has_records(cur, &low, &high, NULL, outcome);
37683768
}
37693769

37703770
/*

fs/xfs/libxfs/xfs_alloc_btree.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -260,20 +260,27 @@ STATIC int64_t
260260
xfs_bnobt_diff_two_keys(
261261
struct xfs_btree_cur *cur,
262262
const union xfs_btree_key *k1,
263-
const union xfs_btree_key *k2)
263+
const union xfs_btree_key *k2,
264+
const union xfs_btree_key *mask)
264265
{
266+
ASSERT(!mask || mask->alloc.ar_startblock);
267+
265268
return (int64_t)be32_to_cpu(k1->alloc.ar_startblock) -
266-
be32_to_cpu(k2->alloc.ar_startblock);
269+
be32_to_cpu(k2->alloc.ar_startblock);
267270
}
268271

269272
STATIC int64_t
270273
xfs_cntbt_diff_two_keys(
271274
struct xfs_btree_cur *cur,
272275
const union xfs_btree_key *k1,
273-
const union xfs_btree_key *k2)
276+
const union xfs_btree_key *k2,
277+
const union xfs_btree_key *mask)
274278
{
275279
int64_t diff;
276280

281+
ASSERT(!mask || (mask->alloc.ar_blockcount &&
282+
mask->alloc.ar_startblock));
283+
277284
diff = be32_to_cpu(k1->alloc.ar_blockcount) -
278285
be32_to_cpu(k2->alloc.ar_blockcount);
279286
if (diff)
@@ -427,8 +434,11 @@ STATIC enum xbtree_key_contig
427434
xfs_allocbt_keys_contiguous(
428435
struct xfs_btree_cur *cur,
429436
const union xfs_btree_key *key1,
430-
const union xfs_btree_key *key2)
437+
const union xfs_btree_key *key2,
438+
const union xfs_btree_key *mask)
431439
{
440+
ASSERT(!mask || mask->alloc.ar_startblock);
441+
432442
return xbtree_key_contig(be32_to_cpu(key1->alloc.ar_startblock),
433443
be32_to_cpu(key2->alloc.ar_startblock));
434444
}

fs/xfs/libxfs/xfs_bmap_btree.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -382,11 +382,14 @@ STATIC int64_t
382382
xfs_bmbt_diff_two_keys(
383383
struct xfs_btree_cur *cur,
384384
const union xfs_btree_key *k1,
385-
const union xfs_btree_key *k2)
385+
const union xfs_btree_key *k2,
386+
const union xfs_btree_key *mask)
386387
{
387388
uint64_t a = be64_to_cpu(k1->bmbt.br_startoff);
388389
uint64_t b = be64_to_cpu(k2->bmbt.br_startoff);
389390

391+
ASSERT(!mask || mask->bmbt.br_startoff);
392+
390393
/*
391394
* Note: This routine previously casted a and b to int64 and subtracted
392395
* them to generate a result. This lead to problems if b was the
@@ -504,8 +507,11 @@ STATIC enum xbtree_key_contig
504507
xfs_bmbt_keys_contiguous(
505508
struct xfs_btree_cur *cur,
506509
const union xfs_btree_key *key1,
507-
const union xfs_btree_key *key2)
510+
const union xfs_btree_key *key2,
511+
const union xfs_btree_key *mask)
508512
{
513+
ASSERT(!mask || mask->bmbt.br_startoff);
514+
509515
return xbtree_key_contig(be64_to_cpu(key1->bmbt.br_startoff),
510516
be64_to_cpu(key2->bmbt.br_startoff));
511517
}

fs/xfs/libxfs/xfs_btree.c

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5030,6 +5030,9 @@ struct xfs_btree_has_records {
50305030
union xfs_btree_key start_key;
50315031
union xfs_btree_key end_key;
50325032

5033+
/* Mask for key comparisons, if desired. */
5034+
const union xfs_btree_key *key_mask;
5035+
50335036
/* Highest record key we've seen so far. */
50345037
union xfs_btree_key high_key;
50355038

@@ -5057,7 +5060,8 @@ xfs_btree_has_records_helper(
50575060
* then there is a hole at the start of the search range.
50585061
* Classify this as sparse and stop immediately.
50595062
*/
5060-
if (xfs_btree_keycmp_lt(cur, &info->start_key, &rec_key))
5063+
if (xfs_btree_masked_keycmp_lt(cur, &info->start_key, &rec_key,
5064+
info->key_mask))
50615065
return -ECANCELED;
50625066
} else {
50635067
/*
@@ -5068,7 +5072,7 @@ xfs_btree_has_records_helper(
50685072
* signal corruption.
50695073
*/
50705074
key_contig = cur->bc_ops->keys_contiguous(cur, &info->high_key,
5071-
&rec_key);
5075+
&rec_key, info->key_mask);
50725076
if (key_contig == XBTREE_KEY_OVERLAP &&
50735077
!(cur->bc_flags & XFS_BTREE_OVERLAPPING))
50745078
return -EFSCORRUPTED;
@@ -5081,7 +5085,8 @@ xfs_btree_has_records_helper(
50815085
* remember it for later.
50825086
*/
50835087
cur->bc_ops->init_high_key_from_rec(&rec_high_key, rec);
5084-
if (xfs_btree_keycmp_gt(cur, &rec_high_key, &info->high_key))
5088+
if (xfs_btree_masked_keycmp_gt(cur, &rec_high_key, &info->high_key,
5089+
info->key_mask))
50855090
info->high_key = rec_high_key; /* struct copy */
50865091

50875092
return 0;
@@ -5092,16 +5097,26 @@ xfs_btree_has_records_helper(
50925097
* map to any records; is fully mapped to records; or is partially mapped to
50935098
* records. This is the btree record equivalent to determining if a file is
50945099
* sparse.
5100+
*
5101+
* For most btree types, the record scan should use all available btree key
5102+
* fields to compare the keys encountered. These callers should pass NULL for
5103+
* @mask. However, some callers (e.g. scanning physical space in the rmapbt)
5104+
* want to ignore some part of the btree record keyspace when performing the
5105+
* comparison. These callers should pass in a union xfs_btree_key object with
5106+
* the fields that *should* be a part of the comparison set to any nonzero
5107+
* value, and the rest zeroed.
50955108
*/
50965109
int
50975110
xfs_btree_has_records(
50985111
struct xfs_btree_cur *cur,
50995112
const union xfs_btree_irec *low,
51005113
const union xfs_btree_irec *high,
5114+
const union xfs_btree_key *mask,
51015115
enum xbtree_recpacking *outcome)
51025116
{
51035117
struct xfs_btree_has_records info = {
51045118
.outcome = XBTREE_RECPACKING_EMPTY,
5119+
.key_mask = mask,
51055120
};
51065121
int error;
51075122

@@ -5129,7 +5144,8 @@ xfs_btree_has_records(
51295144
* the end of the search range, classify this as full. Otherwise,
51305145
* there is a hole at the end of the search range.
51315146
*/
5132-
if (xfs_btree_keycmp_ge(cur, &info.high_key, &info.end_key))
5147+
if (xfs_btree_masked_keycmp_ge(cur, &info.high_key, &info.end_key,
5148+
mask))
51335149
info.outcome = XBTREE_RECPACKING_FULL;
51345150

51355151
out:

fs/xfs/libxfs/xfs_btree.h

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -161,11 +161,14 @@ struct xfs_btree_ops {
161161

162162
/*
163163
* Difference between key2 and key1 -- positive if key1 > key2,
164-
* negative if key1 < key2, and zero if equal.
164+
* negative if key1 < key2, and zero if equal. If the @mask parameter
165+
* is non NULL, each key field to be used in the comparison must
166+
* contain a nonzero value.
165167
*/
166168
int64_t (*diff_two_keys)(struct xfs_btree_cur *cur,
167169
const union xfs_btree_key *key1,
168-
const union xfs_btree_key *key2);
170+
const union xfs_btree_key *key2,
171+
const union xfs_btree_key *mask);
169172

170173
const struct xfs_buf_ops *buf_ops;
171174

@@ -187,10 +190,13 @@ struct xfs_btree_ops {
187190
* @key1 < K < @key2. To determine if two btree records are
188191
* immediately adjacent, @key1 should be the high key of the first
189192
* record and @key2 should be the low key of the second record.
193+
* If the @mask parameter is non NULL, each key field to be used in the
194+
* comparison must contain a nonzero value.
190195
*/
191196
enum xbtree_key_contig (*keys_contiguous)(struct xfs_btree_cur *cur,
192197
const union xfs_btree_key *key1,
193-
const union xfs_btree_key *key2);
198+
const union xfs_btree_key *key2,
199+
const union xfs_btree_key *mask);
194200
};
195201

196202
/*
@@ -581,6 +587,7 @@ typedef bool (*xfs_btree_key_gap_fn)(struct xfs_btree_cur *cur,
581587
int xfs_btree_has_records(struct xfs_btree_cur *cur,
582588
const union xfs_btree_irec *low,
583589
const union xfs_btree_irec *high,
590+
const union xfs_btree_key *mask,
584591
enum xbtree_recpacking *outcome);
585592

586593
bool xfs_btree_has_more_records(struct xfs_btree_cur *cur);
@@ -593,7 +600,7 @@ xfs_btree_keycmp_lt(
593600
const union xfs_btree_key *key1,
594601
const union xfs_btree_key *key2)
595602
{
596-
return cur->bc_ops->diff_two_keys(cur, key1, key2) < 0;
603+
return cur->bc_ops->diff_two_keys(cur, key1, key2, NULL) < 0;
597604
}
598605

599606
static inline bool
@@ -602,7 +609,7 @@ xfs_btree_keycmp_gt(
602609
const union xfs_btree_key *key1,
603610
const union xfs_btree_key *key2)
604611
{
605-
return cur->bc_ops->diff_two_keys(cur, key1, key2) > 0;
612+
return cur->bc_ops->diff_two_keys(cur, key1, key2, NULL) > 0;
606613
}
607614

608615
static inline bool
@@ -611,7 +618,7 @@ xfs_btree_keycmp_eq(
611618
const union xfs_btree_key *key1,
612619
const union xfs_btree_key *key2)
613620
{
614-
return cur->bc_ops->diff_two_keys(cur, key1, key2) == 0;
621+
return cur->bc_ops->diff_two_keys(cur, key1, key2, NULL) == 0;
615622
}
616623

617624
static inline bool
@@ -641,6 +648,37 @@ xfs_btree_keycmp_ne(
641648
return !xfs_btree_keycmp_eq(cur, key1, key2);
642649
}
643650

651+
/* Masked key comparison helpers */
652+
static inline bool
653+
xfs_btree_masked_keycmp_lt(
654+
struct xfs_btree_cur *cur,
655+
const union xfs_btree_key *key1,
656+
const union xfs_btree_key *key2,
657+
const union xfs_btree_key *mask)
658+
{
659+
return cur->bc_ops->diff_two_keys(cur, key1, key2, mask) < 0;
660+
}
661+
662+
static inline bool
663+
xfs_btree_masked_keycmp_gt(
664+
struct xfs_btree_cur *cur,
665+
const union xfs_btree_key *key1,
666+
const union xfs_btree_key *key2,
667+
const union xfs_btree_key *mask)
668+
{
669+
return cur->bc_ops->diff_two_keys(cur, key1, key2, mask) > 0;
670+
}
671+
672+
static inline bool
673+
xfs_btree_masked_keycmp_ge(
674+
struct xfs_btree_cur *cur,
675+
const union xfs_btree_key *key1,
676+
const union xfs_btree_key *key2,
677+
const union xfs_btree_key *mask)
678+
{
679+
return !xfs_btree_masked_keycmp_lt(cur, key1, key2, mask);
680+
}
681+
644682
/* Does this cursor point to the last block in the given level? */
645683
static inline bool
646684
xfs_btree_islastblock(

fs/xfs/libxfs/xfs_ialloc_btree.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -269,10 +269,13 @@ STATIC int64_t
269269
xfs_inobt_diff_two_keys(
270270
struct xfs_btree_cur *cur,
271271
const union xfs_btree_key *k1,
272-
const union xfs_btree_key *k2)
272+
const union xfs_btree_key *k2,
273+
const union xfs_btree_key *mask)
273274
{
275+
ASSERT(!mask || mask->inobt.ir_startino);
276+
274277
return (int64_t)be32_to_cpu(k1->inobt.ir_startino) -
275-
be32_to_cpu(k2->inobt.ir_startino);
278+
be32_to_cpu(k2->inobt.ir_startino);
276279
}
277280

278281
static xfs_failaddr_t
@@ -387,8 +390,11 @@ STATIC enum xbtree_key_contig
387390
xfs_inobt_keys_contiguous(
388391
struct xfs_btree_cur *cur,
389392
const union xfs_btree_key *key1,
390-
const union xfs_btree_key *key2)
393+
const union xfs_btree_key *key2,
394+
const union xfs_btree_key *mask)
391395
{
396+
ASSERT(!mask || mask->inobt.ir_startino);
397+
392398
return xbtree_key_contig(be32_to_cpu(key1->inobt.ir_startino),
393399
be32_to_cpu(key2->inobt.ir_startino));
394400
}

fs/xfs/libxfs/xfs_refcount.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2019,7 +2019,7 @@ xfs_refcount_has_records(
20192019
high.rc.rc_startblock = bno + len - 1;
20202020
low.rc.rc_domain = high.rc.rc_domain = domain;
20212021

2022-
return xfs_btree_has_records(cur, &low, &high, outcome);
2022+
return xfs_btree_has_records(cur, &low, &high, NULL, outcome);
20232023
}
20242024

20252025
int __init

fs/xfs/libxfs/xfs_refcount_btree.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -202,10 +202,13 @@ STATIC int64_t
202202
xfs_refcountbt_diff_two_keys(
203203
struct xfs_btree_cur *cur,
204204
const union xfs_btree_key *k1,
205-
const union xfs_btree_key *k2)
205+
const union xfs_btree_key *k2,
206+
const union xfs_btree_key *mask)
206207
{
208+
ASSERT(!mask || mask->refc.rc_startblock);
209+
207210
return (int64_t)be32_to_cpu(k1->refc.rc_startblock) -
208-
be32_to_cpu(k2->refc.rc_startblock);
211+
be32_to_cpu(k2->refc.rc_startblock);
209212
}
210213

211214
STATIC xfs_failaddr_t
@@ -304,8 +307,11 @@ STATIC enum xbtree_key_contig
304307
xfs_refcountbt_keys_contiguous(
305308
struct xfs_btree_cur *cur,
306309
const union xfs_btree_key *key1,
307-
const union xfs_btree_key *key2)
310+
const union xfs_btree_key *key2,
311+
const union xfs_btree_key *mask)
308312
{
313+
ASSERT(!mask || mask->refc.rc_startblock);
314+
309315
return xbtree_key_contig(be32_to_cpu(key1->refc.rc_startblock),
310316
be32_to_cpu(key2->refc.rc_startblock));
311317
}

fs/xfs/libxfs/xfs_rmap.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2721,6 +2721,9 @@ xfs_rmap_has_records(
27212721
xfs_extlen_t len,
27222722
enum xbtree_recpacking *outcome)
27232723
{
2724+
union xfs_btree_key mask = {
2725+
.rmap.rm_startblock = cpu_to_be32(-1U),
2726+
};
27242727
union xfs_btree_irec low;
27252728
union xfs_btree_irec high;
27262729

@@ -2729,7 +2732,7 @@ xfs_rmap_has_records(
27292732
memset(&high, 0xFF, sizeof(high));
27302733
high.r.rm_startblock = bno + len - 1;
27312734

2732-
return xfs_btree_has_records(cur, &low, &high, outcome);
2735+
return xfs_btree_has_records(cur, &low, &high, &mask, outcome);
27332736
}
27342737

27352738
/*

0 commit comments

Comments
 (0)