if (xfs_has_crc(mp)) { if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid)) return __this_address; if (block->bb_u.s.bb_blkno != cpu_to_be64(xfs_buf_daddr(bp))) return __this_address;
}
if (be32_to_cpu(block->bb_magic) != xfs_btree_magic(mp, cur->bc_ops)) return __this_address; if (be16_to_cpu(block->bb_level) != level) return __this_address; if (be16_to_cpu(block->bb_numrecs) >
cur->bc_ops->get_maxrecs(cur, level)) return __this_address;
agbno = xfs_daddr_to_agbno(mp, xfs_buf_daddr(bp));
fa = xfs_btree_check_agblock_siblings(pag, agbno,
block->bb_u.s.bb_leftsib); if (!fa)
fa = xfs_btree_check_agblock_siblings(pag, agbno,
block->bb_u.s.bb_rightsib); return fa;
}
/* *Debugroutine:checkthatblockheaderisok.
*/ int
xfs_btree_check_block( struct xfs_btree_cur *cur, /* btree cursor */ struct xfs_btree_block *block, /* generic btree block pointer */ int level, /* level of the btree block */ struct xfs_buf *bp) /* buffer containing block, if any */
{ struct xfs_mount *mp = cur->bc_mp;
xfs_failaddr_t fa;
fa = __xfs_btree_check_block(cur, block, level, bp); if (XFS_IS_CORRUPT(mp, fa != NULL) ||
XFS_TEST_ERROR(false, mp, xfs_btree_block_errtag(cur))) { if (bp)
trace_xfs_btree_corrupt(bp, _RET_IP_);
xfs_btree_mark_sick(cur); return -EFSCORRUPTED;
} return0;
}
int
__xfs_btree_check_ptr( struct xfs_btree_cur *cur, constunion xfs_btree_ptr *ptr, int index, int level)
{ if (level <= 0) return -EFSCORRUPTED;
switch (cur->bc_ops->type) { case XFS_BTREE_TYPE_MEM: if (!xfbtree_verify_bno(cur->bc_mem.xfbtree,
be64_to_cpu((&ptr->l)[index]))) return -EFSCORRUPTED; break; case XFS_BTREE_TYPE_INODE: if (!xfs_verify_fsbno(cur->bc_mp,
be64_to_cpu((&ptr->l)[index]))) return -EFSCORRUPTED; break; case XFS_BTREE_TYPE_AG: if (!xfs_verify_agbno(to_perag(cur->bc_group),
be32_to_cpu((&ptr->s)[index]))) return -EFSCORRUPTED; break;
}
return0;
}
/* *Checkthatagiven(indexed)btreepointeratacertainlevelofa *btreeisvalidanddoesn'tpointpastwhereitshould.
*/ staticint
xfs_btree_check_ptr( struct xfs_btree_cur *cur, constunion xfs_btree_ptr *ptr, int index, int level)
{ int error;
error = __xfs_btree_check_ptr(cur, ptr, index, level); if (error) { switch (cur->bc_ops->type) { case XFS_BTREE_TYPE_MEM:
xfs_err(cur->bc_mp, "In-memory: Corrupt %sbt flags 0x%x pointer at level %d index %d fa %pS.",
cur->bc_ops->name, cur->bc_flags, level, index,
__this_address); break; case XFS_BTREE_TYPE_INODE:
xfs_err(cur->bc_mp, "Inode %llu fork %d: Corrupt %sbt pointer at level %d index %d.",
cur->bc_ino.ip->i_ino,
cur->bc_ino.whichfork, cur->bc_ops->name,
level, index); break; case XFS_BTREE_TYPE_AG:
xfs_err(cur->bc_mp, "AG %u: Corrupt %sbt pointer at level %d index %d.",
cur->bc_group->xg_gno, cur->bc_ops->name,
level, index); break;
}
xfs_btree_mark_sick(cur);
}
if (cur->bc_group)
xfs_group_put(cur->bc_group);
kmem_cache_free(cur->bc_cache, cur);
}
/* Return the buffer target for this btree's buffer. */ staticinlinestruct xfs_buftarg *
xfs_btree_buftarg( struct xfs_btree_cur *cur)
{ if (cur->bc_ops->type == XFS_BTREE_TYPE_MEM) return cur->bc_mem.xfbtree->target; return cur->bc_mp->m_ddev_targp;
}
/* Return the block size (in units of 512b sectors) for this btree. */ staticinlineunsignedint
xfs_btree_bbsize( struct xfs_btree_cur *cur)
{ if (cur->bc_ops->type == XFS_BTREE_TYPE_MEM) return XFBNO_BBSIZE; return cur->bc_mp->m_bsize;
}
/* *Calculateoffsetofthen-thblockpointerinabtreeblock.
*/ STATIC size_t
xfs_btree_ptr_offset( struct xfs_btree_cur *cur, int n, int level)
{ return xfs_btree_block_len(cur) +
cur->bc_ops->get_maxrecs(cur, level) * cur->bc_ops->key_len +
(n - 1) * cur->bc_ops->ptr_len;
}
/* *Returnapointertothen-threcordinthebtreeblock.
*/ union xfs_btree_rec *
xfs_btree_rec_addr( struct xfs_btree_cur *cur, int n, struct xfs_btree_block *block)
{ return (union xfs_btree_rec *)
((char *)block + xfs_btree_rec_offset(cur, n));
}
/* *Returnapointertothen-thkeyinthebtreeblock.
*/ union xfs_btree_key *
xfs_btree_key_addr( struct xfs_btree_cur *cur, int n, struct xfs_btree_block *block)
{ return (union xfs_btree_key *)
((char *)block + xfs_btree_key_offset(cur, n));
}
/* *Returnapointertothen-thhighkeyinthebtreeblock.
*/ union xfs_btree_key *
xfs_btree_high_key_addr( struct xfs_btree_cur *cur, int n, struct xfs_btree_block *block)
{ return (union xfs_btree_key *)
((char *)block + xfs_btree_high_key_offset(cur, n));
}
/* *Returnapointertothen-thblockpointerinthebtreeblock.
*/ union xfs_btree_ptr *
xfs_btree_ptr_addr( struct xfs_btree_cur *cur, int n, struct xfs_btree_block *block)
{ int level = xfs_btree_get_level(block);
/* *Computefirstandlastbyteoffsetsforthefieldsgiven. *Interpretstheoffsetstable,whichcontainsstructfieldoffsets.
*/ void
xfs_btree_offsets(
uint32_t fields, /* bitmask of fields */ constshort *offsets, /* table of field offsets */ int nbits, /* number of bits to inspect */ int *first, /* output: first byte offset */ int *last) /* output: last byte offset */
{ int i; /* current bit number */
uint32_t imask; /* mask for current bit number */
/* *Logblockpointerfieldsfromabtreeblock(nonleaf).
*/ STATICvoid
xfs_btree_log_ptrs( struct xfs_btree_cur *cur, /* btree cursor */ struct xfs_buf *bp, /* buffer containing btree block */ int first, /* index of first pointer to log */ int last) /* index of last pointer to log */
{
if (bp) { struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); int level = xfs_btree_get_level(block);
/* We're done if we remain in the block after the increment. */ if (++cur->bc_levels[level].ptr <= xfs_btree_get_numrecs(block)) goto out1;
/* Fail if we just went off the right edge of the tree. */
xfs_btree_get_sibling(cur, block, &ptr, XFS_BB_RIGHTSIB); if (xfs_btree_ptr_is_null(cur, &ptr)) goto out0;
XFS_BTREE_STATS_INC(cur, increment);
/* *Marchupthetreeincrementingpointers. *Stopwhenwedon'tgoofftherightedgeofablock.
*/ for (lev = level + 1; lev < cur->bc_nlevels; lev++) {
block = xfs_btree_get_block(cur, lev, &bp);
#ifdef DEBUG
error = xfs_btree_check_block(cur, block, lev, bp); if (error) goto error0; #endif
if (++cur->bc_levels[lev].ptr <= xfs_btree_get_numrecs(block)) break;
/* Read-ahead the right block for the next loop. */
xfs_btree_readahead(cur, lev, XFS_BTCUR_RIGHTRA);
}
/* *Nowwalkbackdownthetree,fixingupthecursor'sbuffer *pointersandkeynumbers.
*/ for (block = xfs_btree_get_block(cur, lev, &bp); lev > level; ) { union xfs_btree_ptr *ptrp;
/* Fail if we just went off the left edge of the tree. */
xfs_btree_get_sibling(cur, block, &ptr, XFS_BB_LEFTSIB); if (xfs_btree_ptr_is_null(cur, &ptr)) goto out0;
XFS_BTREE_STATS_INC(cur, decrement);
/* *Marchupthetreedecrementingpointers. *Stopwhenwedon'tgoofftheleftedgeofablock.
*/ for (lev = level + 1; lev < cur->bc_nlevels; lev++) { if (--cur->bc_levels[lev].ptr > 0) break; /* Read-ahead the left block for the next loop. */
xfs_btree_readahead(cur, lev, XFS_BTCUR_LEFTRA);
}
/* *Nowwalkbackdownthetree,fixingupthecursor'sbuffer *pointersandkeynumbers.
*/ for (block = xfs_btree_get_block(cur, lev, &bp); lev > level; ) { union xfs_btree_ptr *ptrp;
/* *Lookuptherecord.Thecursorismadetopointtoit,basedondir. *statissetto0ifcan'tfindanysuchrecord,1forsuccess.
*/ int/* error */
xfs_btree_lookup( struct xfs_btree_cur *cur, /* btree cursor */
xfs_lookup_t dir, /* <=, ==, or >= */ int *stat) /* success/failure */
{ struct xfs_btree_block *block; /* current btree block */ int cmp_r; /* current key comparison result */ int error; /* error return value */ int keyno; /* current key number */ int level; /* level in the btree */ union xfs_btree_ptr *pp; /* ptr to btree block */ union xfs_btree_ptr ptr; /* ptr to btree block */
XFS_BTREE_STATS_INC(cur, lookup);
/* No such thing as a zero-level tree. */ if (XFS_IS_CORRUPT(cur->bc_mp, cur->bc_nlevels == 0)) {
xfs_btree_mark_sick(cur); return -EFSCORRUPTED;
}
/* *Iterateovereachlevelinthebtree,startingattheroot. *Foreachlevelabovetheleaves,findthekeyweneed,based *onthelookuprecord,thenfollowthecorrespondingblock *pointerdowntothenextlevel.
*/ for (level = cur->bc_nlevels - 1, cmp_r = 1; level >= 0; level--) { /* Get the block we need to do the lookup on. */
error = xfs_btree_lookup_get_block(cur, level, pp, &block); if (error) goto error0;
if (cmp_r == 0) { /* *Ifwealreadyhadakeymatchatahigherlevel,we *knowweneedtousethefirstentryinthisblock.
*/
keyno = 1;
} else { /* Otherwise search this block. Do a binary search. */
int high; /* high entry number */ int low; /* low entry number */
/* Set low and high entry numbers, 1-based. */
low = 1;
high = xfs_btree_get_numrecs(block); if (!high) { /* Block is empty, must be an empty leaf. */ if (level != 0 || cur->bc_nlevels != 1) {
XFS_CORRUPTION_ERROR(__func__,
XFS_ERRLEVEL_LOW,
cur->bc_mp, block, sizeof(*block));
xfs_btree_mark_sick(cur); return -EFSCORRUPTED;
}
cur->bc_levels[0].ptr = dir != XFS_LOOKUP_LE;
*stat = 0; return0;
}
/* Binary search the block. */ while (low <= high) { union xfs_btree_key key; union xfs_btree_key *kp;
XFS_BTREE_STATS_INC(cur, compare);
/* keyno is average of low and high. */
keyno = (low + high) >> 1;
/* Get current search key */
kp = xfs_lookup_get_search_key(cur, level,
keyno, block, &key);
error = xfs_btree_debug_check_ptr(cur, pp, 0, level); if (error) goto error0;
cur->bc_levels[level].ptr = keyno;
}
}
/* Done with the search. See if we need to adjust the results. */ if (dir != XFS_LOOKUP_LE && cmp_r < 0) {
keyno++; /* *Ifgesearchandwewentofftheendoftheblock,butit's *notthelastblock,we'reinthewrongblock.
*/
xfs_btree_get_sibling(cur, block, &ptr, XFS_BB_RIGHTSIB); if (dir == XFS_LOOKUP_GE &&
keyno > xfs_btree_get_numrecs(block) &&
!xfs_btree_ptr_is_null(cur, &ptr)) { int i;
/* Return if we succeeded or not. */ if (keyno == 0 || keyno > xfs_btree_get_numrecs(block))
*stat = 0; elseif (dir != XFS_LOOKUP_EQ || cmp_r == 0)
*stat = 1; else
*stat = 0; return0;
error0: return error;
}
/* Find the high key storage area from a regular key. */ union xfs_btree_key *
xfs_btree_high_key_from_key( struct xfs_btree_cur *cur, union xfs_btree_key *key)
{
ASSERT(cur->bc_ops->geom_flags & XFS_BTGEO_OVERLAPPING); return (union xfs_btree_key *)((char *)key +
(cur->bc_ops->key_len / 2));
}
/* Determine the low (and high if overlapped) keys of a leaf block */ STATICvoid
xfs_btree_get_leaf_keys( struct xfs_btree_cur *cur, struct xfs_btree_block *block, union xfs_btree_key *key)
{ union xfs_btree_key max_hkey; union xfs_btree_key hkey; union xfs_btree_rec *rec; union xfs_btree_key *high; int n;
/* Determine the low (and high if overlapped) keys of a node block */ STATICvoid
xfs_btree_get_node_keys( struct xfs_btree_cur *cur, struct xfs_btree_block *block, union xfs_btree_key *key)
{ union xfs_btree_key *hkey; union xfs_btree_key *max_hkey; union xfs_btree_key *high; int n;
/* *Updatethelowandhighparentkeysofthegivenlevel,progressing *towardstheroot.Ifforce_allisfalse,stopifthekeysforagiven *leveldonotneedupdating.
*/ STATICint
__xfs_btree_updkeys( struct xfs_btree_cur *cur, int level, struct xfs_btree_block *block, struct xfs_buf *bp0, bool force_all)
{ union xfs_btree_key key; /* keys from current level */ union xfs_btree_key *lkey; /* keys from the next level up */ union xfs_btree_key *hkey; union xfs_btree_key *nlkey; /* keys from the next level up */ union xfs_btree_key *nhkey; struct xfs_buf *bp; int ptr;
/* Update all the keys from some level in cursor back to the root. */ STATICint
xfs_btree_updkeys_force( struct xfs_btree_cur *cur, int level)
{ struct xfs_buf *bp; struct xfs_btree_block *block;
/* *Updatetherecordreferredtobycurtothevalueinthe *givenrecord.Thiseitherworks(return0)orgetsan *EFSCORRUPTEDerror.
*/ int
xfs_btree_update( struct xfs_btree_cur *cur, union xfs_btree_rec *rec)
{ struct xfs_btree_block *block; struct xfs_buf *bp; int error; int ptr; union xfs_btree_rec *rp;
/* Pick up the current block. */
block = xfs_btree_get_block(cur, 0, &bp);
#ifdef DEBUG
error = xfs_btree_check_block(cur, block, 0, bp); if (error) goto error0; #endif /* Get the address of the rec to be updated. */
ptr = cur->bc_levels[0].ptr;
rp = xfs_btree_rec_addr(cur, ptr, block);
/* Fill in the new contents and log them. */
xfs_btree_copy_recs(cur, rp, rec, 1);
xfs_btree_log_recs(cur, bp, ptr, ptr);
/* Pass new key value up to our parent. */ if (xfs_btree_needs_key_update(cur, ptr)) {
error = xfs_btree_update_keys(cur, 0); if (error) goto error0;
}
return0;
error0: return error;
}
/* *Move1recordleftfromcur/levelifpossible. *Updatecurtoreflectthenewpath.
*/ STATICint/* error */
xfs_btree_lshift( struct xfs_btree_cur *cur, int level, int *stat) /* success/failure */
{ struct xfs_buf *lbp; /* left buffer pointer */ struct xfs_btree_block *left; /* left btree block */ int lrecs; /* left record count */ struct xfs_buf *rbp; /* right buffer pointer */ struct xfs_btree_block *right; /* right btree block */ struct xfs_btree_cur *tcur; /* temporary btree cursor */ int rrecs; /* right record count */ union xfs_btree_ptr lptr; /* left btree pointer */ union xfs_btree_key *rkp = NULL; /* right btree key */ union xfs_btree_ptr *rpp = NULL; /* right address pointer */ union xfs_btree_rec *rrp = NULL; /* right record pointer */ int error; /* error return value */ int i;
if (xfs_btree_at_iroot(cur, level)) goto out0;
/* Set up variables for this block as "right". */
right = xfs_btree_get_block(cur, level, &rbp);
/* If we've got no left sibling then we can't shift an entry left. */
xfs_btree_get_sibling(cur, right, &lptr, XFS_BB_LEFTSIB); if (xfs_btree_ptr_is_null(cur, &lptr)) goto out0;
/* *Ifthecursorentryistheonethatwouldbemoved,don't *doit...it'stoocomplicated.
*/ if (cur->bc_levels[level].ptr <= 1) goto out0;
/* Set up the left neighbor as "left". */
error = xfs_btree_read_buf_block(cur, &lptr, 0, &left, &lbp); if (error) goto error0;
/* If it's full, it can't take another entry. */
lrecs = xfs_btree_get_numrecs(left); if (lrecs == cur->bc_ops->get_maxrecs(cur, level)) goto out0;
/* *Ifnon-leaf,copyakeyandaptrtotheleftblock. *Logthechangestotheleftblock.
*/ if (level > 0) { /* It's a non-leaf. Move keys and pointers. */ union xfs_btree_key *lkp; /* left btree key */ union xfs_btree_ptr *lpp; /* left address pointer */
lkp = xfs_btree_key_addr(cur, lrecs, left);
rkp = xfs_btree_key_addr(cur, 1, right);
ASSERT(cur->bc_ops->keys_inorder(cur,
xfs_btree_key_addr(cur, lrecs - 1, left), lkp));
} else { /* It's a leaf. Move records. */ union xfs_btree_rec *lrp; /* left record pointer */
/* *Slidethecontentsofrightdownoneentry.
*/
XFS_BTREE_STATS_ADD(cur, moves, rrecs - 1); if (level > 0) { /* It's a nonleaf. operate on keys and ptrs */ for (i = 0; i < rrecs; i++) {
error = xfs_btree_debug_check_ptr(cur, rpp, i + 1, level); if (error) goto error0;
}
/* If we've got no right sibling then we can't shift an entry right. */
xfs_btree_get_sibling(cur, left, &rptr, XFS_BB_RIGHTSIB); if (xfs_btree_ptr_is_null(cur, &rptr)) goto out0;
/* *Makeaholeatthestartoftherightneighborblock,then *copythelastleftblockentrytothehole.
*/ if (level > 0) { /* It's a nonleaf. make a hole in the keys and ptrs */ union xfs_btree_key *lkp; union xfs_btree_ptr *lpp; union xfs_btree_ptr *rpp;
ASSERT(cur->bc_ops->keys_inorder(cur, rkp,
xfs_btree_key_addr(cur, 2, right)));
} else { /* It's a leaf. make a hole in the records */ union xfs_btree_rec *lrp; union xfs_btree_rec *rrp;
/* *Usingatemporarycursor,updatetheparentkeyvaluesofthe *blockontheright.
*/
error = xfs_btree_dup_cursor(cur, &tcur); if (error) goto error0;
i = xfs_btree_lastrec(tcur, level); if (XFS_IS_CORRUPT(tcur->bc_mp, i != 1)) {
xfs_btree_mark_sick(cur);
error = -EFSCORRUPTED; goto error0;
}
error = xfs_btree_increment(tcur, level, &i); if (error) goto error1;
/* Update the parent high keys of the left block, if needed. */ if (cur->bc_ops->geom_flags & XFS_BTGEO_OVERLAPPING) {
error = xfs_btree_update_keys(cur, level); if (error) goto error1;
}
/* Update the parent keys of the right block. */
error = xfs_btree_update_keys(tcur, level); if (error) goto error1;
/* Allocate the new block. If we can't do it, we're toast. Give up. */
error = xfs_btree_alloc_block(cur, &lptr, &rptr, stat); if (error) goto error0; if (*stat == 0) goto out0;
XFS_BTREE_STATS_INC(cur, alloc);
/* Set up the new block as "right". */
error = xfs_btree_get_buf_block(cur, &rptr, &right, &rbp); if (error) goto error0;
/* Fill in the btree header for the new right block. */
xfs_btree_init_block_cur(cur, rbp, xfs_btree_get_level(left), 0);
/* Adjust numrecs for the later get_*_keys() calls. */
lrecs -= rrecs;
xfs_btree_set_numrecs(left, lrecs);
xfs_btree_set_numrecs(right, xfs_btree_get_numrecs(right) + rrecs);
/* *Copybtreeblockentriesfromtheleftblockovertothe *newblock,theright.Updatetherightblockandlogthe *changes.
*/ if (level > 0) { /* It's a non-leaf. Move keys and pointers. */ union xfs_btree_key *lkp; /* left btree key */ union xfs_btree_ptr *lpp; /* left address pointer */ union xfs_btree_key *rkp; /* right btree key */ union xfs_btree_ptr *rpp; /* right address pointer */
/* Stash the keys of the new block for later insertion. */
xfs_btree_get_node_keys(cur, right, key);
} else { /* It's a leaf. Move records. */ union xfs_btree_rec *lrp; /* left record pointer */ union xfs_btree_rec *rrp; /* right record pointer */
/* Update the parent high keys of the left block, if needed. */ if (cur->bc_ops->geom_flags & XFS_BTGEO_OVERLAPPING) {
error = xfs_btree_update_keys(cur, level); if (error) goto error0;
}
/* Move the records from a root leaf block to a separate block. */ STATICvoid
xfs_btree_promote_leaf_iroot( struct xfs_btree_cur *cur, struct xfs_btree_block *block, struct xfs_buf *cbp, union xfs_btree_ptr *cptr, struct xfs_btree_block *cblock)
{ union xfs_btree_rec *rp; union xfs_btree_rec *crp; union xfs_btree_key *kp; union xfs_btree_ptr *pp; struct xfs_btree_block *broot; int numrecs = xfs_btree_get_numrecs(block);
/* Copy the records from the leaf broot into the new child block. */
rp = xfs_btree_rec_addr(cur, 1, block);
crp = xfs_btree_rec_addr(cur, 1, cblock);
xfs_btree_copy_recs(cur, crp, rp, numrecs);
/* Attach the new block to the cursor and log it. */
xfs_btree_setbuf(cur, 0, cbp);
xfs_btree_log_block(cur, cbp, XFS_BB_ALL_BITS);
xfs_btree_log_recs(cur, cbp, 1, numrecs);
}
/* *Movethekeysandpointersfromarootblocktoaseparateblock. * *Sincethekeyptrsizedoesnotchange,allwehavetodoisincreasethe *treeheight,copythekeyptrstothenewinternalnode(cblock),shrink *theroot,andcopythepointersthere.
*/ STATICint
xfs_btree_promote_node_iroot( struct xfs_btree_cur *cur, struct xfs_btree_block *block, int level, struct xfs_buf *cbp, union xfs_btree_ptr *cptr, struct xfs_btree_block *cblock)
{ union xfs_btree_key *ckp; union xfs_btree_key *kp; union xfs_btree_ptr *cpp; union xfs_btree_ptr *pp; int i; int error; int numrecs = xfs_btree_get_numrecs(block);
/* Check the pointers and copy them to the new child block. */
pp = xfs_btree_ptr_addr(cur, 1, block);
cpp = xfs_btree_ptr_addr(cur, 1, cblock); for (i = 0; i < numrecs; i++) {
error = xfs_btree_debug_check_ptr(cur, pp, i, level); if (error) return error;
}
xfs_btree_copy_ptrs(cur, cpp, pp, numrecs);
/* Attach the new block to the cursor and log it. */
xfs_btree_setbuf(cur, level, cbp);
xfs_btree_log_block(cur, cbp, XFS_BB_ALL_BITS);
xfs_btree_log_keys(cur, cbp, 1, numrecs);
xfs_btree_log_ptrs(cur, cbp, 1, numrecs); return0;
}
/* *Copytheoldinoderootcontentsintoarealblockandmakethe *brootpointtoit.
*/ int/* error */
xfs_btree_new_iroot( struct xfs_btree_cur *cur, /* btree cursor */ int *logflags, /* logging flags for inode */ int *stat) /* return status - 0 fail */
{ struct xfs_buf *cbp; /* buffer for cblock */ struct xfs_btree_block *block; /* btree block */ struct xfs_btree_block *cblock; /* child btree block */ union xfs_btree_ptr aptr; union xfs_btree_ptr nptr; /* new block addr */ int level; /* btree level */ int error; /* error return code */
/* Allocate the new block. If we can't do it, we're toast. Give up. */
error = xfs_btree_alloc_block(cur, &aptr, &nptr, stat); if (error) goto error0; if (*stat == 0) return0;
XFS_BTREE_STATS_INC(cur, alloc);
/* Copy the root into a real block. */
error = xfs_btree_get_buf_block(cur, &nptr, &cblock, &cbp); if (error) goto error0;
staticvoid
xfs_btree_set_root( struct xfs_btree_cur *cur, constunion xfs_btree_ptr *ptr, int inc)
{ if (cur->bc_flags & XFS_BTREE_STAGING) { /* Update the btree root information for a per-AG fake root. */
cur->bc_ag.afake->af_root = be32_to_cpu(ptr->s);
cur->bc_ag.afake->af_levels += inc;
} else {
cur->bc_ops->set_root(cur, ptr, inc);
}
}
/* *Allocateanewrootblock,fillitin.
*/ STATICint/* error */
xfs_btree_new_root( struct xfs_btree_cur *cur, /* btree cursor */ int *stat) /* success/failure */
{ struct xfs_btree_block *block; /* one half of the old root block */ struct xfs_buf *bp; /* buffer containing block */ int error; /* error return value */ struct xfs_buf *lbp; /* left buffer pointer */ struct xfs_btree_block *left; /* left btree block */ struct xfs_buf *nbp; /* new (root) buffer */ struct xfs_btree_block *new; /* new (root) btree block */ int nptr; /* new value for key index, 1 or 2 */ struct xfs_buf *rbp; /* right buffer pointer */ struct xfs_btree_block *right; /* right btree block */ union xfs_btree_ptr rptr; union xfs_btree_ptr lptr;
XFS_BTREE_STATS_INC(cur, newroot);
/* initialise our start point from the cursor */
xfs_btree_init_ptr_from_cur(cur, &rptr);
/* Allocate the new block. If we can't do it, we're toast. Give up. */
error = xfs_btree_alloc_block(cur, &rptr, &lptr, stat); if (error) goto error0; if (*stat == 0) goto out0;
XFS_BTREE_STATS_INC(cur, alloc);
/* Set up the new block. */
error = xfs_btree_get_buf_block(cur, &lptr, &new, &nbp); if (error) goto error0;
/* Set the root in the holding structure increasing the level by 1. */
xfs_btree_set_root(cur, &lptr, 1);
xfs_btree_get_sibling(cur, block, &rptr, XFS_BB_RIGHTSIB); if (!xfs_btree_ptr_is_null(cur, &rptr)) { /* Our block is left, pick up the right block. */
lbp = bp;
xfs_btree_buf_to_ptr(cur, lbp, &lptr);
left = block;
error = xfs_btree_read_buf_block(cur, &rptr, 0, &right, &rbp); if (error) goto error0;
bp = rbp;
nptr = 1;
} else { /* Our block is right, pick up the left block. */
rbp = bp;
xfs_btree_buf_to_ptr(cur, rbp, &rptr);
right = block;
xfs_btree_get_sibling(cur, right, &lptr, XFS_BB_LEFTSIB);
error = xfs_btree_read_buf_block(cur, &lptr, 0, &left, &lbp); if (error) goto error0;
bp = lbp;
nptr = 2;
}
/* Fill in the new block's btree header and log it. */
xfs_btree_init_block_cur(cur, nbp, cur->bc_nlevels, 2);
xfs_btree_log_block(cur, nbp, XFS_BB_ALL_BITS);
ASSERT(!xfs_btree_ptr_is_null(cur, &lptr) &&
!xfs_btree_ptr_is_null(cur, &rptr));
/* Fill in the key data in the new root. */ if (xfs_btree_get_level(left) > 0) { /* *Getthekeysfortheleftblock'skeysandputthemdirectly *intheparentblock.Dothesamefortherightblock.
*/
xfs_btree_get_node_keys(cur, left,
xfs_btree_key_addr(cur, 1, new));
xfs_btree_get_node_keys(cur, right,
xfs_btree_key_addr(cur, 2, new));
} else { /* *Getthekeysfortheleftblock'srecordsandputthem *directlyintheparentblock.Dothesamefortheright *block.
*/
xfs_btree_get_leaf_keys(cur, left,
xfs_btree_key_addr(cur, 1, new));
xfs_btree_get_leaf_keys(cur, right,
xfs_btree_key_addr(cur, 2, new));
}
xfs_btree_log_keys(cur, nbp, 1, 2);
/* Fill in the pointer data in the new root. */
xfs_btree_copy_ptrs(cur,
xfs_btree_ptr_addr(cur, 1, new), &lptr, 1);
xfs_btree_copy_ptrs(cur,
xfs_btree_ptr_addr(cur, 2, new), &rptr, 1);
xfs_btree_log_ptrs(cur, nbp, 1, 2);
STATICint
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_key *key, /* key of new block */ int *stat)
{ int error = 0;
if (xfs_btree_at_iroot(cur, level)) { struct xfs_inode *ip = cur->bc_ino.ip;
if (numrecs < cur->bc_ops->get_dmaxrecs(cur, level)) { /* A root block that can be made bigger. */
cur->bc_ops->broot_realloc(cur, numrecs + 1);
*stat = 1;
} else { /* A root block that needs replacing */ int logflags = 0;
/* *Insertonerecord/level.Returninformationtothecaller *allowingthenextleveluptoproceedifnecessary.
*/ STATICint
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 *rec, /* record to insert */ union xfs_btree_key *key, /* i/o: block key for ptrp */ 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_ptr nptr; /* new block ptr */ struct xfs_btree_cur *ncur = NULL; /* new btree cursor */ union xfs_btree_key nkey; /* new block key */ union xfs_btree_key *lkey; int optr; /* old key/record index */ int ptr; /* key/record index */ int numrecs;/* number of records */ int error; /* error return value */ int i;
xfs_daddr_t old_bn;
/* If we're off the left edge, return failure. */
ptr = cur->bc_levels[level].ptr; if (ptr == 0) {
*stat = 0; return0;
}
optr = ptr;
XFS_BTREE_STATS_INC(cur, insrec);
/* Get pointers to the btree buffer and block. */
block = xfs_btree_get_block(cur, level, &bp);
old_bn = bp ? xfs_buf_daddr(bp) : XFS_BUF_DADDR_NULL;
numrecs = xfs_btree_get_numrecs(block);
/* Check that the new entry is being inserted in the right place. */ if (ptr <= numrecs) { if (level == 0) {
ASSERT(cur->bc_ops->recs_inorder(cur, rec,
xfs_btree_rec_addr(cur, ptr, block)));
} else {
ASSERT(cur->bc_ops->keys_inorder(cur, key,
xfs_btree_key_addr(cur, ptr, block)));
}
} #endif
error = xfs_btree_debug_check_ptr(cur, ptrp, 0, level); if (error) goto error0;
/* 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) {
ASSERT(cur->bc_ops->keys_inorder(cur, 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;
/* Now put the new data in, bump numrecs and log it. */
xfs_btree_copy_recs(cur, rp, rec, 1);
xfs_btree_set_numrecs(block, ++numrecs);
xfs_btree_log_recs(cur, bp, ptr, numrecs); #ifdef DEBUG if (ptr < numrecs) {
ASSERT(cur->bc_ops->recs_inorder(cur, 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);
error0: if (ncur)
xfs_btree_del_cursor(ncur, error); return error;
}
/* *Inserttherecordatthepointreferencedbycur. * *Amulti-levelsplitofthetreeoninsertwillinvalidatetheoriginal *cursor.Allcallersofthisfunctionshouldassumethatthecursoris *nolongervalidandrevalidateit.
*/ 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_key bkey; /* key of block to insert */ union xfs_btree_key *key; union xfs_btree_rec rec; /* record to insert */
level = 0;
ncur = NULL;
pcur = cur;
key = &bkey;
xfs_btree_set_ptr_null(cur, &nptr);
/* Make a key out of the record data to be inserted, and save it. */
cur->bc_ops->init_rec_from_cur(cur, &rec);
cur->bc_ops->init_key_from_rec(key, &rec);
if (XFS_IS_CORRUPT(cur->bc_mp, i != 1)) {
xfs_btree_mark_sick(cur);
error = -EFSCORRUPTED; goto error0;
}
level++;
/* *Seeifthecursorwejustusedistrash. *Can'ttrashthecaller'scursor,butotherwiseweshould *ifncurisanewcursororwe'reabouttobedone.
*/ 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_flags & XFS_BTREE_STAGING))
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));
*stat = i; return0;
error0: return error;
}
/* Move the records from a child leaf block to the root block. */ STATICvoid
xfs_btree_demote_leaf_child( struct xfs_btree_cur *cur, struct xfs_btree_block *cblock, int numrecs)
{ union xfs_btree_rec *rp; union xfs_btree_rec *crp; struct xfs_btree_block *broot;
/* *Movethekeyptrsfromachildnodeblocktotherootblock. * *Sincethekeyptrsizedoesnotchange,allwehavetodoisincreasethe *treeheight,copythekeyptrstothenewinternalnode(cblock),shrink *theroot,andcopythepointersthere.
*/ STATICint
xfs_btree_demote_node_child( struct xfs_btree_cur *cur, struct xfs_btree_block *cblock, int level, int numrecs)
{ struct xfs_btree_block *block; union xfs_btree_key *ckp; union xfs_btree_key *kp; union xfs_btree_ptr *cpp; union xfs_btree_ptr *pp; int i; int error;
/* Excise the entries being deleted. */ if (level > 0) { /* It's a nonleaf. operate on keys and ptrs */ union xfs_btree_key *lkp; union xfs_btree_ptr *lpp;
/* *Ifthere'sarightsibling,seeifit'soktoshiftanentry *outofit.
*/ if (!xfs_btree_ptr_is_null(cur, &rptr)) { /* *Movethetempcursortothelastentryinthenextblock. *Actuallyanyentrybutthefirstwouldsuffice.
*/
i = xfs_btree_lastrec(tcur, level); if (XFS_IS_CORRUPT(cur->bc_mp, i != 1)) {
xfs_btree_mark_sick(cur);
error = -EFSCORRUPTED; goto error0;
}
error = xfs_btree_increment(tcur, level, &i); if (error) goto error0; if (XFS_IS_CORRUPT(cur->bc_mp, i != 1)) {
xfs_btree_mark_sick(cur);
error = -EFSCORRUPTED; goto error0;
}
i = xfs_btree_lastrec(tcur, level); if (XFS_IS_CORRUPT(cur->bc_mp, i != 1)) {
xfs_btree_mark_sick(cur);
error = -EFSCORRUPTED; goto error0;
}
/* Grab a pointer to the block. */
right = xfs_btree_get_block(tcur, level, &rbp); #ifdef DEBUG
error = xfs_btree_check_block(tcur, right, level, rbp); if (error) goto error0; #endif /* Grab the current block number, for future use. */
xfs_btree_get_sibling(tcur, right, &cptr, XFS_BB_LEFTSIB);
/* *Ifrightblockisfullenoughsothatremovingoneentry *won'tmakeittooempty,andleft-shiftinganentryout *ofrighttousworks,we'redone.
*/ if (xfs_btree_get_numrecs(right) - 1 >=
cur->bc_ops->get_minrecs(tcur, level)) {
error = xfs_btree_lshift(tcur, level, &i); if (error) goto error0; if (i) {
ASSERT(xfs_btree_get_numrecs(block) >=
cur->bc_ops->get_minrecs(tcur, level));
/* *Otherwise,grabthenumberofrecordsinrightfor *futurereference,andfixupthetempcursortopoint *toourblockagain(lastrecord).
*/
rrecs = xfs_btree_get_numrecs(right); if (!xfs_btree_ptr_is_null(cur, &lptr)) {
i = xfs_btree_firstrec(tcur, level); if (XFS_IS_CORRUPT(cur->bc_mp, i != 1)) {
xfs_btree_mark_sick(cur);
error = -EFSCORRUPTED; goto error0;
}
error = xfs_btree_decrement(tcur, level, &i); if (error) goto error0; if (XFS_IS_CORRUPT(cur->bc_mp, i != 1)) {
xfs_btree_mark_sick(cur);
error = -EFSCORRUPTED; goto error0;
}
}
}
/* *Ifthere'saleftsibling,seeifit'soktoshiftanentry *outofit.
*/ if (!xfs_btree_ptr_is_null(cur, &lptr)) { /* *Movethetempcursortothefirstentryinthe *previousblock.
*/
i = xfs_btree_firstrec(tcur, level); if (XFS_IS_CORRUPT(cur->bc_mp, i != 1)) {
xfs_btree_mark_sick(cur);
error = -EFSCORRUPTED; goto error0;
}
error = xfs_btree_decrement(tcur, level, &i); if (error) goto error0;
i = xfs_btree_firstrec(tcur, level); if (XFS_IS_CORRUPT(cur->bc_mp, i != 1)) {
xfs_btree_mark_sick(cur);
error = -EFSCORRUPTED; goto error0;
}
/* Grab a pointer to the block. */
left = xfs_btree_get_block(tcur, level, &lbp); #ifdef DEBUG
error = xfs_btree_check_block(cur, left, level, lbp); if (error) goto error0; #endif /* Grab the current block number, for future use. */
xfs_btree_get_sibling(tcur, left, &cptr, XFS_BB_RIGHTSIB);
/* *Ifleftblockisfullenoughsothatremovingoneentry *won'tmakeittooempty,andright-shiftinganentryout *oflefttousworks,we'redone.
*/ if (xfs_btree_get_numrecs(left) - 1 >=
cur->bc_ops->get_minrecs(tcur, level)) {
error = xfs_btree_rshift(tcur, level, &i); if (error) goto error0; if (i) {
ASSERT(xfs_btree_get_numrecs(block) >=
cur->bc_ops->get_minrecs(tcur, level));
xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR);
tcur = NULL; if (level == 0)
cur->bc_levels[0].ptr++;
/* *We'renowgoingtojoin"left"and"right"bymovingallthestuff *in"right"to"left"anddeleting"right".
*/
XFS_BTREE_STATS_ADD(cur, moves, rrecs); if (level > 0) { /* It's a non-leaf. Move keys and pointers. */ union xfs_btree_key *lkp; /* left btree key */ union xfs_btree_ptr *lpp; /* left address pointer */ union xfs_btree_key *rkp; /* right btree key */ union xfs_btree_ptr *rpp; /* right address pointer */
/* If there is a right sibling, point it to the remaining block. */
xfs_btree_get_sibling(cur, left, &cptr, XFS_BB_RIGHTSIB); if (!xfs_btree_ptr_is_null(cur, &cptr)) {
error = xfs_btree_read_buf_block(cur, &cptr, 0, &rrblock, &rrbp); if (error) goto error0;
xfs_btree_set_sibling(cur, rrblock, &lptr, XFS_BB_LEFTSIB);
xfs_btree_log_block(cur, rrbp, XFS_BB_LEFTSIB);
}
/* Free the deleted block. */
error = xfs_btree_free_block(cur, rbp); if (error) goto error0;
/* Return value means the next level up has something to do. */
*stat = 2; return0;
error0: if (tcur)
xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR); return error;
}
/* *Deletetherecordpointedtobycur. *Thecursorreferstotheplacewheretherecordwas(couldbeinserted) *whentheoperationreturns.
*/ int/* error */
xfs_btree_delete( struct xfs_btree_cur *cur, int *stat) /* success/failure */
{ int error; /* error return value */ int level; int i; bool joined = false;
/* *Goupthetree,startingatleaflevel. * *If2isreturnedthenajoinwasdone;gotothenextlevel. *Otherwisewearedone.
*/ for (level = 0, i = 2; i == 2; level++) {
error = xfs_btree_delrec(cur, level, &i); if (error) goto error0; if (i == 2)
joined = true;
}
/* *Ifwecombinedblocksaspartofdeletingtherecord,delrecwon't *haveupdatedtheparenthighkeyssowehavetodothathere.
*/ if (joined && (cur->bc_ops->geom_flags & XFS_BTGEO_OVERLAPPING)) {
error = xfs_btree_updkeys_force(cur, 0); if (error) goto error0;
}
if (i == 0) { for (level = 1; level < cur->bc_nlevels; level++) { if (cur->bc_levels[level].ptr == 0) {
error = xfs_btree_decrement(cur, level, &i); if (error) goto error0; break;
}
}
}
*stat = i; return0;
error0: return error;
}
/* *Getthedatafromthepointed-torecord.
*/ int/* error */
xfs_btree_get_rec( struct xfs_btree_cur *cur, /* btree cursor */ union xfs_btree_rec **recp, /* output: btree record */ int *stat) /* output: success/failure */
{ struct xfs_btree_block *block; /* btree block */ struct xfs_buf *bp; /* buffer pointer */ int ptr; /* record number */ #ifdef DEBUG int error; /* error return value */ #endif
/* Visit a block in a btree. */ STATICint
xfs_btree_visit_block( struct xfs_btree_cur *cur, int level,
xfs_btree_visit_blocks_fn fn, void *data)
{ struct xfs_btree_block *block; struct xfs_buf *bp; union xfs_btree_ptr rptr, bufptr; int error;
/* do right sibling readahead */
xfs_btree_readahead(cur, level, XFS_BTCUR_RIGHTRA);
block = xfs_btree_get_block(cur, level, &bp);
/* process the block */
error = fn(cur, level, data); if (error) return error;
/* now read rh sibling block for next iteration */
xfs_btree_get_sibling(cur, block, &rptr, XFS_BB_RIGHTSIB); if (xfs_btree_ptr_is_null(cur, &rptr)) return -ENOENT;
/* Visit every block in a btree. */ int
xfs_btree_visit_blocks( struct xfs_btree_cur *cur,
xfs_btree_visit_blocks_fn fn, unsignedint flags, void *data)
{ union xfs_btree_ptr lptr; int level; struct xfs_btree_block *block = NULL; int error = 0;
xfs_btree_init_ptr_from_cur(cur, &lptr);
/* for each level */ for (level = cur->bc_nlevels - 1; level >= 0; level--) { /* grab the left hand block */
error = xfs_btree_lookup_get_block(cur, level, &lptr, &block); if (error) return error;
/* readahead the left most block for the next level down */ if (level > 0) { union xfs_btree_ptr *ptr;
advloop: /* Move on to the next record. */
error = xfs_btree_increment(cur, 0, &stat); if (error) break;
}
out: return error;
}
/* *Queryanoverlappedintervalbtreeforallrecordsoverlappingagiven *interval.Thisfunctionroughlyfollowsthealgorithmgivenin *"IntervalTrees"of_IntroductiontoAlgorithms_,whichissection *14.3inthe2ndand3rdeditions. * *First,generatekeysforthelowandhighrecordspassedin. * *Foranyleafnode,generatethehighandlowkeysfortherecord. *Iftherecordkeysoverlapwiththequerylow/highkeys,passthe *recordtothefunctioniterator. * *Foranyinternalnode,comparethelowandhighkeysofeach *pointeragainstthequerylow/highkeys.Ifthere'sanoverlap, *followthepointer. * *Asanoptimization,westopscanningablockwhenwefindalowkey *thatisgreaterthanthequery'shighkey.
*/ STATICint
xfs_btree_overlapped_query_range( struct xfs_btree_cur *cur, constunion xfs_btree_key *low_key, constunion xfs_btree_key *high_key,
xfs_btree_query_range_fn fn, void *priv)
{ union xfs_btree_ptr ptr; union xfs_btree_ptr *pp; union xfs_btree_key rec_key; union xfs_btree_key rec_hkey; union xfs_btree_key *lkp; union xfs_btree_key *hkp; union xfs_btree_rec *recp; struct xfs_btree_block *block; int level; struct xfs_buf *bp; int i; int error;
/* Load the root of the btree. */
level = cur->bc_nlevels - 1;
xfs_btree_init_ptr_from_cur(cur, &ptr);
error = xfs_btree_lookup_get_block(cur, level, &ptr, &block); if (error) return error;
xfs_btree_get_block(cur, level, &bp);
trace_xfs_btree_overlapped_query_range(cur, level, bp); #ifdef DEBUG
error = xfs_btree_check_block(cur, block, level, bp); if (error) goto out; #endif
cur->bc_levels[level].ptr = 1;
while (level < cur->bc_nlevels) {
block = xfs_btree_get_block(cur, level, &bp);
/* End of node, pop back towards the root. */ if (cur->bc_levels[level].ptr >
be16_to_cpu(block->bb_numrecs)) {
pop_up: if (level < cur->bc_nlevels - 1)
cur->bc_levels[level + 1].ptr++;
level++; continue;
}
if (level == 0) { /* Handle a leaf node. */
recp = xfs_btree_rec_addr(cur, cur->bc_levels[0].ptr,
block);
/* Query a btree for all records. */ int
xfs_btree_query_all( struct xfs_btree_cur *cur,
xfs_btree_query_range_fn fn, void *priv)
{ union xfs_btree_key low_key; union xfs_btree_key high_key;
/* Count the blocks in a btree and return the result in *blocks. */ int
xfs_btree_count_blocks( struct xfs_btree_cur *cur,
xfs_filblks_t *blocks)
{
*blocks = 0; return xfs_btree_visit_blocks(cur, xfs_btree_count_blocks_helper,
XFS_BTREE_VISIT_ALL, blocks);
}
/* Compare two btree pointers. */ int
xfs_btree_cmp_two_ptrs( struct xfs_btree_cur *cur, constunion xfs_btree_ptr *a, constunion xfs_btree_ptr *b)
{ if (cur->bc_ops->ptr_len == XFS_BTREE_LONG_PTR_LEN) return cmp_int(be64_to_cpu(a->l), be64_to_cpu(b->l)); return cmp_int(be32_to_cpu(a->s), be32_to_cpu(b->s));
}
struct xfs_btree_has_records { /* Keys for the start and end of the range we want to know about. */ union xfs_btree_key start_key; union xfs_btree_key end_key;
/* Mask for key comparisons, if desired. */ constunion xfs_btree_key *key_mask;
/* Highest record key we've seen so far. */ union xfs_btree_key high_key;
/* Are there more records in this btree? */ bool
xfs_btree_has_more_records( struct xfs_btree_cur *cur)
{ struct xfs_btree_block *block; struct xfs_buf *bp;
block = xfs_btree_get_block(cur, 0, &bp);
/* There are still records in this block. */ if (cur->bc_levels[0].ptr < xfs_btree_get_numrecs(block)) returntrue;
/* There are more record blocks. */ if (cur->bc_ops->ptr_len == XFS_BTREE_LONG_PTR_LEN) return block->bb_u.l.bb_rightsib != cpu_to_be64(NULLFSBLOCK); else return block->bb_u.s.bb_rightsib != cpu_to_be32(NULLAGBLOCK);
}
/* Set up all the btree cursor caches. */ int __init
xfs_btree_init_cur_caches(void)
{ int error;
error = xfs_allocbt_init_cur_cache(); if (error) return error;
error = xfs_inobt_init_cur_cache(); if (error) goto err;
error = xfs_bmbt_init_cur_cache(); if (error) goto err;
error = xfs_rmapbt_init_cur_cache(); if (error) goto err;
error = xfs_refcountbt_init_cur_cache(); if (error) goto err;
error = xfs_rtrmapbt_init_cur_cache(); if (error) goto err;
error = xfs_rtrefcountbt_init_cur_cache(); if (error) goto err;
¤ Diese beiden folgenden Angebotsgruppen bietet das Unternehmen0.207Angebot
(Wie Sie bei der Firma Beratungs- und Dienstleistungen beauftragen können 2026-09-28)
¤