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