]>
git.saurik.com Git - apple/xnu.git/blob - bsd/hfs/hfs_vhash.c
8e403895f5610fb0ac48dcf3543217a9c891d71b
2 * Copyright (c) 1999 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@
23 /* Copyright (c) 1998 Apple Computer, Inc. All Rights Reserved */
25 * Copyright (c) 1982, 1986, 1989, 1991, 1993, 1995
26 * The Regents of the University of California. All rights reserved.
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
36 * 3. All advertising materials mentioning features or use of this software
37 * must display the following acknowledgement:
38 * This product includes software developed by the University of
39 * California, Berkeley and its contributors.
40 * 4. Neither the name of the University nor the names of its contributors
41 * may be used to endorse or promote products derived from this software
42 * without specific prior written permission.
44 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57 * derived from @(#)ufs_ihash.c 8.7 (Berkeley) 5/17/95
60 #include <sys/param.h>
61 #include <sys/systm.h>
62 #include <sys/vnode.h>
63 #include <sys/malloc.h>
65 #include <sys/queue.h>
72 * Structures associated with hfsnode cacheing.
74 LIST_HEAD(vhashhead
, hfsnode
) *vhashtbl
;
75 u_long vhash
; /* size of hash table - 1 */
76 #define HFSNODEHASH(device, nodeID) (&vhashtbl[((device) + (nodeID)) & vhash])
77 struct slock hfs_vhash_slock
;
80 * Initialize hfsnode hash table.
86 vhashtbl
= hashinit(desiredvnodes
, M_HFSMNT
, &vhash
);
87 simple_lock_init(&hfs_vhash_slock
);
91 * Use the device/dirID/forkType tuple to find the incore hfsnode, and return a pointer
92 * to it. If it is in core, but locked, wait for it.
94 * Acceptable forkTypes are kData, kRsrcFork, kDirectory, or kDefault which translates to either
95 * kDataFork or kDirectory
97 * While traversing the hash, expext that a hfsnode is in the midst of being allocated, if so,
98 * then sleep and try again
101 hfs_vhashget(dev
, nodeID
, forkType
)
106 struct proc
*p
= current_proc();
111 * Go through the hash list
112 * If a vnode is in the process of being cleaned out or being
113 * allocated, wait for it to be finished and then try again
116 simple_lock(&hfs_vhash_slock
);
117 for (hp
= HFSNODEHASH(dev
, nodeID
)->lh_first
; hp
; hp
= hp
->h_hash
.le_next
) {
118 if (hp
->h_nodeflags
& IN_ALLOCATING
) {
120 * vnode is being created. Wait for it to finish...
122 hp
->h_nodeflags
|= IN_WANT
;
123 simple_unlock(&hfs_vhash_slock
);
124 tsleep((caddr_t
)hp
, PINOD
, "hfs_vhashget", 0);
127 if ((H_FILEID(hp
) != nodeID
) || (H_DEV(hp
) != dev
) ||
128 (hp
->h_meta
->h_metaflags
& IN_NOEXISTS
))
131 /* SER XXX kDefault of meta data (ksysfile) is not assumed here */
132 if ( (forkType
== kAnyFork
) ||
133 (H_FORKTYPE(hp
) == forkType
) ||
134 ((forkType
== kDefault
) && ((H_FORKTYPE(hp
) == kDirectory
)
135 || (H_FORKTYPE(hp
) == kDataFork
)))) {
137 simple_lock(&vp
->v_interlock
);
138 simple_unlock(&hfs_vhash_slock
);
139 if (vget(vp
, LK_EXCLUSIVE
| LK_INTERLOCK
, p
))
144 simple_unlock(&hfs_vhash_slock
);
152 * Lock the hfsnode and insert the hfsnode into the hash table, and return it locked.
153 * Returns the sibling meta data if it exists, elses return NULL
156 hfs_vhashins_sibling(dev
, nodeID
, hp
, fm
)
160 struct hfsfilemeta
**fm
;
162 struct vhashhead
*ipp
;
164 struct hfsfilemeta
*tfm
;
167 lockmgr(&hp
->h_lock
, LK_EXCLUSIVE
, (struct slock
*)0, current_proc());
170 * Go through the hash list to see if a sibling exists
171 * If it does, store it to return
172 * If a vnode is in the process of being cleaned out or being
173 * allocated, wait for it to be finished and then try again
176 ipp
= HFSNODEHASH(dev
, nodeID
);
179 simple_lock(&hfs_vhash_slock
);
180 for (thp
= ipp
->lh_first
; thp
; thp
= thp
->h_hash
.le_next
) {
181 if (thp
->h_nodeflags
& IN_ALLOCATING
) {
183 * vnode is being created. Wait for it to finish...
185 thp
->h_nodeflags
|= IN_WANT
;
186 simple_unlock(&hfs_vhash_slock
);
187 tsleep((caddr_t
)thp
, PINOD
, "hfs_vhashins_sibling", 0);
190 if ((H_FILEID(thp
) == nodeID
) && (H_DEV(thp
) == dev
)) {
191 tfm
= hp
->h_meta
= thp
->h_meta
;
196 /* Add to sibling list..if it can have them */
197 if (tfm
&& (H_FORKTYPE(hp
)==kDataFork
|| H_FORKTYPE(hp
)==kRsrcFork
)) {
198 simple_lock(&tfm
->h_siblinglock
);
199 CIRCLEQ_INSERT_HEAD(&tfm
->h_siblinghead
, hp
, h_sibling
);
200 simple_unlock(&tfm
->h_siblinglock
);
203 LIST_INSERT_HEAD(ipp
, hp
, h_hash
);
204 simple_unlock(&hfs_vhash_slock
);
211 * Lock the hfsnode and insert the hfsnode into the hash table, and return it locked.
214 hfs_vhashins(dev
, nodeID
, hp
)
219 struct vhashhead
*ipp
;
221 DBG_ASSERT(hp
!= NULL
);
222 DBG_ASSERT(nodeID
!= 0);
224 lockmgr(&hp
->h_lock
, LK_EXCLUSIVE
, (struct slock
*)0, current_proc());
226 simple_lock(&hfs_vhash_slock
);
227 ipp
= HFSNODEHASH(dev
, nodeID
);
228 LIST_INSERT_HEAD(ipp
, hp
, h_hash
);
229 simple_unlock(&hfs_vhash_slock
);
234 * Remove the hfsnode from the hash table and then checks to see if another forks exists.
241 DBG_ASSERT(hp
!= NULL
);
242 DBG_ASSERT(hp
->h_meta
!= NULL
);
244 simple_lock(&hfs_vhash_slock
);
246 /* Test to see if there are siblings, should only apply to forks */
247 if (hp
->h_meta
!= NULL
&& hp
->h_meta
->h_siblinghead
.cqh_first
!= NULL
) {
248 simple_lock(&hp
->h_meta
->h_siblinglock
);
249 CIRCLEQ_REMOVE(&hp
->h_meta
->h_siblinghead
, hp
, h_sibling
);
250 simple_unlock(&hp
->h_meta
->h_siblinglock
);
253 LIST_REMOVE(hp
, h_hash
);
256 hp
->h_hash
.le_next
= NULL
;
257 hp
->h_hash
.le_prev
= NULL
;
261 simple_unlock(&hfs_vhash_slock
);
268 * Moves the entries from one bucket to another
269 * nodeID is the old bucket id
272 hfs_vhashmove(hp
, oldNodeID
)
276 struct vhashhead
*oldHeadIndex
, *newHeadIndex
;
277 struct hfsnode
*thp
, *nextNode
;
280 newNodeID
= H_FILEID(hp
);
281 oldHeadIndex
= HFSNODEHASH(H_DEV(hp
), oldNodeID
);
282 newHeadIndex
= HFSNODEHASH(H_DEV(hp
), newNodeID
);
284 /* If it is moving to the same bucket...then we are done */
285 if (oldHeadIndex
== newHeadIndex
)
290 * Go through the old hash list
291 * If there is a nodeid mismatch, or the nodeid doesnt match the current bucket
292 * remove it and add it to the right bucket.
293 * If a vnode is in the process of being cleaned out or being
294 * allocated, wait for it to be finished and then try again
296 simple_lock(&hfs_vhash_slock
);
297 for (nextNode
= oldHeadIndex
->lh_first
; nextNode
; ) {
298 if (nextNode
->h_nodeflags
& IN_ALLOCATING
) {
300 * vnode is being created. Wait for it to finish...
302 nextNode
->h_nodeflags
|= IN_WANT
;
303 simple_unlock(&hfs_vhash_slock
);
304 tsleep((caddr_t
)nextNode
, PINOD
, "hfs_vhashmove", 0);
309 nextNode
= nextNode
->h_hash
.le_next
;
310 if (newNodeID
== H_FILEID(thp
)) {
311 LIST_REMOVE(thp
, h_hash
);
312 thp
->h_hash
.le_next
= NULL
;
313 thp
->h_hash
.le_next
= NULL
;
314 LIST_INSERT_HEAD(newHeadIndex
, thp
, h_hash
);
318 simple_unlock(&hfs_vhash_slock
);
323 * This will test the hash entry for a given hfsnode
325 * 1. The uniqei existance of the node
326 * 2. All other nodes, proper membership to the hash
327 * 3. Proper termination of the hash
328 * 4. All members have a non-null h_meta
330 void hfs_vhash_dbg(hp
)
333 struct proc
*p
= current_proc(); /* XXX */
335 struct hfsnode
*thp
, *tthp
;
337 int wasFound
= false;
338 struct vhashhead
*ipp
, *jpp
;
339 dev_t dev
= H_DEV(hp
);
340 UInt32 nodeID
= H_FILEID(hp
);
341 UInt8 forkType
= H_FORKTYPE(hp
);
342 u_long forksfound
= 0;
344 if (forkType
==kDataFork
|| forkType
==kRsrcFork
)
348 DEBUG_BREAK_MSG(("hash_dgh: Null hfsnode"));
350 * Go through the hash list
351 * If a vnode is in the process of being cleaned out or being
352 * allocated, wait for it to be finished and then try again
354 ipp
= HFSNODEHASH(dev
, nodeID
);
357 simple_lock(&hfs_vhash_slock
);
358 for (thp
= ipp
->lh_first
; thp
; thp
= thp
->h_hash
.le_next
) {
359 if (thp
->h_nodeflags
& IN_ALLOCATING
) { /* Its in the process of being allocated */
360 simple_unlock(&hfs_vhash_slock
);
361 tsleep((caddr_t
)thp
, PINOD
, "hfs_vhash_ins_meta", 0);
365 if (thp
->h_meta
== NULL
)
366 DEBUG_BREAK_MSG(("hash_dgh: Null hfs_meta"));
367 jpp
= (HFSNODEHASH(H_DEV(thp
), H_FILEID(thp
)));
369 DEBUG_BREAK_MSG(("hash_dgh: Member on wrong hash"));
371 if ((H_FILEID(thp
) == nodeID
) && (H_DEV(thp
) == dev
)) {
374 DEBUG_BREAK_MSG(("hash_dgh: Too many siblings"));
375 if ((1<<H_FORKTYPE(thp
)) & forksfound
)
376 DEBUG_BREAK_MSG(("hash_dgh: Fork already found"));
377 forksfound
|= (1<<H_FORKTYPE(thp
));
379 if (H_FORKTYPE(thp
) == forkType
) {
380 if (wasFound
== true)
381 DEBUG_BREAK_MSG(("hash_dgh: Already found"));
386 simple_unlock(&hfs_vhash_slock
);
389 DEBUG_BREAK_MSG(("hash_dgh: Not found"));
393 #endif /* HFS_DIAGNOSTIC */