kerberos include files moved to /usr/include/kerberosIV
[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 *
0f93ba7b 17 * @(#)vfs_subr.c 7.35 (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();
c0de8792 174
36d09cb1 175/*
ef24f6dd 176 * Initialize the vnode structures and initialize each file system type.
36d09cb1 177 */
ef24f6dd 178vfsinit()
36d09cb1
KM
179{
180 register struct vnode *vp = vnode;
ef24f6dd 181 struct vfsops **vfsp;
36d09cb1 182
ef24f6dd
KM
183 /*
184 * Build vnode free list.
185 */
36d09cb1
KM
186 vfreeh = vp;
187 vfreet = &vp->v_freef;
188 vp->v_freeb = &vfreeh;
189 vp->v_op = &dead_vnodeops;
69384bf7 190 vp->v_type = VBAD;
36d09cb1
KM
191 for (vp++; vp < vnodeNVNODE; vp++) {
192 *vfreet = vp;
193 vp->v_freeb = vfreet;
194 vfreet = &vp->v_freef;
195 vp->v_op = &dead_vnodeops;
69384bf7 196 vp->v_type = VBAD;
36d09cb1
KM
197 }
198 vp--;
199 vp->v_freef = NULL;
ef24f6dd
KM
200 /*
201 * Initialize the vnode name cache
202 */
203 nchinit();
204 /*
205 * Initialize each file system type.
206 */
207 for (vfsp = &vfssw[0]; vfsp <= &vfssw[MOUNT_MAXTYPE]; vfsp++) {
208 if (*vfsp == NULL)
209 continue;
210 (*(*vfsp)->vfs_init)();
211 }
36d09cb1
KM
212}
213
214/*
215 * Return the next vnode from the free list.
216 */
217getnewvnode(tag, mp, vops, vpp)
218 enum vtagtype tag;
219 struct mount *mp;
220 struct vnodeops *vops;
221 struct vnode **vpp;
222{
223 register struct vnode *vp, *vq;
224
225 if ((vp = vfreeh) == NULL) {
226 tablefull("vnode");
227 *vpp = 0;
228 return (ENFILE);
229 }
7f7b7d89 230 if (vp->v_usecount)
36d09cb1
KM
231 panic("free vnode isn't");
232 if (vq = vp->v_freef)
233 vq->v_freeb = &vfreeh;
234 vfreeh = vq;
235 vp->v_freef = NULL;
236 vp->v_freeb = NULL;
ccc07962 237 if (vp->v_type != VBAD)
ef24f6dd 238 vgone(vp);
b027498b 239 vp->v_type = VNON;
36d09cb1
KM
240 vp->v_flag = 0;
241 vp->v_shlockc = 0;
242 vp->v_exlockc = 0;
7f7b7d89 243 vp->v_lastr = 0;
36d09cb1 244 vp->v_socket = 0;
36d09cb1
KM
245 cache_purge(vp);
246 vp->v_tag = tag;
ef24f6dd 247 vp->v_op = vops;
36d09cb1
KM
248 insmntque(vp, mp);
249 VREF(vp);
250 *vpp = vp;
251 return (0);
252}
253
254/*
255 * Move a vnode from one mount queue to another.
256 */
257insmntque(vp, mp)
258 register struct vnode *vp;
259 register struct mount *mp;
260{
261 struct vnode *vq;
262
263 /*
264 * Delete from old mount point vnode list, if on one.
265 */
266 if (vp->v_mountb) {
267 if (vq = vp->v_mountf)
268 vq->v_mountb = vp->v_mountb;
269 *vp->v_mountb = vq;
270 }
271 /*
272 * Insert into list of vnodes for the new mount point, if available.
273 */
a45ff315 274 vp->v_mount = mp;
36d09cb1
KM
275 if (mp == NULL) {
276 vp->v_mountf = NULL;
277 vp->v_mountb = NULL;
278 return;
279 }
280 if (mp->m_mounth) {
281 vp->v_mountf = mp->m_mounth;
282 vp->v_mountb = &mp->m_mounth;
283 mp->m_mounth->v_mountb = &vp->v_mountf;
284 mp->m_mounth = vp;
285 } else {
286 mp->m_mounth = vp;
287 vp->v_mountb = &mp->m_mounth;
288 vp->v_mountf = NULL;
289 }
290}
291
292/*
ef24f6dd
KM
293 * Create a vnode for a block device.
294 * Used for root filesystem, argdev, and swap areas.
295 * Also used for memory file system special devices.
296 */
297bdevvp(dev, vpp)
298 dev_t dev;
299 struct vnode **vpp;
300{
ef24f6dd
KM
301 register struct vnode *vp;
302 struct vnode *nvp;
303 int error;
304
4ef5d036 305 error = getnewvnode(VT_NON, (struct mount *)0, &spec_vnodeops, &nvp);
ef24f6dd
KM
306 if (error) {
307 *vpp = 0;
308 return (error);
309 }
310 vp = nvp;
311 vp->v_type = VBLK;
c0de8792 312 if (nvp = checkalias(vp, dev, (struct mount *)0)) {
ef24f6dd
KM
313 vput(vp);
314 vp = nvp;
315 }
316 *vpp = vp;
317 return (0);
318}
319
320/*
321 * Check to see if the new vnode represents a special device
322 * for which we already have a vnode (either because of
323 * bdevvp() or because of a different vnode representing
324 * the same block device). If such an alias exists, deallocate
f0556f86 325 * the existing contents and return the aliased vnode. The
ef24f6dd
KM
326 * caller is responsible for filling it with its new contents.
327 */
328struct vnode *
c0de8792 329checkalias(nvp, nvp_rdev, mp)
ef24f6dd 330 register struct vnode *nvp;
c0de8792 331 dev_t nvp_rdev;
ef24f6dd
KM
332 struct mount *mp;
333{
334 register struct vnode *vp;
c0de8792 335 struct vnode **vpp;
ef24f6dd
KM
336
337 if (nvp->v_type != VBLK && nvp->v_type != VCHR)
338 return ((struct vnode *)0);
c0de8792
KM
339
340 vpp = &speclisth[SPECHASH(nvp_rdev)];
ef24f6dd 341loop:
c0de8792
KM
342 for (vp = *vpp; vp; vp = vp->v_specnext) {
343 if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type)
ef24f6dd 344 continue;
c0de8792
KM
345 /*
346 * Alias, but not in use, so flush it out.
347 */
7f7b7d89 348 if (vp->v_usecount == 0) {
c0de8792
KM
349 vgone(vp);
350 goto loop;
351 }
ef62830d
KM
352 if (vget(vp))
353 goto loop;
ef24f6dd
KM
354 break;
355 }
c0de8792 356 if (vp == NULL || vp->v_tag != VT_NON) {
c0de8792
KM
357 MALLOC(nvp->v_specinfo, struct specinfo *,
358 sizeof(struct specinfo), M_VNODE, M_WAITOK);
359 nvp->v_rdev = nvp_rdev;
7f7b7d89 360 nvp->v_hashchain = vpp;
c0de8792
KM
361 nvp->v_specnext = *vpp;
362 *vpp = nvp;
40452d5e
KM
363 if (vp != NULL) {
364 nvp->v_flag |= VALIASED;
365 vp->v_flag |= VALIASED;
366 vput(vp);
367 }
ef24f6dd
KM
368 return ((struct vnode *)0);
369 }
2bae1875
KM
370 VOP_UNLOCK(vp);
371 vclean(vp, 0);
ef24f6dd
KM
372 vp->v_op = nvp->v_op;
373 vp->v_tag = nvp->v_tag;
374 nvp->v_type = VNON;
375 insmntque(vp, mp);
376 return (vp);
377}
378
379/*
380 * Grab a particular vnode from the free list, increment its
381 * reference count and lock it. The vnode lock bit is set the
382 * vnode is being eliminated in vgone. The process is awakened
383 * when the transition is completed, and an error returned to
384 * indicate that the vnode is no longer usable (possibly having
385 * been changed to a new file system type).
36d09cb1
KM
386 */
387vget(vp)
388 register struct vnode *vp;
389{
390 register struct vnode *vq;
391
ef24f6dd
KM
392 if (vp->v_flag & VXLOCK) {
393 vp->v_flag |= VXWANT;
394 sleep((caddr_t)vp, PINOD);
395 return (1);
396 }
7f7b7d89 397 if (vp->v_usecount == 0) {
ef24f6dd
KM
398 if (vq = vp->v_freef)
399 vq->v_freeb = vp->v_freeb;
400 else
401 vfreet = vp->v_freeb;
402 *vp->v_freeb = vq;
403 vp->v_freef = NULL;
404 vp->v_freeb = NULL;
405 }
36d09cb1 406 VREF(vp);
ef24f6dd
KM
407 VOP_LOCK(vp);
408 return (0);
36d09cb1
KM
409}
410
411/*
412 * Vnode reference, just increment the count
413 */
414void vref(vp)
415 struct vnode *vp;
416{
417
7f7b7d89 418 vp->v_usecount++;
36d09cb1
KM
419}
420
421/*
422 * vput(), just unlock and vrele()
423 */
424void vput(vp)
425 register struct vnode *vp;
426{
427 VOP_UNLOCK(vp);
428 vrele(vp);
429}
430
431/*
432 * Vnode release.
433 * If count drops to zero, call inactive routine and return to freelist.
434 */
435void vrele(vp)
436 register struct vnode *vp;
437{
438
439 if (vp == NULL)
ef24f6dd 440 panic("vrele: null vp");
7f7b7d89
KM
441 vp->v_usecount--;
442 if (vp->v_usecount < 0)
0bf84b18 443 vprint("vrele: bad ref count", vp);
7f7b7d89 444 if (vp->v_usecount > 0)
36d09cb1 445 return;
36d09cb1
KM
446 if (vfreeh == (struct vnode *)0) {
447 /*
448 * insert into empty list
449 */
450 vfreeh = vp;
451 vp->v_freeb = &vfreeh;
36d09cb1
KM
452 } else {
453 /*
454 * insert at tail of list
455 */
456 *vfreet = vp;
457 vp->v_freeb = vfreet;
36d09cb1 458 }
ef24f6dd
KM
459 vp->v_freef = NULL;
460 vfreet = &vp->v_freef;
461 VOP_INACTIVE(vp);
462}
463
7f7b7d89
KM
464/*
465 * Page or buffer structure gets a reference.
466 */
467vhold(vp)
468 register struct vnode *vp;
469{
470
471 vp->v_holdcnt++;
472}
473
474/*
475 * Page or buffer structure frees a reference.
476 */
477holdrele(vp)
478 register struct vnode *vp;
479{
480
481 if (vp->v_holdcnt <= 0)
482 panic("holdrele: holdcnt");
483 vp->v_holdcnt--;
484}
485
f0556f86
KM
486/*
487 * Remove any vnodes in the vnode table belonging to mount point mp.
488 *
489 * If MNT_NOFORCE is specified, there should not be any active ones,
490 * return error if any are found (nb: this is a user error, not a
491 * system error). If MNT_FORCE is specified, detach any active vnodes
492 * that are found.
493 */
494int busyprt = 0; /* patch to print out busy vnodes */
495
496vflush(mp, skipvp, flags)
497 struct mount *mp;
498 struct vnode *skipvp;
499 int flags;
500{
501 register struct vnode *vp, *nvp;
502 int busy = 0;
503
504 for (vp = mp->m_mounth; vp; vp = nvp) {
505 nvp = vp->v_mountf;
506 /*
507 * Skip over a selected vnode.
508 * Used by ufs to skip over the quota structure inode.
509 */
510 if (vp == skipvp)
511 continue;
512 /*
7f7b7d89 513 * With v_usecount == 0, all we need to do is clear
f0556f86
KM
514 * out the vnode data structures and we are done.
515 */
7f7b7d89 516 if (vp->v_usecount == 0) {
f0556f86
KM
517 vgone(vp);
518 continue;
519 }
520 /*
521 * For block or character devices, revert to an
522 * anonymous device. For all other files, just kill them.
523 */
524 if (flags & MNT_FORCE) {
525 if (vp->v_type != VBLK && vp->v_type != VCHR) {
526 vgone(vp);
527 } else {
528 vclean(vp, 0);
529 vp->v_op = &spec_vnodeops;
530 insmntque(vp, (struct mount *)0);
531 }
532 continue;
533 }
534 if (busyprt)
0bf84b18 535 vprint("vflush: busy vnode", vp);
f0556f86
KM
536 busy++;
537 }
538 if (busy)
539 return (EBUSY);
540 return (0);
541}
542
ef24f6dd
KM
543/*
544 * Disassociate the underlying file system from a vnode.
ef24f6dd 545 */
2bae1875 546void vclean(vp, doclose)
ef24f6dd 547 register struct vnode *vp;
2bae1875 548 long doclose;
ef24f6dd
KM
549{
550 struct vnodeops *origops;
2bae1875 551 int active;
ef24f6dd 552
2bae1875
KM
553 /*
554 * Check to see if the vnode is in use.
0bf84b18
KM
555 * If so we have to reference it before we clean it out
556 * so that its count cannot fall to zero and generate a
557 * race against ourselves to recycle it.
2bae1875 558 */
7f7b7d89 559 if (active = vp->v_usecount)
2bae1875 560 VREF(vp);
2bae1875
KM
561 /*
562 * Prevent the vnode from being recycled or
563 * brought into use while we clean it out.
564 */
0bf84b18
KM
565 if (vp->v_flag & VXLOCK)
566 panic("vclean: deadlock");
ef24f6dd 567 vp->v_flag |= VXLOCK;
0bf84b18
KM
568 /*
569 * Even if the count is zero, the VOP_INACTIVE routine may still
570 * have the object locked while it cleans it out. The VOP_LOCK
571 * ensures that the VOP_INACTIVE routine is done with its work.
572 * For active vnodes, it ensures that no other activity can
573 * occur while the buffer list is being cleaned out.
574 */
575 VOP_LOCK(vp);
576 if (doclose)
577 vinvalbuf(vp, 1);
ef24f6dd
KM
578 /*
579 * Prevent any further operations on the vnode from
580 * being passed through to the old file system.
581 */
582 origops = vp->v_op;
583 vp->v_op = &dead_vnodeops;
584 vp->v_tag = VT_NON;
585 /*
2bae1875
KM
586 * If purging an active vnode, it must be unlocked, closed,
587 * and deactivated before being reclaimed.
ef24f6dd 588 */
0bf84b18 589 (*(origops->vn_unlock))(vp);
2bae1875 590 if (active) {
2bae1875
KM
591 if (doclose)
592 (*(origops->vn_close))(vp, 0, NOCRED);
ef24f6dd
KM
593 (*(origops->vn_inactive))(vp);
594 }
595 /*
596 * Reclaim the vnode.
597 */
598 if ((*(origops->vn_reclaim))(vp))
599 panic("vclean: cannot reclaim");
2bae1875
KM
600 if (active)
601 vrele(vp);
ef24f6dd
KM
602 /*
603 * Done with purge, notify sleepers in vget of the grim news.
604 */
605 vp->v_flag &= ~VXLOCK;
606 if (vp->v_flag & VXWANT) {
607 vp->v_flag &= ~VXWANT;
608 wakeup((caddr_t)vp);
609 }
610}
611
ef62830d
KM
612/*
613 * Eliminate all activity associated with the requested vnode
614 * and with all vnodes aliased to the requested vnode.
615 */
616void vgoneall(vp)
617 register struct vnode *vp;
618{
7f7b7d89 619 register struct vnode *vq;
ef62830d 620
7f7b7d89
KM
621 while (vp->v_flag & VALIASED) {
622 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
160df0cd
KM
623 if (vq->v_rdev != vp->v_rdev ||
624 vq->v_type != vp->v_type || vp == vq)
ef62830d
KM
625 continue;
626 vgone(vq);
7f7b7d89 627 break;
ef62830d
KM
628 }
629 }
630 vgone(vp);
631}
632
ef24f6dd
KM
633/*
634 * Eliminate all activity associated with a vnode
635 * in preparation for reuse.
636 */
637void vgone(vp)
638 register struct vnode *vp;
639{
7f7b7d89 640 register struct vnode *vq;
c0de8792
KM
641 struct vnode *vx;
642 long count;
ef24f6dd 643
4f55e3ec
KM
644 /*
645 * If a vgone (or vclean) is already in progress,
646 * wait until it is done and return.
647 */
648 if (vp->v_flag & VXLOCK) {
649 vp->v_flag |= VXWANT;
650 sleep((caddr_t)vp, PINOD);
651 return;
652 }
ef24f6dd
KM
653 /*
654 * Clean out the filesystem specific data.
655 */
2bae1875 656 vclean(vp, 1);
ef24f6dd
KM
657 /*
658 * Delete from old mount point vnode list, if on one.
659 */
660 if (vp->v_mountb) {
661 if (vq = vp->v_mountf)
662 vq->v_mountb = vp->v_mountb;
663 *vp->v_mountb = vq;
664 vp->v_mountf = NULL;
665 vp->v_mountb = NULL;
666 }
667 /*
668 * If special device, remove it from special device alias list.
669 */
670 if (vp->v_type == VBLK || vp->v_type == VCHR) {
7f7b7d89
KM
671 if (*vp->v_hashchain == vp) {
672 *vp->v_hashchain = vp->v_specnext;
ef24f6dd 673 } else {
7f7b7d89 674 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
c0de8792 675 if (vq->v_specnext != vp)
ef24f6dd 676 continue;
c0de8792 677 vq->v_specnext = vp->v_specnext;
ef24f6dd
KM
678 break;
679 }
c0de8792 680 if (vq == NULL)
ef24f6dd
KM
681 panic("missing bdev");
682 }
c0de8792 683 if (vp->v_flag & VALIASED) {
7f7b7d89
KM
684 count = 0;
685 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
de81e10c
KM
686 if (vq->v_rdev != vp->v_rdev ||
687 vq->v_type != vp->v_type)
c0de8792
KM
688 continue;
689 count++;
690 vx = vq;
691 }
692 if (count == 0)
693 panic("missing alias");
694 if (count == 1)
695 vx->v_flag &= ~VALIASED;
696 vp->v_flag &= ~VALIASED;
697 }
698 FREE(vp->v_specinfo, M_VNODE);
699 vp->v_specinfo = NULL;
ef24f6dd
KM
700 }
701 /*
702 * If it is on the freelist, move it to the head of the list.
703 */
704 if (vp->v_freeb) {
705 if (vq = vp->v_freef)
706 vq->v_freeb = vp->v_freeb;
707 else
708 vfreet = vp->v_freeb;
709 *vp->v_freeb = vq;
710 vp->v_freef = vfreeh;
711 vp->v_freeb = &vfreeh;
712 vfreeh->v_freeb = &vp->v_freef;
713 vfreeh = vp;
714 }
2bae1875 715 vp->v_type = VBAD;
36d09cb1 716}
ef62830d 717
2bcd6066
KM
718/*
719 * Lookup a vnode by device number.
720 */
721vfinddev(dev, type, vpp)
722 dev_t dev;
723 enum vtype type;
724 struct vnode **vpp;
725{
726 register struct vnode *vp;
727
728 for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) {
729 if (dev != vp->v_rdev || type != vp->v_type)
730 continue;
731 *vpp = vp;
732 return (0);
733 }
734 return (1);
735}
736
ef62830d
KM
737/*
738 * Calculate the total number of references to a special device.
739 */
740vcount(vp)
741 register struct vnode *vp;
742{
7f7b7d89 743 register struct vnode *vq;
ef62830d
KM
744 int count;
745
746 if ((vp->v_flag & VALIASED) == 0)
7f7b7d89 747 return (vp->v_usecount);
ef62830d 748loop:
7f7b7d89 749 for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
de81e10c 750 if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type)
ef62830d
KM
751 continue;
752 /*
753 * Alias, but not in use, so flush it out.
754 */
7f7b7d89 755 if (vq->v_usecount == 0) {
ef62830d
KM
756 vgone(vq);
757 goto loop;
758 }
7f7b7d89 759 count += vq->v_usecount;
ef62830d
KM
760 }
761 return (count);
762}
0bf84b18
KM
763
764/*
765 * Print out a description of a vnode.
766 */
767static char *typename[] =
61f846a8 768 { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" };
0bf84b18
KM
769
770vprint(label, vp)
771 char *label;
772 register struct vnode *vp;
773{
f2f730c6 774 char buf[64];
0bf84b18
KM
775
776 if (label != NULL)
777 printf("%s: ", label);
f2f730c6 778 printf("type %s, usecount %d, refcount %d,", typename[vp->v_type],
7f7b7d89 779 vp->v_usecount, vp->v_holdcnt);
f2f730c6
KM
780 buf[0] = '\0';
781 if (vp->v_flag & VROOT)
782 strcat(buf, "|VROOT");
783 if (vp->v_flag & VTEXT)
784 strcat(buf, "|VTEXT");
785 if (vp->v_flag & VXLOCK)
786 strcat(buf, "|VXLOCK");
787 if (vp->v_flag & VXWANT)
788 strcat(buf, "|VXWANT");
789 if (vp->v_flag & VEXLOCK)
790 strcat(buf, "|VEXLOCK");
791 if (vp->v_flag & VSHLOCK)
792 strcat(buf, "|VSHLOCK");
793 if (vp->v_flag & VLWAIT)
794 strcat(buf, "|VLWAIT");
795 if (vp->v_flag & VALIASED)
796 strcat(buf, "|VALIASED");
797 if (vp->v_flag & VBWAIT)
798 strcat(buf, "|VBWAIT");
799 if (buf[0] != '\0')
800 printf(" flags (%s)", &buf[1]);
801 printf("\n\t");
0bf84b18
KM
802 VOP_PRINT(vp);
803}