/*
         * Allocate/initialize a cursor for the by-number freespace btree.
         */
-       bno_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp,
-               args->agno, XFS_BTNUM_BNO, NULL, 0);
+       bno_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
+               args->agno, XFS_BTNUM_BNO);
        /*
         * Lookup bno and minlen in the btree (minlen is irrelevant, really).
         * Look for the closest free block <= bno, it must contain bno
         * We are allocating agbno for rlen [agbno .. end]
         * Allocate/initialize a cursor for the by-size btree.
         */
-       cnt_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp,
-               args->agno, XFS_BTNUM_CNT, NULL, 0);
+       cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
+               args->agno, XFS_BTNUM_CNT);
        ASSERT(args->agbno + args->len <=
                be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length));
        if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen,
        /*
         * Get a cursor for the by-size btree.
         */
-       cnt_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp,
-               args->agno, XFS_BTNUM_CNT, NULL, 0);
+       cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
+               args->agno, XFS_BTNUM_CNT);
        ltlen = 0;
        bno_cur_lt = bno_cur_gt = NULL;
        /*
                /*
                 * Set up a cursor for the by-bno tree.
                 */
-               bno_cur_lt = xfs_btree_init_cursor(args->mp, args->tp,
-                       args->agbp, args->agno, XFS_BTNUM_BNO, NULL, 0);
+               bno_cur_lt = xfs_allocbt_init_cursor(args->mp, args->tp,
+                       args->agbp, args->agno, XFS_BTNUM_BNO);
                /*
                 * Fix up the btree entries.
                 */
        /*
         * Allocate and initialize the cursor for the leftward search.
         */
-       bno_cur_lt = xfs_btree_init_cursor(args->mp, args->tp, args->agbp,
-               args->agno, XFS_BTNUM_BNO, NULL, 0);
+       bno_cur_lt = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
+               args->agno, XFS_BTNUM_BNO);
        /*
         * Lookup <= bno to find the leftward search's starting point.
         */
        /*
         * Allocate and initialize a cursor for the by-size btree.
         */
-       cnt_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp,
-               args->agno, XFS_BTNUM_CNT, NULL, 0);
+       cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
+               args->agno, XFS_BTNUM_CNT);
        bno_cur = NULL;
        /*
         * Look for an entry >= maxlen+alignment-1 blocks.
        /*
         * Allocate and initialize a cursor for the by-block tree.
         */
-       bno_cur = xfs_btree_init_cursor(args->mp, args->tp, args->agbp,
-               args->agno, XFS_BTNUM_BNO, NULL, 0);
+       bno_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp,
+               args->agno, XFS_BTNUM_BNO);
        if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen,
                        rbno, rlen, XFSA_FIXUP_CNT_OK)))
                goto error0;
        /*
         * Allocate and initialize a cursor for the by-block btree.
         */
-       bno_cur = xfs_btree_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_BNO, NULL,
-               0);
+       bno_cur = xfs_allocbt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_BNO);
        cnt_cur = NULL;
        /*
         * Look for a neighboring block on the left (lower block numbers)
        /*
         * Now allocate and initialize a cursor for the by-size tree.
         */
-       cnt_cur = xfs_btree_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_CNT, NULL,
-               0);
+       cnt_cur = xfs_allocbt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_CNT);
        /*
         * Have both left and right contiguous neighbors.
         * Merge all three into a single free block.
 
        }
        return 0;
 }
+
+STATIC struct xfs_btree_cur *
+xfs_allocbt_dup_cursor(
+       struct xfs_btree_cur    *cur)
+{
+       return xfs_allocbt_init_cursor(cur->bc_mp, cur->bc_tp,
+                       cur->bc_private.a.agbp, cur->bc_private.a.agno,
+                       cur->bc_btnum);
+}
+
+static const struct xfs_btree_ops xfs_allocbt_ops = {
+       .dup_cursor             = xfs_allocbt_dup_cursor,
+};
+
+/*
+ * Allocate a new allocation btree cursor.
+ */
+struct xfs_btree_cur *                 /* new alloc btree cursor */
+xfs_allocbt_init_cursor(
+       struct xfs_mount        *mp,            /* file system mount point */
+       struct xfs_trans        *tp,            /* transaction pointer */
+       struct xfs_buf          *agbp,          /* buffer for agf structure */
+       xfs_agnumber_t          agno,           /* allocation group number */
+       xfs_btnum_t             btnum)          /* btree identifier */
+{
+       struct xfs_agf          *agf = XFS_BUF_TO_AGF(agbp);
+       struct xfs_btree_cur    *cur;
+
+       ASSERT(btnum == XFS_BTNUM_BNO || btnum == XFS_BTNUM_CNT);
+
+       cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_SLEEP);
+
+       cur->bc_tp = tp;
+       cur->bc_mp = mp;
+       cur->bc_nlevels = be32_to_cpu(agf->agf_levels[btnum]);
+       cur->bc_btnum = btnum;
+       cur->bc_blocklog = mp->m_sb.sb_blocklog;
+
+       cur->bc_ops = &xfs_allocbt_ops;
+
+       cur->bc_private.a.agbp = agbp;
+       cur->bc_private.a.agno = agno;
+
+       return cur;
+}
 
 extern int xfs_alloc_update(struct xfs_btree_cur *cur, xfs_agblock_t bno,
                                xfs_extlen_t len);
 
