implement generic xfs_btree_lookup
PATCH 12/26 implement generic xfs_btree_lookup
From: Dave Chinner <[email protected]>
[hch: split out from bigger patch and minor adaptions]
Signed-off-by Christoph Hellwig <[email protected]>
fs/xfs/xfs_btree.c +221 -0
@@ -1151,3 +1151,224 @@ error0:return error; } + +STATIC int +xfs_btree_lookup_get_block ( +struct xfs_btree_cur *cur,/* btree cursor */ +int level,/* level in the btree */ +union xfs_btree_ptr *pp,/* ptr to btree block */ +struct xfs_btree_block **blkp)/* return btree block */ +{ +struct xfs_buf *bp;/* buffer pointer for btree block */ +int error =0 ; + +/* special case the root block if in an inode */ +if ((cur->bc_flags &XFS_BTREE_ROOT_IN_INODE ) && + (level == cur->bc_nlevels -1 )) { + *blkp = cur->bc_ops->get_root_from_inode (cur); +return 0 ; + } + +/* +* If the old buffer at this level for the disk address we are +* looking for re-use it. +* +* Otherwise throw it away and get a new one. +*/ + bp = cur->bc_bufs[level]; +if (bp &&XFS_BUF_ADDR (bp) ==xfs_btree_ptr_to_daddr (cur, pp)) { + *blkp =XFS_BUF_TO_BLOCK (bp); +return 0 ; + } + + error =xfs_btree_read_buf_block (cur, pp, level,0 , blkp, &bp); +if (error) +return error; + +xfs_btree_setbuf (cur, level, bp); +return 0 ; +} + +/* +* Get current search key. For level 0 we don't actually have a key +* structure so we make one up from the record. For all other levels +* we just return the right key. +*/ +STATIC union xfs_btree_key * +xfs_lookup_get_search_key ( +struct xfs_btree_cur *cur, +int level, +int keyno, +struct xfs_btree_block *block, +union xfs_btree_key *kp) +{ +if (level ==0 ) { +union xfs_btree_rec *rp; + + rp = cur->bc_ops->rec_addr (cur, keyno, block); + cur->bc_ops->init_key_from_rec (cur, kp, rp); +return kp; + } + +return cur->bc_ops->key_addr (cur, keyno, block); +} + +/* +* 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. +*/ +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 */ +__int64_t diff;/* difference for the current key */ +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_TRACE_CURSOR (cur,XBT_ENTRY ); +XFS_BTREE_TRACE_ARGI (cur, dir); + +XFS_BTREE_STATS_INC (cur, lookup); + + block =NULL ; + keyno =0 ; + +/* initialise start pointer from cursor */ + cur->bc_ops->init_ptr_from_cur (cur, &ptr); + pp = &ptr; + +/* +* 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--) { +/* 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 (diff ==0 ) { +/* +* If we already had a key match at a higher level, we +* know we need to use the first entry in this block. +*/ + 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. */ +ASSERT (level ==0 && cur->bc_nlevels ==1 ); + + cur->bc_ptrs[0 ] = dir !=XFS_LOOKUP_LE ; +XFS_BTREE_TRACE_CURSOR (cur,XBT_EXIT ); + *stat =0 ; +return 0 ; + } + +/* 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); + +/* +* Compute difference to get next direction: +* - less than, move right +* - greater than, move left +* - equal, we're done +*/ + diff = cur->bc_ops->key_diff (cur, kp); +if (diff <0 ) + low = keyno +1 ; +else if (diff >0 ) + high = keyno -1 ; +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 ; + pp = cur->bc_ops->ptr_addr (cur, keyno, block); + +#ifdef DEBUG + error =xfs_btree_check_ptr (cur, pp,0 , level); +if (error) + goto error0; +#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. +*/ +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; + + cur->bc_ptrs[0 ] = keyno; + error =xfs_btree_increment (cur,0 , &i); +if (error) + goto error0; +XFS_WANT_CORRUPTED_RETURN (i ==1 ); +XFS_BTREE_TRACE_CURSOR (cur,XBT_EXIT ); + *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 >xfs_btree_get_numrecs (block)) + *stat =0 ; +else if (dir !=XFS_LOOKUP_EQ || diff ==0 ) + *stat =1 ; +else + *stat =0 ; +XFS_BTREE_TRACE_CURSOR (cur,XBT_EXIT ); +return 0 ; + +error0: +XFS_BTREE_TRACE_CURSOR (cur,XBT_ERROR ); +return error; +}
fs/xfs/xfs_btree.h +16 -0
@@ -194,6 +194,21 @@ struct xfs_btree_ops {/* return address of btree structures */ union xfs_btree_ptr *(*ptr_addr)(struct xfs_btree_cur *cur,int index,struct xfs_btree_block *block); +union xfs_btree_key *(*key_addr)(struct xfs_btree_cur *cur,int index, +struct xfs_btree_block *block); +union xfs_btree_rec *(*rec_addr)(struct xfs_btree_cur *cur,int index, +struct xfs_btree_block *block); + +/* init values of btree structures */ +void (*init_key_from_rec)(struct xfs_btree_cur *cur, +union xfs_btree_key *key, +union xfs_btree_rec *rec); +void (*init_ptr_from_cur)(struct xfs_btree_cur *cur, +union xfs_btree_ptr *ptr); + +/* difference between key value and cursor value */ +__int64_t (*key_diff)(struct xfs_btree_cur *cur, +union xfs_btree_key *key);/* btree tracing */ #ifdef XFS_BTREE_TRACE
@@ -512,6 +527,7 @@ xfs_btree_setbuf(int xfs_btree_increment (struct xfs_btree_cur *,int ,int *);int xfs_btree_decrement (struct xfs_btree_cur *,int ,int *); +int xfs_btree_lookup (struct xfs_btree_cur *,xfs_lookup_t ,int *);/*
fs/xfs/xfs_alloc_btree.c +69 -264
364 lines not on this page · raw message
fs/xfs/xfs_ialloc_btree.c +56 -259
346 lines not on this page · raw message
fs/xfs/xfs_bmap_btree.c +50 -168
249 lines not on this page · raw message
fs/xfs/xfs_alloc.c +48 -0
54 lines not on this page · raw message
fs/xfs/xfs_alloc_btree.h +0 -20
@@ -114,26 +114,6 @@ extern int xfs_alloc_get_rec(struct xfs_extern int xfs_alloc_insert (struct xfs_btree_cur *cur,int *stat);/* -* Lookup the record equal to [bno, len] in the btree given by cur. -*/ -extern int xfs_alloc_lookup_eq (struct xfs_btree_cur *cur,xfs_agblock_t bno, -xfs_extlen_t len,int *stat); - -/* -* Lookup the first record greater than or equal to [bno, len] -* in the btree given by cur. -*/ -extern int xfs_alloc_lookup_ge (struct xfs_btree_cur *cur,xfs_agblock_t bno, -xfs_extlen_t len,int *stat); - -/* -* Lookup the first record less than or equal to [bno, len] -* in the btree given by cur. -*/ -extern int xfs_alloc_lookup_le (struct xfs_btree_cur *cur,xfs_agblock_t bno, -xfs_extlen_t len,int *stat); - -/* * Update the record referred to by cur, to the value given by [bno, len]. * This either works (return 0) or gets an EFSCORRUPTED error. */
fs/xfs/xfs_bmap.c +29 -0
@@ -402,6 +402,35 @@ xfs_bmap_disk_count_leaves(* Bmap internal routines. */ +STATIC int /* error */ +xfs_bmbt_lookup_eq ( +struct xfs_btree_cur *cur, +xfs_fileoff_t off, +xfs_fsblock_t bno, +xfs_filblks_t len, +int *stat)/* success/failure */ +{ + cur->bc_rec.b.br_startoff = off; + cur->bc_rec.b.br_startblock = bno; + cur->bc_rec.b.br_blockcount = len; +return xfs_btree_lookup (cur,XFS_LOOKUP_EQ , stat); +} + +STATIC int /* error */ +xfs_bmbt_lookup_ge ( +struct xfs_btree_cur *cur, +xfs_fileoff_t off, +xfs_fsblock_t bno, +xfs_filblks_t len, +int *stat)/* success/failure */ +{ + cur->bc_rec.b.br_startoff = off; + cur->bc_rec.b.br_startblock = bno; + cur->bc_rec.b.br_blockcount = len; +return xfs_btree_lookup (cur,XFS_LOOKUP_GE , stat); +} + +/* * Called from xfs_bmap_add_attrfork to handle btree format files. */
fs/xfs/xfs_ialloc.c +53 -0
59 lines not on this page · raw message
fs/xfs/xfs_ialloc.h +15 -0
@@ -154,6 +154,21 @@ xfs_ialloc_pagi_init(struct xfs_trans *tp,/* transaction pointer */ xfs_agnumber_t agno); /* allocation group number */ +/* +* Lookup the first record greater than or equal to ino +* in the btree given by cur. +*/ +int xfs_inobt_lookup_ge (struct xfs_btree_cur *cur,xfs_agino_t ino, +__int32_t fcnt,xfs_inofree_t free,int *stat); + +/* +* Lookup the first record less than or equal to ino +* in the btree given by cur. +*/ +int xfs_inobt_lookup_le (struct xfs_btree_cur *cur,xfs_agino_t ino, +__int32_t fcnt,xfs_inofree_t free,int *stat); + +#endif /* __KERNEL__ */ #endif /* __XFS_IALLOC_H__ */
fs/xfs/xfs_ialloc_btree.h +0 -20
@@ -136,26 +136,6 @@ extern int xfs_inobt_get_rec(struct xfs_extern int xfs_inobt_insert (struct xfs_btree_cur *cur,int *stat);/* -* Lookup the record equal to ino in the btree given by cur. -*/ -extern int xfs_inobt_lookup_eq (struct xfs_btree_cur *cur,xfs_agino_t ino, -__int32_t fcnt,xfs_inofree_t free,int *stat); - -/* -* Lookup the first record greater than or equal to ino -* in the btree given by cur. -*/ -extern int xfs_inobt_lookup_ge (struct xfs_btree_cur *cur,xfs_agino_t ino, -__int32_t fcnt,xfs_inofree_t free,int *stat); - -/* -* Lookup the first record less than or equal to ino -* in the btree given by cur. -*/ -extern int xfs_inobt_lookup_le (struct xfs_btree_cur *cur,xfs_agino_t ino, -__int32_t fcnt,xfs_inofree_t free,int *stat); - -/* * Update the record referred to by cur, to the value given * by [ino, fcnt, free]. * This either works (return 0) or gets an EFSCORRUPTED error.
fs/xfs/xfs_bmap_btree.h +0 -4
@@ -254,10 +254,6 @@ extern int xfs_bmbt_insert(struct xfs_btextern 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 ); -extern int xfs_bmbt_lookup_eq (struct xfs_btree_cur *,xfs_fileoff_t , -xfs_fsblock_t ,xfs_filblks_t ,int *); -extern int xfs_bmbt_lookup_ge (struct xfs_btree_cur *,xfs_fileoff_t , -xfs_fsblock_t ,xfs_filblks_t ,int *);/* * Give the bmap btree a new root block. Copy the old broot contents