[XFS] implement generic xfs_btree_insert/insrec
Make the btree insert code generic. Based on a patch from David Chinner with lots of changes to follow the original btree implementations more closely. While this loses some of the generic helper routines for inserting/moving/removing records it also solves some of the one off bugs in the original code and makes it easier to verify. SGI-PV: 985583 SGI-Modid: xfs-linux-melb:xfs-kern:32202a Signed-off-by: Christoph Hellwig <hch@infradead.org> Signed-off-by: Lachlan McIlroy <lachlan@sgi.com> Signed-off-by: Bill O'Donnell <billodo@sgi.com> Signed-off-by: David Chinner <david@fromorbit.com>
This commit is contained in:
parent
ea77b0a66e
commit
4b22a57188
|
@ -408,7 +408,7 @@ xfs_alloc_fixup_trees(
|
|||
if ((error = xfs_alloc_lookup_eq(cnt_cur, nfbno1, nflen1, &i)))
|
||||
return error;
|
||||
XFS_WANT_CORRUPTED_RETURN(i == 0);
|
||||
if ((error = xfs_alloc_insert(cnt_cur, &i)))
|
||||
if ((error = xfs_btree_insert(cnt_cur, &i)))
|
||||
return error;
|
||||
XFS_WANT_CORRUPTED_RETURN(i == 1);
|
||||
}
|
||||
|
@ -416,7 +416,7 @@ xfs_alloc_fixup_trees(
|
|||
if ((error = xfs_alloc_lookup_eq(cnt_cur, nfbno2, nflen2, &i)))
|
||||
return error;
|
||||
XFS_WANT_CORRUPTED_RETURN(i == 0);
|
||||
if ((error = xfs_alloc_insert(cnt_cur, &i)))
|
||||
if ((error = xfs_btree_insert(cnt_cur, &i)))
|
||||
return error;
|
||||
XFS_WANT_CORRUPTED_RETURN(i == 1);
|
||||
}
|
||||
|
@ -444,7 +444,7 @@ xfs_alloc_fixup_trees(
|
|||
if ((error = xfs_alloc_lookup_eq(bno_cur, nfbno2, nflen2, &i)))
|
||||
return error;
|
||||
XFS_WANT_CORRUPTED_RETURN(i == 0);
|
||||
if ((error = xfs_alloc_insert(bno_cur, &i)))
|
||||
if ((error = xfs_btree_insert(bno_cur, &i)))
|
||||
return error;
|
||||
XFS_WANT_CORRUPTED_RETURN(i == 1);
|
||||
}
|
||||
|
@ -1756,7 +1756,7 @@ xfs_free_ag_extent(
|
|||
else {
|
||||
nbno = bno;
|
||||
nlen = len;
|
||||
if ((error = xfs_alloc_insert(bno_cur, &i)))
|
||||
if ((error = xfs_btree_insert(bno_cur, &i)))
|
||||
goto error0;
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
|
||||
}
|
||||
|
@ -1768,7 +1768,7 @@ xfs_free_ag_extent(
|
|||
if ((error = xfs_alloc_lookup_eq(cnt_cur, nbno, nlen, &i)))
|
||||
goto error0;
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 0, error0);
|
||||
if ((error = xfs_alloc_insert(cnt_cur, &i)))
|
||||
if ((error = xfs_btree_insert(cnt_cur, &i)))
|
||||
goto error0;
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
|
||||
xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR);
|
||||
|
|
|
@ -582,256 +582,6 @@ error0:
|
|||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert one record/level. Return information to the caller
|
||||
* allowing the next level up to proceed if necessary.
|
||||
*/
|
||||
STATIC int /* error */
|
||||
xfs_alloc_insrec(
|
||||
xfs_btree_cur_t *cur, /* btree cursor */
|
||||
int level, /* level to insert record at */
|
||||
xfs_agblock_t *bnop, /* i/o: block number inserted */
|
||||
xfs_alloc_rec_t *recp, /* i/o: record data inserted */
|
||||
xfs_btree_cur_t **curp, /* output: new cursor replacing cur */
|
||||
int *stat) /* output: success/failure */
|
||||
{
|
||||
xfs_agf_t *agf; /* allocation group freelist header */
|
||||
xfs_alloc_block_t *block; /* btree block record/key lives in */
|
||||
xfs_buf_t *bp; /* buffer for block */
|
||||
int error; /* error return value */
|
||||
int i; /* loop index */
|
||||
xfs_alloc_key_t key; /* key value being inserted */
|
||||
xfs_alloc_key_t *kp; /* pointer to btree keys */
|
||||
xfs_agblock_t nbno; /* block number of allocated block */
|
||||
xfs_btree_cur_t *ncur; /* new cursor to be used at next lvl */
|
||||
xfs_alloc_key_t nkey; /* new key value, from split */
|
||||
xfs_alloc_rec_t nrec; /* new record value, for caller */
|
||||
int numrecs;
|
||||
int optr; /* old ptr value */
|
||||
xfs_alloc_ptr_t *pp; /* pointer to btree addresses */
|
||||
int ptr; /* index in btree block for this rec */
|
||||
xfs_alloc_rec_t *rp; /* pointer to btree records */
|
||||
|
||||
ASSERT(be32_to_cpu(recp->ar_blockcount) > 0);
|
||||
|
||||
/*
|
||||
* GCC doesn't understand the (arguably complex) control flow in
|
||||
* this function and complains about uninitialized structure fields
|
||||
* without this.
|
||||
*/
|
||||
memset(&nrec, 0, sizeof(nrec));
|
||||
|
||||
/*
|
||||
* If we made it to the root level, allocate a new root block
|
||||
* and we're done.
|
||||
*/
|
||||
if (level >= cur->bc_nlevels) {
|
||||
XFS_STATS_INC(xs_abt_insrec);
|
||||
if ((error = xfs_btree_new_root(cur, &i)))
|
||||
return error;
|
||||
*bnop = NULLAGBLOCK;
|
||||
*stat = i;
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* Make a key out of the record data to be inserted, and save it.
|
||||
*/
|
||||
key.ar_startblock = recp->ar_startblock;
|
||||
key.ar_blockcount = recp->ar_blockcount;
|
||||
optr = ptr = cur->bc_ptrs[level];
|
||||
/*
|
||||
* If we're off the left edge, return failure.
|
||||
*/
|
||||
if (ptr == 0) {
|
||||
*stat = 0;
|
||||
return 0;
|
||||
}
|
||||
XFS_STATS_INC(xs_abt_insrec);
|
||||
/*
|
||||
* Get pointers to the btree buffer and block.
|
||||
*/
|
||||
bp = cur->bc_bufs[level];
|
||||
block = XFS_BUF_TO_ALLOC_BLOCK(bp);
|
||||
numrecs = be16_to_cpu(block->bb_numrecs);
|
||||
#ifdef DEBUG
|
||||
if ((error = xfs_btree_check_sblock(cur, block, level, bp)))
|
||||
return error;
|
||||
/*
|
||||
* Check that the new entry is being inserted in the right place.
|
||||
*/
|
||||
if (ptr <= numrecs) {
|
||||
if (level == 0) {
|
||||
rp = XFS_ALLOC_REC_ADDR(block, ptr, cur);
|
||||
xfs_btree_check_rec(cur->bc_btnum, recp, rp);
|
||||
} else {
|
||||
kp = XFS_ALLOC_KEY_ADDR(block, ptr, cur);
|
||||
xfs_btree_check_key(cur->bc_btnum, &key, kp);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
nbno = NULLAGBLOCK;
|
||||
ncur = NULL;
|
||||
/*
|
||||
* If the block is full, we can't insert the new entry until we
|
||||
* make the block un-full.
|
||||
*/
|
||||
if (numrecs == XFS_ALLOC_BLOCK_MAXRECS(level, cur)) {
|
||||
/*
|
||||
* First, try shifting an entry to the right neighbor.
|
||||
*/
|
||||
if ((error = xfs_btree_rshift(cur, level, &i)))
|
||||
return error;
|
||||
if (i) {
|
||||
/* nothing */
|
||||
}
|
||||
/*
|
||||
* Next, try shifting an entry to the left neighbor.
|
||||
*/
|
||||
else {
|
||||
if ((error = xfs_btree_lshift(cur, level, &i)))
|
||||
return error;
|
||||
if (i)
|
||||
optr = ptr = cur->bc_ptrs[level];
|
||||
else {
|
||||
union xfs_btree_ptr bno = { .s = cpu_to_be32(nbno) };
|
||||
/*
|
||||
* Next, try splitting the current block in
|
||||
* half. If this works we have to re-set our
|
||||
* variables because we could be in a
|
||||
* different block now.
|
||||
*/
|
||||
if ((error = xfs_btree_split(cur, level, &bno,
|
||||
(union xfs_btree_key *)&nkey,
|
||||
&ncur, &i)))
|
||||
return error;
|
||||
nbno = be32_to_cpu(bno.s);
|
||||
if (i) {
|
||||
bp = cur->bc_bufs[level];
|
||||
block = XFS_BUF_TO_ALLOC_BLOCK(bp);
|
||||
#ifdef DEBUG
|
||||
if ((error =
|
||||
xfs_btree_check_sblock(cur,
|
||||
block, level, bp)))
|
||||
return error;
|
||||
#endif
|
||||
ptr = cur->bc_ptrs[level];
|
||||
nrec.ar_startblock = nkey.ar_startblock;
|
||||
nrec.ar_blockcount = nkey.ar_blockcount;
|
||||
}
|
||||
/*
|
||||
* Otherwise the insert fails.
|
||||
*/
|
||||
else {
|
||||
*stat = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* At this point we know there's room for our new entry in the block
|
||||
* we're pointing at.
|
||||
*/
|
||||
numrecs = be16_to_cpu(block->bb_numrecs);
|
||||
if (level > 0) {
|
||||
/*
|
||||
* It's a non-leaf entry. Make a hole for the new data
|
||||
* in the key and ptr regions of the block.
|
||||
*/
|
||||
kp = XFS_ALLOC_KEY_ADDR(block, 1, cur);
|
||||
pp = XFS_ALLOC_PTR_ADDR(block, 1, cur);
|
||||
#ifdef DEBUG
|
||||
for (i = numrecs; i >= ptr; i--) {
|
||||
if ((error = xfs_btree_check_sptr(cur, be32_to_cpu(pp[i - 1]), level)))
|
||||
return error;
|
||||
}
|
||||
#endif
|
||||
memmove(&kp[ptr], &kp[ptr - 1],
|
||||
(numrecs - ptr + 1) * sizeof(*kp));
|
||||
memmove(&pp[ptr], &pp[ptr - 1],
|
||||
(numrecs - ptr + 1) * sizeof(*pp));
|
||||
#ifdef DEBUG
|
||||
if ((error = xfs_btree_check_sptr(cur, *bnop, level)))
|
||||
return error;
|
||||
#endif
|
||||
/*
|
||||
* Now stuff the new data in, bump numrecs and log the new data.
|
||||
*/
|
||||
kp[ptr - 1] = key;
|
||||
pp[ptr - 1] = cpu_to_be32(*bnop);
|
||||
numrecs++;
|
||||
block->bb_numrecs = cpu_to_be16(numrecs);
|
||||
xfs_alloc_log_keys(cur, bp, ptr, numrecs);
|
||||
xfs_alloc_log_ptrs(cur, bp, ptr, numrecs);
|
||||
#ifdef DEBUG
|
||||
if (ptr < numrecs)
|
||||
xfs_btree_check_key(cur->bc_btnum, kp + ptr - 1,
|
||||
kp + ptr);
|
||||
#endif
|
||||
} else {
|
||||
/*
|
||||
* It's a leaf entry. Make a hole for the new record.
|
||||
*/
|
||||
rp = XFS_ALLOC_REC_ADDR(block, 1, cur);
|
||||
memmove(&rp[ptr], &rp[ptr - 1],
|
||||
(numrecs - ptr + 1) * sizeof(*rp));
|
||||
/*
|
||||
* Now stuff the new record in, bump numrecs
|
||||
* and log the new data.
|
||||
*/
|
||||
rp[ptr - 1] = *recp;
|
||||
numrecs++;
|
||||
block->bb_numrecs = cpu_to_be16(numrecs);
|
||||
xfs_alloc_log_recs(cur, bp, ptr, numrecs);
|
||||
#ifdef DEBUG
|
||||
if (ptr < numrecs)
|
||||
xfs_btree_check_rec(cur->bc_btnum, rp + ptr - 1,
|
||||
rp + ptr);
|
||||
#endif
|
||||
}
|
||||
/*
|
||||
* Log the new number of records in the btree header.
|
||||
*/
|
||||
xfs_alloc_log_block(cur->bc_tp, bp, XFS_BB_NUMRECS);
|
||||
/*
|
||||
* If we inserted at the start of a block, update the parents' keys.
|
||||
*/
|
||||
if (optr == 1 && (error = xfs_btree_updkey(cur, (union xfs_btree_key *)&key, level + 1)))
|
||||
return error;
|
||||
/*
|
||||
* Look to see if the longest extent in the allocation group
|
||||
* needs to be updated.
|
||||
*/
|
||||
|
||||
agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp);
|
||||
if (level == 0 &&
|
||||
cur->bc_btnum == XFS_BTNUM_CNT &&
|
||||
be32_to_cpu(block->bb_rightsib) == NULLAGBLOCK &&
|
||||
be32_to_cpu(recp->ar_blockcount) > be32_to_cpu(agf->agf_longest)) {
|
||||
/*
|
||||
* If this is a leaf in the by-size btree and there
|
||||
* is no right sibling block and this block is bigger
|
||||
* than the previous longest block, update it.
|
||||
*/
|
||||
agf->agf_longest = recp->ar_blockcount;
|
||||
cur->bc_mp->m_perag[be32_to_cpu(agf->agf_seqno)].pagf_longest
|
||||
= be32_to_cpu(recp->ar_blockcount);
|
||||
xfs_alloc_log_agf(cur->bc_tp, cur->bc_private.a.agbp,
|
||||
XFS_AGF_LONGEST);
|
||||
}
|
||||
/*
|
||||
* Return the new block number, if any.
|
||||
* If there is one, give back a record value and a cursor too.
|
||||
*/
|
||||
*bnop = nbno;
|
||||
if (nbno != NULLAGBLOCK) {
|
||||
*recp = nrec;
|
||||
*curp = ncur;
|
||||
}
|
||||
*stat = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Log header fields from a btree block.
|
||||
*/
|
||||
|
@ -1019,65 +769,6 @@ xfs_alloc_get_rec(
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert the current record at the point referenced by cur.
|
||||
* The cursor may be inconsistent on return if splits have been done.
|
||||
*/
|
||||
int /* error */
|
||||
xfs_alloc_insert(
|
||||
xfs_btree_cur_t *cur, /* btree cursor */
|
||||
int *stat) /* success/failure */
|
||||
{
|
||||
int error; /* error return value */
|
||||
int i; /* result value, 0 for failure */
|
||||
int level; /* current level number in btree */
|
||||
xfs_agblock_t nbno; /* new block number (split result) */
|
||||
xfs_btree_cur_t *ncur; /* new cursor (split result) */
|
||||
xfs_alloc_rec_t nrec; /* record being inserted this level */
|
||||
xfs_btree_cur_t *pcur; /* previous level's cursor */
|
||||
|
||||
level = 0;
|
||||
nbno = NULLAGBLOCK;
|
||||
nrec.ar_startblock = cpu_to_be32(cur->bc_rec.a.ar_startblock);
|
||||
nrec.ar_blockcount = cpu_to_be32(cur->bc_rec.a.ar_blockcount);
|
||||
ncur = NULL;
|
||||
pcur = cur;
|
||||
/*
|
||||
* Loop going up the tree, starting at the leaf level.
|
||||
* Stop when we don't get a split block, that must mean that
|
||||
* the insert is finished with this level.
|
||||
*/
|
||||
do {
|
||||
/*
|
||||
* Insert nrec/nbno into this level of the tree.
|
||||
* Note if we fail, nbno will be null.
|
||||
*/
|
||||
if ((error = xfs_alloc_insrec(pcur, level++, &nbno, &nrec, &ncur,
|
||||
&i))) {
|
||||
if (pcur != cur)
|
||||
xfs_btree_del_cursor(pcur, XFS_BTREE_ERROR);
|
||||
return error;
|
||||
}
|
||||
/*
|
||||
* See if the cursor we just used is trash.
|
||||
* Can't trash the caller's cursor, but otherwise we should
|
||||
* if ncur is a new cursor or we're about to be done.
|
||||
*/
|
||||
if (pcur != cur && (ncur || nbno == NULLAGBLOCK)) {
|
||||
cur->bc_nlevels = pcur->bc_nlevels;
|
||||
xfs_btree_del_cursor(pcur, XFS_BTREE_NOERROR);
|
||||
}
|
||||
/*
|
||||
* If we got a new cursor, switch to it.
|
||||
*/
|
||||
if (ncur) {
|
||||
pcur = ncur;
|
||||
ncur = NULL;
|
||||
}
|
||||
} while (nbno != NULLAGBLOCK);
|
||||
*stat = i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
STATIC struct xfs_btree_cur *
|
||||
xfs_allocbt_dup_cursor(
|
||||
|
@ -1170,6 +861,12 @@ xfs_allocbt_update_lastrec(
|
|||
return;
|
||||
len = rec->alloc.ar_blockcount;
|
||||
break;
|
||||
case LASTREC_INSREC:
|
||||
if (be32_to_cpu(rec->alloc.ar_blockcount) <=
|
||||
be32_to_cpu(agf->agf_longest))
|
||||
return;
|
||||
len = rec->alloc.ar_blockcount;
|
||||
break;
|
||||
default:
|
||||
ASSERT(0);
|
||||
return;
|
||||
|
@ -1199,6 +896,28 @@ xfs_allocbt_init_key_from_rec(
|
|||
key->alloc.ar_blockcount = rec->alloc.ar_blockcount;
|
||||
}
|
||||
|
||||
STATIC void
|
||||
xfs_allocbt_init_rec_from_key(
|
||||
union xfs_btree_key *key,
|
||||
union xfs_btree_rec *rec)
|
||||
{
|
||||
ASSERT(key->alloc.ar_startblock != 0);
|
||||
|
||||
rec->alloc.ar_startblock = key->alloc.ar_startblock;
|
||||
rec->alloc.ar_blockcount = key->alloc.ar_blockcount;
|
||||
}
|
||||
|
||||
STATIC void
|
||||
xfs_allocbt_init_rec_from_cur(
|
||||
struct xfs_btree_cur *cur,
|
||||
union xfs_btree_rec *rec)
|
||||
{
|
||||
ASSERT(cur->bc_rec.a.ar_startblock != 0);
|
||||
|
||||
rec->alloc.ar_startblock = cpu_to_be32(cur->bc_rec.a.ar_startblock);
|
||||
rec->alloc.ar_blockcount = cpu_to_be32(cur->bc_rec.a.ar_blockcount);
|
||||
}
|
||||
|
||||
STATIC void
|
||||
xfs_allocbt_init_ptr_from_cur(
|
||||
struct xfs_btree_cur *cur,
|
||||
|
@ -1309,6 +1028,8 @@ static const struct xfs_btree_ops xfs_allocbt_ops = {
|
|||
.update_lastrec = xfs_allocbt_update_lastrec,
|
||||
.get_maxrecs = xfs_allocbt_get_maxrecs,
|
||||
.init_key_from_rec = xfs_allocbt_init_key_from_rec,
|
||||
.init_rec_from_key = xfs_allocbt_init_rec_from_key,
|
||||
.init_rec_from_cur = xfs_allocbt_init_rec_from_cur,
|
||||
.init_ptr_from_cur = xfs_allocbt_init_ptr_from_cur,
|
||||
.key_diff = xfs_allocbt_key_diff,
|
||||
|
||||
|
|
|
@ -107,12 +107,6 @@ extern int xfs_alloc_delete(struct xfs_btree_cur *cur, int *stat);
|
|||
extern int xfs_alloc_get_rec(struct xfs_btree_cur *cur, xfs_agblock_t *bno,
|
||||
xfs_extlen_t *len, int *stat);
|
||||
|
||||
/*
|
||||
* Insert the current record at the point referenced by cur.
|
||||
* The cursor may be inconsistent on return if splits have been done.
|
||||
*/
|
||||
extern int xfs_alloc_insert(struct xfs_btree_cur *cur, int *stat);
|
||||
|
||||
|
||||
extern struct xfs_btree_cur *xfs_allocbt_init_cursor(struct xfs_mount *,
|
||||
struct xfs_trans *, struct xfs_buf *,
|
||||
|
|
|
@ -977,7 +977,7 @@ xfs_bmap_add_extent_delay_real(
|
|||
goto done;
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 0, done);
|
||||
cur->bc_rec.b.br_state = XFS_EXT_NORM;
|
||||
if ((error = xfs_bmbt_insert(cur, &i)))
|
||||
if ((error = xfs_btree_insert(cur, &i)))
|
||||
goto done;
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
}
|
||||
|
@ -1053,7 +1053,7 @@ xfs_bmap_add_extent_delay_real(
|
|||
goto done;
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 0, done);
|
||||
cur->bc_rec.b.br_state = XFS_EXT_NORM;
|
||||
if ((error = xfs_bmbt_insert(cur, &i)))
|
||||
if ((error = xfs_btree_insert(cur, &i)))
|
||||
goto done;
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
}
|
||||
|
@ -1143,7 +1143,7 @@ xfs_bmap_add_extent_delay_real(
|
|||
goto done;
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 0, done);
|
||||
cur->bc_rec.b.br_state = XFS_EXT_NORM;
|
||||
if ((error = xfs_bmbt_insert(cur, &i)))
|
||||
if ((error = xfs_btree_insert(cur, &i)))
|
||||
goto done;
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
}
|
||||
|
@ -1198,7 +1198,7 @@ xfs_bmap_add_extent_delay_real(
|
|||
goto done;
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 0, done);
|
||||
cur->bc_rec.b.br_state = XFS_EXT_NORM;
|
||||
if ((error = xfs_bmbt_insert(cur, &i)))
|
||||
if ((error = xfs_btree_insert(cur, &i)))
|
||||
goto done;
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
}
|
||||
|
@ -1651,7 +1651,7 @@ xfs_bmap_add_extent_unwritten_real(
|
|||
oldext)))
|
||||
goto done;
|
||||
cur->bc_rec.b = *new;
|
||||
if ((error = xfs_bmbt_insert(cur, &i)))
|
||||
if ((error = xfs_btree_insert(cur, &i)))
|
||||
goto done;
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
}
|
||||
|
@ -1741,7 +1741,7 @@ xfs_bmap_add_extent_unwritten_real(
|
|||
goto done;
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 0, done);
|
||||
cur->bc_rec.b.br_state = XFS_EXT_NORM;
|
||||
if ((error = xfs_bmbt_insert(cur, &i)))
|
||||
if ((error = xfs_btree_insert(cur, &i)))
|
||||
goto done;
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
}
|
||||
|
@ -1789,7 +1789,7 @@ xfs_bmap_add_extent_unwritten_real(
|
|||
cur->bc_rec.b = PREV;
|
||||
cur->bc_rec.b.br_blockcount =
|
||||
new->br_startoff - PREV.br_startoff;
|
||||
if ((error = xfs_bmbt_insert(cur, &i)))
|
||||
if ((error = xfs_btree_insert(cur, &i)))
|
||||
goto done;
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
/*
|
||||
|
@ -1804,7 +1804,7 @@ xfs_bmap_add_extent_unwritten_real(
|
|||
XFS_WANT_CORRUPTED_GOTO(i == 0, done);
|
||||
/* new middle extent - newext */
|
||||
cur->bc_rec.b.br_state = new->br_state;
|
||||
if ((error = xfs_bmbt_insert(cur, &i)))
|
||||
if ((error = xfs_btree_insert(cur, &i)))
|
||||
goto done;
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
}
|
||||
|
@ -2264,7 +2264,7 @@ xfs_bmap_add_extent_hole_real(
|
|||
goto done;
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 0, done);
|
||||
cur->bc_rec.b.br_state = new->br_state;
|
||||
if ((error = xfs_bmbt_insert(cur, &i)))
|
||||
if ((error = xfs_btree_insert(cur, &i)))
|
||||
goto done;
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, done);
|
||||
}
|
||||
|
@ -3303,7 +3303,7 @@ xfs_bmap_del_extent(
|
|||
if ((error = xfs_btree_increment(cur, 0, &i)))
|
||||
goto done;
|
||||
cur->bc_rec.b = new;
|
||||
error = xfs_bmbt_insert(cur, &i);
|
||||
error = xfs_btree_insert(cur, &i);
|
||||
if (error && error != ENOSPC)
|
||||
goto done;
|
||||
/*
|
||||
|
|
|
@ -456,198 +456,6 @@ error0:
|
|||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert one record/level. Return information to the caller
|
||||
* allowing the next level up to proceed if necessary.
|
||||
*/
|
||||
STATIC int /* error */
|
||||
xfs_bmbt_insrec(
|
||||
xfs_btree_cur_t *cur,
|
||||
int level,
|
||||
xfs_fsblock_t *bnop,
|
||||
xfs_bmbt_rec_t *recp,
|
||||
xfs_btree_cur_t **curp,
|
||||
int *stat) /* no-go/done/continue */
|
||||
{
|
||||
xfs_bmbt_block_t *block; /* bmap btree block */
|
||||
xfs_buf_t *bp; /* buffer for block */
|
||||
int error; /* error return value */
|
||||
int i; /* loop index */
|
||||
xfs_bmbt_key_t key; /* bmap btree key */
|
||||
xfs_bmbt_key_t *kp=NULL; /* pointer to bmap btree key */
|
||||
int logflags; /* inode logging flags */
|
||||
xfs_fsblock_t nbno; /* new block number */
|
||||
struct xfs_btree_cur *ncur; /* new btree cursor */
|
||||
__uint64_t startoff; /* new btree key value */
|
||||
xfs_bmbt_rec_t nrec; /* new record count */
|
||||
int optr; /* old key/record index */
|
||||
xfs_bmbt_ptr_t *pp; /* pointer to bmap block addr */
|
||||
int ptr; /* key/record index */
|
||||
xfs_bmbt_rec_t *rp=NULL; /* pointer to bmap btree rec */
|
||||
int numrecs;
|
||||
|
||||
ASSERT(level < cur->bc_nlevels);
|
||||
XFS_BMBT_TRACE_CURSOR(cur, ENTRY);
|
||||
XFS_BMBT_TRACE_ARGIFR(cur, level, *bnop, recp);
|
||||
ncur = NULL;
|
||||
key.br_startoff = cpu_to_be64(xfs_bmbt_disk_get_startoff(recp));
|
||||
optr = ptr = cur->bc_ptrs[level];
|
||||
if (ptr == 0) {
|
||||
XFS_BMBT_TRACE_CURSOR(cur, EXIT);
|
||||
*stat = 0;
|
||||
return 0;
|
||||
}
|
||||
XFS_STATS_INC(xs_bmbt_insrec);
|
||||
block = xfs_bmbt_get_block(cur, level, &bp);
|
||||
numrecs = be16_to_cpu(block->bb_numrecs);
|
||||
#ifdef DEBUG
|
||||
if ((error = xfs_btree_check_lblock(cur, block, level, bp))) {
|
||||
XFS_BMBT_TRACE_CURSOR(cur, ERROR);
|
||||
return error;
|
||||
}
|
||||
if (ptr <= numrecs) {
|
||||
if (level == 0) {
|
||||
rp = XFS_BMAP_REC_IADDR(block, ptr, cur);
|
||||
xfs_btree_check_rec(XFS_BTNUM_BMAP, recp, rp);
|
||||
} else {
|
||||
kp = XFS_BMAP_KEY_IADDR(block, ptr, cur);
|
||||
xfs_btree_check_key(XFS_BTNUM_BMAP, &key, kp);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
nbno = NULLFSBLOCK;
|
||||
if (numrecs == XFS_BMAP_BLOCK_IMAXRECS(level, cur)) {
|
||||
if (numrecs < XFS_BMAP_BLOCK_DMAXRECS(level, cur)) {
|
||||
/*
|
||||
* A root block, that can be made bigger.
|
||||
*/
|
||||
xfs_iroot_realloc(cur->bc_private.b.ip, 1,
|
||||
cur->bc_private.b.whichfork);
|
||||
block = xfs_bmbt_get_block(cur, level, &bp);
|
||||
} else if (level == cur->bc_nlevels - 1) {
|
||||
if ((error = xfs_btree_new_iroot(cur, &logflags, stat)) ||
|
||||
*stat == 0) {
|
||||
XFS_BMBT_TRACE_CURSOR(cur, ERROR);
|
||||
return error;
|
||||
}
|
||||
xfs_trans_log_inode(cur->bc_tp, cur->bc_private.b.ip,
|
||||
logflags);
|
||||
block = xfs_bmbt_get_block(cur, level, &bp);
|
||||
} else {
|
||||
if ((error = xfs_btree_rshift(cur, level, &i))) {
|
||||
XFS_BMBT_TRACE_CURSOR(cur, ERROR);
|
||||
return error;
|
||||
}
|
||||
if (i) {
|
||||
/* nothing */
|
||||
} else {
|
||||
if ((error = xfs_btree_lshift(cur, level, &i))) {
|
||||
XFS_BMBT_TRACE_CURSOR(cur, ERROR);
|
||||
return error;
|
||||
}
|
||||
if (i) {
|
||||
optr = ptr = cur->bc_ptrs[level];
|
||||
} else {
|
||||
union xfs_btree_ptr bno = { .l = cpu_to_be64(nbno) };
|
||||
union xfs_btree_key skey;
|
||||
if ((error = xfs_btree_split(cur, level,
|
||||
&bno, &skey, &ncur,
|
||||
&i))) {
|
||||
XFS_BMBT_TRACE_CURSOR(cur,
|
||||
ERROR);
|
||||
return error;
|
||||
}
|
||||
nbno = be64_to_cpu(bno.l);
|
||||
startoff = be64_to_cpu(skey.bmbt.br_startoff);
|
||||
if (i) {
|
||||
block = xfs_bmbt_get_block(
|
||||
cur, level, &bp);
|
||||
#ifdef DEBUG
|
||||
if ((error =
|
||||
xfs_btree_check_lblock(cur,
|
||||
block, level, bp))) {
|
||||
XFS_BMBT_TRACE_CURSOR(
|
||||
cur, ERROR);
|
||||
return error;
|
||||
}
|
||||
#endif
|
||||
ptr = cur->bc_ptrs[level];
|
||||
xfs_bmbt_disk_set_allf(&nrec,
|
||||
startoff, 0, 0,
|
||||
XFS_EXT_NORM);
|
||||
} else {
|
||||
XFS_BMBT_TRACE_CURSOR(cur,
|
||||
EXIT);
|
||||
*stat = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
numrecs = be16_to_cpu(block->bb_numrecs);
|
||||
if (level > 0) {
|
||||
kp = XFS_BMAP_KEY_IADDR(block, 1, cur);
|
||||
pp = XFS_BMAP_PTR_IADDR(block, 1, cur);
|
||||
#ifdef DEBUG
|
||||
for (i = numrecs; i >= ptr; i--) {
|
||||
if ((error = xfs_btree_check_lptr_disk(cur, pp[i - 1],
|
||||
level))) {
|
||||
XFS_BMBT_TRACE_CURSOR(cur, ERROR);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
memmove(&kp[ptr], &kp[ptr - 1],
|
||||
(numrecs - ptr + 1) * sizeof(*kp));
|
||||
memmove(&pp[ptr], &pp[ptr - 1],
|
||||
(numrecs - ptr + 1) * sizeof(*pp));
|
||||
#ifdef DEBUG
|
||||
if ((error = xfs_btree_check_lptr(cur, *bnop, level))) {
|
||||
XFS_BMBT_TRACE_CURSOR(cur, ERROR);
|
||||
return error;
|
||||
}
|
||||
#endif
|
||||
kp[ptr - 1] = key;
|
||||
pp[ptr - 1] = cpu_to_be64(*bnop);
|
||||
numrecs++;
|
||||
block->bb_numrecs = cpu_to_be16(numrecs);
|
||||
xfs_bmbt_log_keys(cur, bp, ptr, numrecs);
|
||||
xfs_bmbt_log_ptrs(cur, bp, ptr, numrecs);
|
||||
} else {
|
||||
rp = XFS_BMAP_REC_IADDR(block, 1, cur);
|
||||
memmove(&rp[ptr], &rp[ptr - 1],
|
||||
(numrecs - ptr + 1) * sizeof(*rp));
|
||||
rp[ptr - 1] = *recp;
|
||||
numrecs++;
|
||||
block->bb_numrecs = cpu_to_be16(numrecs);
|
||||
xfs_bmbt_log_recs(cur, bp, ptr, numrecs);
|
||||
}
|
||||
xfs_bmbt_log_block(cur, bp, XFS_BB_NUMRECS);
|
||||
#ifdef DEBUG
|
||||
if (ptr < numrecs) {
|
||||
if (level == 0)
|
||||
xfs_btree_check_rec(XFS_BTNUM_BMAP, rp + ptr - 1,
|
||||
rp + ptr);
|
||||
else
|
||||
xfs_btree_check_key(XFS_BTNUM_BMAP, kp + ptr - 1,
|
||||
kp + ptr);
|
||||
}
|
||||
#endif
|
||||
if (optr == 1 && (error = xfs_btree_updkey(cur, (union xfs_btree_key *)&key, level + 1))) {
|
||||
XFS_BMBT_TRACE_CURSOR(cur, ERROR);
|
||||
return error;
|
||||
}
|
||||
*bnop = nbno;
|
||||
if (nbno != NULLFSBLOCK) {
|
||||
*recp = nrec;
|
||||
*curp = ncur;
|
||||
}
|
||||
XFS_BMBT_TRACE_CURSOR(cur, EXIT);
|
||||
*stat = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
STATIC int
|
||||
xfs_bmbt_killroot(
|
||||
xfs_btree_cur_t *cur)
|
||||
|
@ -1059,67 +867,6 @@ xfs_bmbt_disk_get_startoff(
|
|||
XFS_MASK64LO(64 - BMBT_EXNTFLAG_BITLEN)) >> 9;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert the current record at the point referenced by cur.
|
||||
*
|
||||
* A multi-level split of the tree on insert will invalidate the original
|
||||
* cursor. All callers of this function should assume that the cursor is
|
||||
* no longer valid and revalidate it.
|
||||
*/
|
||||
int /* error */
|
||||
xfs_bmbt_insert(
|
||||
xfs_btree_cur_t *cur,
|
||||
int *stat) /* success/failure */
|
||||
{
|
||||
int error; /* error return value */
|
||||
int i;
|
||||
int level;
|
||||
xfs_fsblock_t nbno;
|
||||
xfs_btree_cur_t *ncur;
|
||||
xfs_bmbt_rec_t nrec;
|
||||
xfs_btree_cur_t *pcur;
|
||||
|
||||
XFS_BMBT_TRACE_CURSOR(cur, ENTRY);
|
||||
level = 0;
|
||||
nbno = NULLFSBLOCK;
|
||||
xfs_bmbt_disk_set_all(&nrec, &cur->bc_rec.b);
|
||||
ncur = NULL;
|
||||
pcur = cur;
|
||||
do {
|
||||
if ((error = xfs_bmbt_insrec(pcur, level++, &nbno, &nrec, &ncur,
|
||||
&i))) {
|
||||
if (pcur != cur)
|
||||
xfs_btree_del_cursor(pcur, XFS_BTREE_ERROR);
|
||||
XFS_BMBT_TRACE_CURSOR(cur, ERROR);
|
||||
return error;
|
||||
}
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
|
||||
if (pcur != cur && (ncur || nbno == NULLFSBLOCK)) {
|
||||
cur->bc_nlevels = pcur->bc_nlevels;
|
||||
cur->bc_private.b.allocated +=
|
||||
pcur->bc_private.b.allocated;
|
||||
pcur->bc_private.b.allocated = 0;
|
||||
ASSERT((cur->bc_private.b.firstblock != NULLFSBLOCK) ||
|
||||
XFS_IS_REALTIME_INODE(cur->bc_private.b.ip));
|
||||
cur->bc_private.b.firstblock =
|
||||
pcur->bc_private.b.firstblock;
|
||||
ASSERT(cur->bc_private.b.flist ==
|
||||
pcur->bc_private.b.flist);
|
||||
xfs_btree_del_cursor(pcur, XFS_BTREE_NOERROR);
|
||||
}
|
||||
if (ncur) {
|
||||
pcur = ncur;
|
||||
ncur = NULL;
|
||||
}
|
||||
} while (nbno != NULLFSBLOCK);
|
||||
XFS_BMBT_TRACE_CURSOR(cur, EXIT);
|
||||
*stat = i;
|
||||
return 0;
|
||||
error0:
|
||||
XFS_BMBT_TRACE_CURSOR(cur, ERROR);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Log fields from the btree block header.
|
||||
*/
|
||||
|
@ -1450,6 +1197,21 @@ xfs_bmbt_dup_cursor(
|
|||
return new;
|
||||
}
|
||||
|
||||
STATIC void
|
||||
xfs_bmbt_update_cursor(
|
||||
struct xfs_btree_cur *src,
|
||||
struct xfs_btree_cur *dst)
|
||||
{
|
||||
ASSERT((dst->bc_private.b.firstblock != NULLFSBLOCK) ||
|
||||
(dst->bc_private.b.ip->i_d.di_flags & XFS_DIFLAG_REALTIME));
|
||||
ASSERT(dst->bc_private.b.flist == src->bc_private.b.flist);
|
||||
|
||||
dst->bc_private.b.allocated += src->bc_private.b.allocated;
|
||||
dst->bc_private.b.firstblock = src->bc_private.b.firstblock;
|
||||
|
||||
src->bc_private.b.allocated = 0;
|
||||
}
|
||||
|
||||
STATIC int
|
||||
xfs_bmbt_alloc_block(
|
||||
struct xfs_btree_cur *cur,
|
||||
|
@ -1544,6 +1306,23 @@ xfs_bmbt_get_maxrecs(
|
|||
return XFS_BMAP_BLOCK_IMAXRECS(level, cur);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the maximum records we could store in the on-disk format.
|
||||
*
|
||||
* For non-root nodes this is equivalent to xfs_bmbt_get_maxrecs, but
|
||||
* for the root node this checks the available space in the dinode fork
|
||||
* so that we can resize the in-memory buffer to match it. After a
|
||||
* resize to the maximum size this function returns the same value
|
||||
* as xfs_bmbt_get_maxrecs for the root node, too.
|
||||
*/
|
||||
STATIC int
|
||||
xfs_bmbt_get_dmaxrecs(
|
||||
struct xfs_btree_cur *cur,
|
||||
int level)
|
||||
{
|
||||
return XFS_BMAP_BLOCK_DMAXRECS(level, cur);
|
||||
}
|
||||
|
||||
STATIC void
|
||||
xfs_bmbt_init_key_from_rec(
|
||||
union xfs_btree_key *key,
|
||||
|
@ -1553,6 +1332,25 @@ xfs_bmbt_init_key_from_rec(
|
|||
cpu_to_be64(xfs_bmbt_disk_get_startoff(&rec->bmbt));
|
||||
}
|
||||
|
||||
STATIC void
|
||||
xfs_bmbt_init_rec_from_key(
|
||||
union xfs_btree_key *key,
|
||||
union xfs_btree_rec *rec)
|
||||
{
|
||||
ASSERT(key->bmbt.br_startoff != 0);
|
||||
|
||||
xfs_bmbt_disk_set_allf(&rec->bmbt, be64_to_cpu(key->bmbt.br_startoff),
|
||||
0, 0, XFS_EXT_NORM);
|
||||
}
|
||||
|
||||
STATIC void
|
||||
xfs_bmbt_init_rec_from_cur(
|
||||
struct xfs_btree_cur *cur,
|
||||
union xfs_btree_rec *rec)
|
||||
{
|
||||
xfs_bmbt_disk_set_all(&rec->bmbt, &cur->bc_rec.b);
|
||||
}
|
||||
|
||||
STATIC void
|
||||
xfs_bmbt_init_ptr_from_cur(
|
||||
struct xfs_btree_cur *cur,
|
||||
|
@ -1660,9 +1458,13 @@ static const struct xfs_btree_ops xfs_bmbt_ops = {
|
|||
.key_len = sizeof(xfs_bmbt_key_t),
|
||||
|
||||
.dup_cursor = xfs_bmbt_dup_cursor,
|
||||
.update_cursor = xfs_bmbt_update_cursor,
|
||||
.alloc_block = xfs_bmbt_alloc_block,
|
||||
.get_maxrecs = xfs_bmbt_get_maxrecs,
|
||||
.get_dmaxrecs = xfs_bmbt_get_dmaxrecs,
|
||||
.init_key_from_rec = xfs_bmbt_init_key_from_rec,
|
||||
.init_rec_from_key = xfs_bmbt_init_rec_from_key,
|
||||
.init_rec_from_cur = xfs_bmbt_init_rec_from_cur,
|
||||
.init_ptr_from_cur = xfs_bmbt_init_ptr_from_cur,
|
||||
.key_diff = xfs_bmbt_key_diff,
|
||||
|
||||
|
|
|
@ -250,7 +250,6 @@ extern void xfs_bmbt_disk_get_all(xfs_bmbt_rec_t *r, xfs_bmbt_irec_t *s);
|
|||
extern xfs_filblks_t xfs_bmbt_disk_get_blockcount(xfs_bmbt_rec_t *r);
|
||||
extern xfs_fileoff_t xfs_bmbt_disk_get_startoff(xfs_bmbt_rec_t *r);
|
||||
|
||||
extern int xfs_bmbt_insert(struct xfs_btree_cur *, int *);
|
||||
extern void xfs_bmbt_log_block(struct xfs_btree_cur *, struct xfs_buf *, int);
|
||||
extern void xfs_bmbt_log_recs(struct xfs_btree_cur *, struct xfs_buf *, int,
|
||||
int);
|
||||
|
|
|
@ -963,6 +963,17 @@ xfs_btree_ptr_is_null(
|
|||
return be32_to_cpu(ptr->s) == NULLAGBLOCK;
|
||||
}
|
||||
|
||||
STATIC void
|
||||
xfs_btree_set_ptr_null(
|
||||
struct xfs_btree_cur *cur,
|
||||
union xfs_btree_ptr *ptr)
|
||||
{
|
||||
if (cur->bc_flags & XFS_BTREE_LONG_PTRS)
|
||||
ptr->l = cpu_to_be64(NULLFSBLOCK);
|
||||
else
|
||||
ptr->s = cpu_to_be32(NULLAGBLOCK);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get/set/init sibling pointers
|
||||
*/
|
||||
|
@ -2697,3 +2708,354 @@ out0:
|
|||
*stat = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
STATIC int
|
||||
xfs_btree_make_block_unfull(
|
||||
struct xfs_btree_cur *cur, /* btree cursor */
|
||||
int level, /* btree level */
|
||||
int numrecs,/* # of recs in block */
|
||||
int *oindex,/* old tree index */
|
||||
int *index, /* new tree index */
|
||||
union xfs_btree_ptr *nptr, /* new btree ptr */
|
||||
struct xfs_btree_cur **ncur, /* new btree cursor */
|
||||
union xfs_btree_rec *nrec, /* new record */
|
||||
int *stat)
|
||||
{
|
||||
union xfs_btree_key key; /* new btree key value */
|
||||
int error = 0;
|
||||
|
||||
if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) &&
|
||||
level == cur->bc_nlevels - 1) {
|
||||
struct xfs_inode *ip = cur->bc_private.b.ip;
|
||||
|
||||
if (numrecs < cur->bc_ops->get_dmaxrecs(cur, level)) {
|
||||
/* A root block that can be made bigger. */
|
||||
|
||||
xfs_iroot_realloc(ip, 1, cur->bc_private.b.whichfork);
|
||||
} else {
|
||||
/* A root block that needs replacing */
|
||||
int logflags = 0;
|
||||
|
||||
error = xfs_btree_new_iroot(cur, &logflags, stat);
|
||||
if (error || *stat == 0)
|
||||
return error;
|
||||
|
||||
xfs_trans_log_inode(cur->bc_tp, ip, logflags);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* First, try shifting an entry to the right neighbor. */
|
||||
error = xfs_btree_rshift(cur, level, stat);
|
||||
if (error || *stat)
|
||||
return error;
|
||||
|
||||
/* Next, try shifting an entry to the left neighbor. */
|
||||
error = xfs_btree_lshift(cur, level, stat);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (*stat) {
|
||||
*oindex = *index = cur->bc_ptrs[level];
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Next, try splitting the current block in half.
|
||||
*
|
||||
* If this works we have to re-set our variables because we
|
||||
* could be in a different block now.
|
||||
*/
|
||||
error = xfs_btree_split(cur, level, nptr, &key, ncur, stat);
|
||||
if (error || *stat == 0)
|
||||
return error;
|
||||
|
||||
|
||||
*index = cur->bc_ptrs[level];
|
||||
cur->bc_ops->init_rec_from_key(&key, nrec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert one record/level. Return information to the caller
|
||||
* allowing the next level up to proceed if necessary.
|
||||
*/
|
||||
STATIC int
|
||||
xfs_btree_insrec(
|
||||
struct xfs_btree_cur *cur, /* btree cursor */
|
||||
int level, /* level to insert record at */
|
||||
union xfs_btree_ptr *ptrp, /* i/o: block number inserted */
|
||||
union xfs_btree_rec *recp, /* i/o: record data inserted */
|
||||
struct xfs_btree_cur **curp, /* output: new cursor replacing cur */
|
||||
int *stat) /* success/failure */
|
||||
{
|
||||
struct xfs_btree_block *block; /* btree block */
|
||||
struct xfs_buf *bp; /* buffer for block */
|
||||
union xfs_btree_key key; /* btree key */
|
||||
union xfs_btree_ptr nptr; /* new block ptr */
|
||||
struct xfs_btree_cur *ncur; /* new btree cursor */
|
||||
union xfs_btree_rec nrec; /* new record count */
|
||||
int optr; /* old key/record index */
|
||||
int ptr; /* key/record index */
|
||||
int numrecs;/* number of records */
|
||||
int error; /* error return value */
|
||||
#ifdef DEBUG
|
||||
int i;
|
||||
#endif
|
||||
|
||||
XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY);
|
||||
XFS_BTREE_TRACE_ARGIPR(cur, level, *ptrp, recp);
|
||||
|
||||
ncur = NULL;
|
||||
|
||||
/*
|
||||
* 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_flags & XFS_BTREE_ROOT_IN_INODE) &&
|
||||
(level >= cur->bc_nlevels)) {
|
||||
error = xfs_btree_new_root(cur, stat);
|
||||
xfs_btree_set_ptr_null(cur, ptrp);
|
||||
|
||||
XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
|
||||
return error;
|
||||
}
|
||||
|
||||
/* If we're off the left edge, return failure. */
|
||||
ptr = cur->bc_ptrs[level];
|
||||
if (ptr == 0) {
|
||||
XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
|
||||
*stat = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Make a key out of the record data to be inserted, and save it. */
|
||||
cur->bc_ops->init_key_from_rec(&key, recp);
|
||||
|
||||
optr = ptr;
|
||||
|
||||
XFS_BTREE_STATS_INC(cur, insrec);
|
||||
|
||||
/* Get pointers to the btree buffer and block. */
|
||||
block = xfs_btree_get_block(cur, level, &bp);
|
||||
numrecs = xfs_btree_get_numrecs(block);
|
||||
|
||||
#ifdef DEBUG
|
||||
error = xfs_btree_check_block(cur, block, level, bp);
|
||||
if (error)
|
||||
goto error0;
|
||||
|
||||
/* Check that the new entry is being inserted in the right place. */
|
||||
if (ptr <= numrecs) {
|
||||
if (level == 0) {
|
||||
xfs_btree_check_rec(cur->bc_btnum, recp,
|
||||
xfs_btree_rec_addr(cur, ptr, block));
|
||||
} else {
|
||||
xfs_btree_check_key(cur->bc_btnum, &key,
|
||||
xfs_btree_key_addr(cur, ptr, block));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If the block is full, we can't insert the new entry until we
|
||||
* make the block un-full.
|
||||
*/
|
||||
xfs_btree_set_ptr_null(cur, &nptr);
|
||||
if (numrecs == cur->bc_ops->get_maxrecs(cur, level)) {
|
||||
error = xfs_btree_make_block_unfull(cur, level, numrecs,
|
||||
&optr, &ptr, &nptr, &ncur, &nrec, stat);
|
||||
if (error || *stat == 0)
|
||||
goto error0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The current block may have changed if the block was
|
||||
* previously full and we have just made space in it.
|
||||
*/
|
||||
block = xfs_btree_get_block(cur, level, &bp);
|
||||
numrecs = xfs_btree_get_numrecs(block);
|
||||
|
||||
#ifdef DEBUG
|
||||
error = xfs_btree_check_block(cur, block, level, bp);
|
||||
if (error)
|
||||
return error;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* At this point we know there's room for our new entry in the block
|
||||
* we're pointing at.
|
||||
*/
|
||||
XFS_BTREE_STATS_ADD(cur, moves, numrecs - ptr + 1);
|
||||
|
||||
if (level > 0) {
|
||||
/* It's a nonleaf. make a hole in the keys and ptrs */
|
||||
union xfs_btree_key *kp;
|
||||
union xfs_btree_ptr *pp;
|
||||
|
||||
kp = xfs_btree_key_addr(cur, ptr, block);
|
||||
pp = xfs_btree_ptr_addr(cur, ptr, block);
|
||||
|
||||
#ifdef DEBUG
|
||||
for (i = numrecs - ptr; i >= 0; i--) {
|
||||
error = xfs_btree_check_ptr(cur, pp, i, level);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
#endif
|
||||
|
||||
xfs_btree_shift_keys(cur, kp, 1, numrecs - ptr + 1);
|
||||
xfs_btree_shift_ptrs(cur, pp, 1, numrecs - ptr + 1);
|
||||
|
||||
#ifdef DEBUG
|
||||
error = xfs_btree_check_ptr(cur, ptrp, 0, level);
|
||||
if (error)
|
||||
goto error0;
|
||||
#endif
|
||||
|
||||
/* Now put the new data in, bump numrecs and log it. */
|
||||
xfs_btree_copy_keys(cur, kp, &key, 1);
|
||||
xfs_btree_copy_ptrs(cur, pp, ptrp, 1);
|
||||
numrecs++;
|
||||
xfs_btree_set_numrecs(block, numrecs);
|
||||
xfs_btree_log_ptrs(cur, bp, ptr, numrecs);
|
||||
xfs_btree_log_keys(cur, bp, ptr, numrecs);
|
||||
#ifdef DEBUG
|
||||
if (ptr < numrecs) {
|
||||
xfs_btree_check_key(cur->bc_btnum, kp,
|
||||
xfs_btree_key_addr(cur, ptr + 1, block));
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
/* It's a leaf. make a hole in the records */
|
||||
union xfs_btree_rec *rp;
|
||||
|
||||
rp = xfs_btree_rec_addr(cur, ptr, block);
|
||||
|
||||
xfs_btree_shift_recs(cur, rp, 1, numrecs - ptr + 1);
|
||||
|
||||
/* Now put the new data in, bump numrecs and log it. */
|
||||
xfs_btree_copy_recs(cur, rp, recp, 1);
|
||||
xfs_btree_set_numrecs(block, ++numrecs);
|
||||
xfs_btree_log_recs(cur, bp, ptr, numrecs);
|
||||
#ifdef DEBUG
|
||||
if (ptr < numrecs) {
|
||||
xfs_btree_check_rec(cur->bc_btnum, rp,
|
||||
xfs_btree_rec_addr(cur, ptr + 1, block));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Log the new number of records in the btree header. */
|
||||
xfs_btree_log_block(cur, bp, XFS_BB_NUMRECS);
|
||||
|
||||
/* If we inserted at the start of a block, update the parents' keys. */
|
||||
if (optr == 1) {
|
||||
error = xfs_btree_updkey(cur, &key, level + 1);
|
||||
if (error)
|
||||
goto error0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are tracking the last record in the tree and
|
||||
* we are at the far right edge of the tree, update it.
|
||||
*/
|
||||
if (xfs_btree_is_lastrec(cur, block, level)) {
|
||||
cur->bc_ops->update_lastrec(cur, block, recp,
|
||||
ptr, LASTREC_INSREC);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the new block number, if any.
|
||||
* If there is one, give back a record value and a cursor too.
|
||||
*/
|
||||
*ptrp = nptr;
|
||||
if (!xfs_btree_ptr_is_null(cur, &nptr)) {
|
||||
*recp = nrec;
|
||||
*curp = ncur;
|
||||
}
|
||||
|
||||
XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
|
||||
*stat = 1;
|
||||
return 0;
|
||||
|
||||
error0:
|
||||
XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
|
||||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert the record at the point referenced by cur.
|
||||
*
|
||||
* A multi-level split of the tree on insert will invalidate the original
|
||||
* cursor. All callers of this function should assume that the cursor is
|
||||
* no longer valid and revalidate it.
|
||||
*/
|
||||
int
|
||||
xfs_btree_insert(
|
||||
struct xfs_btree_cur *cur,
|
||||
int *stat)
|
||||
{
|
||||
int error; /* error return value */
|
||||
int i; /* result value, 0 for failure */
|
||||
int level; /* current level number in btree */
|
||||
union xfs_btree_ptr nptr; /* new block number (split result) */
|
||||
struct xfs_btree_cur *ncur; /* new cursor (split result) */
|
||||
struct xfs_btree_cur *pcur; /* previous level's cursor */
|
||||
union xfs_btree_rec rec; /* record to insert */
|
||||
|
||||
level = 0;
|
||||
ncur = NULL;
|
||||
pcur = cur;
|
||||
|
||||
xfs_btree_set_ptr_null(cur, &nptr);
|
||||
cur->bc_ops->init_rec_from_cur(cur, &rec);
|
||||
|
||||
/*
|
||||
* Loop going up the tree, starting at the leaf level.
|
||||
* Stop when we don't get a split block, that must mean that
|
||||
* the insert is finished with this level.
|
||||
*/
|
||||
do {
|
||||
/*
|
||||
* Insert nrec/nptr into this level of the tree.
|
||||
* Note if we fail, nptr will be null.
|
||||
*/
|
||||
error = xfs_btree_insrec(pcur, level, &nptr, &rec, &ncur, &i);
|
||||
if (error) {
|
||||
if (pcur != cur)
|
||||
xfs_btree_del_cursor(pcur, XFS_BTREE_ERROR);
|
||||
goto error0;
|
||||
}
|
||||
|
||||
XFS_WANT_CORRUPTED_GOTO(i == 1, error0);
|
||||
level++;
|
||||
|
||||
/*
|
||||
* See if the cursor we just used is trash.
|
||||
* Can't trash the caller's cursor, but otherwise we should
|
||||
* if ncur is a new cursor or we're about to be done.
|
||||
*/
|
||||
if (pcur != cur &&
|
||||
(ncur || xfs_btree_ptr_is_null(cur, &nptr))) {
|
||||
/* Save the state from the cursor before we trash it */
|
||||
if (cur->bc_ops->update_cursor)
|
||||
cur->bc_ops->update_cursor(pcur, cur);
|
||||
cur->bc_nlevels = pcur->bc_nlevels;
|
||||
xfs_btree_del_cursor(pcur, XFS_BTREE_NOERROR);
|
||||
}
|
||||
/* If we got a new cursor, switch to it. */
|
||||
if (ncur) {
|
||||
pcur = ncur;
|
||||
ncur = NULL;
|
||||
}
|
||||
} while (!xfs_btree_ptr_is_null(cur, &nptr));
|
||||
|
||||
XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT);
|
||||
*stat = i;
|
||||
return 0;
|
||||
error0:
|
||||
XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR);
|
||||
return error;
|
||||
}
|
||||
|
|
|
@ -186,6 +186,8 @@ struct xfs_btree_ops {
|
|||
|
||||
/* cursor operations */
|
||||
struct xfs_btree_cur *(*dup_cursor)(struct xfs_btree_cur *);
|
||||
void (*update_cursor)(struct xfs_btree_cur *src,
|
||||
struct xfs_btree_cur *dst);
|
||||
|
||||
/* update btree root pointer */
|
||||
void (*set_root)(struct xfs_btree_cur *cur,
|
||||
|
@ -206,9 +208,16 @@ struct xfs_btree_ops {
|
|||
/* records in block/level */
|
||||
int (*get_maxrecs)(struct xfs_btree_cur *cur, int level);
|
||||
|
||||
/* records on disk. Matter for the root in inode case. */
|
||||
int (*get_dmaxrecs)(struct xfs_btree_cur *cur, int level);
|
||||
|
||||
/* init values of btree structures */
|
||||
void (*init_key_from_rec)(union xfs_btree_key *key,
|
||||
union xfs_btree_rec *rec);
|
||||
void (*init_rec_from_key)(union xfs_btree_key *key,
|
||||
union xfs_btree_rec *rec);
|
||||
void (*init_rec_from_cur)(struct xfs_btree_cur *cur,
|
||||
union xfs_btree_rec *rec);
|
||||
void (*init_ptr_from_cur)(struct xfs_btree_cur *cur,
|
||||
union xfs_btree_ptr *ptr);
|
||||
|
||||
|
@ -240,6 +249,7 @@ struct xfs_btree_ops {
|
|||
* Reasons for the update_lastrec method to be called.
|
||||
*/
|
||||
#define LASTREC_UPDATE 0
|
||||
#define LASTREC_INSREC 1
|
||||
|
||||
|
||||
/*
|
||||
|
@ -549,6 +559,7 @@ int xfs_btree_split(struct xfs_btree_cur *, int, union xfs_btree_ptr *,
|
|||
union xfs_btree_key *, struct xfs_btree_cur **, int *);
|
||||
int xfs_btree_new_root(struct xfs_btree_cur *, int *);
|
||||
int xfs_btree_new_iroot(struct xfs_btree_cur *, int *, int *);
|
||||
int xfs_btree_insert(struct xfs_btree_cur *, int *);
|
||||
|
||||
/*
|
||||
* Helpers.
|
||||
|
|
|
@ -418,7 +418,7 @@ xfs_ialloc_ag_alloc(
|
|||
return error;
|
||||
}
|
||||
ASSERT(i == 0);
|
||||
if ((error = xfs_inobt_insert(cur, &i))) {
|
||||
if ((error = xfs_btree_insert(cur, &i))) {
|
||||
xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
|
||||
return error;
|
||||
}
|
||||
|
|
|
@ -514,228 +514,6 @@ error0:
|
|||
return error;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert one record/level. Return information to the caller
|
||||
* allowing the next level up to proceed if necessary.
|
||||
*/
|
||||
STATIC int /* error */
|
||||
xfs_inobt_insrec(
|
||||
xfs_btree_cur_t *cur, /* btree cursor */
|
||||
int level, /* level to insert record at */
|
||||
xfs_agblock_t *bnop, /* i/o: block number inserted */
|
||||
xfs_inobt_rec_t *recp, /* i/o: record data inserted */
|
||||
xfs_btree_cur_t **curp, /* output: new cursor replacing cur */
|
||||
int *stat) /* success/failure */
|
||||
{
|
||||
xfs_inobt_block_t *block; /* btree block record/key lives in */
|
||||
xfs_buf_t *bp; /* buffer for block */
|
||||
int error; /* error return value */
|
||||
int i; /* loop index */
|
||||
xfs_inobt_key_t key; /* key value being inserted */
|
||||
xfs_inobt_key_t *kp=NULL; /* pointer to btree keys */
|
||||
xfs_agblock_t nbno; /* block number of allocated block */
|
||||
xfs_btree_cur_t *ncur; /* new cursor to be used at next lvl */
|
||||
xfs_inobt_key_t nkey; /* new key value, from split */
|
||||
xfs_inobt_rec_t nrec; /* new record value, for caller */
|
||||
int numrecs;
|
||||
int optr; /* old ptr value */
|
||||
xfs_inobt_ptr_t *pp; /* pointer to btree addresses */
|
||||
int ptr; /* index in btree block for this rec */
|
||||
xfs_inobt_rec_t *rp=NULL; /* pointer to btree records */
|
||||
|
||||
/*
|
||||
* GCC doesn't understand the (arguably complex) control flow in
|
||||
* this function and complains about uninitialized structure fields
|
||||
* without this.
|
||||
*/
|
||||
memset(&nrec, 0, sizeof(nrec));
|
||||
|
||||
/*
|
||||
* If we made it to the root level, allocate a new root block
|
||||
* and we're done.
|
||||
*/
|
||||
if (level >= cur->bc_nlevels) {
|
||||
error = xfs_btree_new_root(cur, &i);
|
||||
*bnop = NULLAGBLOCK;
|
||||
*stat = i;
|
||||
return error;
|
||||
}
|
||||
/*
|
||||
* Make a key out of the record data to be inserted, and save it.
|
||||
*/
|
||||
key.ir_startino = recp->ir_startino;
|
||||
optr = ptr = cur->bc_ptrs[level];
|
||||
/*
|
||||
* If we're off the left edge, return failure.
|
||||
*/
|
||||
if (ptr == 0) {
|
||||
*stat = 0;
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* Get pointers to the btree buffer and block.
|
||||
*/
|
||||
bp = cur->bc_bufs[level];
|
||||
block = XFS_BUF_TO_INOBT_BLOCK(bp);
|
||||
numrecs = be16_to_cpu(block->bb_numrecs);
|
||||
#ifdef DEBUG
|
||||
if ((error = xfs_btree_check_sblock(cur, block, level, bp)))
|
||||
return error;
|
||||
/*
|
||||
* Check that the new entry is being inserted in the right place.
|
||||
*/
|
||||
if (ptr <= numrecs) {
|
||||
if (level == 0) {
|
||||
rp = XFS_INOBT_REC_ADDR(block, ptr, cur);
|
||||
xfs_btree_check_rec(cur->bc_btnum, recp, rp);
|
||||
} else {
|
||||
kp = XFS_INOBT_KEY_ADDR(block, ptr, cur);
|
||||
xfs_btree_check_key(cur->bc_btnum, &key, kp);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
nbno = NULLAGBLOCK;
|
||||
ncur = NULL;
|
||||
/*
|
||||
* If the block is full, we can't insert the new entry until we
|
||||
* make the block un-full.
|
||||
*/
|
||||
if (numrecs == XFS_INOBT_BLOCK_MAXRECS(level, cur)) {
|
||||
/*
|
||||
* First, try shifting an entry to the right neighbor.
|
||||
*/
|
||||
if ((error = xfs_btree_rshift(cur, level, &i)))
|
||||
return error;
|
||||
if (i) {
|
||||
/* nothing */
|
||||
}
|
||||
/*
|
||||
* Next, try shifting an entry to the left neighbor.
|
||||
*/
|
||||
else {
|
||||
if ((error = xfs_btree_lshift(cur, level, &i)))
|
||||
return error;
|
||||
if (i) {
|
||||
optr = ptr = cur->bc_ptrs[level];
|
||||
} else {
|
||||
union xfs_btree_ptr bno = { .s = cpu_to_be32(nbno) };
|
||||
/*
|
||||
* Next, try splitting the current block
|
||||
* in half. If this works we have to
|
||||
* re-set our variables because
|
||||
* we could be in a different block now.
|
||||
*/
|
||||
if ((error = xfs_btree_split(cur, level, &bno,
|
||||
(union xfs_btree_key *)&nkey,
|
||||
&ncur, &i)))
|
||||
return error;
|
||||
nbno = be32_to_cpu(bno.s);
|
||||
if (i) {
|
||||
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];
|
||||
nrec.ir_startino = nkey.ir_startino;
|
||||
} else {
|
||||
/*
|
||||
* Otherwise the insert fails.
|
||||
*/
|
||||
*stat = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* At this point we know there's room for our new entry in the block
|
||||
* we're pointing at.
|
||||
*/
|
||||
numrecs = be16_to_cpu(block->bb_numrecs);
|
||||
if (level > 0) {
|
||||
/*
|
||||
* It's a non-leaf entry. Make a hole for the new data
|
||||
* in the key and ptr regions of the block.
|
||||
*/
|
||||
kp = XFS_INOBT_KEY_ADDR(block, 1, cur);
|
||||
pp = XFS_INOBT_PTR_ADDR(block, 1, cur);
|
||||
#ifdef DEBUG
|
||||
for (i = numrecs; i >= ptr; i--) {
|
||||
if ((error = xfs_btree_check_sptr(cur, be32_to_cpu(pp[i - 1]), level)))
|
||||
return error;
|
||||
}
|
||||
#endif
|
||||
memmove(&kp[ptr], &kp[ptr - 1],
|
||||
(numrecs - ptr + 1) * sizeof(*kp));
|
||||
memmove(&pp[ptr], &pp[ptr - 1],
|
||||
(numrecs - ptr + 1) * sizeof(*pp));
|
||||
/*
|
||||
* Now stuff the new data in, bump numrecs and log the new data.
|
||||
*/
|
||||
#ifdef DEBUG
|
||||
if ((error = xfs_btree_check_sptr(cur, *bnop, level)))
|
||||
return error;
|
||||
#endif
|
||||
kp[ptr - 1] = key;
|
||||
pp[ptr - 1] = cpu_to_be32(*bnop);
|
||||
numrecs++;
|
||||
block->bb_numrecs = cpu_to_be16(numrecs);
|
||||
xfs_inobt_log_keys(cur, bp, ptr, numrecs);
|
||||
xfs_inobt_log_ptrs(cur, bp, ptr, numrecs);
|
||||
} else {
|
||||
/*
|
||||
* It's a leaf entry. Make a hole for the new record.
|
||||
*/
|
||||
rp = XFS_INOBT_REC_ADDR(block, 1, cur);
|
||||
memmove(&rp[ptr], &rp[ptr - 1],
|
||||
(numrecs - ptr + 1) * sizeof(*rp));
|
||||
/*
|
||||
* Now stuff the new record in, bump numrecs
|
||||
* and log the new data.
|
||||
*/
|
||||
rp[ptr - 1] = *recp;
|
||||
numrecs++;
|
||||
block->bb_numrecs = cpu_to_be16(numrecs);
|
||||
xfs_inobt_log_recs(cur, bp, ptr, numrecs);
|
||||
}
|
||||
/*
|
||||
* Log the new number of records in the btree header.
|
||||
*/
|
||||
xfs_inobt_log_block(cur->bc_tp, bp, XFS_BB_NUMRECS);
|
||||
#ifdef DEBUG
|
||||
/*
|
||||
* Check that the key/record is in the right place, now.
|
||||
*/
|
||||
if (ptr < numrecs) {
|
||||
if (level == 0)
|
||||
xfs_btree_check_rec(cur->bc_btnum, rp + ptr - 1,
|
||||
rp + ptr);
|
||||
else
|
||||
xfs_btree_check_key(cur->bc_btnum, kp + ptr - 1,
|
||||
kp + ptr);
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
* If we inserted at the start of a block, update the parents' keys.
|
||||
*/
|
||||
if (optr == 1 && (error = xfs_btree_updkey(cur, (union xfs_btree_key *)&key, level + 1)))
|
||||
return error;
|
||||
/*
|
||||
* Return the new block number, if any.
|
||||
* If there is one, give back a record value and a cursor too.
|
||||
*/
|
||||
*bnop = nbno;
|
||||
if (nbno != NULLAGBLOCK) {
|
||||
*recp = nrec;
|
||||
*curp = ncur;
|
||||
}
|
||||
*stat = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Log header fields from a btree block.
|
||||
*/
|
||||
|
@ -912,66 +690,6 @@ xfs_inobt_get_rec(
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert the current record at the point referenced by cur.
|
||||
* The cursor may be inconsistent on return if splits have been done.
|
||||
*/
|
||||
int /* error */
|
||||
xfs_inobt_insert(
|
||||
xfs_btree_cur_t *cur, /* btree cursor */
|
||||
int *stat) /* success/failure */
|
||||
{
|
||||
int error; /* error return value */
|
||||
int i; /* result value, 0 for failure */
|
||||
int level; /* current level number in btree */
|
||||
xfs_agblock_t nbno; /* new block number (split result) */
|
||||
xfs_btree_cur_t *ncur; /* new cursor (split result) */
|
||||
xfs_inobt_rec_t nrec; /* record being inserted this level */
|
||||
xfs_btree_cur_t *pcur; /* previous level's cursor */
|
||||
|
||||
level = 0;
|
||||
nbno = NULLAGBLOCK;
|
||||
nrec.ir_startino = cpu_to_be32(cur->bc_rec.i.ir_startino);
|
||||
nrec.ir_freecount = cpu_to_be32(cur->bc_rec.i.ir_freecount);
|
||||
nrec.ir_free = cpu_to_be64(cur->bc_rec.i.ir_free);
|
||||
ncur = NULL;
|
||||
pcur = cur;
|
||||
/*
|
||||
* Loop going up the tree, starting at the leaf level.
|
||||
* Stop when we don't get a split block, that must mean that
|
||||
* the insert is finished with this level.
|
||||
*/
|
||||
do {
|
||||
/*
|
||||
* Insert nrec/nbno into this level of the tree.
|
||||
* Note if we fail, nbno will be null.
|
||||
*/
|
||||
if ((error = xfs_inobt_insrec(pcur, level++, &nbno, &nrec, &ncur,
|
||||
&i))) {
|
||||
if (pcur != cur)
|
||||
xfs_btree_del_cursor(pcur, XFS_BTREE_ERROR);
|
||||
return error;
|
||||
}
|
||||
/*
|
||||
* See if the cursor we just used is trash.
|
||||
* Can't trash the caller's cursor, but otherwise we should
|
||||
* if ncur is a new cursor or we're about to be done.
|
||||
*/
|
||||
if (pcur != cur && (ncur || nbno == NULLAGBLOCK)) {
|
||||
cur->bc_nlevels = pcur->bc_nlevels;
|
||||
xfs_btree_del_cursor(pcur, XFS_BTREE_NOERROR);
|
||||
}
|
||||
/*
|
||||
* If we got a new cursor, switch to it.
|
||||
*/
|
||||
if (ncur) {
|
||||
pcur = ncur;
|
||||
ncur = NULL;
|
||||
}
|
||||
} while (nbno != NULLAGBLOCK);
|
||||
*stat = i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
STATIC struct xfs_btree_cur *
|
||||
xfs_inobt_dup_cursor(
|
||||
|
@ -1053,6 +771,24 @@ xfs_inobt_init_key_from_rec(
|
|||
key->inobt.ir_startino = rec->inobt.ir_startino;
|
||||
}
|
||||
|
||||
STATIC void
|
||||
xfs_inobt_init_rec_from_key(
|
||||
union xfs_btree_key *key,
|
||||
union xfs_btree_rec *rec)
|
||||
{
|
||||
rec->inobt.ir_startino = key->inobt.ir_startino;
|
||||
}
|
||||
|
||||
STATIC void
|
||||
xfs_inobt_init_rec_from_cur(
|
||||
struct xfs_btree_cur *cur,
|
||||
union xfs_btree_rec *rec)
|
||||
{
|
||||
rec->inobt.ir_startino = cpu_to_be32(cur->bc_rec.i.ir_startino);
|
||||
rec->inobt.ir_freecount = cpu_to_be32(cur->bc_rec.i.ir_freecount);
|
||||
rec->inobt.ir_free = cpu_to_be64(cur->bc_rec.i.ir_free);
|
||||
}
|
||||
|
||||
/*
|
||||
* intial value of ptr for lookup
|
||||
*/
|
||||
|
@ -1152,6 +888,8 @@ static const struct xfs_btree_ops xfs_inobt_ops = {
|
|||
.alloc_block = xfs_inobt_alloc_block,
|
||||
.get_maxrecs = xfs_inobt_get_maxrecs,
|
||||
.init_key_from_rec = xfs_inobt_init_key_from_rec,
|
||||
.init_rec_from_key = xfs_inobt_init_rec_from_key,
|
||||
.init_rec_from_cur = xfs_inobt_init_rec_from_cur,
|
||||
.init_ptr_from_cur = xfs_inobt_init_ptr_from_cur,
|
||||
.key_diff = xfs_inobt_key_diff,
|
||||
|
||||
|
|
|
@ -129,12 +129,6 @@ extern int xfs_inobt_delete(struct xfs_btree_cur *cur, int *stat);
|
|||
extern int xfs_inobt_get_rec(struct xfs_btree_cur *cur, xfs_agino_t *ino,
|
||||
__int32_t *fcnt, xfs_inofree_t *free, int *stat);
|
||||
|
||||
/*
|
||||
* Insert the current record at the point referenced by cur.
|
||||
* The cursor may be inconsistent on return if splits have been done.
|
||||
*/
|
||||
extern int xfs_inobt_insert(struct xfs_btree_cur *cur, int *stat);
|
||||
|
||||
|
||||
extern struct xfs_btree_cur *xfs_inobt_init_cursor(struct xfs_mount *,
|
||||
struct xfs_trans *, struct xfs_buf *, xfs_agnumber_t);
|
||||
|
|
Loading…
Reference in New Issue