+
+extern struct xfs_btree_cur *xfs_allocbt_init_cursor(struct xfs_mount *,
+               struct xfs_trans *, struct xfs_buf *,
+               xfs_agnumber_t, xfs_btnum_t);
+
 #endif /* __XFS_ALLOC_BTREE_H__ */
 
        if (ip->i_df.if_broot_bytes <= XFS_IFORK_DSIZE(ip))
                *flags |= XFS_ILOG_DBROOT;
        else {
-               cur = xfs_btree_init_cursor(mp, tp, NULL, 0, XFS_BTNUM_BMAP, ip,
-                       XFS_DATA_FORK);
+               cur = xfs_bmbt_init_cursor(mp, tp, ip, XFS_DATA_FORK);
                cur->bc_private.b.flist = flist;
                cur->bc_private.b.firstblock = *firstblock;
                if ((error = xfs_bmbt_lookup_ge(cur, 0, 0, 0, &stat)))
         * Need a cursor.  Can't allocate until bb_level is filled in.
         */
        mp = ip->i_mount;
-       cur = xfs_btree_init_cursor(mp, tp, NULL, 0, XFS_BTNUM_BMAP, ip,
-               whichfork);
+       cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork);
        cur->bc_private.b.firstblock = *firstblock;
        cur->bc_private.b.flist = flist;
        cur->bc_private.b.flags = wasdel ? XFS_BTCUR_BPRV_WASDEL : 0;
                                if (abno == NULLFSBLOCK)
                                        break;
                                if ((ifp->if_flags & XFS_IFBROOT) && !cur) {
-                                       cur = xfs_btree_init_cursor(mp,
-                                               tp, NULL, 0, XFS_BTNUM_BMAP,
+                                       cur = xfs_bmbt_init_cursor(mp, tp,
                                                ip, whichfork);
                                        cur->bc_private.b.firstblock =
                                                *firstblock;
                         */
                        ASSERT(mval->br_blockcount <= len);
                        if ((ifp->if_flags & XFS_IFBROOT) && !cur) {
-                               cur = xfs_btree_init_cursor(mp,
-                                       tp, NULL, 0, XFS_BTNUM_BMAP,
-                                       ip, whichfork);
+                               cur = xfs_bmbt_init_cursor(mp,
+                                       tp, ip, whichfork);
                                cur->bc_private.b.firstblock =
                                        *firstblock;
                                cur->bc_private.b.flist = flist;
        logflags = 0;
        if (ifp->if_flags & XFS_IFBROOT) {
                ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE);
-               cur = xfs_btree_init_cursor(mp, tp, NULL, 0, XFS_BTNUM_BMAP, ip,
-                       whichfork);
+               cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork);
                cur->bc_private.b.firstblock = *firstblock;
                cur->bc_private.b.flist = flist;
                cur->bc_private.b.flags = 0;
 
        }
        return 0;
 }
