Removed all patch kit headers, sccsid and rcsid strings, put $Id$ in, some
[unix-history] / sys / kern / vfs_subr.c
CommitLineData
15637ed4
RG
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, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)vfs_subr.c 7.60 (Berkeley) 6/21/91
34 */
35
36/*
37 * External virtual filesystem routines
38 */
39
40#include "param.h"
41#include "proc.h"
42#include "mount.h"
43#include "time.h"
44#include "vnode.h"
45#include "specdev.h"
46#include "namei.h"
47#include "ucred.h"
48#include "buf.h"
49#include "errno.h"
50#include "malloc.h"
51
52/*
53 * Remove a mount point from the list of mounted filesystems.
54 * Unmount of the root is illegal.
55 */
56void
57vfs_remove(mp)
58 register struct mount *mp;
59{
60
61 if (mp == rootfs)
62 panic("vfs_remove: unmounting root");
63 mp->mnt_prev->mnt_next = mp->mnt_next;
64 mp->mnt_next->mnt_prev = mp->mnt_prev;
65 mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0;
66 vfs_unlock(mp);
67}
68
69/*
70 * Lock a filesystem.
71 * Used to prevent access to it while mounting and unmounting.
72 */
73vfs_lock(mp)
74 register struct mount *mp;
75{
76
77 while(mp->mnt_flag & MNT_MLOCK) {
78 mp->mnt_flag |= MNT_MWAIT;
79 sleep((caddr_t)mp, PVFS);
80 }
81 mp->mnt_flag |= MNT_MLOCK;
82 return (0);
83}
84
85/*
86 * Unlock a locked filesystem.
87 * Panic if filesystem is not locked.
88 */
89void
90vfs_unlock(mp)
91 register struct mount *mp;
92{
93
94 if ((mp->mnt_flag & MNT_MLOCK) == 0)
95 panic("vfs_unlock: not locked");
96 mp->mnt_flag &= ~MNT_MLOCK;
97 if (mp->mnt_flag & MNT_MWAIT) {
98 mp->mnt_flag &= ~MNT_MWAIT;
99 wakeup((caddr_t)mp);
100 }
101}
102
103/*
104 * Mark a mount point as busy.
105 * Used to synchronize access and to delay unmounting.
106 */
107vfs_busy(mp)
108 register struct mount *mp;
109{
110
111 while(mp->mnt_flag & MNT_MPBUSY) {
112 mp->mnt_flag |= MNT_MPWANT;
113 sleep((caddr_t)&mp->mnt_flag, PVFS);
114 }
115 if (mp->mnt_flag & MNT_UNMOUNT)
116 return (1);
117 mp->mnt_flag |= MNT_MPBUSY;
118 return (0);
119}
120
121/*
122 * Free a busy filesystem.
123 * Panic if filesystem is not busy.
124 */
125vfs_unbusy(mp)
126 register struct mount *mp;
127{
128
129 if ((mp->mnt_flag & MNT_MPBUSY) == 0)
130 panic("vfs_unbusy: not busy");
131 mp->mnt_flag &= ~MNT_MPBUSY;
132 if (mp->mnt_flag & MNT_MPWANT) {
133 mp->mnt_flag &= ~MNT_MPWANT;
134 wakeup((caddr_t)&mp->mnt_flag);
135 }
136}
137
138/*
139 * Lookup a mount point by filesystem identifier.
140 */
141struct mount *
142getvfs(fsid)
143 fsid_t *fsid;
144{
145 register struct mount *mp;
146
147 mp = rootfs;
148 do {
149 if (mp->mnt_stat.f_fsid.val[0] == fsid->val[0] &&
150 mp->mnt_stat.f_fsid.val[1] == fsid->val[1]) {
151 return (mp);
152 }
153 mp = mp->mnt_next;
154 } while (mp != rootfs);
155 return ((struct mount *)0);
156}
157
158/*
159 * Set vnode attributes to VNOVAL
160 */
161void vattr_null(vap)
162 register struct vattr *vap;
163{
164
165 vap->va_type = VNON;
166 vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid =
167 vap->va_fsid = vap->va_fileid = vap->va_size =
168 vap->va_size_rsv = vap->va_blocksize = vap->va_rdev =
169 vap->va_bytes = vap->va_bytes_rsv =
170 vap->va_atime.tv_sec = vap->va_atime.tv_usec =
171 vap->va_mtime.tv_sec = vap->va_mtime.tv_usec =
172 vap->va_ctime.tv_sec = vap->va_ctime.tv_usec =
173 vap->va_flags = vap->va_gen = VNOVAL;
174}
175
176/*
177 * Routines having to do with the management of the vnode table.
178 */
179struct vnode *vfreeh, **vfreet;
180extern struct vnodeops dead_vnodeops, spec_vnodeops;
181extern void vclean();
182long numvnodes;
183struct vattr va_null;
184
185/*
186 * Initialize the vnode structures and initialize each file system type.
187 */
188vfsinit()
189{
190 struct vfsops **vfsp;
191
192 /*
193 * Initialize the vnode name cache
194 */
195 nchinit();
196 /*
197 * Initialize each file system type.
198 */
199 vattr_null(&va_null);
200 for (vfsp = &vfssw[0]; vfsp <= &vfssw[MOUNT_MAXTYPE]; vfsp++) {
201 if (*vfsp == NULL)
202 continue;
203 (*(*vfsp)->vfs_init)();
204 }
205}
206
207/*
208 * Return the next vnode from the free list.
209 */
210getnewvnode(tag, mp, vops, vpp)
211 enum vtagtype tag;
212 struct mount *mp;
213 struct vnodeops *vops;
214 struct vnode **vpp;
215{
216 register struct vnode *vp, *vq;
217
218 if (numvnodes < desiredvnodes) {
219 vp = (struct vnode *)malloc((u_long)sizeof *vp,
220 M_VNODE, M_WAITOK);
221 bzero((char *)vp, sizeof *vp);
222 numvnodes++;
223 } else {
224 if ((vp = vfreeh) == NULL) {
225 tablefull("vnode");
226 *vpp = 0;
227 return (ENFILE);
228 }
229 if (vp->v_usecount)
230 panic("free vnode isn't");
231 if (vq = vp->v_freef)
232 vq->v_freeb = &vfreeh;
233 else
234 vfreet = &vfreeh;
235 vfreeh = vq;
236 vp->v_freef = NULL;
237 vp->v_freeb = NULL;
238 if (vp->v_type != VBAD)
239 vgone(vp);
240 vp->v_flag = 0;
241 vp->v_lastr = 0;
242 vp->v_socket = 0;
243 }
244 vp->v_type = VNON;
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 */
257insmntque(vp, mp)
258 register struct vnode *vp;
259 register struct mount *mp;
260{
261 register 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 (vq = mp->mnt_mounth)
281 vq->v_mountb = &vp->v_mountf;
282 vp->v_mountf = vq;
283 vp->v_mountb = &mp->mnt_mounth;
284 mp->mnt_mounth = vp;
285}
286
287/*
288 * Make sure all write-behind blocks associated
289 * with mount point are flushed out (from sync).
290 */
291mntflushbuf(mountp, flags)
292 struct mount *mountp;
293 int flags;
294{
295 register struct vnode *vp;
296
297 if ((mountp->mnt_flag & MNT_MPBUSY) == 0)
298 panic("mntflushbuf: not busy");
299loop:
300 for (vp = mountp->mnt_mounth; vp; vp = vp->v_mountf) {
301 if (VOP_ISLOCKED(vp))
302 continue;
303 if (vget(vp))
304 goto loop;
305 vflushbuf(vp, flags);
306 vput(vp);
307 if (vp->v_mount != mountp)
308 goto loop;
309 }
310}
311
312/*
313 * Flush all dirty buffers associated with a vnode.
314 */
315vflushbuf(vp, flags)
316 register struct vnode *vp;
317 int flags;
318{
319 register struct buf *bp;
320 struct buf *nbp;
321 int s;
322
323loop:
324 s = splbio();
325 for (bp = vp->v_dirtyblkhd; bp; bp = nbp) {
326 nbp = bp->b_blockf;
327 if ((bp->b_flags & B_BUSY))
328 continue;
329 if ((bp->b_flags & B_DELWRI) == 0)
330 panic("vflushbuf: not dirty");
331 bremfree(bp);
332 bp->b_flags |= B_BUSY;
333 splx(s);
334 /*
335 * Wait for I/O associated with indirect blocks to complete,
336 * since there is no way to quickly wait for them below.
337 * NB: This is really specific to ufs, but is done here
338 * as it is easier and quicker.
339 */
340 if (bp->b_vp == vp || (flags & B_SYNC) == 0)
341 (void) bawrite(bp);
342 else
343 (void) bwrite(bp);
344 goto loop;
345 }
346 splx(s);
347 if ((flags & B_SYNC) == 0)
348 return;
349 s = splbio();
350 while (vp->v_numoutput) {
351 vp->v_flag |= VBWAIT;
352 sleep((caddr_t)&vp->v_numoutput, PRIBIO + 1);
353 }
354 splx(s);
355 if (vp->v_dirtyblkhd) {
356 vprint("vflushbuf: dirty", vp);
357 goto loop;
358 }
359}
360
361/*
362 * Update outstanding I/O count and do wakeup if requested.
363 */
364vwakeup(bp)
365 register struct buf *bp;
366{
367 register struct vnode *vp;
368
369 bp->b_dirtyoff = bp->b_dirtyend = 0;
370 if (vp = bp->b_vp) {
371 vp->v_numoutput--;
372 if ((vp->v_flag & VBWAIT) && vp->v_numoutput <= 0) {
373 if (vp->v_numoutput < 0)
374 panic("vwakeup: neg numoutput");
375 vp->v_flag &= ~VBWAIT;
376 wakeup((caddr_t)&vp->v_numoutput);
377 }
378 }
379}
380
381/*
382 * Invalidate in core blocks belonging to closed or umounted filesystem
383 *
384 * Go through the list of vnodes associated with the file system;
385 * for each vnode invalidate any buffers that it holds. Normally
386 * this routine is preceeded by a bflush call, so that on a quiescent
387 * filesystem there will be no dirty buffers when we are done. Binval
388 * returns the count of dirty buffers when it is finished.
389 */
390mntinvalbuf(mountp)
391 struct mount *mountp;
392{
393 register struct vnode *vp;
394 int dirty = 0;
395
396 if ((mountp->mnt_flag & MNT_MPBUSY) == 0)
397 panic("mntinvalbuf: not busy");
398loop:
399 for (vp = mountp->mnt_mounth; vp; vp = vp->v_mountf) {
400 if (vget(vp))
401 goto loop;
402 dirty += vinvalbuf(vp, 1);
403 vput(vp);
404 if (vp->v_mount != mountp)
405 goto loop;
406 }
407 return (dirty);
408}
409
410/*
411 * Flush out and invalidate all buffers associated with a vnode.
412 * Called with the underlying object locked.
413 */
414vinvalbuf(vp, save)
415 register struct vnode *vp;
416 int save;
417{
418 register struct buf *bp;
419 struct buf *nbp, *blist;
420 int s, dirty = 0;
421
422 for (;;) {
423 if (blist = vp->v_dirtyblkhd)
424 /* void */;
425 else if (blist = vp->v_cleanblkhd)
426 /* void */;
427 else
428 break;
429 for (bp = blist; bp; bp = nbp) {
430 nbp = bp->b_blockf;
431 s = splbio();
432 if (bp->b_flags & B_BUSY) {
433 bp->b_flags |= B_WANTED;
434 sleep((caddr_t)bp, PRIBIO + 1);
435 splx(s);
436 break;
437 }
438 bremfree(bp);
439 bp->b_flags |= B_BUSY;
440 splx(s);
441 if (save && (bp->b_flags & B_DELWRI)) {
442 dirty++;
443 (void) bwrite(bp);
444 break;
445 }
446 if (bp->b_vp != vp)
447 reassignbuf(bp, bp->b_vp);
448 else
449 bp->b_flags |= B_INVAL;
450 brelse(bp);
451 }
452 }
453 if (vp->v_dirtyblkhd || vp->v_cleanblkhd)
454 panic("vinvalbuf: flush failed");
455 return (dirty);
456}
457
458/*
459 * Associate a buffer with a vnode.
460 */
461bgetvp(vp, bp)
462 register struct vnode *vp;
463 register struct buf *bp;
464{
465 register struct vnode *vq;
466 register struct buf *bq;
467
468 if (bp->b_vp)
469 panic("bgetvp: not free");
470 VHOLD(vp);
471 bp->b_vp = vp;
472 if (vp->v_type == VBLK || vp->v_type == VCHR)
473 bp->b_dev = vp->v_rdev;
474 else
475 bp->b_dev = NODEV;
476 /*
477 * Insert onto list for new vnode.
478 */
479 if (bq = vp->v_cleanblkhd)
480 bq->b_blockb = &bp->b_blockf;
481 bp->b_blockf = bq;
482 bp->b_blockb = &vp->v_cleanblkhd;
483 vp->v_cleanblkhd = bp;
484}
485
486/*
487 * Disassociate a buffer from a vnode.
488 */
489brelvp(bp)
490 register struct buf *bp;
491{
492 struct buf *bq;
493 struct vnode *vp;
494
495 if (bp->b_vp == (struct vnode *) 0)
496 panic("brelvp: NULL");
497 /*
498 * Delete from old vnode list, if on one.
499 */
500 if (bp->b_blockb) {
501 if (bq = bp->b_blockf)
502 bq->b_blockb = bp->b_blockb;
503 *bp->b_blockb = bq;
504 bp->b_blockf = NULL;
505 bp->b_blockb = NULL;
506 }
507 vp = bp->b_vp;
508 bp->b_vp = (struct vnode *) 0;
509 HOLDRELE(vp);
510}
511
512/*
513 * Reassign a buffer from one vnode to another.
514 * Used to assign file specific control information
515 * (indirect blocks) to the vnode to which they belong.
516 */
517reassignbuf(bp, newvp)
518 register struct buf *bp;
519 register struct vnode *newvp;
520{
521 register struct buf *bq, **listheadp;
522
523 if (newvp == NULL)
524 panic("reassignbuf: NULL");
525 /*
526 * Delete from old vnode list, if on one.
527 */
528 if (bp->b_blockb) {
529 if (bq = bp->b_blockf)
530 bq->b_blockb = bp->b_blockb;
531 *bp->b_blockb = bq;
532 }
533 /*
534 * If dirty, put on list of dirty buffers;
535 * otherwise insert onto list of clean buffers.
536 */
537 if (bp->b_flags & B_DELWRI)
538 listheadp = &newvp->v_dirtyblkhd;
539 else
540 listheadp = &newvp->v_cleanblkhd;
541 if (bq = *listheadp)
542 bq->b_blockb = &bp->b_blockf;
543 bp->b_blockf = bq;
544 bp->b_blockb = listheadp;
545 *listheadp = bp;
546}
547
548/*
549 * Create a vnode for a block device.
550 * Used for root filesystem, argdev, and swap areas.
551 * Also used for memory file system special devices.
552 */
553bdevvp(dev, vpp)
554 dev_t dev;
555 struct vnode **vpp;
84367f04
AM
556{
557 return(getdevvp(dev, vpp, VBLK));
558}
559
560
561/*
562 * Create a vnode for a device.
563 * Used by bdevvp (block device) for root file system etc.,
564 * and by cnopen for console (character device).
565 */
566getdevvp(dev, vpp, type)
567 dev_t dev;
568 struct vnode **vpp;
569 enum vtype type;
15637ed4
RG
570{
571 register struct vnode *vp;
572 struct vnode *nvp;
573 int error;
574
575 if (dev == NODEV)
576 return (0);
577 error = getnewvnode(VT_NON, (struct mount *)0, &spec_vnodeops, &nvp);
578 if (error) {
84367f04 579 *vpp = NULLVP;
15637ed4
RG
580 return (error);
581 }
582 vp = nvp;
84367f04 583 vp->v_type = type;
15637ed4
RG
584 if (nvp = checkalias(vp, dev, (struct mount *)0)) {
585 vput(vp);
586 vp = nvp;
587 }
588 *vpp = vp;
589 return (0);
590}
591
592/*
593 * Check to see if the new vnode represents a special device
594 * for which we already have a vnode (either because of
595 * bdevvp() or because of a different vnode representing
596 * the same block device). If such an alias exists, deallocate
597 * the existing contents and return the aliased vnode. The
598 * caller is responsible for filling it with its new contents.
599 */
600struct vnode *
601checkalias(nvp, nvp_rdev, mp)
602 register struct vnode *nvp;
603 dev_t nvp_rdev;
604 struct mount *mp;
605{
606 register struct vnode *vp;
607 struct vnode **vpp;
608
609 if (nvp->v_type != VBLK && nvp->v_type != VCHR)
610 return (NULLVP);
611
612 vpp = &speclisth[SPECHASH(nvp_rdev)];
613loop:
614 for (vp = *vpp; vp; vp = vp->v_specnext) {
615 if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type)
616 continue;
617 /*
618 * Alias, but not in use, so flush it out.
619 */
620 if (vp->v_usecount == 0) {
621 vgone(vp);
622 goto loop;
623 }
624 if (vget(vp))
625 goto loop;
626 break;
627 }
628 if (vp == NULL || vp->v_tag != VT_NON) {
629 MALLOC(nvp->v_specinfo, struct specinfo *,
630 sizeof(struct specinfo), M_VNODE, M_WAITOK);
631 nvp->v_rdev = nvp_rdev;
632 nvp->v_hashchain = vpp;
633 nvp->v_specnext = *vpp;
634 nvp->v_specflags = 0;
635 *vpp = nvp;
636 if (vp != NULL) {
637 nvp->v_flag |= VALIASED;
638 vp->v_flag |= VALIASED;
639 vput(vp);
640 }
641 return (NULLVP);
642 }
643 VOP_UNLOCK(vp);
644 vclean(vp, 0);
645 vp->v_op = nvp->v_op;
646 vp->v_tag = nvp->v_tag;
647 nvp->v_type = VNON;
648 insmntque(vp, mp);
649 return (vp);
650}
651
652/*
653 * Grab a particular vnode from the free list, increment its
654 * reference count and lock it. The vnode lock bit is set the
655 * vnode is being eliminated in vgone. The process is awakened
656 * when the transition is completed, and an error returned to
657 * indicate that the vnode is no longer usable (possibly having
658 * been changed to a new file system type).
659 */
660vget(vp)
661 register struct vnode *vp;
662{
663 register struct vnode *vq;
664
665 if (vp->v_flag & VXLOCK) {
666 vp->v_flag |= VXWANT;
667 sleep((caddr_t)vp, PINOD);
668 return (1);
669 }
670 if (vp->v_usecount == 0) {
671 if (vq = vp->v_freef)
672 vq->v_freeb = vp->v_freeb;
673 else
674 vfreet = vp->v_freeb;
675 *vp->v_freeb = vq;
676 vp->v_freef = NULL;
677 vp->v_freeb = NULL;
678 }
679 VREF(vp);
680 VOP_LOCK(vp);
681 return (0);
682}
683
684/*
685 * Vnode reference, just increment the count
686 */
687void vref(vp)
688 struct vnode *vp;
689{
690
691 vp->v_usecount++;
692}
693
694/*
695 * vput(), just unlock and vrele()
696 */
697void vput(vp)
698 register struct vnode *vp;
699{
700 VOP_UNLOCK(vp);
701 vrele(vp);
702}
703
704/*
705 * Vnode release.
706 * If count drops to zero, call inactive routine and return to freelist.
707 */
708void vrele(vp)
709 register struct vnode *vp;
710{
711 struct proc *p = curproc; /* XXX */
712
713#ifdef DIAGNOSTIC
714 if (vp == NULL)
715 panic("vrele: null vp");
716#endif
717 vp->v_usecount--;
718 if (vp->v_usecount > 0)
719 return;
720#ifdef DIAGNOSTIC
721 if (vp->v_usecount != 0 || vp->v_writecount != 0) {
722 vprint("vrele: bad ref count", vp);
723 panic("vrele: ref cnt");
724 }
725#endif
726 if (vfreeh == NULLVP) {
727 /*
728 * insert into empty list
729 */
730 vfreeh = vp;
731 vp->v_freeb = &vfreeh;
732 } else {
733 /*
734 * insert at tail of list
735 */
736 *vfreet = vp;
737 vp->v_freeb = vfreet;
738 }
739 vp->v_freef = NULL;
740 vfreet = &vp->v_freef;
741 VOP_INACTIVE(vp, p);
742}
743
744/*
745 * Page or buffer structure gets a reference.
746 */
747vhold(vp)
748 register struct vnode *vp;
749{
750
751 vp->v_holdcnt++;
752}
753
754/*
755 * Page or buffer structure frees a reference.
756 */
757holdrele(vp)
758 register struct vnode *vp;
759{
760
761 if (vp->v_holdcnt <= 0)
762 panic("holdrele: holdcnt");
763 vp->v_holdcnt--;
764}
765
766/*
767 * Remove any vnodes in the vnode table belonging to mount point mp.
768 *
769 * If MNT_NOFORCE is specified, there should not be any active ones,
770 * return error if any are found (nb: this is a user error, not a
771 * system error). If MNT_FORCE is specified, detach any active vnodes
772 * that are found.
773 */
774int busyprt = 0; /* patch to print out busy vnodes */
775
776vflush(mp, skipvp, flags)
777 struct mount *mp;
778 struct vnode *skipvp;
779 int flags;
780{
781 register struct vnode *vp, *nvp;
782 int busy = 0;
783
784 if ((mp->mnt_flag & MNT_MPBUSY) == 0)
785 panic("vflush: not busy");
786loop:
787 for (vp = mp->mnt_mounth; vp; vp = nvp) {
788 if (vp->v_mount != mp)
789 goto loop;
790 nvp = vp->v_mountf;
791 /*
792 * Skip over a selected vnode.
793 */
794 if (vp == skipvp)
795 continue;
796 /*
797 * Skip over a vnodes marked VSYSTEM.
798 */
799 if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM))
800 continue;
801 /*
802 * With v_usecount == 0, all we need to do is clear
803 * out the vnode data structures and we are done.
804 */
805 if (vp->v_usecount == 0) {
806 vgone(vp);
807 continue;
808 }
809 /*
810 * For block or character devices, revert to an
811 * anonymous device. For all other files, just kill them.
812 */
813 if (flags & FORCECLOSE) {
814 if (vp->v_type != VBLK && vp->v_type != VCHR) {
815 vgone(vp);
816 } else {
817 vclean(vp, 0);
818 vp->v_op = &spec_vnodeops;
819 insmntque(vp, (struct mount *)0);
820 }
821 continue;
822 }
823 if (busyprt)
824 vprint("vflush: busy vnode", vp);
825 busy++;
826 }
827 if (busy)
828 return (EBUSY);
829 return (0);
830}
831
832/*
833 * Disassociate the underlying file system from a vnode.
834 */
835void vclean(vp, flags)
836 register struct vnode *vp;
837 int flags;
838{
839 struct vnodeops *origops;
840 int active;
841 struct proc *p = curproc; /* XXX */
842
843 /*
844 * Check to see if the vnode is in use.
845 * If so we have to reference it before we clean it out
846 * so that its count cannot fall to zero and generate a
847 * race against ourselves to recycle it.
848 */
849 if (active = vp->v_usecount)
850 VREF(vp);
851 /*
852 * Prevent the vnode from being recycled or
853 * brought into use while we clean it out.
854 */
855 if (vp->v_flag & VXLOCK)
856 panic("vclean: deadlock");
857 vp->v_flag |= VXLOCK;
858 /*
859 * Even if the count is zero, the VOP_INACTIVE routine may still
860 * have the object locked while it cleans it out. The VOP_LOCK
861 * ensures that the VOP_INACTIVE routine is done with its work.
862 * For active vnodes, it ensures that no other activity can
863 * occur while the buffer list is being cleaned out.
864 */
865 VOP_LOCK(vp);
866 if (flags & DOCLOSE)
867 vinvalbuf(vp, 1);
868 /*
869 * Prevent any further operations on the vnode from
870 * being passed through to the old file system.
871 */
872 origops = vp->v_op;
873 vp->v_op = &dead_vnodeops;
874 vp->v_tag = VT_NON;
875 /*
876 * If purging an active vnode, it must be unlocked, closed,
877 * and deactivated before being reclaimed.
878 */
879 (*(origops->vop_unlock))(vp);
880 if (active) {
881 if (flags & DOCLOSE)
882 (*(origops->vop_close))(vp, IO_NDELAY, NOCRED, p);
883 (*(origops->vop_inactive))(vp, p);
884 }
885 /*
886 * Reclaim the vnode.
887 */
888 if ((*(origops->vop_reclaim))(vp))
889 panic("vclean: cannot reclaim");
890 if (active)
891 vrele(vp);
892 /*
893 * Done with purge, notify sleepers in vget of the grim news.
894 */
895 vp->v_flag &= ~VXLOCK;
896 if (vp->v_flag & VXWANT) {
897 vp->v_flag &= ~VXWANT;
898 wakeup((caddr_t)vp);
899 }
900}
901
902/*
903 * Eliminate all activity associated with the requested vnode
904 * and with all vnodes aliased to the requested vnode.
905 */
906void vgoneall(vp)
907 register struct vnode *vp;
908{
909 register struct vnode *vq;
910
911 if (vp->v_flag & VALIASED) {
912 /*
913 * If a vgone (or vclean) is already in progress,
914 * wait until it is done and return.
915 */
916 if (vp->v_flag & VXLOCK) {
917 vp->v_flag |= VXWANT;
918 sleep((caddr_t)vp, PINOD);
919 return;
920 }
921 /*
922 * Ensure that vp will not be vgone'd while we
923 * are eliminating its aliases.
924 */
925 vp->v_flag |= VXLOCK;
926 while (vp->v_flag & VALIASED) {
927 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
928 if (vq->v_rdev != vp->v_rdev ||
929 vq->v_type != vp->v_type || vp == vq)
930 continue;
931 vgone(vq);
932 break;
933 }
934 }
935 /*
936 * Remove the lock so that vgone below will
937 * really eliminate the vnode after which time
938 * vgone will awaken any sleepers.
939 */
940 vp->v_flag &= ~VXLOCK;
941 }
942 vgone(vp);
943}
944
945/*
946 * Eliminate all activity associated with a vnode
947 * in preparation for reuse.
948 */
949void vgone(vp)
950 register struct vnode *vp;
951{
952 register struct vnode *vq;
953 struct vnode *vx;
954 long count;
955
956 /*
957 * If a vgone (or vclean) is already in progress,
958 * wait until it is done and return.
959 */
960 if (vp->v_flag & VXLOCK) {
961 vp->v_flag |= VXWANT;
962 sleep((caddr_t)vp, PINOD);
963 return;
964 }
965 /*
966 * Clean out the filesystem specific data.
967 */
968 vclean(vp, DOCLOSE);
969 /*
970 * Delete from old mount point vnode list, if on one.
971 */
972 if (vp->v_mountb) {
973 if (vq = vp->v_mountf)
974 vq->v_mountb = vp->v_mountb;
975 *vp->v_mountb = vq;
976 vp->v_mountf = NULL;
977 vp->v_mountb = NULL;
978 }
979 /*
980 * If special device, remove it from special device alias list.
981 */
982 if (vp->v_type == VBLK || vp->v_type == VCHR) {
983 if (*vp->v_hashchain == vp) {
984 *vp->v_hashchain = vp->v_specnext;
985 } else {
986 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
987 if (vq->v_specnext != vp)
988 continue;
989 vq->v_specnext = vp->v_specnext;
990 break;
991 }
992 if (vq == NULL)
993 panic("missing bdev");
994 }
995 if (vp->v_flag & VALIASED) {
996 count = 0;
997 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
998 if (vq->v_rdev != vp->v_rdev ||
999 vq->v_type != vp->v_type)
1000 continue;
1001 count++;
1002 vx = vq;
1003 }
1004 if (count == 0)
1005 panic("missing alias");
1006 if (count == 1)
1007 vx->v_flag &= ~VALIASED;
1008 vp->v_flag &= ~VALIASED;
1009 }
1010 FREE(vp->v_specinfo, M_VNODE);
1011 vp->v_specinfo = NULL;
1012 }
1013 /*
1014 * If it is on the freelist, move it to the head of the list.
1015 */
1016 if (vp->v_freeb) {
1017 if (vq = vp->v_freef)
1018 vq->v_freeb = vp->v_freeb;
1019 else
1020 vfreet = vp->v_freeb;
1021 *vp->v_freeb = vq;
1022 vp->v_freef = vfreeh;
1023 vp->v_freeb = &vfreeh;
1024 vfreeh->v_freeb = &vp->v_freef;
1025 vfreeh = vp;
1026 }
1027 vp->v_type = VBAD;
1028}
1029
1030/*
1031 * Lookup a vnode by device number.
1032 */
1033vfinddev(dev, type, vpp)
1034 dev_t dev;
1035 enum vtype type;
1036 struct vnode **vpp;
1037{
1038 register struct vnode *vp;
1039
1040 for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) {
1041 if (dev != vp->v_rdev || type != vp->v_type)
1042 continue;
1043 *vpp = vp;
1044 return (0);
1045 }
1046 return (1);
1047}
1048
1049/*
1050 * Calculate the total number of references to a special device.
1051 */
1052vcount(vp)
1053 register struct vnode *vp;
1054{
1055 register struct vnode *vq;
1056 int count;
1057
1058 if ((vp->v_flag & VALIASED) == 0)
1059 return (vp->v_usecount);
1060loop:
1061 for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
1062 if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type)
1063 continue;
1064 /*
1065 * Alias, but not in use, so flush it out.
1066 */
1067 if (vq->v_usecount == 0) {
1068 vgone(vq);
1069 goto loop;
1070 }
1071 count += vq->v_usecount;
1072 }
1073 return (count);
1074}
1075
1076/*
1077 * Print out a description of a vnode.
1078 */
1079static char *typename[] =
1080 { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" };
1081
1082vprint(label, vp)
1083 char *label;
1084 register struct vnode *vp;
1085{
1086 char buf[64];
1087
1088 if (label != NULL)
1089 printf("%s: ", label);
1090 printf("type %s, usecount %d, writecount %d, refcount %d,",
1091 typename[vp->v_type], vp->v_usecount, vp->v_writecount,
1092 vp->v_holdcnt);
1093 buf[0] = '\0';
1094 if (vp->v_flag & VROOT)
1095 strcat(buf, "|VROOT");
1096 if (vp->v_flag & VTEXT)
1097 strcat(buf, "|VTEXT");
1098 if (vp->v_flag & VSYSTEM)
1099 strcat(buf, "|VSYSTEM");
1100 if (vp->v_flag & VXLOCK)
1101 strcat(buf, "|VXLOCK");
1102 if (vp->v_flag & VXWANT)
1103 strcat(buf, "|VXWANT");
1104 if (vp->v_flag & VBWAIT)
1105 strcat(buf, "|VBWAIT");
1106 if (vp->v_flag & VALIASED)
1107 strcat(buf, "|VALIASED");
1108 if (buf[0] != '\0')
1109 printf(" flags (%s)", &buf[1]);
1110 printf("\n\t");
1111 VOP_PRINT(vp);
1112}
1113
1114#ifdef DEBUG
1115/*
1116 * List all of the locked vnodes in the system.
1117 * Called when debugging the kernel.
1118 */
1119printlockedvnodes()
1120{
1121 register struct mount *mp;
1122 register struct vnode *vp;
1123
1124 printf("Locked vnodes\n");
1125 mp = rootfs;
1126 do {
1127 for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf)
1128 if (VOP_ISLOCKED(vp))
1129 vprint((char *)0, vp);
1130 mp = mp->mnt_next;
1131 } while (mp != rootfs);
1132}
1133#endif
1134
1135int kinfo_vdebug = 1;
1136int kinfo_vgetfailed;
1137#define KINFO_VNODESLOP 10
1138/*
1139 * Dump vnode list (via kinfo).
1140 * Copyout address of vnode followed by vnode.
1141 */
1142/* ARGSUSED */
1143kinfo_vnode(op, where, acopysize, arg, aneeded)
1144 int op;
1145 char *where;
1146 int *acopysize, arg, *aneeded;
1147{
1148 register struct mount *mp = rootfs;
1149 struct mount *omp;
1150 struct vnode *vp;
1151 register char *bp = where, *savebp;
1152 char *ewhere = where + *acopysize;
1153 int error;
1154
1155#define VPTRSZ sizeof (struct vnode *)
1156#define VNODESZ sizeof (struct vnode)
1157 if (where == NULL) {
1158 *aneeded = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ);
1159 return (0);
1160 }
1161
1162 do {
1163 if (vfs_busy(mp)) {
1164 mp = mp->mnt_next;
1165 continue;
1166 }
1167 savebp = bp;
1168again:
1169 for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) {
1170 /*
1171 * Check that the vp is still associated with
1172 * this filesystem. RACE: could have been
1173 * recycled onto the same filesystem.
1174 */
1175 if (vp->v_mount != mp) {
1176 if (kinfo_vdebug)
1177 printf("kinfo: vp changed\n");
1178 bp = savebp;
1179 goto again;
1180 }
1181 if ((bp + VPTRSZ + VNODESZ <= ewhere) &&
1182 ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) ||
1183 (error = copyout((caddr_t)vp, bp + VPTRSZ,
1184 VNODESZ))))
1185 return (error);
1186 bp += VPTRSZ + VNODESZ;
1187 }
1188 omp = mp;
1189 mp = mp->mnt_next;
1190 vfs_unbusy(omp);
1191 } while (mp != rootfs);
1192
1193 *aneeded = bp - where;
1194 if (bp > ewhere)
1195 *acopysize = ewhere - where;
1196 else
1197 *acopysize = bp - where;
1198 return (0);
1199}