|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
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.
11: *
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
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22:
23: /* Copyright (c) 1998 Apple Computer, Inc. All Rights Reserved */
24: /*
25: * Copyright (c) 1982, 1986, 1989, 1991, 1993, 1995
26: * The Regents of the University of California. All rights reserved.
27: *
28: * Redistribution and use in source and binary forms, with or without
29: * modification, are permitted provided that the following conditions
30: * are met:
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.
43: *
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
54: * SUCH DAMAGE.
55: *
56: * @(#)hfs_vhash.c
57: * derived from @(#)ufs_ihash.c 8.7 (Berkeley) 5/17/95
58: */
59:
60: #include <sys/param.h>
61: #include <sys/systm.h>
62: #include <sys/vnode.h>
63: #include <sys/malloc.h>
64: #include <sys/proc.h>
65: #include <sys/queue.h>
66:
67: #include "hfs.h"
68: #include "hfs_dbg.h"
69:
70:
71: /*
72: * Structures associated with hfsnode cacheing.
73: */
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;
78:
79: /*
80: * Initialize hfsnode hash table.
81: */
82: void
83: hfs_vhashinit()
84: {
85:
86: vhashtbl = hashinit(desiredvnodes, M_HFSMNT, &vhash);
87: simple_lock_init(&hfs_vhash_slock);
88: }
89:
90: /*
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.
93: *
94: * Acceptable forkTypes are kData, kRsrcFork, kDirectory, or kDefault which translates to either
95: * kDataFork or kDirectory
96: *
97: * While traversing the hash, expext that a hfsnode is in the midst of being allocated, if so,
98: * then sleep and try again
99: */
100: struct vnode *
101: hfs_vhashget(dev, nodeID, forkType)
102: dev_t dev;
103: UInt32 nodeID;
104: UInt8 forkType;
105: {
106: struct proc *p = current_proc(); /* XXX */
107: struct hfsnode *hp;
108: struct vnode *vp;
109:
110: DBG_ASSERT(forkType!=kUndefinedFork);
111: /*
112: * Go through the hash list
113: * If a vnode is in the process of being cleaned out or being
114: * allocated, wait for it to be finished and then try again
115: */
116: loop:
117: simple_lock(&hfs_vhash_slock);
118: for (hp = HFSNODEHASH(dev, nodeID)->lh_first; hp; hp = hp->h_hash.le_next) {
119: /* The vnode might be in an incomplete state, so sleep until its ready */
120: if (hp->h_nodeflags & IN_ALLOCATING) {
121: simple_unlock(&hfs_vhash_slock);
122: tsleep((caddr_t)hp, PINOD, "hfs_vhashlookup", 0);
123: goto loop;
124: };
125:
126: DBG_ASSERT(hp->h_meta != NULL);
127: if ((H_FILEID(hp) == nodeID) && (H_DEV(hp) == dev)) {
128: /* SER XXX kDefault of meta data (ksysfile) is not assumed here */
129: if ((H_FORKTYPE(hp) == forkType) ||
130: (forkType == kAnyFork) ||
131: ((forkType == kDefault) && ((H_FORKTYPE(hp) == kDirectory)
132: || (H_FORKTYPE(hp) == kDataFork)))) {
133: vp = HTOV(hp);
134: simple_lock(&vp->v_interlock);
135: simple_unlock(&hfs_vhash_slock);
136: if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p))
137: goto loop;
138: return (vp);
139: };
140: };
141: };
142: simple_unlock(&hfs_vhash_slock);
143: return (NULL);
144: }
145:
146:
147:
148:
149: /*
150: * Lock the hfsnode and insert the hfsnode into the hash table, and return it locked.
151: * Returns the sibling meta data if it exists, elses return NULL
152: */
153: void
154: hfs_vhashins_sibling(dev, nodeID, hp, fm)
155: dev_t dev;
156: UInt32 nodeID;
157: struct hfsnode *hp;
158: struct hfsfilemeta **fm;
159: {
160: struct vhashhead *ipp;
161: struct hfsnode *thp;
162: struct hfsfilemeta *tfm;
163:
164: DBG_ASSERT(fm != NULL);
165: DBG_ASSERT(hp != NULL);
166: DBG_ASSERT(hp->h_meta == NULL);
167: DBG_ASSERT(H_FORKTYPE(hp)==kDataFork || H_FORKTYPE(hp)==kRsrcFork);
168:
169: tfm = NULL;
170: lockmgr(&hp->h_lock, LK_EXCLUSIVE, (struct slock *)0, current_proc());
171:
172:
173: /*
174: * Go through the hash list to see if a sibling exists
175: * If it does, store it to return
176: * If a vnode is in the process of being cleaned out or being
177: * allocated, wait for it to be finished and then try again
178: */
179:
180: ipp = HFSNODEHASH(dev, nodeID);
181:
182: loop:
183: simple_lock(&hfs_vhash_slock);
184: for (thp = ipp->lh_first; thp; thp = thp->h_hash.le_next) {
185: if (thp->h_nodeflags & IN_ALLOCATING) { /* Its in the process of being allocated */
186: simple_unlock(&hfs_vhash_slock);
187: tsleep((caddr_t)thp, PINOD, "hfs_vhash_ins_meta", 0);
188: goto loop;
189: };
190:
191: DBG_ASSERT(thp->h_meta != NULL);
192: if ((H_FILEID(thp) == nodeID) && (H_DEV(thp) == dev)) {
193: tfm = hp->h_meta = thp->h_meta;
194: break;
195: };
196: };
197:
198: /* Add to sibling list..if it can have them */
199: if (tfm && (H_FORKTYPE(hp)==kDataFork || H_FORKTYPE(hp)==kRsrcFork)) {
200: DBG_ASSERT(tfm->h_siblinghead.cqh_first != NULL && tfm->h_siblinghead.cqh_last != NULL);
201: simple_lock(&tfm->h_siblinglock);
202: CIRCLEQ_INSERT_HEAD(&tfm->h_siblinghead, hp, h_sibling);
203: simple_unlock(&tfm->h_siblinglock);
204: };
205:
206: LIST_INSERT_HEAD(ipp, hp, h_hash);
207: simple_unlock(&hfs_vhash_slock);
208: *fm = tfm;
209: }
210:
211:
212:
213: /*
214: * Lock the hfsnode and insert the hfsnode into the hash table, and return it locked.
215: */
216: void
217: hfs_vhashins(dev, nodeID, hp)
218: dev_t dev;
219: UInt32 nodeID;
220: struct hfsnode *hp;
221: {
222: struct vhashhead *ipp;
223:
224: DBG_ASSERT(hp != NULL);
225: DBG_ASSERT(nodeID != 0);
226:
227: lockmgr(&hp->h_lock, LK_EXCLUSIVE, (struct slock *)0, current_proc());
228:
229: simple_lock(&hfs_vhash_slock);
230: ipp = HFSNODEHASH(dev, nodeID);
231: LIST_INSERT_HEAD(ipp, hp, h_hash);
232: simple_unlock(&hfs_vhash_slock);
233: }
234:
235:
236: /*
237: * Remove the hfsnode from the hash table and then checks to see if another forks exists.
238: */
239: void
240: hfs_vhashrem(hp)
241: struct hfsnode *hp;
242: {
243:
244: DBG_ASSERT(hp != NULL);
245: DBG_ASSERT(hp->h_meta != NULL);
246:
247: simple_lock(&hfs_vhash_slock);
248:
249: /* Test to see if there are siblings, should only apply to forks */
250: if (hp->h_meta->h_siblinghead.cqh_first != NULL) {
251: simple_lock(&hp->h_meta->h_siblinglock);
252: CIRCLEQ_REMOVE(&hp->h_meta->h_siblinghead, hp, h_sibling);
253: simple_unlock(&hp->h_meta->h_siblinglock);
254: };
255:
256: LIST_REMOVE(hp, h_hash);
257:
258: #if HFS_DIAGNOSTIC
259: hp->h_hash.le_next = NULL;
260: hp->h_hash.le_prev = NULL;
261: #endif
262:
263:
264: simple_unlock(&hfs_vhash_slock);
265:
266:
267: }
268:
269:
270: /*
271: * Moves the entries from one bucket to another
272: * nodeID is the old bucket id
273: */
274: void
275: hfs_vhashmove(hp, oldNodeID)
276: struct hfsnode *hp;
277: UInt32 oldNodeID;
278: {
279: struct vhashhead *oldHeadIndex, *newHeadIndex;
280: struct hfsnode *thp, *nextNode;
281: UInt32 newNodeID;
282:
283: DBG_ASSERT(hp != NULL);
284: DBG_ASSERT(hp->h_meta != NULL);
285:
286: newNodeID = H_FILEID(hp);
287:
288: oldHeadIndex = HFSNODEHASH(H_DEV(hp), oldNodeID);
289: newHeadIndex = HFSNODEHASH(H_DEV(hp), newNodeID);
290:
291: /* If it is moving to the same bucket...then we are done */
292: if (oldHeadIndex == newHeadIndex)
293: return;
294:
295: loop:
296:
297: /*
298: * Go through the old hash list
299: * If there is a nodeid mismatch, or the nodeid doesnt match the current bucket
300: * remove it and add it to the right bucket.
301: * If a vnode is in the process of being cleaned out or being
302: * allocated, wait for it to be finished and then try again
303: */
304: simple_lock(&hfs_vhash_slock);
305: for (nextNode = oldHeadIndex->lh_first; nextNode; ) {
306: if (nextNode->h_nodeflags & IN_ALLOCATING) { /* Its in the process of being allocated */
307: simple_unlock(&hfs_vhash_slock);
308: tsleep((caddr_t)nextNode, PINOD, "hfs_vhashmove", 0);
309: goto loop;
310: };
311:
312: DBG_ASSERT(nextNode->h_meta != NULL);
313: thp = nextNode;
314: nextNode = nextNode->h_hash.le_next;
315: if (newNodeID == H_FILEID(thp)) {
316: LIST_REMOVE(thp, h_hash);
317: thp->h_hash.le_next = NULL;
318: thp->h_hash.le_next = NULL;
319: LIST_INSERT_HEAD(newHeadIndex, thp, h_hash);
320: };
321: };
322:
323: simple_unlock(&hfs_vhash_slock);
324: }
325:
326: #if HFS_DIAGNOSTIC
327: /*
328: * This will test the hash entry for a given hfsnode
329: * It will test:
330: * 1. The uniqei existance of the node
331: * 2. All other nodes, proper membership to the hash
332: * 3. Proper termination of the hash
333: * 4. All members have a non-null h_meta
334: */
335: void hfs_vhash_dbg(hp)
336: struct hfsnode *hp;
337: {
338: struct proc *p = current_proc(); /* XXX */
339: struct vnode *vp;
340: struct hfsnode *thp, *tthp;
341: int maxsiblings = 1;
342: int wasFound = false;
343: struct vhashhead *ipp, *jpp;
344: dev_t dev = H_DEV(hp);
345: UInt32 nodeID = H_FILEID(hp);
346: UInt8 forkType = H_FORKTYPE(hp);
347: u_long forksfound = 0;
348:
349: if (forkType==kDataFork || forkType==kRsrcFork)
350: maxsiblings++;
351:
352: if (hp == NULL)
353: DEBUG_BREAK_MSG(("hash_dgh: Null hfsnode"));
354: /*
355: * Go through the hash list
356: * If a vnode is in the process of being cleaned out or being
357: * allocated, wait for it to be finished and then try again
358: */
359: ipp = HFSNODEHASH(dev, nodeID);
360:
361: loop:
362: simple_lock(&hfs_vhash_slock);
363: for (thp = ipp->lh_first; thp; thp = thp->h_hash.le_next) {
364: if (thp->h_nodeflags & IN_ALLOCATING) { /* Its in the process of being allocated */
365: simple_unlock(&hfs_vhash_slock);
366: tsleep((caddr_t)thp, PINOD, "hfs_vhash_ins_meta", 0);
367: goto loop;
368: };
369:
370: if (thp->h_meta == NULL)
371: DEBUG_BREAK_MSG(("hash_dgh: Null hfs_meta"));
372: jpp = (HFSNODEHASH(H_DEV(thp), H_FILEID(thp)));
373: if (ipp != jpp)
374: DEBUG_BREAK_MSG(("hash_dgh: Member on wrong hash"));
375:
376: if ((H_FILEID(thp) == nodeID) && (H_DEV(thp) == dev)) {
377: maxsiblings--;
378: if (maxsiblings < 0)
379: DEBUG_BREAK_MSG(("hash_dgh: Too many siblings"));
380: if ((1<<H_FORKTYPE(thp)) & forksfound)
381: DEBUG_BREAK_MSG(("hash_dgh: Fork already found"));
382: forksfound |= (1<<H_FORKTYPE(thp));
383:
384: if (H_FORKTYPE(thp) == forkType) {
385: if (wasFound == true)
386: DEBUG_BREAK_MSG(("hash_dgh: Already found"));
387: wasFound = true;
388: };
389: };
390: };
391: simple_unlock(&hfs_vhash_slock);
392:
393: if (! wasFound)
394: DEBUG_BREAK_MSG(("hash_dgh: Not found"));
395:
396: }
397:
398: #endif /* HFS_DIAGNOSTIC */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.