* [PATCH 1/2] xfs: export several rmap btree key/record ops
2026-09-18 18:01 [PATCH 0/2] xfs: dedupe realtime rmap btree code Eric Sandeen
@ 2026-09-18 18:01 ` Eric Sandeen
2026-09-18 18:01 ` [PATCH 2/2] xfs: use the shared rmap btree ops for the rt rmap btree Eric Sandeen
2026-09-21 3:40 ` [PATCH 0/2] xfs: dedupe realtime rmap btree code Darrick J. Wong
2 siblings, 0 replies; 7+ messages in thread
From: Eric Sandeen @ 2026-09-18 18:01 UTC (permalink / raw)
To: linux-xfs; +Cc: cem, Eric Sandeen
The AG rmap btree and the realtime rmap btree have several identical
btree key and record ops.
Export the AG variants of these ops so that they can be shared with the
realtime code in the next patch, to eliminate this copied code.
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---
fs/xfs/libxfs/xfs_rmap_btree.c | 16 ++++++++--------
fs/xfs/libxfs/xfs_rmap_btree.h | 26 ++++++++++++++++++++++++++
2 files changed, 34 insertions(+), 8 deletions(-)
diff --git a/fs/xfs/libxfs/xfs_rmap_btree.c b/fs/xfs/libxfs/xfs_rmap_btree.c
index 10b3272238eb..5b283a5ddd13 100644
--- a/fs/xfs/libxfs/xfs_rmap_btree.c
+++ b/fs/xfs/libxfs/xfs_rmap_btree.c
@@ -170,7 +170,7 @@ static inline __be64 ondisk_rec_offset_to_key(const union xfs_btree_rec *rec)
return rec->rmap.rm_offset & ~cpu_to_be64(XFS_RMAP_OFF_UNWRITTEN);
}
-STATIC void
+void
xfs_rmapbt_init_key_from_rec(
union xfs_btree_key *key,
const union xfs_btree_rec *rec)
@@ -187,7 +187,7 @@ xfs_rmapbt_init_key_from_rec(
* the startblock for all records, and if the record is for a data/attr
* fork mapping, we add blockcount-1 to the offset too.
*/
-STATIC void
+void
xfs_rmapbt_init_high_key_from_rec(
union xfs_btree_key *key,
const union xfs_btree_rec *rec)
@@ -209,7 +209,7 @@ xfs_rmapbt_init_high_key_from_rec(
key->rmap.rm_offset = cpu_to_be64(off);
}
-STATIC void
+void
xfs_rmapbt_init_rec_from_cur(
struct xfs_btree_cur *cur,
union xfs_btree_rec *rec)
@@ -243,7 +243,7 @@ static inline uint64_t offset_keymask(uint64_t offset)
return offset & ~XFS_RMAP_OFF_UNWRITTEN;
}
-STATIC int
+int
xfs_rmapbt_cmp_key_with_cur(
struct xfs_btree_cur *cur,
const union xfs_btree_key *key)
@@ -257,7 +257,7 @@ xfs_rmapbt_cmp_key_with_cur(
offset_keymask(xfs_rmap_irec_offset_pack(rec)));
}
-STATIC int
+int
xfs_rmapbt_cmp_two_keys(
struct xfs_btree_cur *cur,
const union xfs_btree_key *k1,
@@ -390,7 +390,7 @@ const struct xfs_buf_ops xfs_rmapbt_buf_ops = {
.verify_struct = xfs_rmapbt_verify,
};
-STATIC int
+int
xfs_rmapbt_keys_inorder(
struct xfs_btree_cur *cur,
const union xfs_btree_key *k1,
@@ -420,7 +420,7 @@ xfs_rmapbt_keys_inorder(
return 0;
}
-STATIC int
+int
xfs_rmapbt_recs_inorder(
struct xfs_btree_cur *cur,
const union xfs_btree_rec *r1,
@@ -450,7 +450,7 @@ xfs_rmapbt_recs_inorder(
return 0;
}
-STATIC enum xbtree_key_contig
+enum xbtree_key_contig
xfs_rmapbt_keys_contiguous(
struct xfs_btree_cur *cur,
const union xfs_btree_key *key1,
diff --git a/fs/xfs/libxfs/xfs_rmap_btree.h b/fs/xfs/libxfs/xfs_rmap_btree.h
index 119b1567cd0e..82b1a7fd8513 100644
--- a/fs/xfs/libxfs/xfs_rmap_btree.h
+++ b/fs/xfs/libxfs/xfs_rmap_btree.h
@@ -11,6 +11,8 @@ struct xfs_btree_cur;
struct xfs_mount;
struct xbtree_afakeroot;
struct xfbtree;
+union xfs_btree_key;
+union xfs_btree_rec;
/* rmaps only exist on crc enabled filesystems */
#define XFS_RMAP_BLOCK_LEN XFS_BTREE_SBLOCK_CRC_LEN
@@ -69,4 +71,28 @@ struct xfs_btree_cur *xfs_rmapbt_mem_cursor(struct xfs_perag *pag,
int xfs_rmapbt_mem_init(struct xfs_mount *mp, struct xfbtree *xfbtree,
struct xfs_buftarg *btp, xfs_agnumber_t agno);
+/*
+ * Key and record btree ops. The rmap on-disk key/record format is identical
+ * for the AG rmap btree and the realtime rmap btree, so these are shared by
+ * both (see xfs_rtrmap_btree.c).
+ */
+void xfs_rmapbt_init_key_from_rec(union xfs_btree_key *key,
+ const union xfs_btree_rec *rec);
+void xfs_rmapbt_init_high_key_from_rec(union xfs_btree_key *key,
+ const union xfs_btree_rec *rec);
+void xfs_rmapbt_init_rec_from_cur(struct xfs_btree_cur *cur,
+ union xfs_btree_rec *rec);
+int xfs_rmapbt_cmp_key_with_cur(struct xfs_btree_cur *cur,
+ const union xfs_btree_key *key);
+int xfs_rmapbt_cmp_two_keys(struct xfs_btree_cur *cur,
+ const union xfs_btree_key *k1, const union xfs_btree_key *k2,
+ const union xfs_btree_key *mask);
+int xfs_rmapbt_keys_inorder(struct xfs_btree_cur *cur,
+ const union xfs_btree_key *k1, const union xfs_btree_key *k2);
+int xfs_rmapbt_recs_inorder(struct xfs_btree_cur *cur,
+ const union xfs_btree_rec *r1, const union xfs_btree_rec *r2);
+enum xbtree_key_contig xfs_rmapbt_keys_contiguous(struct xfs_btree_cur *cur,
+ const union xfs_btree_key *key1, const union xfs_btree_key *key2,
+ const union xfs_btree_key *mask);
+
#endif /* __XFS_RMAP_BTREE_H__ */
--
2.55.0
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH 2/2] xfs: use the shared rmap btree ops for the rt rmap btree
2026-09-18 18:01 [PATCH 0/2] xfs: dedupe realtime rmap btree code Eric Sandeen
2026-09-18 18:01 ` [PATCH 1/2] xfs: export several rmap btree key/record ops Eric Sandeen
@ 2026-09-18 18:01 ` Eric Sandeen
2026-09-21 3:40 ` [PATCH 0/2] xfs: dedupe realtime rmap btree code Darrick J. Wong
2 siblings, 0 replies; 7+ messages in thread
From: Eric Sandeen @ 2026-09-18 18:01 UTC (permalink / raw)
To: linux-xfs; +Cc: cem, Eric Sandeen
Now that the (identical but for naming) AG variants of these ops are
exported, use them for realtime as well, to eliminate copied code.
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
---
fs/xfs/libxfs/xfs_rtrmap_btree.c | 230 +++----------------------------
1 file changed, 17 insertions(+), 213 deletions(-)
diff --git a/fs/xfs/libxfs/xfs_rtrmap_btree.c b/fs/xfs/libxfs/xfs_rtrmap_btree.c
index 5901d7efd3f6..2f00d0698ae1 100644
--- a/fs/xfs/libxfs/xfs_rtrmap_btree.c
+++ b/fs/xfs/libxfs/xfs_rtrmap_btree.c
@@ -20,6 +20,7 @@
#include "xfs_btree_staging.h"
#include "xfs_metafile.h"
#include "xfs_rmap.h"
+#include "xfs_rmap_btree.h"
#include "xfs_rtrmap_btree.h"
#include "xfs_trace.h"
#include "xfs_cksum.h"
@@ -113,60 +114,6 @@ xfs_rtrmapbt_get_dmaxrecs(
return xfs_rtrmapbt_droot_maxrecs(cur->bc_ino.forksize, level == 0);
}
-/*
- * Convert the ondisk record's offset field into the ondisk key's offset field.
- * Fork and bmbt are significant parts of the rmap record key, but written
- * status is merely a record attribute.
- */
-static inline __be64 ondisk_rec_offset_to_key(const union xfs_btree_rec *rec)
-{
- return rec->rmap.rm_offset & ~cpu_to_be64(XFS_RMAP_OFF_UNWRITTEN);
-}
-
-STATIC void
-xfs_rtrmapbt_init_key_from_rec(
- union xfs_btree_key *key,
- const union xfs_btree_rec *rec)
-{
- key->rmap.rm_startblock = rec->rmap.rm_startblock;
- key->rmap.rm_owner = rec->rmap.rm_owner;
- key->rmap.rm_offset = ondisk_rec_offset_to_key(rec);
-}
-
-STATIC void
-xfs_rtrmapbt_init_high_key_from_rec(
- union xfs_btree_key *key,
- const union xfs_btree_rec *rec)
-{
- uint64_t off;
- int adj;
-
- adj = be32_to_cpu(rec->rmap.rm_blockcount) - 1;
-
- key->rmap.rm_startblock = rec->rmap.rm_startblock;
- be32_add_cpu(&key->rmap.rm_startblock, adj);
- key->rmap.rm_owner = rec->rmap.rm_owner;
- key->rmap.rm_offset = ondisk_rec_offset_to_key(rec);
- if (XFS_RMAP_NON_INODE_OWNER(be64_to_cpu(rec->rmap.rm_owner)) ||
- XFS_RMAP_IS_BMBT_BLOCK(be64_to_cpu(rec->rmap.rm_offset)))
- return;
- off = be64_to_cpu(key->rmap.rm_offset);
- off = (XFS_RMAP_OFF(off) + adj) | (off & ~XFS_RMAP_OFF_MASK);
- key->rmap.rm_offset = cpu_to_be64(off);
-}
-
-STATIC void
-xfs_rtrmapbt_init_rec_from_cur(
- struct xfs_btree_cur *cur,
- union xfs_btree_rec *rec)
-{
- rec->rmap.rm_startblock = cpu_to_be32(cur->bc_rec.r.rm_startblock);
- rec->rmap.rm_blockcount = cpu_to_be32(cur->bc_rec.r.rm_blockcount);
- rec->rmap.rm_owner = cpu_to_be64(cur->bc_rec.r.rm_owner);
- rec->rmap.rm_offset = cpu_to_be64(
- xfs_rmap_irec_offset_pack(&cur->bc_rec.r));
-}
-
STATIC void
xfs_rtrmapbt_init_ptr_from_cur(
struct xfs_btree_cur *cur,
@@ -175,69 +122,6 @@ xfs_rtrmapbt_init_ptr_from_cur(
ptr->l = 0;
}
-/*
- * Mask the appropriate parts of the ondisk key field for a key comparison.
- * Fork and bmbt are significant parts of the rmap record key, but written
- * status is merely a record attribute.
- */
-static inline uint64_t offset_keymask(uint64_t offset)
-{
- return offset & ~XFS_RMAP_OFF_UNWRITTEN;
-}
-
-STATIC int
-xfs_rtrmapbt_cmp_key_with_cur(
- struct xfs_btree_cur *cur,
- const union xfs_btree_key *key)
-{
- struct xfs_rmap_irec *rec = &cur->bc_rec.r;
- const struct xfs_rmap_key *kp = &key->rmap;
-
- return cmp_int(be32_to_cpu(kp->rm_startblock), rec->rm_startblock) ?:
- cmp_int(be64_to_cpu(kp->rm_owner), rec->rm_owner) ?:
- cmp_int(offset_keymask(be64_to_cpu(kp->rm_offset)),
- offset_keymask(xfs_rmap_irec_offset_pack(rec)));
-}
-
-STATIC int
-xfs_rtrmapbt_cmp_two_keys(
- struct xfs_btree_cur *cur,
- const union xfs_btree_key *k1,
- const union xfs_btree_key *k2,
- const union xfs_btree_key *mask)
-{
- const struct xfs_rmap_key *kp1 = &k1->rmap;
- const struct xfs_rmap_key *kp2 = &k2->rmap;
- int d;
-
- /* Doesn't make sense to mask off the physical space part */
- ASSERT(!mask || mask->rmap.rm_startblock);
-
- d = cmp_int(be32_to_cpu(kp1->rm_startblock),
- be32_to_cpu(kp2->rm_startblock));
- if (d)
- return d;
-
- if (!mask || mask->rmap.rm_owner) {
- d = cmp_int(be64_to_cpu(kp1->rm_owner),
- be64_to_cpu(kp2->rm_owner));
- if (d)
- return d;
- }
-
- if (!mask || mask->rmap.rm_offset) {
- /* Doesn't make sense to allow offset but not owner */
- ASSERT(!mask || mask->rmap.rm_owner);
-
- d = cmp_int(offset_keymask(be64_to_cpu(kp1->rm_offset)),
- offset_keymask(be64_to_cpu(kp2->rm_offset)));
- if (d)
- return d;
- }
-
- return 0;
-}
-
static xfs_failaddr_t
xfs_rtrmapbt_verify(
struct xfs_buf *bp)
@@ -304,86 +188,6 @@ const struct xfs_buf_ops xfs_rtrmapbt_buf_ops = {
.verify_struct = xfs_rtrmapbt_verify,
};
-STATIC int
-xfs_rtrmapbt_keys_inorder(
- struct xfs_btree_cur *cur,
- const union xfs_btree_key *k1,
- const union xfs_btree_key *k2)
-{
- uint32_t x;
- uint32_t y;
- uint64_t a;
- uint64_t b;
-
- x = be32_to_cpu(k1->rmap.rm_startblock);
- y = be32_to_cpu(k2->rmap.rm_startblock);
- if (x < y)
- return 1;
- else if (x > y)
- return 0;
- a = be64_to_cpu(k1->rmap.rm_owner);
- b = be64_to_cpu(k2->rmap.rm_owner);
- if (a < b)
- return 1;
- else if (a > b)
- return 0;
- a = offset_keymask(be64_to_cpu(k1->rmap.rm_offset));
- b = offset_keymask(be64_to_cpu(k2->rmap.rm_offset));
- if (a <= b)
- return 1;
- return 0;
-}
-
-STATIC int
-xfs_rtrmapbt_recs_inorder(
- struct xfs_btree_cur *cur,
- const union xfs_btree_rec *r1,
- const union xfs_btree_rec *r2)
-{
- uint32_t x;
- uint32_t y;
- uint64_t a;
- uint64_t b;
-
- x = be32_to_cpu(r1->rmap.rm_startblock);
- y = be32_to_cpu(r2->rmap.rm_startblock);
- if (x < y)
- return 1;
- else if (x > y)
- return 0;
- a = be64_to_cpu(r1->rmap.rm_owner);
- b = be64_to_cpu(r2->rmap.rm_owner);
- if (a < b)
- return 1;
- else if (a > b)
- return 0;
- a = offset_keymask(be64_to_cpu(r1->rmap.rm_offset));
- b = offset_keymask(be64_to_cpu(r2->rmap.rm_offset));
- if (a <= b)
- return 1;
- return 0;
-}
-
-STATIC enum xbtree_key_contig
-xfs_rtrmapbt_keys_contiguous(
- struct xfs_btree_cur *cur,
- const union xfs_btree_key *key1,
- const union xfs_btree_key *key2,
- const union xfs_btree_key *mask)
-{
- ASSERT(!mask || mask->rmap.rm_startblock);
-
- /*
- * We only support checking contiguity of the physical space component.
- * If any callers ever need more specificity than that, they'll have to
- * implement it here.
- */
- ASSERT(!mask || (!mask->rmap.rm_owner && !mask->rmap.rm_offset));
-
- return xbtree_key_contig(be32_to_cpu(key1->rmap.rm_startblock),
- be32_to_cpu(key2->rmap.rm_startblock));
-}
-
static inline void
xfs_rtrmapbt_move_ptrs(
struct xfs_mount *mp,
@@ -486,16 +290,16 @@ const struct xfs_btree_ops xfs_rtrmapbt_ops = {
.get_minrecs = xfs_rtrmapbt_get_minrecs,
.get_maxrecs = xfs_rtrmapbt_get_maxrecs,
.get_dmaxrecs = xfs_rtrmapbt_get_dmaxrecs,
- .init_key_from_rec = xfs_rtrmapbt_init_key_from_rec,
- .init_high_key_from_rec = xfs_rtrmapbt_init_high_key_from_rec,
- .init_rec_from_cur = xfs_rtrmapbt_init_rec_from_cur,
+ .init_key_from_rec = xfs_rmapbt_init_key_from_rec,
+ .init_high_key_from_rec = xfs_rmapbt_init_high_key_from_rec,
+ .init_rec_from_cur = xfs_rmapbt_init_rec_from_cur,
.init_ptr_from_cur = xfs_rtrmapbt_init_ptr_from_cur,
- .cmp_key_with_cur = xfs_rtrmapbt_cmp_key_with_cur,
+ .cmp_key_with_cur = xfs_rmapbt_cmp_key_with_cur,
.buf_ops = &xfs_rtrmapbt_buf_ops,
- .cmp_two_keys = xfs_rtrmapbt_cmp_two_keys,
- .keys_inorder = xfs_rtrmapbt_keys_inorder,
- .recs_inorder = xfs_rtrmapbt_recs_inorder,
- .keys_contiguous = xfs_rtrmapbt_keys_contiguous,
+ .cmp_two_keys = xfs_rmapbt_cmp_two_keys,
+ .keys_inorder = xfs_rmapbt_keys_inorder,
+ .recs_inorder = xfs_rmapbt_recs_inorder,
+ .keys_contiguous = xfs_rmapbt_keys_contiguous,
.broot_realloc = xfs_rtrmapbt_broot_realloc,
};
@@ -595,16 +399,16 @@ const struct xfs_btree_ops xfs_rtrmapbt_mem_ops = {
.free_block = xfbtree_free_block,
.get_minrecs = xfbtree_get_minrecs,
.get_maxrecs = xfbtree_get_maxrecs,
- .init_key_from_rec = xfs_rtrmapbt_init_key_from_rec,
- .init_high_key_from_rec = xfs_rtrmapbt_init_high_key_from_rec,
- .init_rec_from_cur = xfs_rtrmapbt_init_rec_from_cur,
+ .init_key_from_rec = xfs_rmapbt_init_key_from_rec,
+ .init_high_key_from_rec = xfs_rmapbt_init_high_key_from_rec,
+ .init_rec_from_cur = xfs_rmapbt_init_rec_from_cur,
.init_ptr_from_cur = xfbtree_init_ptr_from_cur,
- .cmp_key_with_cur = xfs_rtrmapbt_cmp_key_with_cur,
+ .cmp_key_with_cur = xfs_rmapbt_cmp_key_with_cur,
.buf_ops = &xfs_rtrmapbt_mem_buf_ops,
- .cmp_two_keys = xfs_rtrmapbt_cmp_two_keys,
- .keys_inorder = xfs_rtrmapbt_keys_inorder,
- .recs_inorder = xfs_rtrmapbt_recs_inorder,
- .keys_contiguous = xfs_rtrmapbt_keys_contiguous,
+ .cmp_two_keys = xfs_rmapbt_cmp_two_keys,
+ .keys_inorder = xfs_rmapbt_keys_inorder,
+ .recs_inorder = xfs_rmapbt_recs_inorder,
+ .keys_contiguous = xfs_rmapbt_keys_contiguous,
};
/* Create a cursor for an in-memory btree. */
--
2.55.0
^ permalink raw reply related [flat|nested] 7+ messages in thread