]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs: introduce realtime rmap btree ondisk definitions
authorDarrick J. Wong <djwong@kernel.org>
Mon, 24 Feb 2025 18:21:47 +0000 (10:21 -0800)
committerDarrick J. Wong <djwong@kernel.org>
Tue, 25 Feb 2025 17:15:57 +0000 (09:15 -0800)
Source kernel commit: fc6856c6ff08642e3e8437f0416d70a5e1807010

Add the ondisk structure definitions for realtime rmap btrees. The
realtime rmap btree will be rooted from a hidden inode so it needs to
have a separate btree block magic and pointer format.

Next, add everything needed to read, write and manipulate rmap btree
blocks. This prepares the way for connecting the btree operations
implementation, though embedding the rtrmap btree root in the inode
comes later in the series.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
include/libxfs.h
include/xfs_mount.h
libxfs/Makefile
libxfs/xfs_btree.c
libxfs/xfs_format.h
libxfs/xfs_ondisk.h
libxfs/xfs_rtrmap_btree.c [new file with mode: 0644]
libxfs/xfs_rtrmap_btree.h [new file with mode: 0644]
libxfs/xfs_sb.c
libxfs/xfs_shared.h

index 5689f58c640168c92eb1954c783d167ddd3ed310..af08f176d79a9e2c09840c7565b144574c59a8ce 100644 (file)
@@ -99,6 +99,7 @@ struct iomap;
 #include "xfs_metadir.h"
 #include "xfs_rtgroup.h"
 #include "xfs_rtbitmap.h"
+#include "xfs_rtrmap_btree.h"
 
 #ifndef ARRAY_SIZE
 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
index 532bff8513bf5357a3c167da7c1f2503d2483cbe..0d9b99ef43b4c185061e915bc26020f7d5f47459 100644 (file)
@@ -108,11 +108,14 @@ typedef struct xfs_mount {
        uint                    m_bmap_dmnr[2]; /* XFS_BMAP_BLOCK_DMINRECS */
        uint                    m_rmap_mxr[2];  /* max rmap btree records */
        uint                    m_rmap_mnr[2];  /* min rmap btree records */
+       uint                    m_rtrmap_mxr[2]; /* max rtrmap btree records */
+       uint                    m_rtrmap_mnr[2]; /* min rtrmap btree records */
        uint                    m_refc_mxr[2];  /* max refc btree records */
        uint                    m_refc_mnr[2];  /* min refc btree records */
        uint                    m_alloc_maxlevels; /* max alloc btree levels */
        uint                    m_bm_maxlevels[2];  /* max bmap btree levels */
        uint                    m_rmap_maxlevels; /* max rmap btree levels */
+       uint                    m_rtrmap_maxlevels; /* max rtrmap btree level */
        uint                    m_refc_maxlevels; /* max refc btree levels */
        unsigned int            m_agbtree_maxlevels; /* max level of all AG btrees */
        unsigned int            m_rtbtree_maxlevels; /* max level of all rt btrees */
@@ -259,6 +262,12 @@ static inline bool xfs_has_rtsb(struct xfs_mount *mp)
        return xfs_has_rtgroups(mp) && xfs_has_realtime(mp);
 }
 
+static inline bool xfs_has_rtrmapbt(struct xfs_mount *mp)
+{
+       return xfs_has_rtgroups(mp) && xfs_has_realtime(mp) &&
+              xfs_has_rmapbt(mp);
+}
+
 /* Kernel mount features that we don't support */
 #define __XFS_UNSUPP_FEAT(name) \
 static inline bool xfs_has_ ## name (struct xfs_mount *mp) \
index 42c9f3cc439dc5ed4bac254a559bb07364b32837..d152667eeec27597d2e9064bdb5642157a25a46d 100644 (file)
@@ -65,6 +65,7 @@ HFILES = \
        xfs_rmap_btree.h \
        xfs_rtbitmap.h \
        xfs_rtgroup.h \
+       xfs_rtrmap_btree.h \
        xfs_sb.h \
        xfs_shared.h \
        xfs_trans_resv.h \
@@ -126,6 +127,7 @@ CFILES = buf_mem.c \
        xfs_rmap_btree.c \
        xfs_rtbitmap.c \
        xfs_rtgroup.c \