+
+
+STATIC struct xfs_btree_cur *
+xfs_bmbt_dup_cursor(
+       struct xfs_btree_cur    *cur)
+{
+       struct xfs_btree_cur    *new;
+
+       new = xfs_bmbt_init_cursor(cur->bc_mp, cur->bc_tp,
+                       cur->bc_private.b.ip, cur->bc_private.b.whichfork);
+
+       /*
+        * Copy the firstblock, flist, and flags values,
+        * since init cursor doesn't get them.
+        */
+       new->bc_private.b.firstblock = cur->bc_private.b.firstblock;
+       new->bc_private.b.flist = cur->bc_private.b.flist;
+       new->bc_private.b.flags = cur->bc_private.b.flags;
+
+       return new;
+}
+
+static const struct xfs_btree_ops xfs_bmbt_ops = {
+       .dup_cursor             = xfs_bmbt_dup_cursor,
+};
+
+/*
+ * Allocate a new bmap btree cursor.
+ */
+struct xfs_btree_cur *                         /* new bmap btree cursor */
+xfs_bmbt_init_cursor(
+       struct xfs_mount        *mp,            /* file system mount point */
+       struct xfs_trans        *tp,            /* transaction pointer */
+       struct xfs_inode        *ip,            /* inode owning the btree */
+       int                     whichfork)      /* data or attr fork */
+{
+       struct xfs_ifork        *ifp = XFS_IFORK_PTR(ip, whichfork);
+       struct xfs_btree_cur    *cur;
+
+       cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_SLEEP);
+
+       cur->bc_tp = tp;
+       cur->bc_mp = mp;
+       cur->bc_nlevels = be16_to_cpu(ifp->if_broot->bb_level) + 1;
+       cur->bc_btnum = XFS_BTNUM_BMAP;
+       cur->bc_blocklog = mp->m_sb.sb_blocklog;
+
+       cur->bc_ops = &xfs_bmbt_ops;
+
+       cur->bc_private.b.forksize = XFS_IFORK_SIZE(ip, whichfork);
+       cur->bc_private.b.ip = ip;
+       cur->bc_private.b.firstblock = NULLFSBLOCK;
+       cur->bc_private.b.flist = NULL;
+       cur->bc_private.b.allocated = 0;
+       cur->bc_private.b.flags = 0;
+       cur->bc_private.b.whichfork = whichfork;
+
+       return cur;
+}
 
 struct xfs_btree_lblock;
 struct xfs_mount;
 struct xfs_inode;
+struct xfs_trans;
 
 /*
  * Bmap root header, on-disk form only.
 extern int xfs_bmbt_update(struct xfs_btree_cur *, xfs_fileoff_t,
                                xfs_fsblock_t, xfs_filblks_t, xfs_exntst_t);
 
+extern struct xfs_btree_cur *xfs_bmbt_init_cursor(struct xfs_mount *,
+               struct xfs_trans *, struct xfs_inode *, int);
+
 #endif /* __KERNEL__ */
 
 #endif /* __XFS_BMAP_BTREE_H__ */
 
 
        tp = cur->bc_tp;
        mp = cur->bc_mp;
+
        /*
         * Allocate a new cursor like the old one.
         */
-       new = xfs_btree_init_cursor(mp, tp, cur->bc_private.a.agbp,
-               cur->bc_private.a.agno, cur->bc_btnum, cur->bc_private.b.ip,
-               cur->bc_private.b.whichfork);
+       new = cur->bc_ops->dup_cursor(cur);
+
        /*
         * Copy the record currently in the cursor.
         */
        new->bc_rec = cur->bc_rec;
+
        /*
         * For each level current, re-get the buffer and copy the ptr value.
         */
                } else
                        new->bc_bufs[i] = NULL;
        }
-       /*
-        * For bmap btrees, copy the firstblock, flist, and flags values,
-        * since init cursor doesn't get them.
-        */
-       if (new->bc_btnum == XFS_BTNUM_BMAP) {
-               new->bc_private.b.firstblock = cur->bc_private.b.firstblock;
-               new->bc_private.b.flist = cur->bc_private.b.flist;
-               new->bc_private.b.flags = cur->bc_private.b.flags;
-       }
        *ncur = new;
        return 0;
 }
        return bp;
 }
 
