]> git.saurik.com Git - apple/xnu.git/blob - bsd/hfs/hfs_chash.c
xnu-344.49.tar.gz
[apple/xnu.git] / bsd / hfs / hfs_chash.c
1 /*
2 * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25
26 /*
27 * Copyright (c) 1982, 1986, 1989, 1991, 1993, 1995
28 * The Regents of the University of California. All rights reserved.
29 *
30 * Redistribution and use in source and binary forms, with or without
31 * modification, are permitted provided that the following conditions
32 * are met:
33 * 1. Redistributions of source code must retain the above copyright
34 * notice, this list of conditions and the following disclaimer.
35 * 2. Redistributions in binary form must reproduce the above copyright
36 * notice, this list of conditions and the following disclaimer in the
37 * documentation and/or other materials provided with the distribution.
38 * 3. All advertising materials mentioning features or use of this software
39 * must display the following acknowledgement:
40 * This product includes software developed by the University of
41 * California, Berkeley and its contributors.
42 * 4. Neither the name of the University nor the names of its contributors
43 * may be used to endorse or promote products derived from this software
44 * without specific prior written permission.
45 *
46 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56 * SUCH DAMAGE.
57 *
58 * @(#)hfs_chash.c
59 * derived from @(#)ufs_ihash.c 8.7 (Berkeley) 5/17/95
60 */
61
62 #include <sys/param.h>
63 #include <sys/systm.h>
64 #include <sys/vnode.h>
65 #include <sys/malloc.h>
66 #include <sys/proc.h>
67 #include <sys/queue.h>
68
69 #include "hfs_cnode.h"
70
71
72 /*
73 * Structures associated with cnode caching.
74 */
75 LIST_HEAD(cnodehashhead, cnode) *cnodehashtbl;
76 u_long cnodehash; /* size of hash table - 1 */
77 #define CNODEHASH(device, inum) (&cnodehashtbl[((device) + (inum)) & cnodehash])
78 struct slock hfs_chash_slock;
79
80 /*
81 * Initialize cnode hash table.
82 */
83 __private_extern__
84 void
85 hfs_chashinit()
86 {
87 cnodehashtbl = hashinit(desiredvnodes, M_HFSMNT, &cnodehash);
88 simple_lock_init(&hfs_chash_slock);
89 }
90
91
92 /*
93 * Use the device, inum pair to find the incore cnode.
94 *
95 * If it is in core, but locked, wait for it.
96 *
97 * If the requested vnode (fork) is not available, then
98 * take a reference on the other vnode (fork) so that
99 * the upcoming getnewvnode can not aquire it.
100 */
101 __private_extern__
102 struct cnode *
103 hfs_chashget(dev_t dev, ino_t inum, int wantrsrc,
104 struct vnode **vpp, struct vnode **rvpp)
105 {
106 struct proc *p = current_proc();
107 struct cnode *cp;
108 struct vnode *vp;
109 int error;
110
111 *vpp = NULLVP;
112 *rvpp = NULLVP;
113 /*
114 * Go through the hash list
115 * If a cnode is in the process of being cleaned out or being
116 * allocated, wait for it to be finished and then try again.
117 */
118 loop:
119 simple_lock(&hfs_chash_slock);
120 for (cp = CNODEHASH(dev, inum)->lh_first; cp; cp = cp->c_hash.le_next) {
121 if ((cp->c_fileid != inum) || (cp->c_dev != dev))
122 continue;
123 if (ISSET(cp->c_flag, C_ALLOC)) {
124 /*
125 * cnode is being created. Wait for it to finish.
126 */
127 SET(cp->c_flag, C_WALLOC);
128 simple_unlock(&hfs_chash_slock);
129 (void) tsleep((caddr_t)cp, PINOD, "hfs_chashget-1", 0);
130 goto loop;
131 }
132 if (ISSET(cp->c_flag, C_TRANSIT)) {
133 /*
134 * cnode is getting reclaimed wait for
135 * the operation to complete and return
136 * error
137 */
138 SET(cp->c_flag, C_WTRANSIT);
139 simple_unlock(&hfs_chash_slock);
140 (void)tsleep((caddr_t)cp, PINOD, "hfs_chashget-2", 0);
141 goto loop;
142 }
143 if (cp->c_flag & C_NOEXISTS)
144 continue;
145
146 /*
147 * Try getting the desired vnode first. If
148 * it isn't available then take a reference
149 * on the other vnode.
150 */
151 vp = wantrsrc ? cp->c_rsrc_vp : cp->c_vp;
152 if (vp == NULLVP)
153 vp = wantrsrc ? cp->c_vp : cp->c_rsrc_vp;
154 if (vp == NULLVP)
155 panic("hfs_chashget: orphaned cnode in hash");
156
157 simple_lock(&vp->v_interlock);
158 simple_unlock(&hfs_chash_slock);
159 if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p))
160 goto loop;
161 else if (cp->c_flag & C_NOEXISTS) {
162 /*
163 * While we were blocked the cnode got deleted.
164 */
165 vput(vp);
166 goto loop;
167 }
168
169 if (VNODE_IS_RSRC(vp))
170 *rvpp = vp;
171 else
172 *vpp = vp;
173 /*
174 * Note that vget can block before aquiring the
175 * cnode lock. So we need to check if the vnode
176 * we wanted was created while we blocked.
177 */
178 if (wantrsrc && *rvpp == NULL && cp->c_rsrc_vp) {
179 error = vget(cp->c_rsrc_vp, 0, p);
180 vput(*vpp); /* ref no longer needed */
181 *vpp = NULL;
182 if (error)
183 goto loop;
184 *rvpp = cp->c_rsrc_vp;
185
186 } else if (!wantrsrc && *vpp == NULL && cp->c_vp) {
187 error = vget(cp->c_vp, 0, p);
188 vput(*rvpp); /* ref no longer needed */
189 *rvpp = NULL;
190 if (error)
191 goto loop;
192 *vpp = cp->c_vp;
193 }
194 return (cp);
195 }
196 simple_unlock(&hfs_chash_slock);
197 return (NULL);
198 }
199
200
201 /*
202 * Insert a cnode into the hash table.
203 */
204 __private_extern__
205 void
206 hfs_chashinsert(struct cnode *cp)
207 {
208 if (cp->c_fileid == 0)
209 panic("hfs_chashinsert: trying to insert file id 0");
210 simple_lock(&hfs_chash_slock);
211 LIST_INSERT_HEAD(CNODEHASH(cp->c_dev, cp->c_fileid), cp, c_hash);
212 simple_unlock(&hfs_chash_slock);
213 }
214
215
216 /*
217 * Remove a cnode from the hash table.
218 */
219 __private_extern__
220 void
221 hfs_chashremove(struct cnode *cp)
222 {
223 simple_lock(&hfs_chash_slock);
224 LIST_REMOVE(cp, c_hash);
225 cp->c_hash.le_next = NULL;
226 cp->c_hash.le_prev = NULL;
227 simple_unlock(&hfs_chash_slock);
228 }
229