+       xfs_rtrmap_btree.c \
        xfs_sb.c \
        xfs_symlink_remote.c \
        xfs_trans_inode.c \
index c5a0280a55f3b5f71ee839529add3b846e58c446..8b20458a6cb4c4104c72db1bcf0217b4af9b7eef 100644 (file)
@@ -28,6 +28,7 @@
 #include "xfile.h"
 #include "buf_mem.h"
 #include "xfs_btree_mem.h"
+#include "xfs_rtrmap_btree.h"
 
 /*
  * Btree magic numbers.
@@ -5523,6 +5524,9 @@ xfs_btree_init_cur_caches(void)
        if (error)
                goto err;
        error = xfs_refcountbt_init_cur_cache();
+       if (error)
+               goto err;
+       error = xfs_rtrmapbt_init_cur_cache();
        if (error)
                goto err;
 
@@ -5541,6 +5545,7 @@ xfs_btree_destroy_cur_caches(void)
        xfs_bmbt_destroy_cur_cache();
        xfs_rmapbt_destroy_cur_cache();
        xfs_refcountbt_destroy_cur_cache();
+       xfs_rtrmapbt_destroy_cur_cache();
 }
 
 /* Move the btree cursor before the first record. */
index 4d47a3e723aa13c4be9f01628397d79fda2b8d9d..469fc7afa591b4c3bb036b1a09906902cf7c518e 100644 (file)
@@ -1725,6 +1725,16 @@ typedef __be32 xfs_rmap_ptr_t;
         XFS_FIBT_BLOCK(mp) + 1 : \
         XFS_IBT_BLOCK(mp) + 1)
 