-/*
- * Allocate a new btree cursor.
- * The cursor is either for allocation (A) or bmap (B) or inodes (I).
- */
-xfs_btree_cur_t *                      /* new btree cursor */
-xfs_btree_init_cursor(
-       xfs_mount_t     *mp,            /* file system mount point */
-       xfs_trans_t     *tp,            /* transaction pointer */
-       xfs_buf_t       *agbp,          /* (A only) buffer for agf structure */
-                                       /* (I only) buffer for agi structure */
-       xfs_agnumber_t  agno,           /* (AI only) allocation group number */
-       xfs_btnum_t     btnum,          /* btree identifier */
-       xfs_inode_t     *ip,            /* (B only) inode owning the btree */
-       int             whichfork)      /* (B only) data or attr fork */
-{
-       xfs_agf_t       *agf;           /* (A) allocation group freespace */
-       xfs_agi_t       *agi;           /* (I) allocation group inodespace */
-       xfs_btree_cur_t *cur;           /* return value */
-       xfs_ifork_t     *ifp;           /* (I) inode fork pointer */
-       int             nlevels=0;      /* number of levels in the btree */
-
-       ASSERT(xfs_btree_cur_zone != NULL);
-       /*
-        * Allocate a new cursor.
-        */
-       cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_SLEEP);
-       /*
-        * Deduce the number of btree levels from the arguments.
-        */
-       switch (btnum) {
-       case XFS_BTNUM_BNO:
-       case XFS_BTNUM_CNT:
-               agf = XFS_BUF_TO_AGF(agbp);
-               nlevels = be32_to_cpu(agf->agf_levels[btnum]);
-               break;
-       case XFS_BTNUM_BMAP:
-               ifp = XFS_IFORK_PTR(ip, whichfork);
-               nlevels = be16_to_cpu(ifp->if_broot->bb_level) + 1;
-               break;
-       case XFS_BTNUM_INO:
-               agi = XFS_BUF_TO_AGI(agbp);
-               nlevels = be32_to_cpu(agi->agi_level);
-               break;
-       default:
-               ASSERT(0);
-       }
-       /*
-        * Fill in the common fields.
-        */
-       cur->bc_tp = tp;
-       cur->bc_mp = mp;
-       cur->bc_nlevels = nlevels;
-       cur->bc_btnum = btnum;
-       cur->bc_blocklog = mp->m_sb.sb_blocklog;
-       /*
-        * Fill in private fields.
-        */
-       switch (btnum) {
-       case XFS_BTNUM_BNO:
-       case XFS_BTNUM_CNT:
-               /*
-                * Allocation btree fields.
-                */
-               cur->bc_private.a.agbp = agbp;
-               cur->bc_private.a.agno = agno;
-               break;
-       case XFS_BTNUM_INO:
-               /*
-                * Inode allocation btree fields.
-                */
-               cur->bc_private.a.agbp = agbp;
-               cur->bc_private.a.agno = agno;
-               break;
-       case XFS_BTNUM_BMAP:
-               /*
-                * Bmap btree fields.
-                */
-               cur->bc_private.b.forksize = XFS_IFORK_SIZE(ip, whichfork);
-               cur->bc_private.b.ip = ip;
-               cur->bc_private.b.firstblock = NULLFSBLOCK;
-               cur->bc_private.b.flist = NULL;
-               cur->bc_private.b.allocated = 0;
-               cur->bc_private.b.flags = 0;
-               cur->bc_private.b.whichfork = whichfork;
-               break;
-       default:
-               ASSERT(0);
-       }
-       return cur;
-}
-
 /*
  * Check for the cursor referring to the last block at the given level.
  */
 
 
 #define        XFS_BTREE_MAXLEVELS     8       /* max of all btrees */
 
+struct xfs_btree_ops {
+       /* cursor operations */
+       struct xfs_btree_cur *(*dup_cursor)(struct xfs_btree_cur *);
+};
+
 /*
  * Btree cursor structure.
  * This collects all information needed by the btree code in one place.
 {
        struct xfs_trans        *bc_tp; /* transaction we're in, if any */
        struct xfs_mount        *bc_mp; /* file system mount struct */
+       const struct xfs_btree_ops *bc_ops;
        union {
                xfs_alloc_rec_incore_t  a;
                xfs_bmbt_irec_t         b;
        xfs_agblock_t           agbno,  /* allocation group block number */
        uint                    lock);  /* lock flags for get_buf */
 
-/*
- * Allocate a new btree cursor.
- * The cursor is either for allocation (A) or bmap (B).
- */
-xfs_btree_cur_t *                      /* new btree cursor */
-xfs_btree_init_cursor(
-       struct xfs_mount        *mp,    /* file system mount point */
-       struct xfs_trans        *tp,    /* transaction pointer */
-       struct xfs_buf          *agbp,  /* (A only) buffer for agf structure */
-       xfs_agnumber_t          agno,   /* (A only) allocation group number */
-       xfs_btnum_t             btnum,  /* btree identifier */
-       struct xfs_inode        *ip,    /* (B only) inode owning the btree */
-       int                     whichfork); /* (B only) data/attr fork */
-
 /*
  * Check for the cursor referring to the last block at the given level.
  */
 
        /*
         * Insert records describing the new inode chunk into the btree.
         */
