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