]>
Commit | Line | Data |
---|---|---|
9bccf70c A |
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 | #include <sys/param.h> | |
23 | #include <sys/systm.h> | |
24 | #include <sys/proc.h> | |
25 | #include <sys/vnode.h> | |
26 | #include <sys/mount.h> | |
27 | #include <sys/kernel.h> | |
28 | #include <sys/malloc.h> | |
29 | #include <sys/ubc.h> | |
30 | #include <sys/quota.h> | |
31 | ||
32 | #include <miscfs/specfs/specdev.h> | |
33 | #include <miscfs/fifofs/fifo.h> | |
34 | ||
35 | #include <hfs/hfs.h> | |
36 | #include <hfs/hfs_catalog.h> | |
37 | #include <hfs/hfs_cnode.h> | |
38 | #include <hfs/hfs_quota.h> | |
39 | ||
40 | extern int prtactive; | |
41 | ||
42 | ||
43 | extern void hfs_relnamehints(struct cnode *dcp); | |
44 | ||
45 | ||
46 | /* | |
47 | * Last reference to an cnode. If necessary, write or delete it. | |
48 | */ | |
49 | __private_extern__ | |
50 | int | |
51 | hfs_inactive(ap) | |
52 | struct vop_inactive_args /* { | |
53 | struct vnode *a_vp; | |
54 | } */ *ap; | |
55 | { | |
56 | struct vnode *vp = ap->a_vp; | |
57 | struct cnode *cp = VTOC(vp); | |
58 | struct hfsmount *hfsmp = VTOHFS(vp); | |
59 | struct proc *p = ap->a_p; | |
60 | struct timeval tv; | |
61 | int error = 0; | |
62 | int recycle = 0; | |
63 | int forkcount = 0; | |
64 | int truncated = 0; | |
b4c24cb9 | 65 | int started_tr = 0, grabbed_lock = 0; |
9bccf70c A |
66 | |
67 | if (prtactive && vp->v_usecount != 0) | |
68 | vprint("hfs_inactive: pushing active", vp); | |
69 | ||
70 | /* | |
71 | * Ignore nodes related to stale file handles. | |
72 | */ | |
73 | if (cp->c_mode == 0) | |
74 | goto out; | |
75 | ||
76 | if (vp->v_mount->mnt_flag & MNT_RDONLY) | |
77 | goto out; | |
78 | ||
79 | if (cp->c_datafork) | |
80 | ++forkcount; | |
81 | if (cp->c_rsrcfork) | |
82 | ++forkcount; | |
83 | ||
84 | /* If needed, get rid of any fork's data for a deleted file */ | |
85 | if ((cp->c_flag & C_DELETED) && | |
86 | vp->v_type == VREG && | |
87 | (VTOF(vp)->ff_blocks != 0)) { | |
88 | error = VOP_TRUNCATE(vp, (off_t)0, IO_NDELAY, NOCRED, p); | |
9bccf70c | 89 | truncated = 1; |
b4c24cb9 A |
90 | // have to do this to prevent the lost ubc_info panic |
91 | SET(cp->c_flag, C_TRANSIT); | |
9bccf70c | 92 | recycle = 1; |
b4c24cb9 | 93 | if (error) goto out; |
9bccf70c A |
94 | } |
95 | ||
96 | /* | |
97 | * Check for a postponed deletion. | |
98 | * (only delete cnode when the last fork goes inactive) | |
99 | */ | |
100 | if ((cp->c_flag & C_DELETED) && (forkcount <= 1)) { | |
101 | /* | |
102 | * Mark cnode in transit so that one can get this | |
103 | * cnode from cnode hash. | |
104 | */ | |
105 | SET(cp->c_flag, C_TRANSIT); | |
106 | cp->c_flag &= ~C_DELETED; | |
107 | cp->c_rdev = 0; | |
108 | ||
b4c24cb9 A |
109 | // XXXdbg |
110 | hfs_global_shared_lock_acquire(hfsmp); | |
111 | grabbed_lock = 1; | |
112 | if (hfsmp->jnl) { | |
113 | if (journal_start_transaction(hfsmp->jnl) != 0) { | |
114 | error = EINVAL; | |
115 | goto out; | |
116 | } | |
117 | started_tr = 1; | |
118 | } | |
119 | ||
9bccf70c A |
120 | /* Lock catalog b-tree */ |
121 | error = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p); | |
122 | if (error) goto out; | |
123 | ||
124 | if (cp->c_blocks > 0) | |
125 | printf("hfs_inactive: attempting to delete a non-empty file!"); | |
126 | ||
127 | /* | |
128 | * The descriptor name may be zero, | |
129 | * in which case the fileid is used. | |
130 | */ | |
131 | error = cat_delete(hfsmp, &cp->c_desc, &cp->c_attr); | |
132 | ||
133 | if (error && truncated && (error != ENXIO)) | |
134 | printf("hfs_inactive: couldn't delete a truncated file!"); | |
135 | ||
136 | /* Update HFS Private Data dir */ | |
137 | if (error == 0) { | |
138 | hfsmp->hfs_privdir_attr.ca_entries--; | |
139 | (void)cat_update(hfsmp, &hfsmp->hfs_privdir_desc, | |
140 | &hfsmp->hfs_privdir_attr, NULL, NULL); | |
141 | } | |
142 | ||
143 | /* Unlock catalog b-tree */ | |
144 | (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); | |
145 | if (error) goto out; | |
146 | ||
147 | #if QUOTA | |
148 | if (!hfs_getinoquota(cp)) | |
149 | (void)hfs_chkiq(cp, -1, NOCRED, 0); | |
150 | #endif /* QUOTA */ | |
151 | ||
152 | cp->c_mode = 0; | |
153 | cp->c_flag |= C_NOEXISTS | C_CHANGE | C_UPDATE; | |
154 | ||
155 | if (error == 0) | |
156 | hfs_volupdate(hfsmp, VOL_RMFILE, 0); | |
157 | } | |
158 | ||
159 | /* Push any defered access times to disk */ | |
160 | if (cp->c_flag & C_ATIMEMOD) { | |
161 | cp->c_flag &= ~C_ATIMEMOD; | |
162 | if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSPlusSigWord) | |
163 | cp->c_flag |= C_MODIFIED; | |
164 | } | |
b4c24cb9 A |
165 | |
166 | if (cp->c_flag & (C_ACCESS | C_CHANGE | C_MODIFIED | C_UPDATE)) { | |
167 | tv = time; | |
168 | VOP_UPDATE(vp, &tv, &tv, 0); | |
169 | } | |
9bccf70c | 170 | out: |
b4c24cb9 A |
171 | // XXXdbg - have to do this because a goto could have come here |
172 | if (started_tr) { | |
173 | journal_end_transaction(hfsmp->jnl); | |
174 | started_tr = 0; | |
175 | } | |
176 | if (grabbed_lock) { | |
177 | hfs_global_shared_lock_release(hfsmp); | |
178 | } | |
179 | ||
9bccf70c A |
180 | VOP_UNLOCK(vp, 0, p); |
181 | /* | |
182 | * If we are done with the vnode, reclaim it | |
183 | * so that it can be reused immediately. | |
184 | */ | |
185 | if (cp->c_mode == 0 || recycle) | |
186 | vrecycle(vp, (struct slock *)0, p); | |
187 | ||
188 | return (error); | |
189 | } | |
190 | ||
191 | ||
192 | /* | |
193 | * Reclaim a cnode so that it can be used for other purposes. | |
194 | */ | |
195 | __private_extern__ | |
196 | int | |
197 | hfs_reclaim(ap) | |
198 | struct vop_reclaim_args /* { | |
199 | struct vnode *a_vp; | |
200 | } */ *ap; | |
201 | { | |
202 | struct vnode *vp = ap->a_vp; | |
203 | struct cnode *cp = VTOC(vp); | |
204 | struct vnode *devvp = NULL; | |
205 | struct filefork *fp = NULL; | |
206 | struct filefork *altfp = NULL; | |
207 | int i; | |
208 | ||
209 | if (prtactive && vp->v_usecount != 0) | |
210 | vprint("hfs_reclaim(): pushing active", vp); | |
211 | ||
212 | devvp = cp->c_devvp; /* For later releasing */ | |
213 | ||
214 | /* | |
215 | * Find file fork for this vnode (if any) | |
216 | * Also check if another fork is active | |
217 | */ | |
218 | if ((fp = cp->c_datafork) && (cp->c_vp == vp)) { | |
219 | cp->c_datafork = NULL; | |
220 | cp->c_vp = NULL; | |
221 | altfp = cp->c_rsrcfork; | |
222 | } else if ((fp = cp->c_rsrcfork) && (cp->c_rsrc_vp == vp)) { | |
223 | cp->c_rsrcfork = NULL; | |
224 | cp->c_rsrc_vp = NULL; | |
225 | altfp = cp->c_datafork; | |
226 | } else { | |
227 | cp->c_vp = NULL; | |
228 | fp = NULL; | |
229 | altfp = NULL; | |
230 | } | |
231 | ||
232 | /* | |
233 | * On the last fork, remove the cnode from its hash chain. | |
234 | */ | |
235 | if (altfp == NULL) | |
236 | hfs_chashremove(cp); | |
237 | ||
238 | /* Release the file fork and related data (can block) */ | |
239 | if (fp) { | |
240 | fp->ff_cp = NULL; | |
241 | /* Dump cached symlink data */ | |
242 | if ((vp->v_type == VLNK) && (fp->ff_symlinkptr != NULL)) { | |
243 | FREE(fp->ff_symlinkptr, M_TEMP); | |
244 | fp->ff_symlinkptr = NULL; | |
245 | } | |
246 | FREE_ZONE(fp, sizeof(struct filefork), M_HFSFORK); | |
247 | fp = NULL; | |
248 | } | |
249 | ||
250 | /* | |
251 | * Purge old data structures associated with the cnode. | |
252 | */ | |
253 | cache_purge(vp); | |
254 | if (devvp && altfp == NULL) { | |
255 | cp->c_devvp = NULL; | |
256 | vrele(devvp); | |
257 | } | |
258 | ||
259 | vp->v_data = NULL; | |
260 | ||
261 | /* | |
262 | * If there was only one active fork then we can release the cnode. | |
263 | */ | |
264 | if (altfp == NULL) { | |
265 | #if QUOTA | |
266 | for (i = 0; i < MAXQUOTAS; i++) { | |
267 | if (cp->c_dquot[i] != NODQUOT) { | |
268 | dqrele(vp, cp->c_dquot[i]); | |
269 | cp->c_dquot[i] = NODQUOT; | |
270 | } | |
271 | } | |
272 | #endif /* QUOTA */ | |
273 | /* | |
274 | * Free any left over directory indices | |
275 | */ | |
276 | if (vp->v_type == VDIR) | |
277 | hfs_relnamehints(cp); | |
278 | ||
279 | /* | |
280 | * If the descriptor has a name then release it | |
281 | */ | |
282 | if (cp->c_desc.cd_flags & CD_HASBUF) { | |
283 | char *nameptr; | |
284 | ||
285 | nameptr = cp->c_desc.cd_nameptr; | |
286 | cp->c_desc.cd_nameptr = 0; | |
287 | cp->c_desc.cd_flags &= ~CD_HASBUF; | |
288 | cp->c_desc.cd_namelen = 0; | |
289 | FREE(nameptr, M_TEMP); | |
290 | } | |
291 | CLR(cp->c_flag, (C_ALLOC | C_TRANSIT)); | |
292 | if (ISSET(cp->c_flag, C_WALLOC) || ISSET(cp->c_flag, C_WTRANSIT)) | |
293 | wakeup(cp); | |
294 | FREE_ZONE(cp, sizeof(struct cnode), M_HFSNODE); | |
295 | ||
296 | } | |
297 | ||
298 | return (0); | |
299 | } | |
300 | ||
301 | ||
302 | /* | |
303 | * get a cnode | |
304 | * | |
305 | * called by hfs_lookup and hfs_vget (descp == NULL) | |
306 | * | |
307 | * returns a locked vnode for cnode for given cnid/fileid | |
308 | */ | |
309 | __private_extern__ | |
310 | int | |
311 | hfs_getcnode(struct hfsmount *hfsmp, cnid_t cnid, struct cat_desc *descp, int wantrsrc, | |
312 | struct cat_attr *attrp, struct cat_fork *forkp, struct vnode **vpp) | |
313 | { | |
314 | dev_t dev = hfsmp->hfs_raw_dev; | |
315 | struct vnode *vp = NULL; | |
316 | struct vnode *rvp = NULL; | |
317 | struct vnode *new_vp = NULL; | |
318 | struct cnode *cp = NULL; | |
319 | struct proc *p = current_proc(); | |
320 | int retval = E_NONE; | |
321 | ||
322 | /* Check if unmount in progress */ | |
323 | if (HFSTOVFS(hfsmp)->mnt_kern_flag & MNTK_UNMOUNT) { | |
324 | *vpp = NULL; | |
325 | return (EPERM); | |
326 | } | |
327 | ||
328 | /* | |
329 | * Check the hash for an active cnode | |
330 | */ | |
331 | cp = hfs_chashget(dev, cnid, wantrsrc, &vp, &rvp); | |
332 | if (cp != NULL) { | |
333 | /* hide open files that have been deleted */ | |
334 | if ((hfsmp->hfs_private_metadata_dir != 0) | |
335 | && (cp->c_parentcnid == hfsmp->hfs_private_metadata_dir) | |
336 | && (cp->c_nlink == 0)) { | |
337 | retval = ENOENT; | |
338 | goto exit; | |
339 | } | |
b4c24cb9 A |
340 | |
341 | /* Hide private journal files */ | |
342 | if (hfsmp->jnl && | |
343 | (cp->c_parentcnid == kRootDirID) && | |
344 | ((cp->c_cnid == hfsmp->hfs_jnlfileid) || | |
345 | (cp->c_cnid == hfsmp->hfs_jnlinfoblkid))) { | |
346 | retval = ENOENT; | |
347 | goto exit; | |
348 | } | |
349 | ||
9bccf70c A |
350 | if (wantrsrc && rvp != NULL) { |
351 | vp = rvp; | |
352 | rvp = NULL; | |
353 | goto done; | |
354 | } | |
355 | if (!wantrsrc && vp != NULL) { | |
356 | /* Hardlinks need an updated catalog descriptor */ | |
357 | if (descp && cp->c_flag & C_HARDLINK) { | |
358 | replace_desc(cp, descp); | |
359 | } | |
360 | /* We have a vnode so we're done. */ | |
361 | goto done; | |
362 | } | |
363 | } | |
364 | ||
365 | /* | |
366 | * There was no active vnode so get a new one. | |
367 | * Use the existing cnode (if any). | |
368 | */ | |
369 | if (descp != NULL) { | |
370 | /* | |
371 | * hfs_lookup case, use descp, attrp and forkp | |
372 | */ | |
373 | retval = hfs_getnewvnode(hfsmp, cp, descp, wantrsrc, attrp, | |
374 | forkp, &new_vp); | |
375 | } else { | |
376 | struct cat_desc cndesc = {0}; | |
377 | struct cat_attr cnattr = {0}; | |
378 | struct cat_fork cnfork = {0}; | |
379 | ||
380 | /* | |
381 | * hfs_vget case, need to lookup entry (by file id) | |
382 | */ | |
383 | if (cnid == kRootParID) { | |
384 | static char hfs_rootname[] = "/"; | |
385 | ||
386 | cndesc.cd_nameptr = &hfs_rootname[0]; | |
387 | cndesc.cd_namelen = 1; | |
388 | cndesc.cd_parentcnid = kRootParID; | |
389 | cndesc.cd_cnid = kRootParID; | |
390 | cndesc.cd_flags = CD_ISDIR; | |
391 | ||
392 | cnattr.ca_fileid = kRootParID; | |
393 | cnattr.ca_nlink = 2; | |
394 | cnattr.ca_mode = (S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO); | |
395 | } else { | |
396 | /* Lock catalog b-tree */ | |
397 | retval = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_SHARED, p); | |
398 | if (retval) | |
399 | goto exit; | |
400 | ||
401 | retval = cat_idlookup(hfsmp, cnid, &cndesc, &cnattr, &cnfork); | |
402 | ||
403 | /* Unlock catalog b-tree */ | |
404 | (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); | |
405 | if (retval) | |
406 | goto exit; | |
407 | ||
408 | /* Hide open files that have been deleted */ | |
409 | if ((hfsmp->hfs_private_metadata_dir != 0) && | |
410 | (cndesc.cd_parentcnid == hfsmp->hfs_private_metadata_dir)) { | |
411 | cat_releasedesc(&cndesc); | |
412 | retval = ENOENT; | |
413 | goto exit; | |
414 | } | |
415 | } | |
416 | ||
417 | retval = hfs_getnewvnode(hfsmp, cp, &cndesc, 0, &cnattr, &cnfork, &new_vp); | |
418 | ||
419 | /* Hardlinks may need an updated catalog descriptor */ | |
420 | if (retval == 0 | |
421 | && new_vp | |
422 | && (VTOC(new_vp)->c_flag & C_HARDLINK) | |
423 | && cndesc.cd_nameptr | |
424 | && cndesc.cd_namelen > 0) { | |
425 | replace_desc(VTOC(new_vp), &cndesc); | |
426 | } | |
427 | cat_releasedesc(&cndesc); | |
428 | } | |
429 | exit: | |
430 | /* Release reference taken on opposite vnode (if any). */ | |
431 | if (vp) | |
432 | vput(vp); | |
433 | else if (rvp) | |
434 | vput(rvp); | |
435 | ||
436 | if (retval) { | |
437 | *vpp = NULL; | |
438 | return (retval); | |
439 | } | |
440 | vp = new_vp; | |
441 | done: | |
442 | /* The cnode's vnode should be in vp. */ | |
443 | if (vp == NULL) | |
444 | panic("hfs_getcnode: missing vp!"); | |
445 | ||
446 | UBCINFOCHECK("hfs_getcnode", vp); | |
447 | *vpp = vp; | |
448 | return (0); | |
449 | } | |
450 | ||
451 | ||
452 | /* | |
453 | * hfs_getnewvnode - get new default vnode | |
454 | * | |
455 | * the vnode is returned locked | |
456 | */ | |
457 | extern int (**hfs_vnodeop_p) (void *); | |
458 | extern int (**hfs_specop_p) (void *); | |
459 | extern int (**hfs_fifoop_p) (void *); | |
460 | ||
461 | __private_extern__ | |
462 | int | |
463 | hfs_getnewvnode(struct hfsmount *hfsmp, struct cnode *cp, | |
464 | struct cat_desc *descp, int wantrsrc, | |
465 | struct cat_attr *attrp, struct cat_fork *forkp, | |
466 | struct vnode **vpp) | |
467 | { | |
468 | struct mount *mp = HFSTOVFS(hfsmp); | |
469 | struct vnode *vp = NULL; | |
470 | struct vnode *rvp = NULL; | |
471 | struct vnode *new_vp = NULL; | |
472 | struct cnode *cp2 = NULL; | |
473 | struct filefork *fp = NULL; | |
474 | int allocated = 0; | |
475 | int i; | |
476 | int retval; | |
477 | dev_t dev; | |
478 | struct proc *p = current_proc(); | |
479 | ||
480 | /* Bail when unmount is in progress */ | |
481 | if (mp->mnt_kern_flag & MNTK_UNMOUNT) { | |
482 | *vpp = NULL; | |
483 | return (EPERM); | |
484 | } | |
485 | ||
486 | #if !FIFO | |
487 | if (IFTOVT(attrp->ca_mode) == VFIFO) { | |
488 | *vpp = NULL; | |
489 | return (EOPNOTSUPP); | |
490 | } | |
491 | #endif | |
492 | dev = hfsmp->hfs_raw_dev; | |
493 | ||
494 | /* If no cnode was passed in then create one */ | |
495 | if (cp == NULL) { | |
496 | MALLOC_ZONE(cp2, struct cnode *, sizeof(struct cnode), | |
497 | M_HFSNODE, M_WAITOK); | |
498 | bzero(cp2, sizeof(struct cnode)); | |
499 | allocated = 1; | |
500 | SET(cp2->c_flag, C_ALLOC); | |
501 | cp2->c_cnid = descp->cd_cnid; | |
502 | cp2->c_fileid = attrp->ca_fileid; | |
503 | cp2->c_dev = dev; | |
504 | lockinit(&cp2->c_lock, PINOD, "cnode", 0, 0); | |
505 | (void) lockmgr(&cp2->c_lock, LK_EXCLUSIVE, (struct slock *)0, p); | |
506 | /* | |
507 | * There were several blocking points since we first | |
508 | * checked the hash. Now that we're through blocking, | |
509 | * check the hash again in case we're racing for the | |
510 | * same cnode. | |
511 | */ | |
512 | cp = hfs_chashget(dev, attrp->ca_fileid, wantrsrc, &vp, &rvp); | |
513 | if (cp != NULL) { | |
514 | /* We lost the race - use the winner's cnode */ | |
515 | FREE_ZONE(cp2, sizeof(struct cnode), M_HFSNODE); | |
516 | allocated = 0; | |
517 | if (wantrsrc && rvp != NULL) { | |
518 | *vpp = rvp; | |
519 | return (0); | |
520 | } | |
521 | if (!wantrsrc && vp != NULL) { | |
522 | *vpp = vp; | |
523 | return (0); | |
524 | } | |
525 | } else /* allocated */ { | |
526 | cp = cp2; | |
527 | hfs_chashinsert(cp); | |
528 | } | |
529 | } | |
530 | ||
531 | /* Allocate a new vnode. If unsuccesful, leave after freeing memory */ | |
532 | if ((retval = getnewvnode(VT_HFS, mp, hfs_vnodeop_p, &new_vp))) { | |
533 | if (allocated) { | |
534 | hfs_chashremove(cp); | |
535 | if (ISSET(cp->c_flag, C_WALLOC)) { | |
536 | CLR(cp->c_flag, C_WALLOC); | |
537 | wakeup(cp); | |
538 | } | |
539 | FREE_ZONE(cp2, sizeof(struct cnode), M_HFSNODE); | |
540 | allocated = 0; | |
541 | } else if (rvp) { | |
542 | vput(rvp); | |
543 | } else if (vp) { | |
544 | vput(vp); | |
545 | } | |
546 | *vpp = NULL; | |
547 | return (retval); | |
548 | } | |
549 | if (allocated) { | |
550 | bcopy(attrp, &cp->c_attr, sizeof(struct cat_attr)); | |
551 | bcopy(descp, &cp->c_desc, sizeof(struct cat_desc)); | |
552 | } | |
553 | new_vp->v_data = cp; | |
554 | if (wantrsrc && S_ISREG(cp->c_mode)) | |
555 | cp->c_rsrc_vp = new_vp; | |
556 | else | |
557 | cp->c_vp = new_vp; | |
558 | ||
559 | /* Release reference taken on opposite vnode (if any). */ | |
560 | if (rvp) | |
561 | vput(rvp); | |
562 | if (vp) | |
563 | vput(vp); | |
564 | ||
565 | vp = new_vp; | |
566 | vp->v_ubcinfo = UBC_NOINFO; | |
567 | ||
568 | /* | |
569 | * If this is a new cnode then initialize it using descp and attrp... | |
570 | */ | |
571 | if (allocated) { | |
572 | /* The name was inherited so clear descriptor state... */ | |
573 | descp->cd_namelen = 0; | |
574 | descp->cd_nameptr = NULL; | |
575 | descp->cd_flags &= ~CD_HASBUF; | |
576 | ||
577 | /* Tag hardlinks */ | |
578 | if (IFTOVT(cp->c_mode) == VREG && | |
579 | (descp->cd_cnid != attrp->ca_fileid)) { | |
580 | cp->c_flag |= C_HARDLINK; | |
581 | } | |
582 | ||
583 | /* Take one dev reference for each non-directory cnode */ | |
584 | if (IFTOVT(cp->c_mode) != VDIR) { | |
585 | cp->c_devvp = hfsmp->hfs_devvp; | |
586 | VREF(cp->c_devvp); | |
587 | } | |
588 | #if QUOTA | |
589 | for (i = 0; i < MAXQUOTAS; i++) | |
590 | cp->c_dquot[i] = NODQUOT; | |
591 | #endif /* QUOTA */ | |
592 | } | |
593 | ||
594 | if (IFTOVT(cp->c_mode) != VDIR) { | |
595 | if (forkp && attrp->ca_blocks < forkp->cf_blocks) | |
596 | panic("hfs_getnewvnode: bad ca_blocks (too small)"); | |
597 | /* | |
598 | * Allocate and initialize a file fork... | |
599 | */ | |
600 | MALLOC_ZONE(fp, struct filefork *, sizeof(struct filefork), | |
601 | M_HFSFORK, M_WAITOK); | |
602 | bzero(fp, sizeof(struct filefork)); | |
603 | fp->ff_cp = cp; | |
604 | if (forkp) | |
605 | bcopy(forkp, &fp->ff_data, sizeof(HFSPlusForkData)); | |
606 | if (fp->ff_clumpsize == 0) | |
607 | fp->ff_clumpsize = HFSTOVCB(hfsmp)->vcbClpSiz; | |
608 | rl_init(&fp->ff_invalidranges); | |
609 | if (wantrsrc) { | |
610 | if (cp->c_rsrcfork != NULL) | |
611 | panic("stale rsrc fork"); | |
612 | cp->c_rsrcfork = fp; | |
613 | } else { | |
614 | if (cp->c_datafork != NULL) | |
615 | panic("stale data fork"); | |
616 | cp->c_datafork = fp; | |
617 | } | |
618 | } | |
619 | ||
620 | /* | |
621 | * Finish vnode initialization. | |
622 | * Setting the v_type 'stamps' the vnode as 'complete', | |
623 | * so should be done almost last. | |
624 | * | |
625 | * At this point the vnode should be locked and fully | |
626 | * allocated. And ready to be used or accessed. (though | |
627 | * having it locked prevents most of this, it can still | |
628 | * be accessed through lists and hashes). | |
629 | */ | |
630 | vp->v_type = IFTOVT(cp->c_mode); | |
631 | ||
632 | /* Tag system files */ | |
633 | if ((descp->cd_cnid < kHFSFirstUserCatalogNodeID) && (vp->v_type == VREG)) | |
634 | vp->v_flag |= VSYSTEM; | |
635 | /* Tag root directory */ | |
636 | if (cp->c_cnid == kRootDirID) | |
637 | vp->v_flag |= VROOT; | |
638 | ||
639 | if ((vp->v_type == VREG) && !(vp->v_flag & VSYSTEM) | |
640 | && (UBCINFOMISSING(vp) || UBCINFORECLAIMED(vp))) { | |
641 | ubc_info_init(vp); | |
642 | } else { | |
643 | vp->v_ubcinfo = UBC_NOINFO; | |
644 | } | |
645 | ||
646 | if (vp->v_type == VCHR || vp->v_type == VBLK) { | |
647 | struct vnode *nvp; | |
648 | ||
649 | vp->v_op = hfs_specop_p; | |
650 | if ((nvp = checkalias(vp, cp->c_rdev, mp))) { | |
651 | /* | |
652 | * Discard unneeded vnode, but save its cnode. | |
653 | * Note that the lock is carried over in the | |
654 | * cnode to the replacement vnode. | |
655 | */ | |
656 | nvp->v_data = vp->v_data; | |
657 | vp->v_data = NULL; | |
658 | vp->v_op = spec_vnodeop_p; | |
659 | vrele(vp); | |
660 | vgone(vp); | |
661 | /* | |
662 | * Reinitialize aliased cnode. | |
663 | * Assume its not a resource fork. | |
664 | */ | |
665 | cp->c_vp = nvp; | |
666 | vp = nvp; | |
667 | } | |
668 | } else if (vp->v_type == VFIFO) { | |
669 | #if FIFO | |
670 | vp->v_op = hfs_fifoop_p; | |
671 | #endif | |
672 | } | |
673 | ||
674 | /* Vnode is now initialized - see if anyone was waiting for it. */ | |
675 | CLR(cp->c_flag, C_ALLOC); | |
676 | if (ISSET(cp->c_flag, C_WALLOC)) { | |
677 | CLR(cp->c_flag, C_WALLOC); | |
678 | wakeup((caddr_t)cp); | |
679 | } | |
680 | ||
681 | *vpp = vp; | |
682 | return (0); | |
683 | } | |
684 |