📄 xfs_alloc_btree.c
字号:
*/STATIC voidxfs_alloc_log_ptrs( xfs_btree_cur_t *cur, /* btree cursor */ xfs_buf_t *bp, /* buffer containing btree block */ int pfirst, /* index of first pointer to log */ int plast) /* index of last pointer to log */{ xfs_alloc_block_t *block; /* btree block to log from */ int first; /* first byte offset logged */ int last; /* last byte offset logged */ xfs_alloc_ptr_t *pp; /* block-pointer pointer in btree blk */ block = XFS_BUF_TO_ALLOC_BLOCK(bp); pp = XFS_ALLOC_PTR_ADDR(block, 1, cur); first = (int)((xfs_caddr_t)&pp[pfirst - 1] - (xfs_caddr_t)block); last = (int)(((xfs_caddr_t)&pp[plast] - 1) - (xfs_caddr_t)block); xfs_trans_log_buf(cur->bc_tp, bp, first, last);}/* * Log records from a btree block (leaf). */STATIC voidxfs_alloc_log_recs( xfs_btree_cur_t *cur, /* btree cursor */ xfs_buf_t *bp, /* buffer containing btree block */ int rfirst, /* index of first record to log */ int rlast) /* index of last record to log */{ xfs_alloc_block_t *block; /* btree block to log from */ int first; /* first byte offset logged */ int last; /* last byte offset logged */ xfs_alloc_rec_t *rp; /* record pointer for btree block */ block = XFS_BUF_TO_ALLOC_BLOCK(bp); rp = XFS_ALLOC_REC_ADDR(block, 1, cur);#ifdef DEBUG { xfs_agf_t *agf; xfs_alloc_rec_t *p; agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); for (p = &rp[rfirst - 1]; p <= &rp[rlast - 1]; p++) ASSERT(be32_to_cpu(p->ar_startblock) + be32_to_cpu(p->ar_blockcount) <= be32_to_cpu(agf->agf_length)); }#endif first = (int)((xfs_caddr_t)&rp[rfirst - 1] - (xfs_caddr_t)block); last = (int)(((xfs_caddr_t)&rp[rlast] - 1) - (xfs_caddr_t)block); xfs_trans_log_buf(cur->bc_tp, bp, first, last);}/* * Lookup the record. The cursor is made to point to it, based on dir. * Return 0 if can't find any such record, 1 for success. */STATIC int /* error */xfs_alloc_lookup( xfs_btree_cur_t *cur, /* btree cursor */ xfs_lookup_t dir, /* <=, ==, or >= */ int *stat) /* success/failure */{ xfs_agblock_t agbno; /* a.g. relative btree block number */ xfs_agnumber_t agno; /* allocation group number */ xfs_alloc_block_t *block=NULL; /* current btree block */ int diff; /* difference for the current key */ int error; /* error return value */ int keyno=0; /* current key number */ int level; /* level in the btree */ xfs_mount_t *mp; /* file system mount point */ XFS_STATS_INC(xs_abt_lookup); /* * Get the allocation group header, and the root block number. */ mp = cur->bc_mp; { xfs_agf_t *agf; /* a.g. freespace header */ agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); agno = be32_to_cpu(agf->agf_seqno); agbno = be32_to_cpu(agf->agf_roots[cur->bc_btnum]); } /* * Iterate over each level in the btree, starting at the root. * For each level above the leaves, find the key we need, based * on the lookup record, then follow the corresponding block * pointer down to the next level. */ for (level = cur->bc_nlevels - 1, diff = 1; level >= 0; level--) { xfs_buf_t *bp; /* buffer pointer for btree block */ xfs_daddr_t d; /* disk address of btree block */ /* * Get the disk address we're looking for. */ d = XFS_AGB_TO_DADDR(mp, agno, agbno); /* * If the old buffer at this level is for a different block, * throw it away, otherwise just use it. */ bp = cur->bc_bufs[level]; if (bp && XFS_BUF_ADDR(bp) != d) bp = NULL; if (!bp) { /* * Need to get a new buffer. Read it, then * set it in the cursor, releasing the old one. */ if ((error = xfs_btree_read_bufs(mp, cur->bc_tp, agno, agbno, 0, &bp, XFS_ALLOC_BTREE_REF))) return error; xfs_btree_setbuf(cur, level, bp); /* * Point to the btree block, now that we have the buffer */ block = XFS_BUF_TO_ALLOC_BLOCK(bp); if ((error = xfs_btree_check_sblock(cur, block, level, bp))) return error; } else block = XFS_BUF_TO_ALLOC_BLOCK(bp); /* * If we already had a key match at a higher level, we know * we need to use the first entry in this block. */ if (diff == 0) keyno = 1; /* * Otherwise we need to search this block. Do a binary search. */ else { int high; /* high entry number */ xfs_alloc_key_t *kkbase=NULL;/* base of keys in block */ xfs_alloc_rec_t *krbase=NULL;/* base of records in block */ int low; /* low entry number */ /* * Get a pointer to keys or records. */ if (level > 0) kkbase = XFS_ALLOC_KEY_ADDR(block, 1, cur); else krbase = XFS_ALLOC_REC_ADDR(block, 1, cur); /* * Set low and high entry numbers, 1-based. */ low = 1; if (!(high = be16_to_cpu(block->bb_numrecs))) { /* * If the block is empty, the tree must * be an empty leaf. */ ASSERT(level == 0 && cur->bc_nlevels == 1); cur->bc_ptrs[0] = dir != XFS_LOOKUP_LE; *stat = 0; return 0; } /* * Binary search the block. */ while (low <= high) { xfs_extlen_t blockcount; /* key value */ xfs_agblock_t startblock; /* key value */ XFS_STATS_INC(xs_abt_compare); /* * keyno is average of low and high. */ keyno = (low + high) >> 1; /* * Get startblock & blockcount. */ if (level > 0) { xfs_alloc_key_t *kkp; kkp = kkbase + keyno - 1; startblock = be32_to_cpu(kkp->ar_startblock); blockcount = be32_to_cpu(kkp->ar_blockcount); } else { xfs_alloc_rec_t *krp; krp = krbase + keyno - 1; startblock = be32_to_cpu(krp->ar_startblock); blockcount = be32_to_cpu(krp->ar_blockcount); } /* * Compute difference to get next direction. */ if (cur->bc_btnum == XFS_BTNUM_BNO) diff = (int)startblock - (int)cur->bc_rec.a.ar_startblock; else if (!(diff = (int)blockcount - (int)cur->bc_rec.a.ar_blockcount)) diff = (int)startblock - (int)cur->bc_rec.a.ar_startblock; /* * Less than, move right. */ if (diff < 0) low = keyno + 1; /* * Greater than, move left. */ else if (diff > 0) high = keyno - 1; /* * Equal, we're done. */ else break; } } /* * If there are more levels, set up for the next level * by getting the block number and filling in the cursor. */ if (level > 0) { /* * If we moved left, need the previous key number, * unless there isn't one. */ if (diff > 0 && --keyno < 1) keyno = 1; agbno = be32_to_cpu(*XFS_ALLOC_PTR_ADDR(block, keyno, cur));#ifdef DEBUG if ((error = xfs_btree_check_sptr(cur, agbno, level))) return error;#endif cur->bc_ptrs[level] = keyno; } } /* * Done with the search. * See if we need to adjust the results. */ if (dir != XFS_LOOKUP_LE && diff < 0) { keyno++; /* * If ge search and we went off the end of the block, but it's * not the last block, we're in the wrong block. */ if (dir == XFS_LOOKUP_GE && keyno > be16_to_cpu(block->bb_numrecs) && be32_to_cpu(block->bb_rightsib) != NULLAGBLOCK) { int i; cur->bc_ptrs[0] = keyno; if ((error = xfs_alloc_increment(cur, 0, &i))) return error; XFS_WANT_CORRUPTED_RETURN(i == 1); *stat = 1; return 0; } } else if (dir == XFS_LOOKUP_LE && diff > 0) keyno--; cur->bc_ptrs[0] = keyno; /* * Return if we succeeded or not. */ if (keyno == 0 || keyno > be16_to_cpu(block->bb_numrecs)) *stat = 0; else *stat = ((dir != XFS_LOOKUP_EQ) || (diff == 0)); return 0;}/* * Move 1 record left from cur/level if possible. * Update cur to reflect the new path. */STATIC int /* error */xfs_alloc_lshift( xfs_btree_cur_t *cur, /* btree cursor */ int level, /* level to shift record on */ int *stat) /* success/failure */{ int error; /* error return value */#ifdef DEBUG int i; /* loop index */#endif xfs_alloc_key_t key; /* key value for leaf level upward */ xfs_buf_t *lbp; /* buffer for left neighbor block */ xfs_alloc_block_t *left; /* left neighbor btree block */ int nrec; /* new number of left block entries */ xfs_buf_t *rbp; /* buffer for right (current) block */ xfs_alloc_block_t *right; /* right (current) btree block */ xfs_alloc_key_t *rkp=NULL; /* key pointer for right block */ xfs_alloc_ptr_t *rpp=NULL; /* address pointer for right block */ xfs_alloc_rec_t *rrp=NULL; /* record pointer for right block */ /* * Set up variables for this block as "right". */ rbp = cur->bc_bufs[level]; right = XFS_BUF_TO_ALLOC_BLOCK(rbp);#ifdef DEBUG if ((error = xfs_btree_check_sblock(cur, right, level, rbp))) return error;#endif /* * If we've got no left sibling then we can't shift an entry left. */ if (be32_to_cpu(right->bb_leftsib) == NULLAGBLOCK) { *stat = 0; return 0; } /* * If the cursor entry is the one that would be moved, don't * do it... it's too complicated. */ if (cur->bc_ptrs[level] <= 1) { *stat = 0; return 0; } /* * Set up the left neighbor as "left". */ if ((error = xfs_btree_read_bufs(cur->bc_mp, cur->bc_tp, cur->bc_private.a.agno, be32_to_cpu(right->bb_leftsib), 0, &lbp, XFS_ALLOC_BTREE_REF))) return error; left = XFS_BUF_TO_ALLOC_BLOCK(lbp); if ((error = xfs_btree_check_sblock(cur, left, level, lbp))) return error; /* * If it's full, it can't take another entry. */ if (be16_to_cpu(left->bb_numrecs) == XFS_ALLOC_BLOCK_MAXRECS(level, cur)) { *stat = 0; return 0; } nrec = be16_to_cpu(left->bb_numrecs) + 1; /* * If non-leaf, copy a key and a ptr to the left block. */ if (level > 0) { xfs_alloc_key_t *lkp; /* key pointer for left block */ xfs_alloc_ptr_t *lpp; /* address pointer for left block */ lkp = XFS_ALLOC_KEY_ADDR(left, nrec, cur); rkp = XFS_ALLOC_KEY_ADDR(right, 1, cur); *lkp = *rkp; xfs_alloc_log_keys(cur, lbp, nrec, nrec); lpp = XFS_ALLOC_PTR_ADDR(left, nrec, cur); rpp = XFS_ALLOC_PTR_ADDR(right, 1, cur);#ifdef DEBUG if ((error = xfs_btree_check_sptr(cur, be32_to_cpu(*rpp), level))) return error;#endif *lpp = *rpp; xfs_alloc_log_ptrs(cur, lbp, nrec, nrec); xfs_btree_check_key(cur->bc_btnum, lkp - 1, lkp); } /* * If leaf, copy a record to the left block. */ else { xfs_alloc_rec_t *lrp; /* record pointer for left block */ lrp = XFS_ALLOC_REC_ADDR(left, nrec, cur); rrp = XFS_ALLOC_REC_ADDR(right, 1, cur); *lrp = *rrp; xfs_alloc_log_recs(cur, lbp, nrec, nrec); xfs_btree_check_rec(cur->bc_btnum, lrp - 1, lrp); } /* * Bump and log left's numrecs, decrement and log right's numrecs. */ be16_add(&left->bb_numrecs, 1); xfs_alloc_log_block(cur->bc_tp, lbp, XFS_BB_NUMRECS); be16_add(&right->bb_numrecs, -1); xfs_alloc_log_block(cur->bc_tp, rbp, XFS_BB_NUMRECS); /* * Slide the contents of right down one entry. */ if (level > 0) {#ifdef DEBUG for (i = 0; i < be16_to_cpu(right->bb_numrecs); i++) { if ((error = xfs_btree_check_sptr(cur, be32_to_cpu(rpp[i + 1]), level))) return error; }#endif memmove(rkp, rkp + 1, be16_to_cpu(right->bb_numrecs) * sizeof(*rkp)); memmove(rpp, rpp + 1, be16_to_cpu(right->bb_numrecs) * sizeof(*rpp)); xfs_alloc_log_keys(cur, rbp, 1, be16_to_cpu(right->bb_numrecs)); xfs_alloc_log_ptrs(cur, rbp, 1, be16_to_cpu(right->bb_numrecs)); } else { memmove(rrp, rrp + 1, be16_to_cpu(right->bb_numrecs) * sizeof(*rrp)); xfs_alloc_log_recs(cur, rbp, 1, be16_to_cpu(right->bb_numrecs)); key.ar_startblock = rrp->ar_startblock; key.ar_blockcount = rrp->ar_blockcount; rkp = &key; } /* * Update the parent key values of right. */ if ((error = xfs_alloc_updkey(cur, rkp, level + 1))) return error; /* * Slide the cursor value left one. */ cur->bc_ptrs[level]--; *stat = 1; return 0;}/* * Allocate a new root block, fill it in. */STATIC int /* error */xfs_alloc_newroot( xfs_btree_cur_t *cur, /* btree cursor */ int *stat) /* success/failure */{ int error; /* error return value */ xfs_agblock_t lbno; /* left block number */ xfs_buf_t *lbp; /* left btree buffer */ xfs_alloc_block_t *left; /* left btree block */ xfs_mount_t *mp; /* mount structure */ xfs_agblock_t nbno; /* new block number */ xfs_buf_t *nbp; /* new (root) buffer */ xfs_alloc_block_t *new; /* new (root) btree block */ int nptr; /* new value for key index, 1 or 2 */ xfs_agblock_t rbno; /* right block number */ xfs_buf_t *rbp; /* right btree buffer */ xfs_alloc_block_t *right; /* right btree block */ mp = cur->bc_mp; ASSERT(cur->bc_nlevels < XFS_AG_MAXLEVELS(mp)); /* * Get a buffer from the freelist blocks, for the new root. */ error = xfs_alloc_get_freelist(cur->bc_tp, cur->bc_private.a.agbp, &nbno, 1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -