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