]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - fs/xfs/xfs_ialloc_btree.c
[XFS] implement generic xfs_btree_rshift
[linux-2.6-omap-h63xx.git] / fs / xfs / xfs_ialloc_btree.c
index 83502f3edef0d99477e6fb539418950ec9019c9b..457f88a76e10d718345741d15d1607cecb939de2 100644 (file)
@@ -45,10 +45,8 @@ STATIC void xfs_inobt_log_ptrs(xfs_btree_cur_t *, xfs_buf_t *, int, int);
 STATIC void xfs_inobt_log_recs(xfs_btree_cur_t *, xfs_buf_t *, int, int);
 STATIC int xfs_inobt_lshift(xfs_btree_cur_t *, int, int *);
 STATIC int xfs_inobt_newroot(xfs_btree_cur_t *, int *);
-STATIC int xfs_inobt_rshift(xfs_btree_cur_t *, int, int *);
 STATIC int xfs_inobt_split(xfs_btree_cur_t *, int, xfs_agblock_t *,
                xfs_inobt_key_t *, xfs_btree_cur_t **, int *);
-STATIC int xfs_inobt_updkey(xfs_btree_cur_t *, xfs_inobt_key_t *, int);
 
 /*
  * Single level of the xfs_inobt_delete record deletion routine.
@@ -205,7 +203,7 @@ xfs_inobt_delrec(
                        cur->bc_bufs[level] = NULL;
                        cur->bc_nlevels--;
                } else if (level > 0 &&
-                          (error = xfs_inobt_decrement(cur, level, &i)))
+                          (error = xfs_btree_decrement(cur, level, &i)))
                        return error;
                *stat = 1;
                return 0;
@@ -214,7 +212,7 @@ xfs_inobt_delrec(
         * If we deleted the leftmost entry in the block, update the
         * key values above us in the tree.
         */
-       if (ptr == 1 && (error = xfs_inobt_updkey(cur, kp, level + 1)))
+       if (ptr == 1 && (error = xfs_btree_updkey(cur, (union xfs_btree_key *)kp, level + 1)))
                return error;
        /*
         * If the number of records remaining in the block is at least
@@ -222,7 +220,7 @@ xfs_inobt_delrec(
         */
        if (numrecs >= XFS_INOBT_BLOCK_MINRECS(level, cur)) {
                if (level > 0 &&
-                   (error = xfs_inobt_decrement(cur, level, &i)))
+                   (error = xfs_btree_decrement(cur, level, &i)))
                        return error;
                *stat = 1;
                return 0;