-       cur = xfs_btree_init_cursor(args.mp, tp, agbp, agno,
-                       XFS_BTNUM_INO, (xfs_inode_t *)0, 0);
+       cur = xfs_inobt_init_cursor(args.mp, tp, agbp, agno);
        for (thisino = newino;
             thisino < newino + newlen;
             thisino += XFS_INODES_PER_CHUNK) {
         */
        agno = tagno;
        *IO_agbp = NULL;
-       cur = xfs_btree_init_cursor(mp, tp, agbp, be32_to_cpu(agi->agi_seqno),
-                                   XFS_BTNUM_INO, (xfs_inode_t *)0, 0);
+       cur = xfs_inobt_init_cursor(mp, tp, agbp, be32_to_cpu(agi->agi_seqno));
        /*
         * If pagino is 0 (this is the root inode allocation) use newino.
         * This must work because we've just allocated some.
        /*
         * Initialize the cursor.
         */
-       cur = xfs_btree_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO,
-               (xfs_inode_t *)0, 0);
+       cur = xfs_inobt_init_cursor(mp, tp, agbp, agno);
 #ifdef DEBUG
        if (cur->bc_nlevels == 1) {
                int freecount = 0;
 #endif /* DEBUG */
                        return error;
                }
-               cur = xfs_btree_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO,
-                       (xfs_inode_t *)0, 0);
+               cur = xfs_inobt_init_cursor(mp, tp, agbp, agno);
                if ((error = xfs_inobt_lookup_le(cur, agino, 0, 0, &i))) {
 #ifdef DEBUG
                        xfs_fs_cmn_err(CE_ALERT, mp, "xfs_dilocate: "
 
        }
        return 0;
 }
+
+STATIC struct xfs_btree_cur *
+xfs_inobt_dup_cursor(
+       struct xfs_btree_cur    *cur)
+{
+       return xfs_inobt_init_cursor(cur->bc_mp, cur->bc_tp,
+                       cur->bc_private.a.agbp, cur->bc_private.a.agno);
+}
+
+static const struct xfs_btree_ops xfs_inobt_ops = {
+       .dup_cursor             = xfs_inobt_dup_cursor,
+};
+
+/*
+ * Allocate a new inode btree cursor.
+ */
+struct xfs_btree_cur *                         /* new inode btree cursor */
+xfs_inobt_init_cursor(
+       struct xfs_mount        *mp,            /* file system mount point */
+       struct xfs_trans        *tp,            /* transaction pointer */
+       struct xfs_buf          *agbp,          /* buffer for agi structure */
+       xfs_agnumber_t          agno)           /* allocation group number */
+{
+       struct xfs_agi          *agi = XFS_BUF_TO_AGI(agbp);
+       struct xfs_btree_cur    *cur;
+
+       cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_SLEEP);
+
+       cur->bc_tp = tp;
+       cur->bc_mp = mp;
+       cur->bc_nlevels = be32_to_cpu(agi->agi_level);
+       cur->bc_btnum = XFS_BTNUM_INO;
+       cur->bc_blocklog = mp->m_sb.sb_blocklog;
+
+       cur->bc_ops = &xfs_inobt_ops;
+
+       cur->bc_private.a.agbp = agbp;
+       cur->bc_private.a.agno = agno;
+
+       return cur;
+}
 
 extern int xfs_inobt_update(struct xfs_btree_cur *cur, xfs_agino_t ino,
                                __int32_t fcnt, xfs_inofree_t free);
 
+
+extern struct xfs_btree_cur *xfs_inobt_init_cursor(struct xfs_mount *,
+               struct xfs_trans *, struct xfs_buf *, xfs_agnumber_t);
+
 #endif /* __XFS_IALLOC_BTREE_H__ */
 
                /*
                 * Allocate and initialize a btree cursor for ialloc btree.
                 */
-               cur = xfs_btree_init_cursor(mp, NULL, agbp, agno, XFS_BTNUM_INO,
-                                               (xfs_inode_t *)0, 0);
+               cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno);
                irbp = irbuf;
                irbufend = irbuf + nirbuf;
                end_of_ag = 0;
                                agino = 0;
                                continue;
                        }
-                       cur = xfs_btree_init_cursor(mp, NULL, agbp, agno,
-                               XFS_BTNUM_INO, (xfs_inode_t *)0, 0);
+                       cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno);
                        error = xfs_inobt_lookup_ge(cur, agino, 0, 0, &tmp);
                        if (error) {
                                xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);