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