@@ -253,7 +251,7 @@ xfs_inobt_delrec(
                 */
                i = xfs_btree_lastrec(tcur, level);
                XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
-               if ((error = xfs_inobt_increment(tcur, level, &i)))
+               if ((error = xfs_btree_increment(tcur, level, &i)))
                        goto error0;
                XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
                i = xfs_btree_lastrec(tcur, level);
@@ -286,7 +284,7 @@ xfs_inobt_delrec(
                                xfs_btree_del_cursor(tcur,
                                                     XFS_BTREE_NOERROR);
                                if (level > 0 &&
-                                   (error = xfs_inobt_decrement(cur, level,
+                                   (error = xfs_btree_decrement(cur, level,
                                                &i)))
                                        return error;
                                *stat = 1;
@@ -301,7 +299,7 @@ xfs_inobt_delrec(
                rrecs = be16_to_cpu(right->bb_numrecs);
                if (lbno != NULLAGBLOCK) {
                        xfs_btree_firstrec(tcur, level);
-                       if ((error = xfs_inobt_decrement(tcur, level, &i)))
+                       if ((error = xfs_btree_decrement(tcur, level, &i)))
                                goto error0;
                }
        }
@@ -315,7 +313,7 @@ xfs_inobt_delrec(
                 * previous block.
                 */
                xfs_btree_firstrec(tcur, level);
-               if ((error = xfs_inobt_decrement(tcur, level, &i)))
+               if ((error = xfs_btree_decrement(tcur, level, &i)))
                        goto error0;
                xfs_btree_firstrec(tcur, level);
                /*
@@ -338,7 +336,7 @@ xfs_inobt_delrec(
                 */
                if (be16_to_cpu(left->bb_numrecs) - 1 >=
                     XFS_INOBT_BLOCK_MINRECS(level, cur)) {
-                       if ((error = xfs_inobt_rshift(tcur, level, &i)))
+                       if ((error = xfs_btree_rshift(tcur, level, &i)))
                                goto error0;
                        if (i) {
                                ASSERT(be16_to_cpu(block->bb_numrecs) >=
@@ -414,7 +412,7 @@ xfs_inobt_delrec(
         * Just return.  This is probably a logic error, but it's not fatal.
         */
        else {
-               if (level > 0 && (error = xfs_inobt_decrement(cur, level, &i)))
+               if (level > 0 && (error = xfs_btree_decrement(cur, level, &i)))
                        return error;
                *stat = 1;
                return 0;
@@ -463,7 +461,7 @@ xfs_inobt_delrec(
         * us, increment the cursor at that level.
         */
        else if (level + 1 < cur->bc_nlevels &&
-                (error = xfs_alloc_increment(cur, level + 1, &i)))
+                (error = xfs_btree_increment(cur, level + 1, &i)))
                return error;
        /*
         * Fix up the number of records in the surviving block.
@@ -609,7 +607,7 @@ xfs_inobt_insrec(
                /*
                 * First, try shifting an entry to the right neighbor.
                 */
-               if ((error = xfs_inobt_rshift(cur, level, &i)))
+               if ((error = xfs_btree_rshift(cur, level, &i)))
                        return error;
                if (i) {
                        /* nothing */
@@ -723,7 +721,7 @@ xfs_inobt_insrec(
        /*
         * If we inserted at the start of a block, update the parents' keys.
         */
-       if (optr == 1 && (error = xfs_inobt_updkey(cur, &key, level + 1)))
+       if (optr == 1 && (error = xfs_btree_updkey(cur, (union xfs_btree_key *)&key, level + 1)))
                return error;
        /*
         * Return the new block number, if any.
@@ -828,212 +826,6 @@ xfs_inobt_log_recs(
        xfs_trans_log_buf(cur->bc_tp, bp, first, last);
 }
 
-/*
- * Lookup the record.  The cursor is made to point to it, based on dir.
- * Return 0 if can't find any such record, 1 for success.
- */
-STATIC int                             /* error */
-xfs_inobt_lookup(
-       xfs_btree_cur_t         *cur,   /* btree cursor */
-       xfs_lookup_t            dir,    /* <=, ==, or >= */
-       int                     *stat)  /* success/failure */
-{
-       xfs_agblock_t           agbno;  /* a.g. relative btree block number */
-       xfs_agnumber_t          agno;   /* allocation group number */
-       xfs_inobt_block_t       *block=NULL;    /* current btree block */
-       __int64_t               diff;   /* difference for the current key */
-       int                     error;  /* error return value */
-       int                     keyno=0;        /* current key number */
-       int                     level;  /* level in the btree */
-       xfs_mount_t             *mp;    /* file system mount point */
-
-       /*
-        * Get the allocation group header, and the root block number.
-        */
-       mp = cur->bc_mp;
-       {
-               xfs_agi_t       *agi;   /* a.g. inode header */
-
-               agi = XFS_BUF_TO_AGI(cur->bc_private.a.agbp);
-               agno = be32_to_cpu(agi->agi_seqno);
-               agbno = be32_to_cpu(agi->agi_root);
-       }
-       /*
-        * Iterate over each level in the btree, starting at the root.
-        * For each level above the leaves, find the key we need, based
-        * on the lookup record, then follow the corresponding block
-        * pointer down to the next level.
-        */
-       for (level = cur->bc_nlevels - 1, diff = 1; level >= 0; level--) {
-               xfs_buf_t       *bp;    /* buffer pointer for btree block */
-               xfs_daddr_t     d;      /* disk address of btree block */
-
-               /*
-                * Get the disk address we're looking for.
-                */
-               d = XFS_AGB_TO_DADDR(mp, agno, agbno);
-               /*
-                * If the old buffer at this level is for a different block,
-                * throw it away, otherwise just use it.
-                */
-               bp = cur->bc_bufs[level];
-               if (bp && XFS_BUF_ADDR(bp) != d)
-                       bp = NULL;
-               if (!bp) {
-                       /*
-                        * Need to get a new buffer.  Read it, then
-                        * set it in the cursor, releasing the old one.
-                        */
-                       if ((error = xfs_btree_read_bufs(mp, cur->bc_tp,
-                                       agno, agbno, 0, &bp, XFS_INO_BTREE_REF)))
-                               return error;
-                       xfs_btree_setbuf(cur, level, bp);
-                       /*
-                        * Point to the btree block, now that we have the buffer
-                        */
-                       block = XFS_BUF_TO_INOBT_BLOCK(bp);
-                       if ((error = xfs_btree_check_sblock(cur, block, level,
-                                       bp)))
-                               return error;
-               } else
-                       block = XFS_BUF_TO_INOBT_BLOCK(bp);
-               /*
-                * If we already had a key match at a higher level, we know
-                * we need to use the first entry in this block.
-                */
-               if (diff == 0)
-                       keyno = 1;
-               /*
-                * Otherwise we need to search this block.  Do a binary search.
-                */
-               else {
-                       int             high;   /* high entry number */
-                       xfs_inobt_key_t *kkbase=NULL;/* base of keys in block */
-                       xfs_inobt_rec_t *krbase=NULL;/* base of records in block */
-                       int             low;    /* low entry number */
-
-                       /*
-                        * Get a pointer to keys or records.
-                        */
-                       if (level > 0)
-                               kkbase = XFS_INOBT_KEY_ADDR(block, 1, cur);
-                       else
-                               krbase = XFS_INOBT_REC_ADDR(block, 1, cur);
-                       /*
-                        * Set low and high entry numbers, 1-based.
-                        */
-                       low = 1;
-                       if (!(high = be16_to_cpu(block->bb_numrecs))) {
-                               /*
-                                * If the block is empty, the tree must
-                                * be an empty leaf.
-                                */
-                               ASSERT(level == 0 && cur->bc_nlevels == 1);
-                               cur->bc_ptrs[0] = dir != XFS_LOOKUP_LE;
-                               *stat = 0;
-                               return 0;
-                       }
-                       /*
-                        * Binary search the block.
-                        */
-                       while (low <= high) {
-                               xfs_agino_t     startino;       /* key value */
-
-                               /*
-                                * keyno is average of low and high.
-                                */
-                               keyno = (low + high) >> 1;
-                               /*
-                                * Get startino.
-                                */
-                               if (level > 0) {
-                                       xfs_inobt_key_t *kkp;
-
-                                       kkp = kkbase + keyno - 1;
-                                       startino = be32_to_cpu(kkp->ir_startino);
-                               } else {
-                                       xfs_inobt_rec_t *krp;
-
-                                       krp = krbase + keyno - 1;
-                                       startino = be32_to_cpu(krp->ir_startino);
-                               }
-                               /*
-                                * Compute difference to get next direction.
-                                */
-                               diff = (__int64_t)
-                                       startino - cur->bc_rec.i.ir_startino;
-                               /*
-                                * Less than, move right.
-                                */
-                               if (diff < 0)
-                                       low = keyno + 1;
-                               /*
-                                * Greater than, move left.
-                                */
-                               else if (diff > 0)
-                                       high = keyno - 1;
-                               /*
-                                * Equal, we're done.
-                                */
-                               else
-                                       break;
-                       }
-               }
-               /*
-                * If there are more levels, set up for the next level
-                * by getting the block number and filling in the cursor.
-                */
-               if (level > 0) {
-                       /*
-                        * If we moved left, need the previous key number,
-                        * unless there isn't one.
-                        */
-                       if (diff > 0 && --keyno < 1)
-                               keyno = 1;
-                       agbno = be32_to_cpu(*XFS_INOBT_PTR_ADDR(block, keyno, cur));
-#ifdef DEBUG
-                       if ((error = xfs_btree_check_sptr(cur, agbno, level)))
-                               return error;
-#endif
-                       cur->bc_ptrs[level] = keyno;
-               }
-       }
-       /*
-        * Done with the search.
-        * See if we need to adjust the results.
-        */
-       if (dir != XFS_LOOKUP_LE && diff < 0) {
-               keyno++;
-               /*
-                * If ge search and we went off the end of the block, but it's
-                * not the last block, we're in the wrong block.
-                */
-               if (dir == XFS_LOOKUP_GE &&
-                   keyno > be16_to_cpu(block->bb_numrecs) &&
-                   be32_to_cpu(block->bb_rightsib) != NULLAGBLOCK) {
-                       int     i;
-
-                       cur->bc_ptrs[0] = keyno;
-                       if ((error = xfs_inobt_increment(cur, 0, &i)))
-                               return error;
-                       ASSERT(i == 1);
-                       *stat = 1;
-                       return 0;
-               }
-       }
-       else if (dir == XFS_LOOKUP_LE && diff > 0)
-               keyno--;
-       cur->bc_ptrs[0] = keyno;
-       /*
-        * Return if we succeeded or not.
-        */
-       if (keyno == 0 || keyno > be16_to_cpu(block->bb_numrecs))
-               *stat = 0;
-       else
-               *stat = ((dir != XFS_LOOKUP_EQ) || (diff == 0));
-       return 0;
-}
-
 /*
  * Move 1 record left from cur/level if possible.
  * Update cur to reflect the new path.
@@ -1166,7 +958,7 @@ xfs_inobt_lshift(
        /*
         * Update the parent key values of right.
         */
-       if ((error = xfs_inobt_updkey(cur, rkp, level + 1)))
+       if ((error = xfs_btree_updkey(cur, (union xfs_btree_key *)rkp, level + 1)))
                return error;
        /*
         * Slide the cursor value left one.
@@ -1323,136 +1115,6 @@ xfs_inobt_newroot(
        return 0;
 }
 
-/*
- * Move 1 record right from cur/level if possible.
- * Update cur to reflect the new path.
- */
-STATIC int                             /* error */
-xfs_inobt_rshift(
-       xfs_btree_cur_t         *cur,   /* btree cursor */
-       int                     level,  /* level to shift record on */
-       int                     *stat)  /* success/failure */
-{
-       int                     error;  /* error return value */
-       int                     i;      /* loop index */
-       xfs_inobt_key_t         key;    /* key value for leaf level upward */
-       xfs_buf_t               *lbp;   /* buffer for left (current) block */
-       xfs_inobt_block_t       *left;  /* left (current) btree block */
-       xfs_inobt_key_t         *lkp;   /* key pointer for left block */
-       xfs_inobt_ptr_t         *lpp;   /* address pointer for left block */
-       xfs_inobt_rec_t         *lrp;   /* record pointer for left block */
-       xfs_buf_t               *rbp;   /* buffer for right neighbor block */
-       xfs_inobt_block_t       *right; /* right neighbor btree block */
-       xfs_inobt_key_t         *rkp;   /* key pointer for right block */
-       xfs_inobt_ptr_t         *rpp;   /* address pointer for right block */
-       xfs_inobt_rec_t         *rrp=NULL;      /* record pointer for right block */
-       xfs_btree_cur_t         *tcur;  /* temporary cursor */
-
-       /*
-        * Set up variables for this block as "left".
-        */
-       lbp = cur->bc_bufs[level];
-       left = XFS_BUF_TO_INOBT_BLOCK(lbp);
-#ifdef DEBUG
-       if ((error = xfs_btree_check_sblock(cur, left, level, lbp)))
-               return error;
-#endif
-       /*
-        * If we've got no right sibling then we can't shift an entry right.
-        */
-       if (be32_to_cpu(left->bb_rightsib) == NULLAGBLOCK) {
-               *stat = 0;
-               return 0;
-       }
-       /*
-        * If the cursor entry is the one that would be moved, don't
-        * do it... it's too complicated.
-        */
-       if (cur->bc_ptrs[level] >= be16_to_cpu(left->bb_numrecs)) {
-               *stat = 0;
-               return 0;
-       }
-       /*
-        * Set up the right neighbor as "right".
-        */
-       if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp,
-                       cur->bc_private.a.agno, be32_to_cpu(left->bb_rightsib),
-                       0, &rbp, XFS_INO_BTREE_REF)))
-               return error;
-       right = XFS_BUF_TO_INOBT_BLOCK(rbp);
-       if ((error = xfs_btree_check_sblock(cur, right, level, rbp)))
-               return error;
-       /*
-        * If it's full, it can't take another entry.
-        */
-       if (be16_to_cpu(right->bb_numrecs) == XFS_INOBT_BLOCK_MAXRECS(level, cur)) {
-               *stat = 0;
-               return 0;
-       }
-       /*
-        * Make a hole at the start of the right neighbor block, then
-        * copy the last left block entry to the hole.
-        */
-       if (level > 0) {
-               lkp = XFS_INOBT_KEY_ADDR(left, be16_to_cpu(left->bb_numrecs), cur);
-               lpp = XFS_INOBT_PTR_ADDR(left, be16_to_cpu(left->bb_numrecs), cur);
-               rkp = XFS_INOBT_KEY_ADDR(right, 1, cur);
-               rpp = XFS_INOBT_PTR_ADDR(right, 1, cur);
-#ifdef DEBUG
-               for (i = be16_to_cpu(right->bb_numrecs) - 1; i >= 0; i--) {
-                       if ((error = xfs_btree_check_sptr(cur, be32_to_cpu(rpp[i]), level)))
-                               return error;
-               }
-#endif
-               memmove(rkp + 1, rkp, be16_to_cpu(right->bb_numrecs) * sizeof(*rkp));
-               memmove(rpp + 1, rpp, be16_to_cpu(right->bb_numrecs) * sizeof(*rpp));
-#ifdef DEBUG
-               if ((error = xfs_btree_check_sptr(cur, be32_to_cpu(*lpp), level)))
-                       return error;
-#endif
-               *rkp = *lkp;
-               *rpp = *lpp;
-               xfs_inobt_log_keys(cur, rbp, 1, be16_to_cpu(right->bb_numrecs) + 1);
-               xfs_inobt_log_ptrs(cur, rbp, 1, be16_to_cpu(right->bb_numrecs) + 1);
-       } else {
-               lrp = XFS_INOBT_REC_ADDR(left, be16_to_cpu(left->bb_numrecs), cur);
-               rrp = XFS_INOBT_REC_ADDR(right, 1, cur);
-               memmove(rrp + 1, rrp, be16_to_cpu(right->bb_numrecs) * sizeof(*rrp));
-               *rrp = *lrp;
-               xfs_inobt_log_recs(cur, rbp, 1, be16_to_cpu(right->bb_numrecs) + 1);
-               key.ir_startino = rrp->ir_startino;
-               rkp = &key;
-       }
-       /*
-        * Decrement and log left's numrecs, bump and log right's numrecs.
-        */
-       be16_add_cpu(&left->bb_numrecs, -1);
-       xfs_inobt_log_block(cur->bc_tp, lbp, XFS_BB_NUMRECS);
-       be16_add_cpu(&right->bb_numrecs, 1);
-#ifdef DEBUG
-       if (level > 0)
-               xfs_btree_check_key(cur->bc_btnum, rkp, rkp + 1);
-       else
-               xfs_btree_check_rec(cur->bc_btnum, rrp, rrp + 1);
-#endif
-       xfs_inobt_log_block(cur->bc_tp, rbp, XFS_BB_NUMRECS);
-       /*
-        * Using a temporary cursor, update the parent key values of the
-        * block on the right.
-        */
-       if ((error = xfs_btree_dup_cursor(cur, &tcur)))
-               return error;
-       xfs_btree_lastrec(tcur, level);
-       if ((error = xfs_inobt_increment(tcur, level, &i)) ||
-           (error = xfs_inobt_updkey(tcur, rkp, level + 1))) {
-               xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR);
-               return error;
-       }
-       xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR);
-       *stat = 1;
-       return 0;
-}
-
 /*
  * Split cur/level block in half.
  * Return new block number and its first record (to be inserted into parent).
@@ -1612,133 +1274,10 @@ xfs_inobt_split(
        return 0;
 }
 
-/*
- * Update keys at all levels from here to the root along the cursor's path.
- */
-STATIC int                             /* error */
-xfs_inobt_updkey(
-       xfs_btree_cur_t         *cur,   /* btree cursor */
-       xfs_inobt_key_t         *keyp,  /* new key value to update to */
-       int                     level)  /* starting level for update */
-{
-       int                     ptr;    /* index of key in block */
-
-       /*
-        * Go up the tree from this level toward the root.
-        * At each level, update the key value to the value input.
-        * Stop when we reach a level where the cursor isn't pointing
-        * at the first entry in the block.
-        */
-       for (ptr = 1; ptr == 1 && level < cur->bc_nlevels; level++) {
-               xfs_buf_t               *bp;    /* buffer for block */
-               xfs_inobt_block_t       *block; /* btree block */
-#ifdef DEBUG
-               int                     error;  /* error return value */
-#endif
-               xfs_inobt_key_t         *kp;    /* ptr to btree block keys */
-
-               bp = cur->bc_bufs[level];
-               block = XFS_BUF_TO_INOBT_BLOCK(bp);
-#ifdef DEBUG
-               if ((error = xfs_btree_check_sblock(cur, block, level, bp)))
-                       return error;
-#endif
-               ptr = cur->bc_ptrs[level];
-               kp = XFS_INOBT_KEY_ADDR(block, ptr, cur);
-               *kp = *keyp;
-               xfs_inobt_log_keys(cur, bp, ptr, ptr);
-       }
-       return 0;
-}
-
 /*
  * Externally visible routines.
  */
 
-/*
- * Decrement cursor by one record at the level.
- * For nonzero levels the leaf-ward information is untouched.
- */
-int                                    /* error */
-xfs_inobt_decrement(
-       xfs_btree_cur_t         *cur,   /* btree cursor */
-       int                     level,  /* level in btree, 0 is leaf */
-       int                     *stat)  /* success/failure */
-{
-       xfs_inobt_block_t       *block; /* btree block */
-       int                     error;
-       int                     lev;    /* btree level */
-
-       ASSERT(level < cur->bc_nlevels);
-       /*
-        * Read-ahead to the left at this level.
-        */
-       xfs_btree_readahead(cur, level, XFS_BTCUR_LEFTRA);
-       /*
-        * Decrement the ptr at this level.  If we're still in the block
-        * then we're done.
-        */
-       if (--cur->bc_ptrs[level] > 0) {
-               *stat = 1;
-               return 0;
-       }
-       /*
-        * Get a pointer to the btree block.
-        */
-       block = XFS_BUF_TO_INOBT_BLOCK(cur->bc_bufs[level]);
-#ifdef DEBUG
-       if ((error = xfs_btree_check_sblock(cur, block, level,
-                       cur->bc_bufs[level])))
-               return error;
-#endif
-       /*
-        * If we just went off the left edge of the tree, return failure.
-        */
-       if (be32_to_cpu(block->bb_leftsib) == NULLAGBLOCK) {
-               *stat = 0;
-               return 0;
-       }
-       /*
-        * March up the tree decrementing pointers.
-        * Stop when we don't go off the left edge of a block.
-        */
-       for (lev = level + 1; lev < cur->bc_nlevels; lev++) {
-               if (--cur->bc_ptrs[lev] > 0)
-                       break;
-               /*
-                * Read-ahead the left block, we're going to read it
-                * in the next loop.
-                */
-               xfs_btree_readahead(cur, lev, XFS_BTCUR_LEFTRA);
-       }
-       /*
-        * If we went off the root then we are seriously confused.
-        */
-       ASSERT(lev < cur->bc_nlevels);
-       /*
-        * Now walk back down the tree, fixing up the cursor's buffer
-        * pointers and key numbers.
-        */
-       for (block = XFS_BUF_TO_INOBT_BLOCK(cur->bc_bufs[lev]); lev > level; ) {
-               xfs_agblock_t   agbno;  /* block number of btree block */
-               xfs_buf_t       *bp;    /* buffer containing btree block */
-
-               agbno = be32_to_cpu(*XFS_INOBT_PTR_ADDR(block, cur->bc_ptrs[lev], cur));
-               if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp,
-                               cur->bc_private.a.agno, agbno, 0, &bp,
-                               XFS_INO_BTREE_REF)))
-                       return error;
-               lev--;
-               xfs_btree_setbuf(cur, lev, bp);
-               block = XFS_BUF_TO_INOBT_BLOCK(bp);
-               if ((error = xfs_btree_check_sblock(cur, block, lev, bp)))
-                       return error;
-               cur->bc_ptrs[lev] = be16_to_cpu(block->bb_numrecs);
-       }
-       *stat = 1;
-       return 0;
-}
-
 /*
  * Delete the record pointed to by cur.
  * The cursor refers to the place where the record was (could be inserted)
@@ -1765,7 +1304,7 @@ xfs_inobt_delete(
        if (i == 0) {
                for (level = 1; level < cur->bc_nlevels; level++) {
                        if (cur->bc_ptrs[level] == 0) {
-                               if ((error = xfs_inobt_decrement(cur, level, &i)))
+                               if ((error = xfs_btree_decrement(cur, level, &i)))
                                        return error;
                                break;
                        }
@@ -1820,97 +1359,6 @@ xfs_inobt_get_rec(
        return 0;
 }
 
-/*
- * Increment cursor by one record at the level.
- * For nonzero levels the leaf-ward information is untouched.
- */
-int                                    /* error */
-xfs_inobt_increment(
-       xfs_btree_cur_t         *cur,   /* btree cursor */
-       int                     level,  /* level in btree, 0 is leaf */
-       int                     *stat)  /* success/failure */
-{
-       xfs_inobt_block_t       *block; /* btree block */
-       xfs_buf_t               *bp;    /* buffer containing btree block */
-       int                     error;  /* error return value */
-       int                     lev;    /* btree level */
-
-       ASSERT(level < cur->bc_nlevels);
-       /*
-        * Read-ahead to the right at this level.
-        */
-       xfs_btree_readahead(cur, level, XFS_BTCUR_RIGHTRA);
-       /*
-        * Get a pointer to the btree block.
-        */
-       bp = cur->bc_bufs[level];
-       block = XFS_BUF_TO_INOBT_BLOCK(bp);
-#ifdef DEBUG
-       if ((error = xfs_btree_check_sblock(cur, block, level, bp)))
-               return error;
-#endif
-       /*
-        * Increment the ptr at this level.  If we're still in the block
-        * then we're done.
-        */
-       if (++cur->bc_ptrs[level] <= be16_to_cpu(block->bb_numrecs)) {
-               *stat = 1;
-               return 0;
-       }
-       /*
-        * If we just went off the right edge of the tree, return failure.
-        */
-       if (be32_to_cpu(block->bb_rightsib) == NULLAGBLOCK) {
-               *stat = 0;
-               return 0;
-       }
-       /*
-        * March up the tree incrementing pointers.
-        * Stop when we don't go off the right edge of a block.
-        */
-       for (lev = level + 1; lev < cur->bc_nlevels; lev++) {
-               bp = cur->bc_bufs[lev];
-               block = XFS_BUF_TO_INOBT_BLOCK(bp);
-#ifdef DEBUG
-               if ((error = xfs_btree_check_sblock(cur, block, lev, bp)))
-                       return error;
-#endif
-               if (++cur->bc_ptrs[lev] <= be16_to_cpu(block->bb_numrecs))
-                       break;
-               /*
-                * Read-ahead the right block, we're going to read it
-                * in the next loop.
-                */
-               xfs_btree_readahead(cur, lev, XFS_BTCUR_RIGHTRA);
-       }
-       /*
-        * If we went off the root then we are seriously confused.
-        */
-       ASSERT(lev < cur->bc_nlevels);
-       /*
-        * Now walk back down the tree, fixing up the cursor's buffer
-        * pointers and key numbers.
-        */
-       for (bp = cur->bc_bufs[lev], block = XFS_BUF_TO_INOBT_BLOCK(bp);
-            lev > level; ) {
-               xfs_agblock_t   agbno;  /* block number of btree block */
-
-               agbno = be32_to_cpu(*XFS_INOBT_PTR_ADDR(block, cur->bc_ptrs[lev], cur));
-               if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp,
-                               cur->bc_private.a.agno, agbno, 0, &bp,
-                               XFS_INO_BTREE_REF)))
-                       return error;
-               lev--;
-               xfs_btree_setbuf(cur, lev, bp);
-               block = XFS_BUF_TO_INOBT_BLOCK(bp);
-               if ((error = xfs_btree_check_sblock(cur, block, lev, bp)))
-                       return error;
-               cur->bc_ptrs[lev] = 1;
-       }
-       *stat = 1;
-       return 0;
-}
-
 /*
  * Insert the current record at the point referenced by cur.
  * The cursor may be inconsistent on return if splits have been done.
@@ -1972,107 +1420,163 @@ xfs_inobt_insert(
        return 0;
 }
 
-/*
- * Lookup the record equal to ino in the btree given by cur.
- */
-int                                    /* error */
-xfs_inobt_lookup_eq(
-       xfs_btree_cur_t *cur,           /* btree cursor */
-       xfs_agino_t     ino,            /* starting inode of chunk */
-       __int32_t       fcnt,           /* free inode count */
-       xfs_inofree_t   free,           /* free inode mask */
-       int             *stat)          /* success/failure */
+STATIC struct xfs_btree_cur *
+xfs_inobt_dup_cursor(
+       struct xfs_btree_cur    *cur)
 {
-       cur->bc_rec.i.ir_startino = ino;
-       cur->bc_rec.i.ir_freecount = fcnt;
-       cur->bc_rec.i.ir_free = free;
-       return xfs_inobt_lookup(cur, XFS_LOOKUP_EQ, stat);
+       return xfs_inobt_init_cursor(cur->bc_mp, cur->bc_tp,
+                       cur->bc_private.a.agbp, cur->bc_private.a.agno);
 }
 
-/*
- * Lookup the first record greater than or equal to ino
- * in the btree given by cur.
- */
-int                                    /* error */
-xfs_inobt_lookup_ge(
-       xfs_btree_cur_t *cur,           /* btree cursor */
-       xfs_agino_t     ino,            /* starting inode of chunk */
-       __int32_t       fcnt,           /* free inode count */
-       xfs_inofree_t   free,           /* free inode mask */
-       int             *stat)          /* success/failure */
+STATIC int
+xfs_inobt_get_maxrecs(
+       struct xfs_btree_cur    *cur,
+       int                     level)
 {
-       cur->bc_rec.i.ir_startino = ino;
-       cur->bc_rec.i.ir_freecount = fcnt;
-       cur->bc_rec.i.ir_free = free;
-       return xfs_inobt_lookup(cur, XFS_LOOKUP_GE, stat);
+       return cur->bc_mp->m_inobt_mxr[level != 0];
+}
+
+STATIC void
+xfs_inobt_init_key_from_rec(
+       union xfs_btree_key     *key,
+       union xfs_btree_rec     *rec)
+{
+       key->inobt.ir_startino = rec->inobt.ir_startino;
 }
 
 /*
- * Lookup the first record less than or equal to ino
- * in the btree given by cur.
+ * intial value of ptr for lookup
  */
-int                                    /* error */
-xfs_inobt_lookup_le(
-       xfs_btree_cur_t *cur,           /* btree cursor */
-       xfs_agino_t     ino,            /* starting inode of chunk */
-       __int32_t       fcnt,           /* free inode count */
-       xfs_inofree_t   free,           /* free inode mask */
-       int             *stat)          /* success/failure */
+STATIC void
+xfs_inobt_init_ptr_from_cur(
+       struct xfs_btree_cur    *cur,
+       union xfs_btree_ptr     *ptr)
 {
-       cur->bc_rec.i.ir_startino = ino;
-       cur->bc_rec.i.ir_freecount = fcnt;
-       cur->bc_rec.i.ir_free = free;
-       return xfs_inobt_lookup(cur, XFS_LOOKUP_LE, stat);
+       struct xfs_agi          *agi = XFS_BUF_TO_AGI(cur->bc_private.a.agbp);
+
+       ASSERT(cur->bc_private.a.agno == be32_to_cpu(agi->agi_seqno));
+
+       ptr->s = agi->agi_root;
 }
 
+STATIC __int64_t
+xfs_inobt_key_diff(
+       struct xfs_btree_cur    *cur,
+       union xfs_btree_key     *key)
+{
+       return (__int64_t)be32_to_cpu(key->inobt.ir_startino) -
+                         cur->bc_rec.i.ir_startino;
+}
+
+#ifdef XFS_BTREE_TRACE
+ktrace_t       *xfs_inobt_trace_buf;
+
+STATIC void
+xfs_inobt_trace_enter(
+       struct xfs_btree_cur    *cur,
+       const char              *func,
+       char                    *s,
+       int                     type,
+       int                     line,
+       __psunsigned_t          a0,
+       __psunsigned_t          a1,
+       __psunsigned_t          a2,
+       __psunsigned_t          a3,
+       __psunsigned_t          a4,
+       __psunsigned_t          a5,
+       __psunsigned_t          a6,
+       __psunsigned_t          a7,
+       __psunsigned_t          a8,
+       __psunsigned_t          a9,
+       __psunsigned_t          a10)
+{
+       ktrace_enter(xfs_inobt_trace_buf, (void *)(__psint_t)type,
+               (void *)func, (void *)s, NULL, (void *)cur,
+               (void *)a0, (void *)a1, (void *)a2, (void *)a3,
+               (void *)a4, (void *)a5, (void *)a6, (void *)a7,
+               (void *)a8, (void *)a9, (void *)a10);
+}
+
+STATIC void
+xfs_inobt_trace_cursor(
+       struct xfs_btree_cur    *cur,
+       __uint32_t              *s0,
+       __uint64_t              *l0,
+       __uint64_t              *l1)
+{
+       *s0 = cur->bc_private.a.agno;
+       *l0 = cur->bc_rec.i.ir_startino;
+       *l1 = cur->bc_rec.i.ir_free;
+}
+
+STATIC void
+xfs_inobt_trace_key(
+       struct xfs_btree_cur    *cur,
+       union xfs_btree_key     *key,
+       __uint64_t              *l0,
+       __uint64_t              *l1)
+{
+       *l0 = be32_to_cpu(key->inobt.ir_startino);
+       *l1 = 0;
+}
+
+STATIC void
+xfs_inobt_trace_record(
+       struct xfs_btree_cur    *cur,
+       union xfs_btree_rec     *rec,
+       __uint64_t              *l0,
+       __uint64_t              *l1,
+       __uint64_t              *l2)
+{
+       *l0 = be32_to_cpu(rec->inobt.ir_startino);
+       *l1 = be32_to_cpu(rec->inobt.ir_freecount);
+       *l2 = be64_to_cpu(rec->inobt.ir_free);
+}
+#endif /* XFS_BTREE_TRACE */
+
+static const struct xfs_btree_ops xfs_inobt_ops = {
+       .rec_len                = sizeof(xfs_inobt_rec_t),
+       .key_len                = sizeof(xfs_inobt_key_t),
+
+       .dup_cursor             = xfs_inobt_dup_cursor,
+       .get_maxrecs            = xfs_inobt_get_maxrecs,
+       .init_key_from_rec      = xfs_inobt_init_key_from_rec,
+       .init_ptr_from_cur      = xfs_inobt_init_ptr_from_cur,
+       .key_diff               = xfs_inobt_key_diff,
+
+#ifdef XFS_BTREE_TRACE
+       .trace_enter            = xfs_inobt_trace_enter,
+       .trace_cursor           = xfs_inobt_trace_cursor,
+       .trace_key              = xfs_inobt_trace_key,
+       .trace_record           = xfs_inobt_trace_record,
+#endif
+};
+
 /*
- * Update the record referred to by cur, to the value given
- * by [ino, fcnt, free].
- * This either works (return 0) or gets an EFSCORRUPTED error.
+ * Allocate a new inode btree cursor.
  */
-int                                    /* error */
-xfs_inobt_update(
-       xfs_btree_cur_t         *cur,   /* btree cursor */
-       xfs_agino_t             ino,    /* starting inode of chunk */
-       __int32_t               fcnt,   /* free inode count */
-       xfs_inofree_t           free)   /* free inode mask */
+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 */
 {
-       xfs_inobt_block_t       *block; /* btree block to update */
-       xfs_buf_t               *bp;    /* buffer containing btree block */
-       int                     error;  /* error return value */
-       int                     ptr;    /* current record number (updating) */
-       xfs_inobt_rec_t         *rp;    /* pointer to updated record */
+       struct xfs_agi          *agi = XFS_BUF_TO_AGI(agbp);
+       struct xfs_btree_cur    *cur;
 
-       /*
-        * Pick up the current block.
-        */
-       bp = cur->bc_bufs[0];
-       block = XFS_BUF_TO_INOBT_BLOCK(bp);
-#ifdef DEBUG
-       if ((error = xfs_btree_check_sblock(cur, block, 0, bp)))
-               return error;
-#endif
-       /*
-        * Get the address of the rec to be updated.
-        */
-       ptr = cur->bc_ptrs[0];
-       rp = XFS_INOBT_REC_ADDR(block, ptr, cur);
-       /*
-        * Fill in the new contents and log them.
-        */
-       rp->ir_startino = cpu_to_be32(ino);
-       rp->ir_freecount = cpu_to_be32(fcnt);
-       rp->ir_free = cpu_to_be64(free);
-       xfs_inobt_log_recs(cur, bp, ptr, ptr);
-       /*
-        * Updating first record in leaf. Pass new key value up to our parent.
-        */
-       if (ptr == 1) {
-               xfs_inobt_key_t key;    /* key containing [ino] */
+       cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_SLEEP);
 
-               key.ir_startino = cpu_to_be32(ino);
-               if ((error = xfs_inobt_updkey(cur, &key, 1)))
-                       return error;
-       }
-       return 0;
+       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;
 }