1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59#include <sys/param.h>
60#include <sys/systm.h>
61#include <sys/vnode.h>
62#include <sys/kernel.h>
63#include <sys/malloc.h>
64#include <sys/proc.h>
65#include <sys/queue.h>
66
67
68#include "hfs.h"
69#include "hfs_cnode.h"
70
71extern lck_attr_t * hfs_lock_attr;
72extern lck_grp_t * hfs_mutex_group;
73extern lck_grp_t * hfs_rwlock_group;
74
75lck_grp_t * chash_lck_grp;
76lck_grp_attr_t * chash_lck_grp_attr;
77lck_attr_t * chash_lck_attr;
78
79
80
81
82LIST_HEAD(cnodehashhead, cnode) *cnodehashtbl;
83u_long cnodehash;
84#define CNODEHASH(device, inum) (&cnodehashtbl[((device) + (inum)) & cnodehash])
85
86lck_mtx_t hfs_chash_mutex;
87
88
89
90
91
92__private_extern__
93void
94hfs_chashinit()
95{
96 cnodehashtbl = hashinit(desiredvnodes, M_HFSMNT, &cnodehash);
97
98 chash_lck_grp_attr= lck_grp_attr_alloc_init();
99 lck_grp_attr_setstat(chash_lck_grp_attr);
100 chash_lck_grp = lck_grp_alloc_init("cnode_hash", chash_lck_grp_attr);
101
102 chash_lck_attr = lck_attr_alloc_init();
103
104
105 lck_mtx_init(&hfs_chash_mutex, chash_lck_grp, chash_lck_attr);
106}
107
108
109
110
111
112
113
114__private_extern__
115struct vnode *
116hfs_chash_getvnode(dev_t dev, ino_t inum, int wantrsrc, int skiplock)
117{
118 struct cnode *cp;
119 struct vnode *vp;
120 int error;
121 uint32_t vid;
122
123
124
125
126
127
128loop:
129 lck_mtx_lock(&hfs_chash_mutex);
130 for (cp = CNODEHASH(dev, inum)->lh_first; cp; cp = cp->c_hash.le_next) {
131 if ((cp->c_fileid != inum) || (cp->c_dev != dev))
132 continue;
133
134 if (ISSET(cp->c_hflag, H_ALLOC | H_TRANSIT | H_ATTACH)) {
135 SET(cp->c_hflag, H_WAITING);
136
137 (void) msleep(cp, &hfs_chash_mutex, PDROP | PINOD,
138 "hfs_chash_getvnode", 0);
139 goto loop;
140 }
141
142
143
144
145
146
147 if (cp->c_flag & (C_NOEXISTS | C_DELETED)) {
148 continue;
149 }
150
151 vp = wantrsrc ? cp->c_rsrc_vp : cp->c_vp;
152 if (vp == NULLVP)
153 goto exit;
154
155 vid = vnode_vid(vp);
156 lck_mtx_unlock(&hfs_chash_mutex);
157
158 if ((error = vnode_getwithvid(vp, vid))) {
159
160
161
162
163 return (NULL);
164 }
165 if (!skiplock && hfs_lock(cp, HFS_EXCLUSIVE_LOCK) != 0) {
166 vnode_put(vp);
167 return (NULL);
168 }
169
170
171
172
173
174
175
176
177 if (cp->c_flag & (C_NOEXISTS | C_DELETED)) {
178 if (!skiplock)
179 hfs_unlock(cp);
180 vnode_put(vp);
181
182 return (NULL);
183 }
184 return (vp);
185 }
186exit:
187 lck_mtx_unlock(&hfs_chash_mutex);
188 return (NULL);
189}
190
191
192
193
194
195
196
197
198__private_extern__
199int
200hfs_chash_snoop(dev_t dev, ino_t inum, int (*callout)(const struct cat_desc *,
201 const struct cat_attr *, void *), void * arg)
202{
203 struct cnode *cp;
204 int result = ENOENT;
205
206
207
208
209
210
211 lck_mtx_lock(&hfs_chash_mutex);
212 for (cp = CNODEHASH(dev, inum)->lh_first; cp; cp = cp->c_hash.le_next) {
213 if ((cp->c_fileid != inum) || (cp->c_dev != dev))
214 continue;
215
216 if (!ISSET(cp->c_hflag, H_ALLOC | H_TRANSIT | H_ATTACH)) {
217 result = callout(&cp->c_desc, &cp->c_attr, arg);
218 }
219 break;
220 }
221 lck_mtx_unlock(&hfs_chash_mutex);
222 return (result);
223}
224
225
226
227
228
229
230
231
232__private_extern__
233struct cnode *
234hfs_chash_getcnode(dev_t dev, ino_t inum, struct vnode **vpp, int wantrsrc, int skiplock)
235{
236 struct cnode *cp;
237 struct cnode *ncp = NULL;
238 vnode_t vp;
239 uint32_t vid;
240
241
242
243
244
245
246loop:
247 lck_mtx_lock(&hfs_chash_mutex);
248
249loop_with_lock:
250 for (cp = CNODEHASH(dev, inum)->lh_first; cp; cp = cp->c_hash.le_next) {
251 if ((cp->c_fileid != inum) || (cp->c_dev != dev))
252 continue;
253
254
255
256 if (ISSET(cp->c_hflag, H_ALLOC | H_ATTACH | H_TRANSIT)) {
257 SET(cp->c_hflag, H_WAITING);
258
259 (void) msleep(cp, &hfs_chash_mutex, PINOD,
260 "hfs_chash_getcnode", 0);
261 goto loop_with_lock;
262 }
263
264
265
266
267
268
269 if (cp->c_flag & (C_NOEXISTS | C_DELETED)) {
270 continue;
271 }
272 vp = wantrsrc ? cp->c_rsrc_vp : cp->c_vp;
273 if (vp == NULL) {
274
275
276
277 SET(cp->c_hflag, H_ATTACH);
278
279 lck_mtx_unlock(&hfs_chash_mutex);
280 } else {
281 vid = vnode_vid(vp);
282
283 lck_mtx_unlock(&hfs_chash_mutex);
284
285 if (vnode_getwithvid(vp, vid))
286 goto loop;
287 }
288 if (ncp) {
289
290
291
292
293
294 FREE_ZONE(ncp, sizeof(struct cnode), M_HFSNODE);
295 ncp = NULL;
296 }
297 if (!skiplock && hfs_lock(cp, HFS_EXCLUSIVE_LOCK) != 0) {
298 if (vp != NULLVP)
299 vnode_put(vp);
300 lck_mtx_lock(&hfs_chash_mutex);
301
302 if (vp == NULLVP)
303 CLR(cp->c_hflag, H_ATTACH);
304 goto loop_with_lock;
305 }
306
307
308
309
310
311
312
313 if (cp->c_flag & (C_NOEXISTS | C_DELETED)) {
314 if (!skiplock)
315 hfs_unlock(cp);
316 if (vp != NULLVP)
317 vnode_put(vp);
318 lck_mtx_lock(&hfs_chash_mutex);
319
320 if (vp == NULLVP)
321 CLR(cp->c_hflag, H_ATTACH);
322 goto loop_with_lock;
323 }
324 *vpp = vp;
325 return (cp);
326 }
327
328
329
330
331 if (skiplock)
332 panic("%s - should never get here when skiplock is set \n", __FUNCTION__);
333
334 if (ncp == NULL) {
335 lck_mtx_unlock(&hfs_chash_mutex);
336
337 MALLOC_ZONE(ncp, struct cnode *, sizeof(struct cnode), M_HFSNODE, M_WAITOK);
338
339
340
341
342
343
344 goto loop;
345 }
346 bzero(ncp, sizeof(struct cnode));
347 SET(ncp->c_hflag, H_ALLOC);
348 ncp->c_fileid = inum;
349 ncp->c_dev = dev;
350 TAILQ_INIT(&ncp->c_hintlist);
351
352 lck_rw_init(&ncp->c_rwlock, hfs_rwlock_group, hfs_lock_attr);
353 if (!skiplock)
354 (void) hfs_lock(ncp, HFS_EXCLUSIVE_LOCK);
355
356
357 LIST_INSERT_HEAD(CNODEHASH(dev, inum), ncp, c_hash);
358 lck_mtx_unlock(&hfs_chash_mutex);
359
360 *vpp = NULL;
361 return (ncp);
362}
363
364
365__private_extern__
366void
367hfs_chashwakeup(struct cnode *cp, int hflags)
368{
369 lck_mtx_lock(&hfs_chash_mutex);
370
371 CLR(cp->c_hflag, hflags);
372
373 if (ISSET(cp->c_hflag, H_WAITING)) {
374 CLR(cp->c_hflag, H_WAITING);
375 wakeup((caddr_t)cp);
376 }
377 lck_mtx_unlock(&hfs_chash_mutex);
378}
379
380
381
382
383
384__private_extern__
385void
386hfs_chash_rehash(struct cnode *cp1, struct cnode *cp2)
387{
388 lck_mtx_lock(&hfs_chash_mutex);
389
390 LIST_REMOVE(cp1, c_hash);
391 LIST_REMOVE(cp2, c_hash);
392 LIST_INSERT_HEAD(CNODEHASH(cp1->c_dev, cp1->c_fileid), cp1, c_hash);
393 LIST_INSERT_HEAD(CNODEHASH(cp2->c_dev, cp2->c_fileid), cp2, c_hash);
394
395 lck_mtx_unlock(&hfs_chash_mutex);
396}
397
398
399
400
401
402__private_extern__
403int
404hfs_chashremove(struct cnode *cp)
405{
406 lck_mtx_lock(&hfs_chash_mutex);
407
408
409 if (ISSET(cp->c_hflag, H_ATTACH)) {
410 lck_mtx_unlock(&hfs_chash_mutex);
411 return (EBUSY);
412 }
413 LIST_REMOVE(cp, c_hash);
414 cp->c_hash.le_next = NULL;
415 cp->c_hash.le_prev = NULL;
416
417 lck_mtx_unlock(&hfs_chash_mutex);
418 return (0);
419}
420
421
422
423
424__private_extern__
425void
426hfs_chash_abort(struct cnode *cp)
427{
428 lck_mtx_lock(&hfs_chash_mutex);
429
430 LIST_REMOVE(cp, c_hash);
431 cp->c_hash.le_next = NULL;
432 cp->c_hash.le_prev = NULL;
433
434 CLR(cp->c_hflag, H_ATTACH | H_ALLOC);
435 if (ISSET(cp->c_hflag, H_WAITING)) {
436 CLR(cp->c_hflag, H_WAITING);
437 wakeup((caddr_t)cp);
438 }
439 lck_mtx_unlock(&hfs_chash_mutex);
440}
441
442
443
444
445
446__private_extern__
447void
448hfs_chash_mark_in_transit(struct cnode *cp)
449{
450 lck_mtx_lock(&hfs_chash_mutex);
451
452 SET(cp->c_hflag, H_TRANSIT);
453
454 lck_mtx_unlock(&hfs_chash_mutex);
455}
456