blkflush is no longer used;
[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 *
4dbe3531 17 * @(#)vfs_subr.c 7.20 (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 }
ef24f6dd 235 if (vp->v_count)
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;
248 vp->v_socket = 0;
36d09cb1
KM
249 cache_purge(vp);
250 vp->v_tag = tag;
ef24f6dd 251 vp->v_op = vops;
36d09cb1
KM
252 insmntque(vp, mp);
253 VREF(vp);
254 *vpp = vp;
255 return (0);
256}
257
258/*
259 * Move a vnode from one mount queue to another.
260 */
261insmntque(vp, mp)
262 register struct vnode *vp;
263 register struct mount *mp;
264{
265 struct vnode *vq;
266
267 /*
268 * Delete from old mount point vnode list, if on one.
269 */
270 if (vp->v_mountb) {
271 if (vq = vp->v_mountf)
272 vq->v_mountb = vp->v_mountb;
273 *vp->v_mountb = vq;
274 }
275 /*
276 * Insert into list of vnodes for the new mount point, if available.
277 */
a45ff315 278 vp->v_mount = mp;
36d09cb1
KM
279 if (mp == NULL) {
280 vp->v_mountf = NULL;
281 vp->v_mountb = NULL;
282 return;
283 }
284 if (mp->m_mounth) {
285 vp->v_mountf = mp->m_mounth;
286 vp->v_mountb = &mp->m_mounth;
287 mp->m_mounth->v_mountb = &vp->v_mountf;
288 mp->m_mounth = vp;
289 } else {
290 mp->m_mounth = vp;
291 vp->v_mountb = &mp->m_mounth;
292 vp->v_mountf = NULL;
293 }
294}
295
296/*
ef24f6dd
KM
297 * Create a vnode for a block device.
298 * Used for root filesystem, argdev, and swap areas.
299 * Also used for memory file system special devices.
300 */
301bdevvp(dev, vpp)
302 dev_t dev;
303 struct vnode **vpp;
304{
ef24f6dd
KM
305 register struct vnode *vp;
306 struct vnode *nvp;
307 int error;
308
4ef5d036 309 error = getnewvnode(VT_NON, (struct mount *)0, &spec_vnodeops, &nvp);
ef24f6dd
KM
310 if (error) {
311 *vpp = 0;
312 return (error);
313 }
314 vp = nvp;
315 vp->v_type = VBLK;
c0de8792 316 if (nvp = checkalias(vp, dev, (struct mount *)0)) {
ef24f6dd
KM
317 vput(vp);
318 vp = nvp;
319 }
320 *vpp = vp;
321 return (0);
322}
323
324/*
325 * Check to see if the new vnode represents a special device
326 * for which we already have a vnode (either because of
327 * bdevvp() or because of a different vnode representing
328 * the same block device). If such an alias exists, deallocate
f0556f86 329 * the existing contents and return the aliased vnode. The
ef24f6dd
KM
330 * caller is responsible for filling it with its new contents.
331 */
332struct vnode *
c0de8792 333checkalias(nvp, nvp_rdev, mp)
ef24f6dd 334 register struct vnode *nvp;
c0de8792 335 dev_t nvp_rdev;
ef24f6dd
KM
336 struct mount *mp;
337{
338 register struct vnode *vp;
c0de8792 339 struct vnode **vpp;
ef24f6dd
KM
340
341 if (nvp->v_type != VBLK && nvp->v_type != VCHR)
342 return ((struct vnode *)0);
c0de8792
KM
343
344 vpp = &speclisth[SPECHASH(nvp_rdev)];
ef24f6dd 345loop:
c0de8792
KM
346 for (vp = *vpp; vp; vp = vp->v_specnext) {
347 if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type)
ef24f6dd 348 continue;
c0de8792
KM
349 /*
350 * Alias, but not in use, so flush it out.
351 */
ef62830d 352 if (vp->v_count == 0) {
c0de8792
KM
353 vgone(vp);
354 goto loop;
355 }
ef62830d
KM
356 if (vget(vp))
357 goto loop;
ef24f6dd
KM
358 break;
359 }
c0de8792
KM
360 if (vp == NULL || vp->v_tag != VT_NON) {
361 if (vp != NULL) {
c0de8792 362 nvp->v_flag |= VALIASED;
a45ff315
KM
363 vp->v_flag |= VALIASED;
364 vput(vp);
c0de8792
KM
365 }
366 MALLOC(nvp->v_specinfo, struct specinfo *,
367 sizeof(struct specinfo), M_VNODE, M_WAITOK);
368 nvp->v_rdev = nvp_rdev;
369 nvp->v_mounton = NULL;
370 nvp->v_lastr = 0;
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 }
402 if (vp->v_count == 0) {
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
423 vp->v_count++;
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");
36d09cb1
KM
446 vp->v_count--;
447 if (vp->v_count < 0)
0bf84b18 448 vprint("vrele: bad ref count", vp);
36d09cb1
KM
449 if (vp->v_count > 0)
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
f0556f86
KM
469/*
470 * Remove any vnodes in the vnode table belonging to mount point mp.
471 *
472 * If MNT_NOFORCE is specified, there should not be any active ones,
473 * return error if any are found (nb: this is a user error, not a
474 * system error). If MNT_FORCE is specified, detach any active vnodes
475 * that are found.
476 */
477int busyprt = 0; /* patch to print out busy vnodes */
478
479vflush(mp, skipvp, flags)
480 struct mount *mp;
481 struct vnode *skipvp;
482 int flags;
483{
484 register struct vnode *vp, *nvp;
485 int busy = 0;
486
487 for (vp = mp->m_mounth; vp; vp = nvp) {
488 nvp = vp->v_mountf;
489 /*
490 * Skip over a selected vnode.
491 * Used by ufs to skip over the quota structure inode.
492 */
493 if (vp == skipvp)
494 continue;
495 /*
496 * With v_count == 0, all we need to do is clear
497 * out the vnode data structures and we are done.
498 */
499 if (vp->v_count == 0) {
500 vgone(vp);
501 continue;
502 }
503 /*
504 * For block or character devices, revert to an
505 * anonymous device. For all other files, just kill them.
506 */
507 if (flags & MNT_FORCE) {
508 if (vp->v_type != VBLK && vp->v_type != VCHR) {
509 vgone(vp);
510 } else {
511 vclean(vp, 0);
512 vp->v_op = &spec_vnodeops;
513 insmntque(vp, (struct mount *)0);
514 }
515 continue;
516 }
517 if (busyprt)
0bf84b18 518 vprint("vflush: busy vnode", vp);
f0556f86
KM
519 busy++;
520 }
521 if (busy)
522 return (EBUSY);
523 return (0);
524}
525
ef24f6dd
KM
526/*
527 * Disassociate the underlying file system from a vnode.
ef24f6dd 528 */
2bae1875 529void vclean(vp, doclose)
ef24f6dd 530 register struct vnode *vp;
2bae1875 531 long doclose;
ef24f6dd
KM
532{
533 struct vnodeops *origops;
2bae1875 534 int active;
ef24f6dd 535
2bae1875
KM
536 /*
537 * Check to see if the vnode is in use.
0bf84b18
KM
538 * If so we have to reference it before we clean it out
539 * so that its count cannot fall to zero and generate a
540 * race against ourselves to recycle it.
2bae1875 541 */
0bf84b18 542 if (active = vp->v_count)
2bae1875 543 VREF(vp);
2bae1875
KM
544 /*
545 * Prevent the vnode from being recycled or
546 * brought into use while we clean it out.
547 */
0bf84b18
KM
548 if (vp->v_flag & VXLOCK)
549 panic("vclean: deadlock");
ef24f6dd 550 vp->v_flag |= VXLOCK;
0bf84b18
KM
551 /*
552 * Even if the count is zero, the VOP_INACTIVE routine may still
553 * have the object locked while it cleans it out. The VOP_LOCK
554 * ensures that the VOP_INACTIVE routine is done with its work.
555 * For active vnodes, it ensures that no other activity can
556 * occur while the buffer list is being cleaned out.
557 */
558 VOP_LOCK(vp);
559 if (doclose)
560 vinvalbuf(vp, 1);
ef24f6dd
KM
561 /*
562 * Prevent any further operations on the vnode from
563 * being passed through to the old file system.
564 */
565 origops = vp->v_op;
566 vp->v_op = &dead_vnodeops;
567 vp->v_tag = VT_NON;
568 /*
2bae1875
KM
569 * If purging an active vnode, it must be unlocked, closed,
570 * and deactivated before being reclaimed.
ef24f6dd 571 */
0bf84b18 572 (*(origops->vn_unlock))(vp);
2bae1875 573 if (active) {
2bae1875
KM
574 if (doclose)
575 (*(origops->vn_close))(vp, 0, NOCRED);
ef24f6dd
KM
576 (*(origops->vn_inactive))(vp);
577 }
578 /*
579 * Reclaim the vnode.
580 */
581 if ((*(origops->vn_reclaim))(vp))
582 panic("vclean: cannot reclaim");
2bae1875
KM
583 if (active)
584 vrele(vp);
ef24f6dd
KM
585 /*
586 * Done with purge, notify sleepers in vget of the grim news.
587 */
588 vp->v_flag &= ~VXLOCK;
589 if (vp->v_flag & VXWANT) {
590 vp->v_flag &= ~VXWANT;
591 wakeup((caddr_t)vp);
592 }
593}
594
ef62830d
KM
595/*
596 * Eliminate all activity associated with the requested vnode
597 * and with all vnodes aliased to the requested vnode.
598 */
599void vgoneall(vp)
600 register struct vnode *vp;
601{
602 register struct vnode *vq, **vpp;
603
604 if (vp->v_flag & VALIASED) {
605 vpp = &speclisth[SPECHASH(vp->v_rdev)];
606 loop:
607 for (vq = *vpp; vq; vq = vq->v_specnext) {
608 if (vq->v_rdev != vp->v_rdev || vp == vq)
609 continue;
610 vgone(vq);
611 goto loop;
612 }
613 }
614 vgone(vp);
615}
616
ef24f6dd
KM
617/*
618 * Eliminate all activity associated with a vnode
619 * in preparation for reuse.
620 */
621void vgone(vp)
622 register struct vnode *vp;
623{
c0de8792
KM
624 register struct vnode *vq, **vpp;
625 struct vnode *vx;
626 long count;
ef24f6dd 627
ef24f6dd
KM
628 /*
629 * Clean out the filesystem specific data.
630 */
2bae1875 631 vclean(vp, 1);
ef24f6dd
KM
632 /*
633 * Delete from old mount point vnode list, if on one.
634 */
635 if (vp->v_mountb) {
636 if (vq = vp->v_mountf)
637 vq->v_mountb = vp->v_mountb;
638 *vp->v_mountb = vq;
639 vp->v_mountf = NULL;
640 vp->v_mountb = NULL;
641 }
642 /*
643 * If special device, remove it from special device alias list.
644 */
645 if (vp->v_type == VBLK || vp->v_type == VCHR) {
c0de8792
KM
646 vpp = &speclisth[SPECHASH(vp->v_rdev)];
647 if (*vpp == vp) {
648 *vpp = vp->v_specnext;
ef24f6dd 649 } else {
c0de8792
KM
650 for (vq = *vpp; vq; vq = vq->v_specnext) {
651 if (vq->v_specnext != vp)
ef24f6dd 652 continue;
c0de8792 653 vq->v_specnext = vp->v_specnext;
ef24f6dd
KM
654 break;
655 }
c0de8792 656 if (vq == NULL)
ef24f6dd
KM
657 panic("missing bdev");
658 }
c0de8792
KM
659 if (vp->v_flag & VALIASED) {
660 for (count = 0, vq = *vpp; vq; vq = vq->v_specnext) {
661 if (vq->v_rdev != vp->v_rdev)
662 continue;
663 count++;
664 vx = vq;
665 }
666 if (count == 0)
667 panic("missing alias");
668 if (count == 1)
669 vx->v_flag &= ~VALIASED;
670 vp->v_flag &= ~VALIASED;
671 }
672 FREE(vp->v_specinfo, M_VNODE);
673 vp->v_specinfo = NULL;
ef24f6dd
KM
674 }
675 /*
676 * If it is on the freelist, move it to the head of the list.
677 */
678 if (vp->v_freeb) {
679 if (vq = vp->v_freef)
680 vq->v_freeb = vp->v_freeb;
681 else
682 vfreet = vp->v_freeb;
683 *vp->v_freeb = vq;
684 vp->v_freef = vfreeh;
685 vp->v_freeb = &vfreeh;
686 vfreeh->v_freeb = &vp->v_freef;
687 vfreeh = vp;
688 }
2bae1875 689 vp->v_type = VBAD;
36d09cb1 690}
ef62830d
KM
691
692/*
693 * Calculate the total number of references to a special device.
694 */
695vcount(vp)
696 register struct vnode *vp;
697{
698 register struct vnode *vq, **vpp;
699 int count;
700
701 if ((vp->v_flag & VALIASED) == 0)
702 return (vp->v_count);
703 vpp = &speclisth[SPECHASH(vp->v_rdev)];
704loop:
705 for (count = 0, vq = *vpp; vq; vq = vq->v_specnext) {
706 if (vq->v_rdev != vp->v_rdev)
707 continue;
708 /*
709 * Alias, but not in use, so flush it out.
710 */
711 if (vq->v_count == 0) {
712 vgone(vq);
713 goto loop;
714 }
715 count += vq->v_count;
716 }
717 return (count);
718}
0bf84b18
KM
719
720/*
721 * Print out a description of a vnode.
722 */
723static char *typename[] =
724 { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VBAD" };
725
726vprint(label, vp)
727 char *label;
728 register struct vnode *vp;
729{
730
731 if (label != NULL)
732 printf("%s: ", label);
733 printf("type %s, count %d, ", typename[vp->v_type], vp->v_count);
734 VOP_PRINT(vp);
735}