2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
22 #include "../headers/BTreesPrivate.h"
23 #include "sys/malloc.h"
34 * Each kernel thread can have it's own reserve of b-tree
35 * nodes. This reserve info is kept in a hash table.
37 * Don't forget to call BTReleaseReserve when you're finished
38 * or you will leave stale node reserves in the hash.
43 * BE CAREFUL WHEN INCREASING THE SIZE OF THIS STRUCT!
45 * It must remain equal in size to the opaque cat_cookie_t
46 * struct (in hfs_catalog.h).
49 LIST_ENTRY(nreserve
) nr_hash
; /* hash chain */
50 int nr_nodecnt
; /* count of nodes held in reserve */
51 int nr_newnodes
; /* nodes that were allocated */
52 struct vnode
*nr_btvp
; /* b-tree file vnode */
53 void *nr_tag
; /* unique tag (per thread) */
56 #define NR_GET_TAG() (current_act())
60 #define NR_HASH(btvp, tag) \
61 (&nr_hashtbl[((((int)(btvp)) >> 8) ^ ((int)(tag) >> 4)) & nr_hashmask])
63 LIST_HEAD(nodereserve
, nreserve
) *nr_hashtbl
;
68 /* Internal Node Reserve Hash Routines (private) */
69 static void nr_insert (struct vnode
*, struct nreserve
*nrp
, int);
70 static void nr_delete (struct vnode
*, struct nreserve
*nrp
, int *);
71 static int nr_lookup (struct vnode
*);
72 static void nr_update (struct vnode
*, int);
76 * BTReserveSetup - initialize the node reserve hash table
82 if (sizeof(struct nreserve
) != sizeof(cat_cookie_t
))
83 panic("BTReserveSetup: nreserve size != opaque struct size");
85 nr_hashtbl
= hashinit(NR_CACHE
, M_HFSMNT
, &nr_hashmask
);
90 * BTAvailNodes - obtain the actual available nodes (for current thread)
95 BTAvailableNodes(BTreeControlBlock
*btree
)
99 availNodes
= (SInt32
)btree
->freeNodes
- (SInt32
)btree
->reservedNodes
;
101 return (availNodes
+ nr_lookup(btree
->fileRefNum
));
106 * BTReserveSpace - obtain a node reserve (for current thread)
108 * Used by the Catalog Layer (hfs_catalog.c) to reserve space.
112 BTReserveSpace(FCB
*file
, int operations
, void* data
)
114 BTreeControlBlock
*btree
;
115 int rsrvNodes
, availNodes
, totalNodes
;
117 int inserts
, deletes
;
120 btree
= (BTreeControlBlockPtr
)file
->fcbBTCBPtr
;
122 REQUIRE_FILE_LOCK(btree
->fileRefNum
, true);
125 * The node reserve is based on the number of b-tree
126 * operations (insert/deletes) and the height of the
129 height
= btree
->treeDepth
;
130 inserts
= operations
& 0xffff;
131 deletes
= operations
>> 16;
133 rsrvNodes
= 1; /* allow for at least one root split */
135 rsrvNodes
+= (deletes
* (height
- 1)) - 1;
137 rsrvNodes
+= (inserts
* height
) + 1;
139 availNodes
= btree
->freeNodes
- btree
->reservedNodes
;
141 if (rsrvNodes
> availNodes
) {
142 totalNodes
= rsrvNodes
+ btree
->totalNodes
- availNodes
;
144 /* See if we also need a map node */
145 if (totalNodes
> CalcMapBits(btree
))
147 if ((err
= ExtendBTree(btree
, totalNodes
)))
151 btree
->reservedNodes
+= rsrvNodes
;
152 nr_insert(btree
->fileRefNum
, (struct nreserve
*)data
, rsrvNodes
);
158 * BTReleaseReserve - release the node reserve held by current thread
160 * Used by the Catalog Layer (hfs_catalog.c) to relinquish reserved space.
164 BTReleaseReserve(FCB
*file
, void* data
)
166 BTreeControlBlock
*btree
;
169 btree
= (BTreeControlBlockPtr
)file
->fcbBTCBPtr
;
171 REQUIRE_FILE_LOCK(btree
->fileRefNum
, true);
173 nr_delete(btree
->fileRefNum
, (struct nreserve
*)data
, &nodecnt
);
176 btree
->reservedNodes
-= nodecnt
;
182 * BTUpdateReserve - update a node reserve for allocations that occured.
186 BTUpdateReserve(BTreeControlBlockPtr btreePtr
, int nodes
)
188 nr_update(btreePtr
->fileRefNum
, nodes
);
192 /*----------------------------------------------------------------------------*/
193 /* Node Reserve Hash Functions (private) */
200 * Insert a new node reserve.
203 nr_insert(struct vnode
* btvp
, struct nreserve
*nrp
, int nodecnt
)
205 struct nodereserve
*nrhead
;
206 struct nreserve
*tmp_nrp
;
207 void * tag
= NR_GET_TAG();
210 * Check the cache - there may already be a reserve
212 nrhead
= NR_HASH(btvp
, tag
);
213 for (tmp_nrp
= nrhead
->lh_first
; tmp_nrp
;
214 tmp_nrp
= tmp_nrp
->nr_hash
.le_next
) {
215 if ((tmp_nrp
->nr_tag
== tag
) && (tmp_nrp
->nr_btvp
== btvp
)) {
221 nrp
->nr_nodecnt
= nodecnt
;
222 nrp
->nr_newnodes
= 0;
225 LIST_INSERT_HEAD(nrhead
, nrp
, nr_hash
);
230 * Delete a node reserve.
233 nr_delete(struct vnode
* btvp
, struct nreserve
*nrp
, int *nodecnt
)
235 void * tag
= NR_GET_TAG();
238 if ((nrp
->nr_tag
!= tag
) || (nrp
->nr_btvp
!= btvp
))
239 panic("nr_delete: invalid NR (%08x)", nrp
);
240 LIST_REMOVE(nrp
, nr_hash
);
241 *nodecnt
= nrp
->nr_nodecnt
;
242 bzero(nrp
, sizeof(struct nreserve
));
250 * Lookup a node reserve.
253 nr_lookup(struct vnode
* btvp
)
255 struct nodereserve
*nrhead
;
256 struct nreserve
*nrp
;
257 void* tag
= NR_GET_TAG();
259 nrhead
= NR_HASH(btvp
, tag
);
260 for (nrp
= nrhead
->lh_first
; nrp
; nrp
= nrp
->nr_hash
.le_next
) {
261 if ((nrp
->nr_tag
== tag
) && (nrp
->nr_btvp
== btvp
))
262 return (nrp
->nr_nodecnt
- nrp
->nr_newnodes
);
268 * Update a node reserve for any allocations that occured.
271 nr_update(struct vnode
* btvp
, int nodecnt
)
273 struct nodereserve
*nrhead
;
274 struct nreserve
*nrp
;
275 void* tag
= NR_GET_TAG();
277 nrhead
= NR_HASH(btvp
, tag
);
278 for (nrp
= nrhead
->lh_first
; nrp
; nrp
= nrp
->nr_hash
.le_next
) {
279 if ((nrp
->nr_tag
== tag
) && (nrp
->nr_btvp
== btvp
)) {
280 nrp
->nr_newnodes
+= nodecnt
;