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