+/*
+ * Realtime Reverse mapping btree format definitions
+ *
+ * This is a btree for reverse mapping records for realtime volumes
+ */
+#define        XFS_RTRMAP_CRC_MAGIC    0x4d415052      /* 'MAPR' */
+
+/* inode-based btree pointer type */
+typedef __be64 xfs_rtrmap_ptr_t;
+
 /*
  * Reference Count Btree format definitions
  *
index ad0dedf00f189815d87d9f7453f5d46e25c036ee..2c50877a1a2f0bee42583c1b239e1567216f40e6 100644 (file)
@@ -83,6 +83,7 @@ xfs_check_ondisk_structs(void)
        XFS_CHECK_STRUCT_SIZE(union xfs_rtword_raw,             4);
        XFS_CHECK_STRUCT_SIZE(union xfs_suminfo_raw,            4);
        XFS_CHECK_STRUCT_SIZE(struct xfs_rtbuf_blkinfo,         48);
+       XFS_CHECK_STRUCT_SIZE(xfs_rtrmap_ptr_t,                 8);
 
        /*
         * m68k has problems with struct xfs_attr_leaf_name_remote, but we pad
diff --git a/libxfs/xfs_rtrmap_btree.c b/libxfs/xfs_rtrmap_btree.c
new file mode 100644 (file)
index 0000000..a06cb09
--- /dev/null
@@ -0,0 +1,269 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2018-2024 Oracle.  All Rights Reserved.
+ * Author: Darrick J. Wong <djwong@kernel.org>
+ */
+#include "libxfs_priv.h"
+#include "xfs_fs.h"
+#include "xfs_shared.h"
+#include "xfs_format.h"
+#include "xfs_log_format.h"
+#include "xfs_trans_resv.h"
+#include "xfs_bit.h"
+#include "xfs_sb.h"
+#include "xfs_mount.h"
+#include "xfs_defer.h"
+#include "xfs_inode.h"
+#include "xfs_trans.h"
+#include "xfs_alloc.h"
+#include "xfs_btree.h"
+#include "xfs_btree_staging.h"
+#include "xfs_rtrmap_btree.h"
+#include "xfs_trace.h"
+#include "xfs_cksum.h"
+#include "xfs_rtgroup.h"
+
+static struct kmem_cache       *xfs_rtrmapbt_cur_cache;
+
+/*
+ * Realtime Reverse Map btree.
+ *
+ * This is a btree used to track the owner(s) of a given extent in the realtime
+ * device.  See the comments in xfs_rmap_btree.c for more information.
+ *
+ * This tree is basically the same as the regular rmap btree except that it
+ * is rooted in an inode and does not live in free space.
+ */
+
+static struct xfs_btree_cur *
+xfs_rtrmapbt_dup_cursor(
+       struct xfs_btree_cur    *cur)
+{
+       return xfs_rtrmapbt_init_cursor(cur->bc_tp, to_rtg(cur->bc_group));
+}
+
+static xfs_failaddr_t
+xfs_rtrmapbt_verify(
+       struct xfs_buf          *bp)
+{
+       struct xfs_mount        *mp = bp->b_target->bt_mount;
+       struct xfs_btree_block  *block = XFS_BUF_TO_BLOCK(bp);
+       xfs_failaddr_t          fa;
+       int                     level;
+
+       if (!xfs_verify_magic(bp, block->bb_magic))
+               return __this_address;
+
+       if (!xfs_has_rmapbt(mp))
+               return __this_address;
+       fa = xfs_btree_fsblock_v5hdr_verify(bp, XFS_RMAP_OWN_UNKNOWN);
+       if (fa)
+               return fa;
+       level = be16_to_cpu(block->bb_level);
+       if (level > mp->m_rtrmap_maxlevels)
+               return __this_address;
+
+       return xfs_btree_fsblock_verify(bp, mp->m_rtrmap_mxr[level != 0]);
+}
+
+static void
+xfs_rtrmapbt_read_verify(
+       struct xfs_buf  *bp)
+{
+       xfs_failaddr_t  fa;
+
+       if (!xfs_btree_fsblock_verify_crc(bp))
+               xfs_verifier_error(bp, -EFSBADCRC, __this_address);
+       else {
+               fa = xfs_rtrmapbt_verify(bp);
+               if (fa)
+                       xfs_verifier_error(bp, -EFSCORRUPTED, fa);
+       }
+
+       if (bp->b_error)
+               trace_xfs_btree_corrupt(bp, _RET_IP_);
+}
+
+static void
+xfs_rtrmapbt_write_verify(
+       struct xfs_buf  *bp)
+{
+       xfs_failaddr_t  fa;
+
+       fa = xfs_rtrmapbt_verify(bp);
+       if (fa) {
+               trace_xfs_btree_corrupt(bp, _RET_IP_);
+               xfs_verifier_error(bp, -EFSCORRUPTED, fa);
+               return;
+       }
+       xfs_btree_fsblock_calc_crc(bp);
+
+}
+
+const struct xfs_buf_ops xfs_rtrmapbt_buf_ops = {
+       .name                   = "xfs_rtrmapbt",
+       .magic                  = { 0, cpu_to_be32(XFS_RTRMAP_CRC_MAGIC) },
+       .verify_read            = xfs_rtrmapbt_read_verify,
+       .verify_write           = xfs_rtrmapbt_write_verify,
+       .verify_struct          = xfs_rtrmapbt_verify,
+};
+
+const struct xfs_btree_ops xfs_rtrmapbt_ops = {
+       .name                   = "rtrmap",
+       .type                   = XFS_BTREE_TYPE_INODE,
+       .geom_flags             = XFS_BTGEO_OVERLAPPING |
+                                 XFS_BTGEO_IROOT_RECORDS,
+
+       .rec_len                = sizeof(struct xfs_rmap_rec),
+       /* Overlapping btree; 2 keys per pointer. */
+       .key_len                = 2 * sizeof(struct xfs_rmap_key),
+       .ptr_len                = XFS_BTREE_LONG_PTR_LEN,
+
+       .lru_refs               = XFS_RMAP_BTREE_REF,
+       .statoff                = XFS_STATS_CALC_INDEX(xs_rtrmap_2),
+
+       .dup_cursor             = xfs_rtrmapbt_dup_cursor,
+       .buf_ops                = &xfs_rtrmapbt_buf_ops,
+};
+
+/* Allocate a new rt rmap btree cursor. */
+struct xfs_btree_cur *
+xfs_rtrmapbt_init_cursor(
+       struct xfs_trans        *tp,
+       struct xfs_rtgroup      *rtg)
+{
+       struct xfs_inode        *ip = NULL;
+       struct xfs_mount        *mp = rtg_mount(rtg);
+       struct xfs_btree_cur    *cur;
+
+       return NULL; /* XXX */
+
+       xfs_assert_ilocked(ip, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL);
+
+       cur = xfs_btree_alloc_cursor(mp, tp, &xfs_rtrmapbt_ops,
+                       mp->m_rtrmap_maxlevels, xfs_rtrmapbt_cur_cache);
+
+       cur->bc_ino.ip = ip;
+       cur->bc_group = xfs_group_hold(rtg_group(rtg));
+       cur->bc_ino.whichfork = XFS_DATA_FORK;
+       cur->bc_nlevels = be16_to_cpu(ip->i_df.if_broot->bb_level) + 1;
+       cur->bc_ino.forksize = xfs_inode_fork_size(ip, XFS_DATA_FORK);
+
+       return cur;
+}
+
+/*
+ * Install a new rt reverse mapping btree root.  Caller is responsible for
+ * invalidating and freeing the old btree blocks.
+ */
+void
+xfs_rtrmapbt_commit_staged_btree(
+       struct xfs_btree_cur    *cur,
+       struct xfs_trans        *tp)
+{
+       struct xbtree_ifakeroot *ifake = cur->bc_ino.ifake;
+       struct xfs_ifork        *ifp;
+       int                     flags = XFS_ILOG_CORE | XFS_ILOG_DBROOT;
+
+       ASSERT(cur->bc_flags & XFS_BTREE_STAGING);
+
+       /*
+        * Free any resources hanging off the real fork, then shallow-copy the
+        * staging fork's contents into the real fork to transfer everything
+        * we just built.
+        */
+       ifp = xfs_ifork_ptr(cur->bc_ino.ip, XFS_DATA_FORK);
+       xfs_idestroy_fork(ifp);
+       memcpy(ifp, ifake->if_fork, sizeof(struct xfs_ifork));
+
+       cur->bc_ino.ip->i_projid = cur->bc_group->xg_gno;
+       xfs_trans_log_inode(tp, cur->bc_ino.ip, flags);
+       xfs_btree_commit_ifakeroot(cur, tp, XFS_DATA_FORK);
+}
+
+/* Calculate number of records in a rt reverse mapping btree block. */
+static inline unsigned int
+xfs_rtrmapbt_block_maxrecs(
+       unsigned int            blocklen,
+       bool                    leaf)
+{
+       if (leaf)
+               return blocklen / sizeof(struct xfs_rmap_rec);
+       return blocklen /
+               (2 * sizeof(struct xfs_rmap_key) + sizeof(xfs_rtrmap_ptr_t));
+}
+
+/*
+ * Calculate number of records in an rt reverse mapping btree block.
+ */
+unsigned int
+xfs_rtrmapbt_maxrecs(
+       struct xfs_mount        *mp,
+       unsigned int            blocklen,
+       bool                    leaf)
+{
+       blocklen -= XFS_RTRMAP_BLOCK_LEN;
+       return xfs_rtrmapbt_block_maxrecs(blocklen, leaf);
+}
+
+/* Compute the max possible height for realtime reverse mapping btrees. */
+unsigned int
+xfs_rtrmapbt_maxlevels_ondisk(void)
+{
+       unsigned int            minrecs[2];
+       unsigned int            blocklen;
+
+       blocklen = XFS_MIN_CRC_BLOCKSIZE - XFS_BTREE_LBLOCK_CRC_LEN;
+
+       minrecs[0] = xfs_rtrmapbt_block_maxrecs(blocklen, true) / 2;
+       minrecs[1] = xfs_rtrmapbt_block_maxrecs(blocklen, false) / 2;
+
+       /* We need at most one record for every block in an rt group. */
+       return xfs_btree_compute_maxlevels(minrecs, XFS_MAX_RGBLOCKS);
+}
+
+int __init
+xfs_rtrmapbt_init_cur_cache(void)
+{
+       xfs_rtrmapbt_cur_cache = kmem_cache_create("xfs_rtrmapbt_cur",
+                       xfs_btree_cur_sizeof(xfs_rtrmapbt_maxlevels_ondisk()),
+                       0, 0, NULL);
+
+       if (!xfs_rtrmapbt_cur_cache)
+               return -ENOMEM;
+       return 0;
+}
+
+void
+xfs_rtrmapbt_destroy_cur_cache(void)
+{
+       kmem_cache_destroy(xfs_rtrmapbt_cur_cache);
+       xfs_rtrmapbt_cur_cache = NULL;
+}
+
+/* Compute the maximum height of an rt reverse mapping btree. */
+void
+xfs_rtrmapbt_compute_maxlevels(
+       struct xfs_mount        *mp)
+{
+       unsigned int            d_maxlevels, r_maxlevels;
+
+       if (!xfs_has_rtrmapbt(mp)) {
+               mp->m_rtrmap_maxlevels = 0;
+               return;
+       }
+
+       /*
+        * The realtime rmapbt lives on the data device, which means that its
+        * maximum height is constrained by the size of the data device and
+        * the height required to store one rmap record for each block in an
+        * rt group.
+        */
+       d_maxlevels = xfs_btree_space_to_height(mp->m_rtrmap_mnr,
+                               mp->m_sb.sb_dblocks);
+       r_maxlevels = xfs_btree_compute_maxlevels(mp->m_rtrmap_mnr,
+                               mp->m_groups[XG_TYPE_RTG].blocks);
+
+       /* Add one level to handle the inode root level. */
+       mp->m_rtrmap_maxlevels = min(d_maxlevels, r_maxlevels) + 1;
+}
diff --git a/libxfs/xfs_rtrmap_btree.h b/libxfs/xfs_rtrmap_btree.h
new file mode 100644 (file)
index 0000000..7d1a3a4
--- /dev/null
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (c) 2018-2024 Oracle.  All Rights Reserved.
+ * Author: Darrick J. Wong <djwong@kernel.org>
+ */
+#ifndef __XFS_RTRMAP_BTREE_H__
+#define __XFS_RTRMAP_BTREE_H__
+
+struct xfs_buf;
+struct xfs_btree_cur;
+struct xfs_mount;
+struct xbtree_ifakeroot;
+struct xfs_rtgroup;
+
+/* rmaps only exist on crc enabled filesystems */
+#define XFS_RTRMAP_BLOCK_LEN   XFS_BTREE_LBLOCK_CRC_LEN
+
+struct xfs_btree_cur *xfs_rtrmapbt_init_cursor(struct xfs_trans *tp,
+               struct xfs_rtgroup *rtg);
+struct xfs_btree_cur *xfs_rtrmapbt_stage_cursor(struct xfs_mount *mp,
+               struct xfs_rtgroup *rtg, struct xfs_inode *ip,
+               struct xbtree_ifakeroot *ifake);
+void xfs_rtrmapbt_commit_staged_btree(struct xfs_btree_cur *cur,
+               struct xfs_trans *tp);
+unsigned int xfs_rtrmapbt_maxrecs(struct xfs_mount *mp, unsigned int blocklen,
+               bool leaf);
+void xfs_rtrmapbt_compute_maxlevels(struct xfs_mount *mp);
+
+/*
+ * Addresses of records, keys, and pointers within an incore rtrmapbt block.
+ *
+ * (note that some of these may appear unused, but they are used in userspace)
+ */
+static inline struct xfs_rmap_rec *
+xfs_rtrmap_rec_addr(
+       struct xfs_btree_block  *block,
+       unsigned int            index)
+{
+       return (struct xfs_rmap_rec *)
+               ((char *)block + XFS_RTRMAP_BLOCK_LEN +
+                (index - 1) * sizeof(struct xfs_rmap_rec));
+}
+
+static inline struct xfs_rmap_key *
+xfs_rtrmap_key_addr(
+       struct xfs_btree_block  *block,
+       unsigned int            index)
+{
+       return (struct xfs_rmap_key *)
+               ((char *)block + XFS_RTRMAP_BLOCK_LEN +
+                (index - 1) * 2 * sizeof(struct xfs_rmap_key));
+}
+
+static inline struct xfs_rmap_key *
+xfs_rtrmap_high_key_addr(
+       struct xfs_btree_block  *block,
+       unsigned int            index)
+{
+       return (struct xfs_rmap_key *)
+               ((char *)block + XFS_RTRMAP_BLOCK_LEN +
+                sizeof(struct xfs_rmap_key) +
+                (index - 1) * 2 * sizeof(struct xfs_rmap_key));
+}
+
+static inline xfs_rtrmap_ptr_t *
+xfs_rtrmap_ptr_addr(
+       struct xfs_btree_block  *block,
+       unsigned int            index,
+       unsigned int            maxrecs)
+{
+       return (xfs_rtrmap_ptr_t *)
+               ((char *)block + XFS_RTRMAP_BLOCK_LEN +
+                maxrecs * 2 * sizeof(struct xfs_rmap_key) +
+                (index - 1) * sizeof(xfs_rtrmap_ptr_t));
+}
+
+unsigned int xfs_rtrmapbt_maxlevels_ondisk(void);
+
+int __init xfs_rtrmapbt_init_cur_cache(void);
+void xfs_rtrmapbt_destroy_cur_cache(void);
+
+#endif /* __XFS_RTRMAP_BTREE_H__ */
index ff23803a8065bf2ac1fea3fbbc40c191bf10d398..467d64e199d22e55a6aab55afaee06eb58bee170 100644 (file)
@@ -25,6 +25,7 @@
 #include "xfs_ag.h"
 #include "xfs_rtbitmap.h"
 #include "xfs_rtgroup.h"
