missing splbio (from Naomi@osf)
[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 *
4f55e3ec 17 * @(#)vfs_subr.c 7.32 (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"
c60798ca
KM
28#include "namei.h"
29#include "ucred.h"
3c4390e8 30#include "errno.h"
ef24f6dd 31#include "malloc.h"
3c4390e8 32
70f64c83
KM
33/*
34 * Shorthand notation.
35 */
36#define v_hashchain v_specinfo->si_hashchain
37#define v_specnext v_specinfo->si_specnext
38
3c4390e8
KM
39/*
40 * Remove a mount point from the list of mounted filesystems.
41 * Unmount of the root is illegal.
42 */
43void
44vfs_remove(mp)
45 register struct mount *mp;
46{
47
48 if (mp == rootfs)
49 panic("vfs_remove: unmounting root");
50 mp->m_prev->m_next = mp->m_next;
51 mp->m_next->m_prev = mp->m_prev;
52 mp->m_vnodecovered->v_mountedhere = (struct mount *)0;
53 vfs_unlock(mp);
54}
55
56/*
57 * Lock a filesystem.
58 * Used to prevent access to it while mounting and unmounting.
59 */
60vfs_lock(mp)
61 register struct mount *mp;
62{
63
594501df
KM
64 while(mp->m_flag & M_MLOCK) {
65 mp->m_flag |= M_MWAIT;
66 sleep((caddr_t)mp, PVFS);
67 }
3c4390e8
KM
68 mp->m_flag |= M_MLOCK;
69 return (0);
70}
71
72/*
73 * Unlock a locked filesystem.
74 * Panic if filesystem is not locked.
75 */
76void
77vfs_unlock(mp)
78 register struct mount *mp;
79{
80
81 if ((mp->m_flag & M_MLOCK) == 0)
82 panic("vfs_unlock: locked fs");
83 mp->m_flag &= ~M_MLOCK;
84 if (mp->m_flag & M_MWAIT) {
85 mp->m_flag &= ~M_MWAIT;
86 wakeup((caddr_t)mp);
87 }
88}
89
90/*
91 * Lookup a mount point by filesystem identifier.
92 */
93struct mount *
94getvfs(fsid)
95 fsid_t *fsid;
96{
97 register struct mount *mp;
98
d713f801
KM
99 mp = rootfs;
100 do {
8393745b
KM
101 if (mp->m_stat.f_fsid.val[0] == fsid->val[0] &&
102 mp->m_stat.f_fsid.val[1] == fsid->val[1]) {
d713f801 103 return (mp);
3c4390e8 104 }
d713f801
KM
105 mp = mp->m_next;
106 } while (mp != rootfs);
107 return ((struct mount *)0);
3c4390e8
KM
108}
109
110/*
111 * Set vnode attributes to VNOVAL
112 */
113void vattr_null(vap)
114 register struct vattr *vap;
115{
116
117 vap->va_type = VNON;
118 vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid =
119 vap->va_fsid = vap->va_fileid = vap->va_size =
120 vap->va_size1 = vap->va_blocksize = vap->va_rdev =
121 vap->va_bytes = vap->va_bytes1 =
122 vap->va_atime.tv_sec = vap->va_atime.tv_usec =
123 vap->va_mtime.tv_sec = vap->va_mtime.tv_usec =
8cf4d4fb
KM
124 vap->va_ctime.tv_sec = vap->va_ctime.tv_usec =
125 vap->va_flags = vap->va_gen = VNOVAL;
3c4390e8 126}
c60798ca
KM
127
128/*
129 * Initialize a nameidata structure
130 */
131ndinit(ndp)
132 register struct nameidata *ndp;
133{
134
135 bzero((caddr_t)ndp, sizeof(struct nameidata));
136 ndp->ni_iov = &ndp->ni_nd.nd_iovec;
137 ndp->ni_iovcnt = 1;
138 ndp->ni_base = (caddr_t)&ndp->ni_dent;
139 ndp->ni_rw = UIO_WRITE;
4dbe3531 140 ndp->ni_uioseg = UIO_SYSSPACE;
c60798ca
KM
141}
142
143/*
144 * Duplicate a nameidata structure
145 */
146nddup(ndp, newndp)
147 register struct nameidata *ndp, *newndp;
148{
149
150 ndinit(newndp);
151 newndp->ni_cdir = ndp->ni_cdir;
8fe1c702 152 VREF(newndp->ni_cdir);
c60798ca
KM
153 newndp->ni_rdir = ndp->ni_rdir;
154 if (newndp->ni_rdir)
8fe1c702 155 VREF(newndp->ni_rdir);
c60798ca
KM
156 newndp->ni_cred = ndp->ni_cred;
157 crhold(newndp->ni_cred);
158}
159
160/*
161 * Release a nameidata structure
162 */
163ndrele(ndp)
164 register struct nameidata *ndp;
165{
166
167 vrele(ndp->ni_cdir);
168 if (ndp->ni_rdir)
169 vrele(ndp->ni_rdir);
170 crfree(ndp->ni_cred);
171}
36d09cb1
KM
172
173/*
174 * Routines having to do with the management of the vnode table.
175 */
176struct vnode *vfreeh, **vfreet;
4ef5d036 177extern struct vnodeops dead_vnodeops, spec_vnodeops;
32339c94 178extern void vclean();
c0de8792
KM
179
180#define SPECHSZ 64
181#if ((SPECHSZ&(SPECHSZ-1)) == 0)
182#define SPECHASH(rdev) (((rdev>>5)+(rdev))&(SPECHSZ-1))
183#else
184#define SPECHASH(rdev) (((unsigned)((rdev>>5)+(rdev)))%SPECHSZ)
185#endif
186struct vnode *speclisth[SPECHSZ];
36d09cb1
KM
187
188/*
ef24f6dd 189 * Initialize the vnode structures and initialize each file system type.
36d09cb1 190 */
ef24f6dd 191vfsinit()
36d09cb1
KM
192{
193 register struct vnode *vp = vnode;
ef24f6dd 194 struct vfsops **vfsp;
36d09cb1 195
ef24f6dd
KM
196 /*
197 * Build vnode free list.
198 */
36d09cb1
KM
199 vfreeh = vp;
200 vfreet = &vp->v_freef;
201 vp->v_freeb = &vfreeh;
202 vp->v_op = &dead_vnodeops;
69384bf7 203 vp->v_type = VBAD;
36d09cb1
KM
204 for (vp++; vp < vnodeNVNODE; vp++) {
205 *vfreet = vp;
206 vp->v_freeb = vfreet;
207 vfreet = &vp->v_freef;
208 vp->v_op = &dead_vnodeops;
69384bf7 209 vp->v_type = VBAD;
36d09cb1
KM
210 }
211 vp--;
212 vp->v_freef = NULL;
ef24f6dd
KM
213 /*
214 * Initialize the vnode name cache
215 */
216 nchinit();
217 /*
218 * Initialize each file system type.
219 */
220 for (vfsp = &vfssw[0]; vfsp <= &vfssw[MOUNT_MAXTYPE]; vfsp++) {
221 if (*vfsp == NULL)
222 continue;
223 (*(*vfsp)->vfs_init)();
224 }
36d09cb1
KM
225}
226
227/*
228 * Return the next vnode from the free list.
229 */
230getnewvnode(tag, mp, vops, vpp)
231 enum vtagtype tag;
232 struct mount *mp;
233 struct vnodeops *vops;
234 struct vnode **vpp;
235{
236 register struct vnode *vp, *vq;
237
238 if ((vp = vfreeh) == NULL) {
239 tablefull("vnode");
240 *vpp = 0;
241 return (ENFILE);
242 }
7f7b7d89 243 if (vp->v_usecount)
36d09cb1
KM
244 panic("free vnode isn't");
245 if (vq = vp->v_freef)
246 vq->v_freeb = &vfreeh;
247 vfreeh = vq;
248 vp->v_freef = NULL;
249 vp->v_freeb = NULL;
ccc07962 250 if (vp->v_type != VBAD)
ef24f6dd 251 vgone(vp);
b027498b 252 vp->v_type = VNON;
36d09cb1
KM
253 vp->v_flag = 0;
254 vp->v_shlockc = 0;
255 vp->v_exlockc = 0;
7f7b7d89 256 vp->v_lastr = 0;
36d09cb1 257 vp->v_socket = 0;
36d09cb1
KM
258 cache_purge(vp);
259 vp->v_tag = tag;
ef24f6dd 260 vp->v_op = vops;
36d09cb1
KM
261 insmntque(vp, mp);
262 VREF(vp);
263 *vpp = vp;
264 return (0);
265}
266
267/*
268 * Move a vnode from one mount queue to another.
269 */
270insmntque(vp, mp)
271 register struct vnode *vp;
272 register struct mount *mp;
273{
274 struct vnode *vq;
275
276 /*
277 * Delete from old mount point vnode list, if on one.
278 */
279 if (vp->v_mountb) {
280 if (vq = vp->v_mountf)
281 vq->v_mountb = vp->v_mountb;
282 *vp->v_mountb = vq;
283 }
284 /*
285 * Insert into list of vnodes for the new mount point, if available.
286 */
a45ff315 287 vp->v_mount = mp;
36d09cb1
KM
288 if (mp == NULL) {
289 vp->v_mountf = NULL;
290 vp->v_mountb = NULL;
291 return;
292 }
293 if (mp->m_mounth) {
294 vp->v_mountf = mp->m_mounth;
295 vp->v_mountb = &mp->m_mounth;
296 mp->m_mounth->v_mountb = &vp->v_mountf;
297 mp->m_mounth = vp;
298 } else {
299 mp->m_mounth = vp;
300 vp->v_mountb = &mp->m_mounth;
301 vp->v_mountf = NULL;
302 }
303}
304
305/*
ef24f6dd
KM
306 * Create a vnode for a block device.
307 * Used for root filesystem, argdev, and swap areas.
308 * Also used for memory file system special devices.
309 */
310bdevvp(dev, vpp)
311 dev_t dev;
312 struct vnode **vpp;
313{
ef24f6dd
KM
314 register struct vnode *vp;
315 struct vnode *nvp;
316 int error;
317
4ef5d036 318 error = getnewvnode(VT_NON, (struct mount *)0, &spec_vnodeops, &nvp);
ef24f6dd
KM
319 if (error) {
320 *vpp = 0;
321 return (error);
322 }
323 vp = nvp;
324 vp->v_type = VBLK;
c0de8792 325 if (nvp = checkalias(vp, dev, (struct mount *)0)) {
ef24f6dd
KM
326 vput(vp);
327 vp = nvp;
328 }
329 *vpp = vp;
330 return (0);
331}
332
333/*
334 * Check to see if the new vnode represents a special device
335 * for which we already have a vnode (either because of
336 * bdevvp() or because of a different vnode representing
337 * the same block device). If such an alias exists, deallocate
f0556f86 338 * the existing contents and return the aliased vnode. The
ef24f6dd
KM
339 * caller is responsible for filling it with its new contents.
340 */
341struct vnode *
c0de8792 342checkalias(nvp, nvp_rdev, mp)
ef24f6dd 343 register struct vnode *nvp;
c0de8792 344 dev_t nvp_rdev;
ef24f6dd
KM
345 struct mount *mp;
346{
347 register struct vnode *vp;
c0de8792 348 struct vnode **vpp;
ef24f6dd
KM
349
350 if (nvp->v_type != VBLK && nvp->v_type != VCHR)
351 return ((struct vnode *)0);
c0de8792
KM
352
353 vpp = &speclisth[SPECHASH(nvp_rdev)];
ef24f6dd 354loop:
c0de8792
KM
355 for (vp = *vpp; vp; vp = vp->v_specnext) {
356 if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type)
ef24f6dd 357 continue;
c0de8792
KM
358 /*
359 * Alias, but not in use, so flush it out.
360 */
7f7b7d89 361 if (vp->v_usecount == 0) {
c0de8792
KM
362 vgone(vp);
363 goto loop;
364 }
ef62830d
KM
365 if (vget(vp))
366 goto loop;
ef24f6dd
KM
367 break;
368 }
c0de8792
KM
369 if (vp == NULL || vp->v_tag != VT_NON) {
370 if (vp != NULL) {
c0de8792 371 nvp->v_flag |= VALIASED;
a45ff315
KM
372 vp->v_flag |= VALIASED;
373 vput(vp);
c0de8792
KM
374 }
375 MALLOC(nvp->v_specinfo, struct specinfo *,
376 sizeof(struct specinfo), M_VNODE, M_WAITOK);
377 nvp->v_rdev = nvp_rdev;
7f7b7d89 378 nvp->v_hashchain = vpp;
c0de8792
KM
379 nvp->v_specnext = *vpp;
380 *vpp = nvp;
ef24f6dd
KM
381 return ((struct vnode *)0);
382 }
2bae1875
KM
383 VOP_UNLOCK(vp);
384 vclean(vp, 0);
ef24f6dd
KM
385 vp->v_op = nvp->v_op;
386 vp->v_tag = nvp->v_tag;
387 nvp->v_type = VNON;
388 insmntque(vp, mp);
389 return (vp);
390}
391
392/*
393 * Grab a particular vnode from the free list, increment its
394 * reference count and lock it. The vnode lock bit is set the
395 * vnode is being eliminated in vgone. The process is awakened
396 * when the transition is completed, and an error returned to
397 * indicate that the vnode is no longer usable (possibly having
398 * been changed to a new file system type).
36d09cb1
KM
399 */
400vget(vp)
401 register struct vnode *vp;
402{
403 register struct vnode *vq;
404
ef24f6dd
KM
405 if (vp->v_flag & VXLOCK) {
406 vp->v_flag |= VXWANT;
407 sleep((caddr_t)vp, PINOD);
408 return (1);
409 }
7f7b7d89 410 if (vp->v_usecount == 0) {
ef24f6dd
KM
411 if (vq = vp->v_freef)
412 vq->v_freeb = vp->v_freeb;
413 else
414 vfreet = vp->v_freeb;
415 *vp->v_freeb = vq;
416 vp->v_freef = NULL;
417 vp->v_freeb = NULL;
418 }
36d09cb1 419 VREF(vp);
ef24f6dd
KM
420 VOP_LOCK(vp);
421 return (0);
36d09cb1
KM
422}
423
424/*
425 * Vnode reference, just increment the count
426 */
427void vref(vp)
428 struct vnode *vp;
429{
430
7f7b7d89 431 vp->v_usecount++;
36d09cb1
KM
432}
433
434/*
435 * vput(), just unlock and vrele()
436 */
437void vput(vp)
438 register struct vnode *vp;
439{
440 VOP_UNLOCK(vp);
441 vrele(vp);
442}
443
444/*
445 * Vnode release.
446 * If count drops to zero, call inactive routine and return to freelist.
447 */
448void vrele(vp)
449 register struct vnode *vp;
450{
451
452 if (vp == NULL)
ef24f6dd 453 panic("vrele: null vp");
7f7b7d89
KM
454 vp->v_usecount--;
455 if (vp->v_usecount < 0)
0bf84b18 456 vprint("vrele: bad ref count", vp);
7f7b7d89 457 if (vp->v_usecount > 0)
36d09cb1 458 return;
36d09cb1
KM
459 if (vfreeh == (struct vnode *)0) {
460 /*
461 * insert into empty list
462 */
463 vfreeh = vp;
464 vp->v_freeb = &vfreeh;
36d09cb1
KM
465 } else {
466 /*
467 * insert at tail of list
468 */
469 *vfreet = vp;
470 vp->v_freeb = vfreet;
36d09cb1 471 }
ef24f6dd
KM
472 vp->v_freef = NULL;
473 vfreet = &vp->v_freef;
474 VOP_INACTIVE(vp);
475}
476
7f7b7d89
KM
477/*
478 * Page or buffer structure gets a reference.
479 */
480vhold(vp)
481 register struct vnode *vp;
482{
483
484 vp->v_holdcnt++;
485}
486
487/*
488 * Page or buffer structure frees a reference.
489 */
490holdrele(vp)
491 register struct vnode *vp;
492{
493
494 if (vp->v_holdcnt <= 0)
495 panic("holdrele: holdcnt");
496 vp->v_holdcnt--;
497}
498
f0556f86
KM
499/*
500 * Remove any vnodes in the vnode table belonging to mount point mp.
501 *
502 * If MNT_NOFORCE is specified, there should not be any active ones,
503 * return error if any are found (nb: this is a user error, not a
504 * system error). If MNT_FORCE is specified, detach any active vnodes
505 * that are found.
506 */
507int busyprt = 0; /* patch to print out busy vnodes */
508
509vflush(mp, skipvp, flags)
510 struct mount *mp;
511 struct vnode *skipvp;
512 int flags;
513{
514 register struct vnode *vp, *nvp;
515 int busy = 0;
516
517 for (vp = mp->m_mounth; vp; vp = nvp) {
518 nvp = vp->v_mountf;
519 /*
520 * Skip over a selected vnode.
521 * Used by ufs to skip over the quota structure inode.
522 */
523 if (vp == skipvp)
524 continue;
525 /*
7f7b7d89 526 * With v_usecount == 0, all we need to do is clear
f0556f86
KM
527 * out the vnode data structures and we are done.
528 */
7f7b7d89 529 if (vp->v_usecount == 0) {
f0556f86
KM
530 vgone(vp);
531 continue;
532 }
533 /*
534 * For block or character devices, revert to an
535 * anonymous device. For all other files, just kill them.
536 */
537 if (flags & MNT_FORCE) {
538 if (vp->v_type != VBLK && vp->v_type != VCHR) {
539 vgone(vp);
540 } else {
541 vclean(vp, 0);
542 vp->v_op = &spec_vnodeops;
543 insmntque(vp, (struct mount *)0);
544 }
545 continue;
546 }
547 if (busyprt)
0bf84b18 548 vprint("vflush: busy vnode", vp);
f0556f86
KM
549 busy++;
550 }
551 if (busy)
552 return (EBUSY);
553 return (0);
554}
555
ef24f6dd
KM
556/*
557 * Disassociate the underlying file system from a vnode.
ef24f6dd 558 */
2bae1875 559void vclean(vp, doclose)
ef24f6dd 560 register struct vnode *vp;
2bae1875 561 long doclose;
ef24f6dd
KM
562{
563 struct vnodeops *origops;
2bae1875 564 int active;
ef24f6dd 565
2bae1875
KM
566 /*
567 * Check to see if the vnode is in use.
0bf84b18
KM
568 * If so we have to reference it before we clean it out
569 * so that its count cannot fall to zero and generate a
570 * race against ourselves to recycle it.
2bae1875 571 */
7f7b7d89 572 if (active = vp->v_usecount)
2bae1875 573 VREF(vp);
2bae1875
KM
574 /*
575 * Prevent the vnode from being recycled or
576 * brought into use while we clean it out.
577 */
0bf84b18
KM
578 if (vp->v_flag & VXLOCK)
579 panic("vclean: deadlock");
ef24f6dd 580 vp->v_flag |= VXLOCK;
0bf84b18
KM
581 /*
582 * Even if the count is zero, the VOP_INACTIVE routine may still
583 * have the object locked while it cleans it out. The VOP_LOCK
584 * ensures that the VOP_INACTIVE routine is done with its work.
585 * For active vnodes, it ensures that no other activity can
586 * occur while the buffer list is being cleaned out.
587 */
588 VOP_LOCK(vp);
589 if (doclose)
590 vinvalbuf(vp, 1);
ef24f6dd
KM
591 /*
592 * Prevent any further operations on the vnode from
593 * being passed through to the old file system.
594 */
595 origops = vp->v_op;
596 vp->v_op = &dead_vnodeops;
597 vp->v_tag = VT_NON;
598 /*
2bae1875
KM
599 * If purging an active vnode, it must be unlocked, closed,
600 * and deactivated before being reclaimed.
ef24f6dd 601 */
0bf84b18 602 (*(origops->vn_unlock))(vp);
2bae1875 603 if (active) {
2bae1875
KM
604 if (doclose)
605 (*(origops->vn_close))(vp, 0, NOCRED);
ef24f6dd
KM
606 (*(origops->vn_inactive))(vp);
607 }
608 /*
609 * Reclaim the vnode.
610 */
611 if ((*(origops->vn_reclaim))(vp))
612 panic("vclean: cannot reclaim");
2bae1875
KM
613 if (active)
614 vrele(vp);
ef24f6dd
KM
615 /*
616 * Done with purge, notify sleepers in vget of the grim news.
617 */
618 vp->v_flag &= ~VXLOCK;
619 if (vp->v_flag & VXWANT) {
620 vp->v_flag &= ~VXWANT;
621 wakeup((caddr_t)vp);
622 }
623}
624
ef62830d
KM
625/*
626 * Eliminate all activity associated with the requested vnode
627 * and with all vnodes aliased to the requested vnode.
628 */
629void vgoneall(vp)
630 register struct vnode *vp;
631{
7f7b7d89 632 register struct vnode *vq;
ef62830d 633
7f7b7d89
KM
634 while (vp->v_flag & VALIASED) {
635 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
160df0cd
KM
636 if (vq->v_rdev != vp->v_rdev ||
637 vq->v_type != vp->v_type || vp == vq)
ef62830d
KM
638 continue;
639 vgone(vq);
7f7b7d89 640 break;
ef62830d
KM
641 }
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}