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