5 * Brad Boyer (flar@allandria.com)
6 * (C) 2003 Ardis Technologies <roman@ardistech.com>
8 * Search routines for btrees
11 #include <linux/slab.h>
14 int hfs_find_init(struct hfs_btree
*tree
, struct hfs_find_data
*fd
)
20 ptr
= kmalloc(tree
->max_key_len
* 2 + 4, GFP_KERNEL
);
24 fd
->key
= ptr
+ tree
->max_key_len
+ 2;
25 dprint(DBG_BNODE_REFS
, "find_init: %d (%p)\n", tree
->cnid
, __builtin_return_address(0));
26 down(&tree
->tree_lock
);
30 void hfs_find_exit(struct hfs_find_data
*fd
)
32 hfs_bnode_put(fd
->bnode
);
33 kfree(fd
->search_key
);
34 dprint(DBG_BNODE_REFS
, "find_exit: %d (%p)\n", fd
->tree
->cnid
, __builtin_return_address(0));
35 up(&fd
->tree
->tree_lock
);
39 /* Find the record in bnode that best matches key (not greater than...)*/
40 int __hfs_brec_find(struct hfs_bnode
*bnode
, struct hfs_find_data
*fd
)
49 e
= bnode
->num_recs
- 1;
53 len
= hfs_brec_lenoff(bnode
, rec
, &off
);
54 keylen
= hfs_brec_keylen(bnode
, rec
);
55 if (keylen
== HFS_BAD_KEYLEN
) {
59 hfs_bnode_read(bnode
, fd
->key
, off
, keylen
);
60 cmpval
= bnode
->tree
->keycmp(fd
->key
, fd
->search_key
);
71 if (rec
!= e
&& e
>= 0) {
72 len
= hfs_brec_lenoff(bnode
, e
, &off
);
73 keylen
= hfs_brec_keylen(bnode
, e
);
74 if (keylen
== HFS_BAD_KEYLEN
) {
78 hfs_bnode_read(bnode
, fd
->key
, off
, keylen
);
83 fd
->keylength
= keylen
;
84 fd
->entryoffset
= off
+ keylen
;
85 fd
->entrylength
= len
- keylen
;
89 /* Traverse a B*Tree from the root to a leaf finding best fit to key */
90 /* Return allocated copy of node found, set recnum to best record */
91 int hfs_brec_find(struct hfs_find_data
*fd
)
93 struct hfs_btree
*tree
;
94 struct hfs_bnode
*bnode
;
101 hfs_bnode_put(fd
->bnode
);
106 height
= tree
->depth
;
110 bnode
= hfs_bnode_find(tree
, nidx
);
112 res
= PTR_ERR(bnode
);
116 if (bnode
->height
!= height
)
118 if (bnode
->type
!= (--height
? HFS_NODE_INDEX
: HFS_NODE_LEAF
))
120 bnode
->parent
= parent
;
122 res
= __hfs_brec_find(bnode
, fd
);
129 hfs_bnode_read(bnode
, &data
, fd
->entryoffset
, 4);
130 nidx
= be32_to_cpu(data
);
131 hfs_bnode_put(bnode
);
137 printk(KERN_ERR
"hfs: inconsistency in B*Tree (%d,%d,%d,%u,%u)\n",
138 height
, bnode
->height
, bnode
->type
, nidx
, parent
);
141 hfs_bnode_put(bnode
);
145 int hfs_brec_read(struct hfs_find_data
*fd
, void *rec
, int rec_len
)
149 res
= hfs_brec_find(fd
);
152 if (fd
->entrylength
> rec_len
)
154 hfs_bnode_read(fd
->bnode
, rec
, fd
->entryoffset
, fd
->entrylength
);
158 int hfs_brec_goto(struct hfs_find_data
*fd
, int cnt
)
160 struct hfs_btree
*tree
;
161 struct hfs_bnode
*bnode
;
163 u16 off
, len
, keylen
;
170 while (cnt
> fd
->record
) {
171 cnt
-= fd
->record
+ 1;
172 fd
->record
= bnode
->num_recs
- 1;
178 hfs_bnode_put(bnode
);
179 bnode
= hfs_bnode_find(tree
, idx
);
181 res
= PTR_ERR(bnode
);
188 while (cnt
>= bnode
->num_recs
- fd
->record
) {
189 cnt
-= bnode
->num_recs
- fd
->record
;
196 hfs_bnode_put(bnode
);
197 bnode
= hfs_bnode_find(tree
, idx
);
199 res
= PTR_ERR(bnode
);
207 len
= hfs_brec_lenoff(bnode
, fd
->record
, &off
);
208 keylen
= hfs_brec_keylen(bnode
, fd
->record
);
209 if (keylen
== HFS_BAD_KEYLEN
) {
214 fd
->keylength
= keylen
;
215 fd
->entryoffset
= off
+ keylen
;
216 fd
->entrylength
= len
- keylen
;
217 hfs_bnode_read(bnode
, fd
->key
, off
, keylen
);