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