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