new IBM 8512 High Function Terminal (HFT) entry
[unix-history] / usr / src / sys / kern / vfs_subr.c
CommitLineData
3c4390e8
KM
1/*
2 * Copyright (c) 1989 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16 *
1a80f56e 17 * @(#)vfs_subr.c 7.38 (Berkeley) %G%
3c4390e8
KM
18 */
19
20/*
21 * External virtual filesystem routines
22 */
23
24#include "param.h"
25#include "mount.h"
26#include "time.h"
27#include "vnode.h"
0f93ba7b 28#include "specdev.h"
c60798ca
KM
29#include "namei.h"
30#include "ucred.h"
3c4390e8 31#include "errno.h"
ef24f6dd 32#include "malloc.h"
3c4390e8 33
3c4390e8
KM
34/*
35 * Remove a mount point from the list of mounted filesystems.
36 * Unmount of the root is illegal.
37 */
38void
39vfs_remove(mp)
40 register struct mount *mp;
41{
42
43 if (mp == rootfs)
44 panic("vfs_remove: unmounting root");
45 mp->m_prev->m_next = mp->m_next;
46 mp->m_next->m_prev = mp->m_prev;
47 mp->m_vnodecovered->v_mountedhere = (struct mount *)0;
48 vfs_unlock(mp);
49}
50
51/*
52 * Lock a filesystem.
53 * Used to prevent access to it while mounting and unmounting.
54 */
55vfs_lock(mp)
56 register struct mount *mp;
57{
58
594501df
KM
59 while(mp->m_flag & M_MLOCK) {
60 mp->m_flag |= M_MWAIT;
61 sleep((caddr_t)mp, PVFS);
62 }
3c4390e8
KM
63 mp->m_flag |= M_MLOCK;
64 return (0);
65}
66
67/*
68 * Unlock a locked filesystem.
69 * Panic if filesystem is not locked.
70 */
71void
72vfs_unlock(mp)
73 register struct mount *mp;
74{
75
76 if ((mp->m_flag & M_MLOCK) == 0)
77 panic("vfs_unlock: locked fs");
78 mp->m_flag &= ~M_MLOCK;
79 if (mp->m_flag & M_MWAIT) {
80 mp->m_flag &= ~M_MWAIT;
81 wakeup((caddr_t)mp);
82 }
83}
84
85/*
86 * Lookup a mount point by filesystem identifier.
87 */
88struct mount *
89getvfs(fsid)
90 fsid_t *fsid;
91{
92 register struct mount *mp;
93
d713f801
KM
94 mp = rootfs;
95 do {
8393745b
KM
96 if (mp->m_stat.f_fsid.val[0] == fsid->val[0] &&
97 mp->m_stat.f_fsid.val[1] == fsid->val[1]) {
d713f801 98 return (mp);
3c4390e8 99 }
d713f801
KM
100 mp = mp->m_next;
101 } while (mp != rootfs);
102 return ((struct mount *)0);
3c4390e8
KM
103}
104
105/*
106 * Set vnode attributes to VNOVAL
107 */
108void vattr_null(vap)
109 register struct vattr *vap;
110{
111
112 vap->va_type = VNON;
113 vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid =
114 vap->va_fsid = vap->va_fileid = vap->va_size =
8fae943a
KM
115 vap->va_size_rsv = vap->va_blocksize = vap->va_rdev =
116 vap->va_bytes = vap->va_bytes_rsv =
3c4390e8
KM
117 vap->va_atime.tv_sec = vap->va_atime.tv_usec =
118 vap->va_mtime.tv_sec = vap->va_mtime.tv_usec =
8cf4d4fb
KM
119 vap->va_ctime.tv_sec = vap->va_ctime.tv_usec =
120 vap->va_flags = vap->va_gen = VNOVAL;
3c4390e8 121}
c60798ca
KM
122
123/*
124 * Initialize a nameidata structure
125 */
126ndinit(ndp)
127 register struct nameidata *ndp;
128{
129
130 bzero((caddr_t)ndp, sizeof(struct nameidata));
131 ndp->ni_iov = &ndp->ni_nd.nd_iovec;
132 ndp->ni_iovcnt = 1;
133 ndp->ni_base = (caddr_t)&ndp->ni_dent;
134 ndp->ni_rw = UIO_WRITE;
4dbe3531 135 ndp->ni_uioseg = UIO_SYSSPACE;
c60798ca
KM
136}
137
138/*
139 * Duplicate a nameidata structure
140 */
141nddup(ndp, newndp)
142 register struct nameidata *ndp, *newndp;
143{
144
145 ndinit(newndp);
146 newndp->ni_cdir = ndp->ni_cdir;
8fe1c702 147 VREF(newndp->ni_cdir);
c60798ca
KM
148 newndp->ni_rdir = ndp->ni_rdir;
149 if (newndp->ni_rdir)
8fe1c702 150 VREF(newndp->ni_rdir);
c60798ca
KM
151 newndp->ni_cred = ndp->ni_cred;
152 crhold(newndp->ni_cred);
153}
154
155/*
156 * Release a nameidata structure
157 */
158ndrele(ndp)
159 register struct nameidata *ndp;
160{
161
162 vrele(ndp->ni_cdir);
163 if (ndp->ni_rdir)
164 vrele(ndp->ni_rdir);
165 crfree(ndp->ni_cred);
166}
36d09cb1
KM
167
168/*
169 * Routines having to do with the management of the vnode table.
170 */
171struct vnode *vfreeh, **vfreet;
4ef5d036 172extern struct vnodeops dead_vnodeops, spec_vnodeops;
32339c94 173extern void vclean();
1a80f56e 174long numvnodes;
c0de8792 175
36d09cb1 176/*
ef24f6dd 177 * Initialize the vnode structures and initialize each file system type.
36d09cb1 178 */
ef24f6dd 179vfsinit()
36d09cb1 180{
ef24f6dd 181 struct vfsops **vfsp;
36d09cb1 182
ef24f6dd
KM
183 /*
184 * Initialize the vnode name cache
185 */
186 nchinit();
187 /*
188 * Initialize each file system type.
189 */
190 for (vfsp = &vfssw[0]; vfsp <= &vfssw[MOUNT_MAXTYPE]; vfsp++) {
191 if (*vfsp == NULL)
192 continue;
193 (*(*vfsp)->vfs_init)();
194 }
36d09cb1
KM
195}
196
197/*
198 * Return the next vnode from the free list.
199 */
200getnewvnode(tag, mp, vops, vpp)
201 enum vtagtype tag;
202 struct mount *mp;
203 struct vnodeops *vops;
204 struct vnode **vpp;
205{
206 register struct vnode *vp, *vq;
207
1a80f56e
KM
208 if (numvnodes < desiredvnodes) {
209 vp = (struct vnode *)malloc(sizeof *vp, M_VNODE, M_WAITOK);
210 bzero((char *)vp, sizeof *vp);
211 numvnodes++;
212 } else {
213 if ((vp = vfreeh) == NULL) {
214 tablefull("vnode");
215 *vpp = 0;
216 return (ENFILE);
217 }
218 if (vp->v_usecount)
219 panic("free vnode isn't");
220 if (vq = vp->v_freef)
221 vq->v_freeb = &vfreeh;
222 else
223 vfreet = &vfreeh;
224 vfreeh = vq;
225 vp->v_freef = NULL;
226 vp->v_freeb = NULL;
227 if (vp->v_type != VBAD)
228 vgone(vp);
229 vp->v_flag = 0;
230 vp->v_shlockc = 0;
231 vp->v_exlockc = 0;
232 vp->v_lastr = 0;
233 vp->v_socket = 0;
36d09cb1 234 }
b027498b 235 vp->v_type = VNON;
36d09cb1
KM
236 cache_purge(vp);
237 vp->v_tag = tag;
ef24f6dd 238 vp->v_op = vops;
36d09cb1
KM
239 insmntque(vp, mp);
240 VREF(vp);
241 *vpp = vp;
242 return (0);
243}
244
245/*
246 * Move a vnode from one mount queue to another.
247 */
248insmntque(vp, mp)
249 register struct vnode *vp;
250 register struct mount *mp;
251{
252 struct vnode *vq;
253
254 /*
255 * Delete from old mount point vnode list, if on one.
256 */
257 if (vp->v_mountb) {
258 if (vq = vp->v_mountf)
259 vq->v_mountb = vp->v_mountb;
260 *vp->v_mountb = vq;
261 }
262 /*
263 * Insert into list of vnodes for the new mount point, if available.
264 */
a45ff315 265 vp->v_mount = mp;
36d09cb1
KM
266 if (mp == NULL) {
267 vp->v_mountf = NULL;
268 vp->v_mountb = NULL;
269 return;
270 }
271 if (mp->m_mounth) {
272 vp->v_mountf = mp->m_mounth;
273 vp->v_mountb = &mp->m_mounth;
274 mp->m_mounth->v_mountb = &vp->v_mountf;
275 mp->m_mounth = vp;
276 } else {
277 mp->m_mounth = vp;
278 vp->v_mountb = &mp->m_mounth;
279 vp->v_mountf = NULL;
280 }
281}
282
283/*
ef24f6dd
KM
284 * Create a vnode for a block device.
285 * Used for root filesystem, argdev, and swap areas.
286 * Also used for memory file system special devices.
287 */
288bdevvp(dev, vpp)
289 dev_t dev;
290 struct vnode **vpp;
291{
ef24f6dd
KM
292 register struct vnode *vp;
293 struct vnode *nvp;
294 int error;
295
4ef5d036 296 error = getnewvnode(VT_NON, (struct mount *)0, &spec_vnodeops, &nvp);
ef24f6dd
KM
297 if (error) {
298 *vpp = 0;
299 return (error);
300 }
301 vp = nvp;
302 vp->v_type = VBLK;
c0de8792 303 if (nvp = checkalias(vp, dev, (struct mount *)0)) {
ef24f6dd
KM
304 vput(vp);
305 vp = nvp;
306 }
307 *vpp = vp;
308 return (0);
309}
310
311/*
312 * Check to see if the new vnode represents a special device
313 * for which we already have a vnode (either because of
314 * bdevvp() or because of a different vnode representing
315 * the same block device). If such an alias exists, deallocate
f0556f86 316 * the existing contents and return the aliased vnode. The
ef24f6dd
KM
317 * caller is responsible for filling it with its new contents.
318 */
319struct vnode *
c0de8792 320checkalias(nvp, nvp_rdev, mp)
ef24f6dd 321 register struct vnode *nvp;
c0de8792 322 dev_t nvp_rdev;
ef24f6dd
KM
323 struct mount *mp;
324{
325 register struct vnode *vp;
c0de8792 326 struct vnode **vpp;
ef24f6dd
KM
327
328 if (nvp->v_type != VBLK && nvp->v_type != VCHR)
329 return ((struct vnode *)0);
c0de8792
KM
330
331 vpp = &speclisth[SPECHASH(nvp_rdev)];
ef24f6dd 332loop:
c0de8792
KM
333 for (vp = *vpp; vp; vp = vp->v_specnext) {
334 if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type)
ef24f6dd 335 continue;
c0de8792
KM
336 /*
337 * Alias, but not in use, so flush it out.
338 */
7f7b7d89 339 if (vp->v_usecount == 0) {
c0de8792
KM
340 vgone(vp);
341 goto loop;
342 }
ef62830d
KM
343 if (vget(vp))
344 goto loop;
ef24f6dd
KM
345 break;
346 }
c0de8792 347 if (vp == NULL || vp->v_tag != VT_NON) {
c0de8792
KM
348 MALLOC(nvp->v_specinfo, struct specinfo *,
349 sizeof(struct specinfo), M_VNODE, M_WAITOK);
350 nvp->v_rdev = nvp_rdev;
7f7b7d89 351 nvp->v_hashchain = vpp;
c0de8792
KM
352 nvp->v_specnext = *vpp;
353 *vpp = nvp;
40452d5e
KM
354 if (vp != NULL) {
355 nvp->v_flag |= VALIASED;
356 vp->v_flag |= VALIASED;
357 vput(vp);
358 }
ef24f6dd
KM
359 return ((struct vnode *)0);
360 }
2bae1875
KM
361 VOP_UNLOCK(vp);
362 vclean(vp, 0);
ef24f6dd
KM
363 vp->v_op = nvp->v_op;
364 vp->v_tag = nvp->v_tag;
365 nvp->v_type = VNON;
366 insmntque(vp, mp);
367 return (vp);
368}
369
370/*
371 * Grab a particular vnode from the free list, increment its
372 * reference count and lock it. The vnode lock bit is set the
373 * vnode is being eliminated in vgone. The process is awakened
374 * when the transition is completed, and an error returned to
375 * indicate that the vnode is no longer usable (possibly having
376 * been changed to a new file system type).
36d09cb1
KM
377 */
378vget(vp)
379 register struct vnode *vp;
380{
381 register struct vnode *vq;
382
ef24f6dd
KM
383 if (vp->v_flag & VXLOCK) {
384 vp->v_flag |= VXWANT;
385 sleep((caddr_t)vp, PINOD);
386 return (1);
387 }
7f7b7d89 388 if (vp->v_usecount == 0) {
ef24f6dd
KM
389 if (vq = vp->v_freef)
390 vq->v_freeb = vp->v_freeb;
391 else
392 vfreet = vp->v_freeb;
393 *vp->v_freeb = vq;
394 vp->v_freef = NULL;
395 vp->v_freeb = NULL;
396 }
36d09cb1 397 VREF(vp);
ef24f6dd
KM
398 VOP_LOCK(vp);
399 return (0);
36d09cb1
KM
400}
401
402/*
403 * Vnode reference, just increment the count
404 */
405void vref(vp)
406 struct vnode *vp;
407{
408
7f7b7d89 409 vp->v_usecount++;
36d09cb1
KM
410}
411
412/*
413 * vput(), just unlock and vrele()
414 */
415void vput(vp)
416 register struct vnode *vp;
417{
418 VOP_UNLOCK(vp);
419 vrele(vp);
420}
421
422/*
423 * Vnode release.
424 * If count drops to zero, call inactive routine and return to freelist.
425 */
426void vrele(vp)
427 register struct vnode *vp;
428{
429
430 if (vp == NULL)
ef24f6dd 431 panic("vrele: null vp");
7f7b7d89
KM
432 vp->v_usecount--;
433 if (vp->v_usecount < 0)
0bf84b18 434 vprint("vrele: bad ref count", vp);
7f7b7d89 435 if (vp->v_usecount > 0)
36d09cb1 436 return;
36d09cb1
KM
437 if (vfreeh == (struct vnode *)0) {
438 /*
439 * insert into empty list
440 */
441 vfreeh = vp;
442 vp->v_freeb = &vfreeh;
36d09cb1
KM
443 } else {
444 /*
445 * insert at tail of list
446 */
447 *vfreet = vp;
448 vp->v_freeb = vfreet;
36d09cb1 449 }
ef24f6dd
KM
450 vp->v_freef = NULL;
451 vfreet = &vp->v_freef;
452 VOP_INACTIVE(vp);
453}
454
7f7b7d89
KM
455/*
456 * Page or buffer structure gets a reference.
457 */
458vhold(vp)
459 register struct vnode *vp;
460{
461
462 vp->v_holdcnt++;
463}
464
465/*
466 * Page or buffer structure frees a reference.
467 */
468holdrele(vp)
469 register struct vnode *vp;
470{
471
472 if (vp->v_holdcnt <= 0)
473 panic("holdrele: holdcnt");
474 vp->v_holdcnt--;
475}
476
f0556f86
KM
477/*
478 * Remove any vnodes in the vnode table belonging to mount point mp.
479 *
480 * If MNT_NOFORCE is specified, there should not be any active ones,
481 * return error if any are found (nb: this is a user error, not a
482 * system error). If MNT_FORCE is specified, detach any active vnodes
483 * that are found.
484 */
485int busyprt = 0; /* patch to print out busy vnodes */
486
487vflush(mp, skipvp, flags)
488 struct mount *mp;
489 struct vnode *skipvp;
490 int flags;
491{
492 register struct vnode *vp, *nvp;
493 int busy = 0;
494
495 for (vp = mp->m_mounth; vp; vp = nvp) {
496 nvp = vp->v_mountf;
497 /*
498 * Skip over a selected vnode.
499 * Used by ufs to skip over the quota structure inode.
500 */
501 if (vp == skipvp)
502 continue;
503 /*
7f7b7d89 504 * With v_usecount == 0, all we need to do is clear
f0556f86
KM
505 * out the vnode data structures and we are done.
506 */
7f7b7d89 507 if (vp->v_usecount == 0) {
f0556f86
KM
508 vgone(vp);
509 continue;
510 }
511 /*
512 * For block or character devices, revert to an
513 * anonymous device. For all other files, just kill them.
514 */
515 if (flags & MNT_FORCE) {
516 if (vp->v_type != VBLK && vp->v_type != VCHR) {
517 vgone(vp);
518 } else {
519 vclean(vp, 0);
520 vp->v_op = &spec_vnodeops;
521 insmntque(vp, (struct mount *)0);
522 }
523 continue;
524 }
525 if (busyprt)
0bf84b18 526 vprint("vflush: busy vnode", vp);
f0556f86
KM
527 busy++;
528 }
529 if (busy)
530 return (EBUSY);
531 return (0);
532}
533
ef24f6dd
KM
534/*
535 * Disassociate the underlying file system from a vnode.
ef24f6dd 536 */
2bae1875 537void vclean(vp, doclose)
ef24f6dd 538 register struct vnode *vp;
2bae1875 539 long doclose;
ef24f6dd
KM
540{
541 struct vnodeops *origops;
2bae1875 542 int active;
ef24f6dd 543
2bae1875
KM
544 /*
545 * Check to see if the vnode is in use.
0bf84b18
KM
546 * If so we have to reference it before we clean it out
547 * so that its count cannot fall to zero and generate a
548 * race against ourselves to recycle it.
2bae1875 549 */
7f7b7d89 550 if (active = vp->v_usecount)
2bae1875 551 VREF(vp);
2bae1875
KM
552 /*
553 * Prevent the vnode from being recycled or
554 * brought into use while we clean it out.
555 */
0bf84b18
KM
556 if (vp->v_flag & VXLOCK)
557 panic("vclean: deadlock");
ef24f6dd 558 vp->v_flag |= VXLOCK;
0bf84b18
KM
559 /*
560 * Even if the count is zero, the VOP_INACTIVE routine may still
561 * have the object locked while it cleans it out. The VOP_LOCK
562 * ensures that the VOP_INACTIVE routine is done with its work.
563 * For active vnodes, it ensures that no other activity can
564 * occur while the buffer list is being cleaned out.
565 */
566 VOP_LOCK(vp);
567 if (doclose)
568 vinvalbuf(vp, 1);
ef24f6dd
KM
569 /*
570 * Prevent any further operations on the vnode from
571 * being passed through to the old file system.
572 */
573 origops = vp->v_op;
574 vp->v_op = &dead_vnodeops;
575 vp->v_tag = VT_NON;
576 /*
2bae1875
KM
577 * If purging an active vnode, it must be unlocked, closed,
578 * and deactivated before being reclaimed.
ef24f6dd 579 */
0bf84b18 580 (*(origops->vn_unlock))(vp);
2bae1875 581 if (active) {
2bae1875
KM
582 if (doclose)
583 (*(origops->vn_close))(vp, 0, NOCRED);
ef24f6dd
KM
584 (*(origops->vn_inactive))(vp);
585 }
586 /*
587 * Reclaim the vnode.
588 */
589 if ((*(origops->vn_reclaim))(vp))
590 panic("vclean: cannot reclaim");
2bae1875
KM
591 if (active)
592 vrele(vp);
ef24f6dd
KM
593 /*
594 * Done with purge, notify sleepers in vget of the grim news.
595 */
596 vp->v_flag &= ~VXLOCK;
597 if (vp->v_flag & VXWANT) {
598 vp->v_flag &= ~VXWANT;
599 wakeup((caddr_t)vp);
600 }
601}
602
ef62830d
KM
603/*
604 * Eliminate all activity associated with the requested vnode
605 * and with all vnodes aliased to the requested vnode.
606 */
607void vgoneall(vp)
608 register struct vnode *vp;
609{
7f7b7d89 610 register struct vnode *vq;
ef62830d 611
7a7b3a95
KM
612 if (vp->v_flag & VALIASED) {
613 /*
614 * If a vgone (or vclean) is already in progress,
615 * wait until it is done and return.
616 */
617 if (vp->v_flag & VXLOCK) {
618 vp->v_flag |= VXWANT;
619 sleep((caddr_t)vp, PINOD);
620 return;
621 }
622 /*
623 * Ensure that vp will not be vgone'd while we
624 * are eliminating its aliases.
625 */
626 vp->v_flag |= VXLOCK;
627 while (vp->v_flag & VALIASED) {
628 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
629 if (vq->v_rdev != vp->v_rdev ||
630 vq->v_type != vp->v_type || vp == vq)
631 continue;
632 vgone(vq);
633 break;
634 }
ef62830d 635 }
7a7b3a95
KM
636 /*
637 * Remove the lock so that vgone below will
638 * really eliminate the vnode after which time
639 * vgone will awaken any sleepers.
640 */
641 vp->v_flag &= ~VXLOCK;
ef62830d
KM
642 }
643 vgone(vp);
644}
645
ef24f6dd
KM
646/*
647 * Eliminate all activity associated with a vnode
648 * in preparation for reuse.
649 */
650void vgone(vp)
651 register struct vnode *vp;
652{
7f7b7d89 653 register struct vnode *vq;
c0de8792
KM
654 struct vnode *vx;
655 long count;
ef24f6dd 656
4f55e3ec
KM
657 /*
658 * If a vgone (or vclean) is already in progress,
659 * wait until it is done and return.
660 */
661 if (vp->v_flag & VXLOCK) {
662 vp->v_flag |= VXWANT;
663 sleep((caddr_t)vp, PINOD);
664 return;
665 }
ef24f6dd
KM
666 /*
667 * Clean out the filesystem specific data.
668 */
2bae1875 669 vclean(vp, 1);
ef24f6dd
KM
670 /*
671 * Delete from old mount point vnode list, if on one.
672 */
673 if (vp->v_mountb) {
674 if (vq = vp->v_mountf)
675 vq->v_mountb = vp->v_mountb;
676 *vp->v_mountb = vq;
677 vp->v_mountf = NULL;
678 vp->v_mountb = NULL;
679 }
680 /*
681 * If special device, remove it from special device alias list.
682 */
683 if (vp->v_type == VBLK || vp->v_type == VCHR) {
7f7b7d89
KM
684 if (*vp->v_hashchain == vp) {
685 *vp->v_hashchain = vp->v_specnext;
ef24f6dd 686 } else {
7f7b7d89 687 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
c0de8792 688 if (vq->v_specnext != vp)
ef24f6dd 689 continue;
c0de8792 690 vq->v_specnext = vp->v_specnext;
ef24f6dd
KM
691 break;
692 }
c0de8792 693 if (vq == NULL)
ef24f6dd
KM
694 panic("missing bdev");
695 }
c0de8792 696 if (vp->v_flag & VALIASED) {
7f7b7d89
KM
697 count = 0;
698 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
de81e10c
KM
699 if (vq->v_rdev != vp->v_rdev ||
700 vq->v_type != vp->v_type)
c0de8792
KM
701 continue;
702 count++;
703 vx = vq;
704 }
705 if (count == 0)
706 panic("missing alias");
707 if (count == 1)
708 vx->v_flag &= ~VALIASED;
709 vp->v_flag &= ~VALIASED;
710 }
711 FREE(vp->v_specinfo, M_VNODE);
712 vp->v_specinfo = NULL;
ef24f6dd
KM
713 }
714 /*
715 * If it is on the freelist, move it to the head of the list.
716 */
717 if (vp->v_freeb) {
718 if (vq = vp->v_freef)
719 vq->v_freeb = vp->v_freeb;
720 else
721 vfreet = vp->v_freeb;
722 *vp->v_freeb = vq;
723 vp->v_freef = vfreeh;
724 vp->v_freeb = &vfreeh;
725 vfreeh->v_freeb = &vp->v_freef;
726 vfreeh = vp;
727 }
2bae1875 728 vp->v_type = VBAD;
36d09cb1 729}
ef62830d 730
2bcd6066
KM
731/*
732 * Lookup a vnode by device number.
733 */
734vfinddev(dev, type, vpp)
735 dev_t dev;
736 enum vtype type;
737 struct vnode **vpp;
738{
739 register struct vnode *vp;
740
741 for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) {
742 if (dev != vp->v_rdev || type != vp->v_type)
743 continue;
744 *vpp = vp;
745 return (0);
746 }
747 return (1);
748}
749
ef62830d
KM
750/*
751 * Calculate the total number of references to a special device.
752 */
753vcount(vp)
754 register struct vnode *vp;
755{
7f7b7d89 756 register struct vnode *vq;
ef62830d
KM
757 int count;
758
759 if ((vp->v_flag & VALIASED) == 0)
7f7b7d89 760 return (vp->v_usecount);
ef62830d 761loop:
7f7b7d89 762 for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
de81e10c 763 if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type)
ef62830d
KM
764 continue;
765 /*
766 * Alias, but not in use, so flush it out.
767 */
7f7b7d89 768 if (vq->v_usecount == 0) {
ef62830d
KM
769 vgone(vq);
770 goto loop;
771 }
7f7b7d89 772 count += vq->v_usecount;
ef62830d
KM
773 }
774 return (count);
775}
0bf84b18
KM
776
777/*
778 * Print out a description of a vnode.
779 */
780static char *typename[] =
61f846a8 781 { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" };
0bf84b18
KM
782
783vprint(label, vp)
784 char *label;
785 register struct vnode *vp;
786{
f2f730c6 787 char buf[64];
0bf84b18
KM
788
789 if (label != NULL)
790 printf("%s: ", label);
f2f730c6 791 printf("type %s, usecount %d, refcount %d,", typename[vp->v_type],
7f7b7d89 792 vp->v_usecount, vp->v_holdcnt);
f2f730c6
KM
793 buf[0] = '\0';
794 if (vp->v_flag & VROOT)
795 strcat(buf, "|VROOT");
796 if (vp->v_flag & VTEXT)
797 strcat(buf, "|VTEXT");
798 if (vp->v_flag & VXLOCK)
799 strcat(buf, "|VXLOCK");
800 if (vp->v_flag & VXWANT)
801 strcat(buf, "|VXWANT");
802 if (vp->v_flag & VEXLOCK)
803 strcat(buf, "|VEXLOCK");
804 if (vp->v_flag & VSHLOCK)
805 strcat(buf, "|VSHLOCK");
806 if (vp->v_flag & VLWAIT)
807 strcat(buf, "|VLWAIT");
808 if (vp->v_flag & VALIASED)
809 strcat(buf, "|VALIASED");
810 if (vp->v_flag & VBWAIT)
811 strcat(buf, "|VBWAIT");
812 if (buf[0] != '\0')
813 printf(" flags (%s)", &buf[1]);
814 printf("\n\t");
0bf84b18
KM
815 VOP_PRINT(vp);
816}