xfs_alloc_btree.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,070 行 · 第 1/5 页
C
2,070 行
*stat = 1; return 0;}/* * Log header fields from a btree block. */STATIC voidxfs_alloc_log_block( xfs_trans_t *tp, /* transaction pointer */ xfs_buf_t *bp, /* buffer containing btree block */ int fields) /* mask of fields: XFS_BB_... */{ int first; /* first byte offset logged */ int last; /* last byte offset logged */ static const short offsets[] = { /* table of offsets */ offsetof(xfs_alloc_block_t, bb_magic), offsetof(xfs_alloc_block_t, bb_level), offsetof(xfs_alloc_block_t, bb_numrecs), offsetof(xfs_alloc_block_t, bb_leftsib), offsetof(xfs_alloc_block_t, bb_rightsib), sizeof(xfs_alloc_block_t) }; xfs_btree_offsets(fields, offsets, XFS_BB_NUM_BITS, &first, &last); xfs_trans_log_buf(tp, bp, first, last);}/* * Log keys from a btree block (nonleaf). */STATIC voidxfs_alloc_log_keys( xfs_btree_cur_t *cur, /* btree cursor */ xfs_buf_t *bp, /* buffer containing btree block */ int kfirst, /* index of first key to log */ int klast) /* index of last key to log */{ xfs_alloc_block_t *block; /* btree block to log from */ int first; /* first byte offset logged */ xfs_alloc_key_t *kp; /* key pointer in btree block */ int last; /* last byte offset logged */ block = XFS_BUF_TO_ALLOC_BLOCK(bp); kp = XFS_ALLOC_KEY_ADDR(block, 1, cur); first = (int)((xfs_caddr_t)&kp[kfirst - 1] - (xfs_caddr_t)block); last = (int)(((xfs_caddr_t)&kp[klast] - 1) - (xfs_caddr_t)block); xfs_trans_log_buf(cur->bc_tp, bp, first, last);}/* * Log block pointer fields from a btree block (nonleaf). */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(INT_GET(p->ar_startblock, ARCH_CONVERT) + INT_GET(p->ar_blockcount, ARCH_CONVERT) <= INT_GET(agf->agf_length, ARCH_CONVERT)); }#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 = INT_GET(agf->agf_seqno, ARCH_CONVERT); agbno = INT_GET(agf->agf_roots[cur->bc_btnum], ARCH_CONVERT); } /* * 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 = (xfs_buf_t *)0; 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 = INT_GET(block->bb_numrecs, ARCH_CONVERT))) { /* * 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 = INT_GET(kkp->ar_startblock, ARCH_CONVERT); blockcount = INT_GET(kkp->ar_blockcount, ARCH_CONVERT); } else { xfs_alloc_rec_t *krp; krp = krbase + keyno - 1; startblock = INT_GET(krp->ar_startblock, ARCH_CONVERT); blockcount = INT_GET(krp->ar_blockcount, ARCH_CONVERT); } /* * 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 = INT_GET(*XFS_ALLOC_PTR_ADDR(block, keyno, cur), ARCH_CONVERT);#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 > INT_GET(block->bb_numrecs, ARCH_CONVERT) && INT_GET(block->bb_rightsib, ARCH_CONVERT) != 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 > INT_GET(block->bb_numrecs, ARCH_CONVERT)) *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 (INT_GET(right->bb_leftsib, ARCH_CONVERT) == 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, INT_GET(right->bb_leftsib, ARCH_CONVERT), 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 (INT_GET(left->bb_numrecs, ARCH_CONVERT) == XFS_ALLOC_BLOCK_MAXRECS(level, cur)) { *stat = 0; return 0; } nrec = INT_GET(left->bb_numrecs, ARCH_CONVERT) + 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, INT_GET(*rpp, ARCH_CONVERT), level))) return error;#endif *lpp = *rpp; /* INT_: copy */ 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 {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?