+#include "xfs_rtrmap_btree.h"
 
 /*
  * Physical superblock buffer manipulations. Shared with libxfs in userspace.
@@ -1212,6 +1213,11 @@ xfs_sb_mount_common(
        mp->m_rmap_mnr[0] = mp->m_rmap_mxr[0] / 2;
        mp->m_rmap_mnr[1] = mp->m_rmap_mxr[1] / 2;
 
+       mp->m_rtrmap_mxr[0] = xfs_rtrmapbt_maxrecs(mp, sbp->sb_blocksize, true);
+       mp->m_rtrmap_mxr[1] = xfs_rtrmapbt_maxrecs(mp, sbp->sb_blocksize, false);
+       mp->m_rtrmap_mnr[0] = mp->m_rtrmap_mxr[0] / 2;
+       mp->m_rtrmap_mnr[1] = mp->m_rtrmap_mxr[1] / 2;
+
        mp->m_refc_mxr[0] = xfs_refcountbt_maxrecs(mp, sbp->sb_blocksize, true);
        mp->m_refc_mxr[1] = xfs_refcountbt_maxrecs(mp, sbp->sb_blocksize, false);
        mp->m_refc_mnr[0] = mp->m_refc_mxr[0] / 2;
index e7efdb9ceaf3821082bd7390873cf54c28057a8a..da23dac22c3f08238c99f037b08cbb5ab0a99d52 100644 (file)
@@ -42,6 +42,7 @@ extern const struct xfs_buf_ops xfs_rtbitmap_buf_ops;
 extern const struct xfs_buf_ops xfs_rtsummary_buf_ops;
 extern const struct xfs_buf_ops xfs_rtbuf_ops;
 extern const struct xfs_buf_ops xfs_rtsb_buf_ops;
+extern const struct xfs_buf_ops xfs_rtrmapbt_buf_ops;
 extern const struct xfs_buf_ops xfs_sb_buf_ops;
 extern const struct xfs_buf_ops xfs_sb_quiet_buf_ops;
 extern const struct xfs_buf_ops xfs_symlink_buf_ops;
@@ -55,6 +56,7 @@ extern const struct xfs_btree_ops xfs_bmbt_ops;
 extern const struct xfs_btree_ops xfs_refcountbt_ops;
 extern const struct xfs_btree_ops xfs_rmapbt_ops;
 extern const struct xfs_btree_ops xfs_rmapbt_mem_ops;
+extern const struct xfs_btree_ops xfs_rtrmapbt_ops;
 
 static inline bool xfs_btree_is_bno(const struct xfs_btree_ops *ops)
 {
@@ -100,6 +102,11 @@ static inline bool xfs_btree_is_mem_rmap(const struct xfs_btree_ops *ops)
 # define xfs_btree_is_mem_rmap(...)    (false)
 #endif
 
+static inline bool xfs_btree_is_rtrmap(const struct xfs_btree_ops *ops)
+{
+       return ops == &xfs_rtrmapbt_ops;
+}
+
 /* log size calculation functions */
 int    xfs_log_calc_unit_res(struct xfs_mount *mp, int unit_bytes);
 int    xfs_log_calc_minimum_size(struct xfs_mount *);