}
 
 const struct xfs_btree_ops xfs_bnobt_ops = {
+       .type                   = XFS_BTREE_TYPE_AG,
+
        .rec_len                = sizeof(xfs_alloc_rec_t),
        .key_len                = sizeof(xfs_alloc_key_t),
        .ptr_len                = XFS_BTREE_SHORT_PTR_LEN,
 };
 
 const struct xfs_btree_ops xfs_cntbt_ops = {
+       .type                   = XFS_BTREE_TYPE_AG,
        .geom_flags             = XFS_BTGEO_LASTREC_UPDATE,
 
        .rec_len                = sizeof(xfs_alloc_rec_t),
 
 }
 
 const struct xfs_btree_ops xfs_bmbt_ops = {
-       .geom_flags             = XFS_BTGEO_ROOT_IN_INODE,
+       .type                   = XFS_BTREE_TYPE_INODE,
 
        .rec_len                = sizeof(xfs_bmbt_rec_t),
        .key_len                = sizeof(xfs_bmbt_key_t),
 
         */
        ASSERT(cur->bc_btnum != XFS_BTNUM_BMAP || cur->bc_ino.allocated == 0 ||
               xfs_is_shutdown(cur->bc_mp) || error != 0);
+
+       switch (cur->bc_ops->type) {
+       case XFS_BTREE_TYPE_AG:
+               if (cur->bc_ag.pag)
+                       xfs_perag_put(cur->bc_ag.pag);
+               break;
+       case XFS_BTREE_TYPE_INODE:
+               /* nothing to do */
+               break;
+       }
+
        if (unlikely(cur->bc_flags & XFS_BTREE_STAGING))
                kfree(cur->bc_ops);
-       if (!(cur->bc_ops->ptr_len == XFS_BTREE_LONG_PTR_LEN) && cur->bc_ag.pag)
-               xfs_perag_put(cur->bc_ag.pag);
        kmem_cache_free(cur->bc_cache, cur);
 }
 
 xfs_btree_ifork_ptr(
        struct xfs_btree_cur    *cur)
 {
-       ASSERT(cur->bc_ops->geom_flags & XFS_BTGEO_ROOT_IN_INODE);
+       ASSERT(cur->bc_ops->type == XFS_BTREE_TYPE_INODE);
 
        if (cur->bc_flags & XFS_BTREE_STAGING)
                return cur->bc_ino.ifake->if_fork;
        int                     level,  /* level in btree */
        struct xfs_buf          **bpp)  /* buffer containing the block */
 {
-       if ((cur->bc_ops->geom_flags & XFS_BTGEO_ROOT_IN_INODE) &&
-           (level == cur->bc_nlevels - 1)) {
+       if (cur->bc_ops->type == XFS_BTREE_TYPE_INODE &&
+           level == cur->bc_nlevels - 1) {
                *bpp = NULL;
                return xfs_btree_get_iroot(cur);
        }
         * No readahead needed if we are at the root level and the
         * btree root is stored in the inode.
         */
-       if ((cur->bc_ops->geom_flags & XFS_BTGEO_ROOT_IN_INODE) &&
-           (lev == cur->bc_nlevels - 1))
+       if (cur->bc_ops->type == XFS_BTREE_TYPE_INODE &&
+           lev == cur->bc_nlevels - 1)
                return 0;
 
        if ((cur->bc_levels[lev].ra | lr) == cur->bc_levels[lev].ra)
                        buf->bb_u.l.bb_lsn = 0;
                }
        } else {
-               /* owner is a 32 bit value on short blocks */
-               __u32 __owner = (__u32)owner;
-
                buf->bb_u.s.bb_leftsib = cpu_to_be32(NULLAGBLOCK);
                buf->bb_u.s.bb_rightsib = cpu_to_be32(NULLAGBLOCK);
                if (crc) {
                        buf->bb_u.s.bb_blkno = cpu_to_be64(blkno);
-                       buf->bb_u.s.bb_owner = cpu_to_be32(__owner);
+                       /* owner is a 32 bit value on short blocks */
+                       buf->bb_u.s.bb_owner = cpu_to_be32((__u32)owner);
                        uuid_copy(&buf->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid);
                        buf->bb_u.s.bb_lsn = 0;
                }
 xfs_btree_owner(
        struct xfs_btree_cur    *cur)
 {
-       if (cur->bc_ops->geom_flags & XFS_BTGEO_ROOT_IN_INODE)
+       if (cur->bc_ops->type == XFS_BTREE_TYPE_INODE)
                return cur->bc_ino.ip->i_ino;
        return cur->bc_ag.pag->pag_agno;
 }
         * confused or have the tree root in an inode.
         */
        if (lev == cur->bc_nlevels) {
-               if (cur->bc_ops->geom_flags & XFS_BTGEO_ROOT_IN_INODE)
+               if (cur->bc_ops->type == XFS_BTREE_TYPE_INODE)
                        goto out0;
                ASSERT(0);
                xfs_btree_mark_sick(cur);
         * or the root of the tree is in an inode.
         */
        if (lev == cur->bc_nlevels) {
-               if (cur->bc_ops->geom_flags & XFS_BTGEO_ROOT_IN_INODE)
+               if (cur->bc_ops->type == XFS_BTREE_TYPE_INODE)
                        goto out0;
                ASSERT(0);
                xfs_btree_mark_sick(cur);
        int                     error = 0;
 
        /* special case the root block if in an inode */
-       if ((cur->bc_ops->geom_flags & XFS_BTGEO_ROOT_IN_INODE) &&
-           (level == cur->bc_nlevels - 1)) {
+       if (cur->bc_ops->type == XFS_BTREE_TYPE_INODE &&
+           level == cur->bc_nlevels - 1) {
                *blkp = xfs_btree_get_iroot(cur);
                return 0;
        }
        int                     error;          /* error return value */
        int                     i;
 
-       if ((cur->bc_ops->geom_flags & XFS_BTGEO_ROOT_IN_INODE) &&
+       if ((cur->bc_ops->type == XFS_BTREE_TYPE_INODE) &&
            level == cur->bc_nlevels - 1)
                goto out0;
 
        int                     error;          /* error return value */
        int                     i;              /* loop counter */
 
-       if ((cur->bc_ops->geom_flags & XFS_BTGEO_ROOT_IN_INODE) &&
-           (level == cur->bc_nlevels - 1))
+       if (cur->bc_ops->type == XFS_BTREE_TYPE_INODE &&
+           level == cur->bc_nlevels - 1)
                goto out0;
 
        /* Set up variables for this block as "left". */
 #define xfs_btree_split        __xfs_btree_split
 #endif /* __KERNEL__ */
 
-
 /*
  * Copy the old inode root contents into a real block and make the
  * broot point to it.
 
        XFS_BTREE_STATS_INC(cur, newroot);
 
-       ASSERT(cur->bc_ops->geom_flags & XFS_BTGEO_ROOT_IN_INODE);
+       ASSERT(cur->bc_ops->type == XFS_BTREE_TYPE_INODE);
 
        level = cur->bc_nlevels - 1;
 
 {
        int                     error = 0;
 
-       if ((cur->bc_ops->geom_flags & XFS_BTGEO_ROOT_IN_INODE) &&
+       if (cur->bc_ops->type == XFS_BTREE_TYPE_INODE &&
            level == cur->bc_nlevels - 1) {
                struct xfs_inode *ip = cur->bc_ino.ip;
 
         * If we have an external root pointer, and we've made it to the
         * root level, allocate a new root block and we're done.
         */
-       if (!(cur->bc_ops->geom_flags & XFS_BTGEO_ROOT_IN_INODE) &&
-           (level >= cur->bc_nlevels)) {
+       if (cur->bc_ops->type != XFS_BTREE_TYPE_INODE &&
+           level >= cur->bc_nlevels) {
                error = xfs_btree_new_root(cur, stat);
                xfs_btree_set_ptr_null(cur, ptrp);
 
 #endif
        int                     i;
 
-       ASSERT(cur->bc_ops->geom_flags & XFS_BTGEO_ROOT_IN_INODE);
+       ASSERT(cur->bc_ops->type == XFS_BTREE_TYPE_INODE);
        ASSERT(cur->bc_nlevels > 1);
 
        /*
         * nothing left to do.
         */
        if (level == cur->bc_nlevels - 1) {
-               if (cur->bc_ops->geom_flags & XFS_BTGEO_ROOT_IN_INODE) {
+               if (cur->bc_ops->type == XFS_BTREE_TYPE_INODE) {
                        xfs_iroot_realloc(cur->bc_ino.ip, -1,
                                          cur->bc_ino.whichfork);
 
        xfs_btree_get_sibling(cur, block, &rptr, XFS_BB_RIGHTSIB);
        xfs_btree_get_sibling(cur, block, &lptr, XFS_BB_LEFTSIB);
 
-       if (cur->bc_ops->geom_flags & XFS_BTGEO_ROOT_IN_INODE) {
+       if (cur->bc_ops->type == XFS_BTREE_TYPE_INODE) {
                /*
                 * One child of root, need to get a chance to copy its contents
                 * into the root and delete it. Can't go up to next level,
         * If we joined with the right neighbor and there's a level above
         * us, increment the cursor at that level.
         */
-       else if ((cur->bc_ops->geom_flags & XFS_BTGEO_ROOT_IN_INODE) ||
-                  (level + 1 < cur->bc_nlevels)) {
+       else if (cur->bc_ops->type == XFS_BTREE_TYPE_INODE ||
+                level + 1 < cur->bc_nlevels) {
                error = xfs_btree_increment(cur, level + 1, &i);
                if (error)
                        goto error0;
         * though, so everything is consistent in memory.
         */
        if (!bp) {
-               ASSERT(cur->bc_ops->geom_flags & XFS_BTGEO_ROOT_IN_INODE);
+               ASSERT(cur->bc_ops->type == XFS_BTREE_TYPE_INODE);
                ASSERT(level == cur->bc_nlevels - 1);
                return 0;
        }
 
 #define XFS_BTREE_LONG_PTR_LEN         (sizeof(__be64))
 #define XFS_BTREE_SHORT_PTR_LEN                (sizeof(__be32))
 
+enum xfs_btree_type {
+       XFS_BTREE_TYPE_AG,
+       XFS_BTREE_TYPE_INODE,
+};
+
 struct xfs_btree_ops {
+       /* Type of btree - AG-rooted or inode-rooted */
+       enum xfs_btree_type     type;
+
        /* XFS_BTGEO_* flags that determine the geometry of the btree */
        unsigned int            geom_flags;
 
 };
 
 /* btree geometry flags */
-#define XFS_BTGEO_ROOT_IN_INODE                (1U << 0) /* root may be variable size */
-#define XFS_BTGEO_LASTREC_UPDATE       (1U << 1) /* track last rec externally */
-#define XFS_BTGEO_OVERLAPPING          (1U << 2) /* overlapping intervals */
+#define XFS_BTGEO_LASTREC_UPDATE       (1U << 0) /* track last rec externally */
+#define XFS_BTGEO_OVERLAPPING          (1U << 1) /* overlapping intervals */
 
 /*
  * Reasons for the update_lastrec method to be called.
        /*
         * Short btree pointers need an agno to be able to turn the pointers
         * into physical addresses for IO, so the btree cursor switches between
-        * bc_ino and bc_ag based on whether XFS_BTGEO_ROOT_IN_INODE is set for
+        * bc_ino and bc_ag based on bc_ops->type.
         * the cursor.
         */
        union {
 
        struct xfs_btree_ops            *nops;
 
        ASSERT(!(cur->bc_flags & XFS_BTREE_STAGING));
-       ASSERT(!(cur->bc_ops->geom_flags & XFS_BTGEO_ROOT_IN_INODE));
+       ASSERT(cur->bc_ops->type != XFS_BTREE_TYPE_INODE);
        ASSERT(cur->bc_tp == NULL);
 
        nops = kmalloc(sizeof(struct xfs_btree_ops), GFP_KERNEL | __GFP_NOFAIL);
        struct xfs_btree_ops            *nops;
 
        ASSERT(!(cur->bc_flags & XFS_BTREE_STAGING));
-       ASSERT(cur->bc_ops->geom_flags & XFS_BTGEO_ROOT_IN_INODE);
+       ASSERT(cur->bc_ops->type == XFS_BTREE_TYPE_INODE);
        ASSERT(cur->bc_tp == NULL);
 
        nops = kmalloc(sizeof(struct xfs_btree_ops), GFP_KERNEL | __GFP_NOFAIL);
        struct xfs_btree_block          *new_block;
        int                             ret;
 
-       if ((cur->bc_ops->geom_flags & XFS_BTGEO_ROOT_IN_INODE) &&
+       if (cur->bc_ops->type == XFS_BTREE_TYPE_INODE &&
            level == cur->bc_nlevels - 1) {
                struct xfs_ifork        *ifp = xfs_btree_ifork_ptr(cur);
                size_t                  new_size;
                xfs_btree_bload_level_geometry(cur, bbl, level, nr_this_level,
                                &avg_per_block, &level_blocks, &dontcare64);
 
-               if (cur->bc_ops->geom_flags & XFS_BTGEO_ROOT_IN_INODE) {
+               if (cur->bc_ops->type == XFS_BTREE_TYPE_INODE) {
                        /*
                         * If all the items we want to store at this level
                         * would fit in the inode root block, then we have our
                return -EOVERFLOW;
 
        bbl->btree_height = cur->bc_nlevels;
-       if (cur->bc_ops->geom_flags & XFS_BTGEO_ROOT_IN_INODE)
+       if (cur->bc_ops->type == XFS_BTREE_TYPE_INODE)
                bbl->nr_blocks = nr_blocks - 1;
        else
                bbl->nr_blocks = nr_blocks;
        }
 
        /* Initialize the new root. */
-       if (cur->bc_ops->geom_flags & XFS_BTGEO_ROOT_IN_INODE) {
+       if (cur->bc_ops->type == XFS_BTREE_TYPE_INODE) {
                ASSERT(xfs_btree_ptr_is_null(cur, &ptr));
                cur->bc_ino.ifake->if_levels = cur->bc_nlevels;
                cur->bc_ino.ifake->if_blocks = total_blocks - 1;
 
 
        /*
         * This function should return the size of the in-core btree root
-        * block.  It is only necessary for XFS_BTGEO_ROOT_IN_INODE btree
-        * types.
+        * block.  It is only necessary for XFS_BTREE_TYPE_INODE btrees.
         */
        xfs_btree_bload_iroot_size_fn   iroot_size;
 
 
 }
 
 const struct xfs_btree_ops xfs_inobt_ops = {
+       .type                   = XFS_BTREE_TYPE_AG,
+
        .rec_len                = sizeof(xfs_inobt_rec_t),
        .key_len                = sizeof(xfs_inobt_key_t),
        .ptr_len                = XFS_BTREE_SHORT_PTR_LEN,
 };
 
 const struct xfs_btree_ops xfs_finobt_ops = {
+       .type                   = XFS_BTREE_TYPE_AG,
+
        .rec_len                = sizeof(xfs_inobt_rec_t),
        .key_len                = sizeof(xfs_inobt_key_t),
        .ptr_len                = XFS_BTREE_SHORT_PTR_LEN,
 
 }
 
 const struct xfs_btree_ops xfs_refcountbt_ops = {
+       .type                   = XFS_BTREE_TYPE_AG,
+
        .rec_len                = sizeof(struct xfs_refcount_rec),
        .key_len                = sizeof(struct xfs_refcount_key),
        .ptr_len                = XFS_BTREE_SHORT_PTR_LEN,
 
 }
 
 const struct xfs_btree_ops xfs_rmapbt_ops = {
+       .type                   = XFS_BTREE_TYPE_AG,
        .geom_flags             = XFS_BTGEO_OVERLAPPING,
 
        .rec_len                = sizeof(struct xfs_rmap_rec),
 
                *error = 0;
                fallthrough;
        default:
-               if (cur->bc_ops->geom_flags & XFS_BTGEO_ROOT_IN_INODE)
+               if (cur->bc_ops->type == XFS_BTREE_TYPE_INODE)
                        trace_xchk_ifork_btree_op_error(sc, cur, level,
                                        *error, ret_ip);
                else
 {
        sc->sm->sm_flags |= errflag;
 
-       if (cur->bc_ops->geom_flags & XFS_BTGEO_ROOT_IN_INODE)
+       if (cur->bc_ops->type == XFS_BTREE_TYPE_INODE)
                trace_xchk_ifork_btree_error(sc, cur, level,
                                ret_ip);
        else
        bool                    res;
 
        /* A btree rooted in an inode has no block pointer to the root. */
-       if ((bs->cur->bc_ops->geom_flags & XFS_BTGEO_ROOT_IN_INODE) &&
+       if (bs->cur->bc_ops->type == XFS_BTREE_TYPE_INODE &&
            level == bs->cur->bc_nlevels)
                return true;
 
         * sc->sa so that we can check for the presence of an ownership record
         * in the rmap btree for the AG containing the block.
         */
-       init_sa = bs->cur->bc_ops->geom_flags & XFS_BTGEO_ROOT_IN_INODE;
+       init_sa = bs->cur->bc_ops->type != XFS_BTREE_TYPE_AG;
        if (init_sa) {
                error = xchk_ag_init_existing(bs->sc, agno, &bs->sc->sa);
                if (!xchk_btree_xref_process_error(bs->sc, bs->cur,
         * up.
         */
        if (bp == NULL) {
-               if (!(cur->bc_ops->geom_flags & XFS_BTGEO_ROOT_IN_INODE))
+               if (cur->bc_ops->type != XFS_BTREE_TYPE_INODE)
                        xchk_btree_set_corrupt(bs->sc, bs->cur, level);
                return 0;
        }
         * child block might be less than the standard minrecs, but that's ok
         * provided that there's only one direct child of the root.
         */
-       if ((cur->bc_ops->geom_flags & XFS_BTGEO_ROOT_IN_INODE) &&
+       if (cur->bc_ops->type == XFS_BTREE_TYPE_INODE &&
            level == cur->bc_nlevels - 2) {
                struct xfs_btree_block  *root_block;
                struct xfs_buf          *root_bp;
 
                                xfs_buf_daddr(cur->bc_levels[level].bp));
 
        if (level == cur->bc_nlevels - 1 &&
-           (cur->bc_ops->geom_flags & XFS_BTGEO_ROOT_IN_INODE))
+           cur->bc_ops->type == XFS_BTREE_TYPE_INODE)
                return XFS_INO_TO_FSB(cur->bc_mp, cur->bc_ino.ip->i_ino);
 
        return NULLFSBLOCK;
 
        ),
        TP_fast_assign(
                __entry->dev = cur->bc_mp->m_super->s_dev;
-               if (cur->bc_ops->geom_flags & XFS_BTGEO_ROOT_IN_INODE) {
+               if (cur->bc_ops->type == XFS_BTREE_TYPE_INODE) {
                        __entry->agno = 0;
                        __entry->ino = cur->bc_ino.ip->i_ino;
                } else {
                __entry->dev = cur->bc_mp->m_super->s_dev;
                __entry->agno = xfs_daddr_to_agno(cur->bc_mp,
                                                        xfs_buf_daddr(bp));
-               if (cur->bc_ops->geom_flags & XFS_BTGEO_ROOT_IN_INODE)
+               if (cur->bc_ops->type == XFS_BTREE_TYPE_INODE)
                        __entry->ino = cur->bc_ino.ip->i_ino;
                else
                        __entry->ino = 0;