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