386BSD 0.1 development
[unix-history] / usr / src / sys.386bsd / kern / vfs_subr.c
CommitLineData
b688fc87
WJ
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;
556{
557 register struct vnode *vp;
558 struct vnode *nvp;
559 int error;
560
561 if (dev == NODEV)
562 return (0);
563 error = getnewvnode(VT_NON, (struct mount *)0, &spec_vnodeops, &nvp);
564 if (error) {
565 *vpp = 0;
566 return (error);
567 }
568 vp = nvp;
569 vp->v_type = VBLK;
570 if (nvp = checkalias(vp, dev, (struct mount *)0)) {
571 vput(vp);
572 vp = nvp;
573 }
574 *vpp = vp;
575 return (0);
576}
577
578/*
579 * Check to see if the new vnode represents a special device
580 * for which we already have a vnode (either because of
581 * bdevvp() or because of a different vnode representing
582 * the same block device). If such an alias exists, deallocate
583 * the existing contents and return the aliased vnode. The
584 * caller is responsible for filling it with its new contents.
585 */
586struct vnode *
587checkalias(nvp, nvp_rdev, mp)
588 register struct vnode *nvp;
589 dev_t nvp_rdev;
590 struct mount *mp;
591{
592 register struct vnode *vp;
593 struct vnode **vpp;
594
595 if (nvp->v_type != VBLK && nvp->v_type != VCHR)
596 return (NULLVP);
597
598 vpp = &speclisth[SPECHASH(nvp_rdev)];
599loop:
600 for (vp = *vpp; vp; vp = vp->v_specnext) {
601 if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type)
602 continue;
603 /*
604 * Alias, but not in use, so flush it out.
605 */
606 if (vp->v_usecount == 0) {
607 vgone(vp);
608 goto loop;
609 }
610 if (vget(vp))
611 goto loop;
612 break;
613 }
614 if (vp == NULL || vp->v_tag != VT_NON) {
615 MALLOC(nvp->v_specinfo, struct specinfo *,
616 sizeof(struct specinfo), M_VNODE, M_WAITOK);
617 nvp->v_rdev = nvp_rdev;
618 nvp->v_hashchain = vpp;
619 nvp->v_specnext = *vpp;
620 nvp->v_specflags = 0;
621 *vpp = nvp;
622 if (vp != NULL) {
623 nvp->v_flag |= VALIASED;
624 vp->v_flag |= VALIASED;
625 vput(vp);
626 }
627 return (NULLVP);
628 }
629 VOP_UNLOCK(vp);
630 vclean(vp, 0);
631 vp->v_op = nvp->v_op;
632 vp->v_tag = nvp->v_tag;
633 nvp->v_type = VNON;
634 insmntque(vp, mp);
635 return (vp);
636}
637
638/*
639 * Grab a particular vnode from the free list, increment its
640 * reference count and lock it. The vnode lock bit is set the
641 * vnode is being eliminated in vgone. The process is awakened
642 * when the transition is completed, and an error returned to
643 * indicate that the vnode is no longer usable (possibly having
644 * been changed to a new file system type).
645 */
646vget(vp)
647 register struct vnode *vp;
648{
649 register struct vnode *vq;
650
651 if (vp->v_flag & VXLOCK) {
652 vp->v_flag |= VXWANT;
653 sleep((caddr_t)vp, PINOD);
654 return (1);
655 }
656 if (vp->v_usecount == 0) {
657 if (vq = vp->v_freef)
658 vq->v_freeb = vp->v_freeb;
659 else
660 vfreet = vp->v_freeb;
661 *vp->v_freeb = vq;
662 vp->v_freef = NULL;
663 vp->v_freeb = NULL;
664 }
665 VREF(vp);
666 VOP_LOCK(vp);
667 return (0);
668}
669
670/*
671 * Vnode reference, just increment the count
672 */
673void vref(vp)
674 struct vnode *vp;
675{
676
677 vp->v_usecount++;
678}
679
680/*
681 * vput(), just unlock and vrele()
682 */
683void vput(vp)
684 register struct vnode *vp;
685{
686 VOP_UNLOCK(vp);
687 vrele(vp);
688}
689
690/*
691 * Vnode release.
692 * If count drops to zero, call inactive routine and return to freelist.
693 */
694void vrele(vp)
695 register struct vnode *vp;
696{
697 struct proc *p = curproc; /* XXX */
698
699#ifdef DIAGNOSTIC
700 if (vp == NULL)
701 panic("vrele: null vp");
702#endif
703 vp->v_usecount--;
704 if (vp->v_usecount > 0)
705 return;
706#ifdef DIAGNOSTIC
707 if (vp->v_usecount != 0 || vp->v_writecount != 0) {
708 vprint("vrele: bad ref count", vp);
709 panic("vrele: ref cnt");
710 }
711#endif
712 if (vfreeh == NULLVP) {
713 /*
714 * insert into empty list
715 */
716 vfreeh = vp;
717 vp->v_freeb = &vfreeh;
718 } else {
719 /*
720 * insert at tail of list
721 */
722 *vfreet = vp;
723 vp->v_freeb = vfreet;
724 }
725 vp->v_freef = NULL;
726 vfreet = &vp->v_freef;
727 VOP_INACTIVE(vp, p);
728}
729
730/*
731 * Page or buffer structure gets a reference.
732 */
733vhold(vp)
734 register struct vnode *vp;
735{
736
737 vp->v_holdcnt++;
738}
739
740/*
741 * Page or buffer structure frees a reference.
742 */
743holdrele(vp)
744 register struct vnode *vp;
745{
746
747 if (vp->v_holdcnt <= 0)
748 panic("holdrele: holdcnt");
749 vp->v_holdcnt--;
750}
751
752/*
753 * Remove any vnodes in the vnode table belonging to mount point mp.
754 *
755 * If MNT_NOFORCE is specified, there should not be any active ones,
756 * return error if any are found (nb: this is a user error, not a
757 * system error). If MNT_FORCE is specified, detach any active vnodes
758 * that are found.
759 */
760int busyprt = 0; /* patch to print out busy vnodes */
761
762vflush(mp, skipvp, flags)
763 struct mount *mp;
764 struct vnode *skipvp;
765 int flags;
766{
767 register struct vnode *vp, *nvp;
768 int busy = 0;
769
770 if ((mp->mnt_flag & MNT_MPBUSY) == 0)
771 panic("vflush: not busy");
772loop:
773 for (vp = mp->mnt_mounth; vp; vp = nvp) {
774 if (vp->v_mount != mp)
775 goto loop;
776 nvp = vp->v_mountf;
777 /*
778 * Skip over a selected vnode.
779 */
780 if (vp == skipvp)
781 continue;
782 /*
783 * Skip over a vnodes marked VSYSTEM.
784 */
785 if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM))
786 continue;
787 /*
788 * With v_usecount == 0, all we need to do is clear
789 * out the vnode data structures and we are done.
790 */
791 if (vp->v_usecount == 0) {
792 vgone(vp);
793 continue;
794 }
795 /*
796 * For block or character devices, revert to an
797 * anonymous device. For all other files, just kill them.
798 */
799 if (flags & FORCECLOSE) {
800 if (vp->v_type != VBLK && vp->v_type != VCHR) {
801 vgone(vp);
802 } else {
803 vclean(vp, 0);
804 vp->v_op = &spec_vnodeops;
805 insmntque(vp, (struct mount *)0);
806 }
807 continue;
808 }
809 if (busyprt)
810 vprint("vflush: busy vnode", vp);
811 busy++;
812 }
813 if (busy)
814 return (EBUSY);
815 return (0);
816}
817
818/*
819 * Disassociate the underlying file system from a vnode.
820 */
821void vclean(vp, flags)
822 register struct vnode *vp;
823 int flags;
824{
825 struct vnodeops *origops;
826 int active;
827 struct proc *p = curproc; /* XXX */
828
829 /*
830 * Check to see if the vnode is in use.
831 * If so we have to reference it before we clean it out
832 * so that its count cannot fall to zero and generate a
833 * race against ourselves to recycle it.
834 */
835 if (active = vp->v_usecount)
836 VREF(vp);
837 /*
838 * Prevent the vnode from being recycled or
839 * brought into use while we clean it out.
840 */
841 if (vp->v_flag & VXLOCK)
842 panic("vclean: deadlock");
843 vp->v_flag |= VXLOCK;
844 /*
845 * Even if the count is zero, the VOP_INACTIVE routine may still
846 * have the object locked while it cleans it out. The VOP_LOCK
847 * ensures that the VOP_INACTIVE routine is done with its work.
848 * For active vnodes, it ensures that no other activity can
849 * occur while the buffer list is being cleaned out.
850 */
851 VOP_LOCK(vp);
852 if (flags & DOCLOSE)
853 vinvalbuf(vp, 1);
854 /*
855 * Prevent any further operations on the vnode from
856 * being passed through to the old file system.
857 */
858 origops = vp->v_op;
859 vp->v_op = &dead_vnodeops;
860 vp->v_tag = VT_NON;
861 /*
862 * If purging an active vnode, it must be unlocked, closed,
863 * and deactivated before being reclaimed.
864 */
865 (*(origops->vop_unlock))(vp);
866 if (active) {
867 if (flags & DOCLOSE)
868 (*(origops->vop_close))(vp, IO_NDELAY, NOCRED, p);
869 (*(origops->vop_inactive))(vp, p);
870 }
871 /*
872 * Reclaim the vnode.
873 */
874 if ((*(origops->vop_reclaim))(vp))
875 panic("vclean: cannot reclaim");
876 if (active)
877 vrele(vp);
878 /*
879 * Done with purge, notify sleepers in vget of the grim news.
880 */
881 vp->v_flag &= ~VXLOCK;
882 if (vp->v_flag & VXWANT) {
883 vp->v_flag &= ~VXWANT;
884 wakeup((caddr_t)vp);
885 }
886}
887
888/*
889 * Eliminate all activity associated with the requested vnode
890 * and with all vnodes aliased to the requested vnode.
891 */
892void vgoneall(vp)
893 register struct vnode *vp;
894{
895 register struct vnode *vq;
896
897 if (vp->v_flag & VALIASED) {
898 /*
899 * If a vgone (or vclean) is already in progress,
900 * wait until it is done and return.
901 */
902 if (vp->v_flag & VXLOCK) {
903 vp->v_flag |= VXWANT;
904 sleep((caddr_t)vp, PINOD);
905 return;
906 }
907 /*
908 * Ensure that vp will not be vgone'd while we
909 * are eliminating its aliases.
910 */
911 vp->v_flag |= VXLOCK;
912 while (vp->v_flag & VALIASED) {
913 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
914 if (vq->v_rdev != vp->v_rdev ||
915 vq->v_type != vp->v_type || vp == vq)
916 continue;
917 vgone(vq);
918 break;
919 }
920 }
921 /*
922 * Remove the lock so that vgone below will
923 * really eliminate the vnode after which time
924 * vgone will awaken any sleepers.
925 */
926 vp->v_flag &= ~VXLOCK;
927 }
928 vgone(vp);
929}
930
931/*
932 * Eliminate all activity associated with a vnode
933 * in preparation for reuse.
934 */
935void vgone(vp)
936 register struct vnode *vp;
937{
938 register struct vnode *vq;
939 struct vnode *vx;
940 long count;
941
942 /*
943 * If a vgone (or vclean) is already in progress,
944 * wait until it is done and return.
945 */
946 if (vp->v_flag & VXLOCK) {
947 vp->v_flag |= VXWANT;
948 sleep((caddr_t)vp, PINOD);
949 return;
950 }
951 /*
952 * Clean out the filesystem specific data.
953 */
954 vclean(vp, DOCLOSE);
955 /*
956 * Delete from old mount point vnode list, if on one.
957 */
958 if (vp->v_mountb) {
959 if (vq = vp->v_mountf)
960 vq->v_mountb = vp->v_mountb;
961 *vp->v_mountb = vq;
962 vp->v_mountf = NULL;
963 vp->v_mountb = NULL;
964 }
965 /*
966 * If special device, remove it from special device alias list.
967 */
968 if (vp->v_type == VBLK || vp->v_type == VCHR) {
969 if (*vp->v_hashchain == vp) {
970 *vp->v_hashchain = vp->v_specnext;
971 } else {
972 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
973 if (vq->v_specnext != vp)
974 continue;
975 vq->v_specnext = vp->v_specnext;
976 break;
977 }
978 if (vq == NULL)
979 panic("missing bdev");
980 }
981 if (vp->v_flag & VALIASED) {
982 count = 0;
983 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
984 if (vq->v_rdev != vp->v_rdev ||
985 vq->v_type != vp->v_type)
986 continue;
987 count++;
988 vx = vq;
989 }
990 if (count == 0)
991 panic("missing alias");
992 if (count == 1)
993 vx->v_flag &= ~VALIASED;
994 vp->v_flag &= ~VALIASED;
995 }
996 FREE(vp->v_specinfo, M_VNODE);
997 vp->v_specinfo = NULL;
998 }
999 /*
1000 * If it is on the freelist, move it to the head of the list.
1001 */
1002 if (vp->v_freeb) {
1003 if (vq = vp->v_freef)
1004 vq->v_freeb = vp->v_freeb;
1005 else
1006 vfreet = vp->v_freeb;
1007 *vp->v_freeb = vq;
1008 vp->v_freef = vfreeh;
1009 vp->v_freeb = &vfreeh;
1010 vfreeh->v_freeb = &vp->v_freef;
1011 vfreeh = vp;
1012 }
1013 vp->v_type = VBAD;
1014}
1015
1016/*
1017 * Lookup a vnode by device number.
1018 */
1019vfinddev(dev, type, vpp)
1020 dev_t dev;
1021 enum vtype type;
1022 struct vnode **vpp;
1023{
1024 register struct vnode *vp;
1025
1026 for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) {
1027 if (dev != vp->v_rdev || type != vp->v_type)
1028 continue;
1029 *vpp = vp;
1030 return (0);
1031 }
1032 return (1);
1033}
1034
1035/*
1036 * Calculate the total number of references to a special device.
1037 */
1038vcount(vp)
1039 register struct vnode *vp;
1040{
1041 register struct vnode *vq;
1042 int count;
1043
1044 if ((vp->v_flag & VALIASED) == 0)
1045 return (vp->v_usecount);
1046loop:
1047 for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
1048 if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type)
1049 continue;
1050 /*
1051 * Alias, but not in use, so flush it out.
1052 */
1053 if (vq->v_usecount == 0) {
1054 vgone(vq);
1055 goto loop;
1056 }
1057 count += vq->v_usecount;
1058 }
1059 return (count);
1060}
1061
1062/*
1063 * Print out a description of a vnode.
1064 */
1065static char *typename[] =
1066 { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" };
1067
1068vprint(label, vp)
1069 char *label;
1070 register struct vnode *vp;
1071{
1072 char buf[64];
1073
1074 if (label != NULL)
1075 printf("%s: ", label);
1076 printf("type %s, usecount %d, writecount %d, refcount %d,",
1077 typename[vp->v_type], vp->v_usecount, vp->v_writecount,
1078 vp->v_holdcnt);
1079 buf[0] = '\0';
1080 if (vp->v_flag & VROOT)
1081 strcat(buf, "|VROOT");
1082 if (vp->v_flag & VTEXT)
1083 strcat(buf, "|VTEXT");
1084 if (vp->v_flag & VSYSTEM)
1085 strcat(buf, "|VSYSTEM");
1086 if (vp->v_flag & VXLOCK)
1087 strcat(buf, "|VXLOCK");
1088 if (vp->v_flag & VXWANT)
1089 strcat(buf, "|VXWANT");
1090 if (vp->v_flag & VBWAIT)
1091 strcat(buf, "|VBWAIT");
1092 if (vp->v_flag & VALIASED)
1093 strcat(buf, "|VALIASED");
1094 if (buf[0] != '\0')
1095 printf(" flags (%s)", &buf[1]);
1096 printf("\n\t");
1097 VOP_PRINT(vp);
1098}
1099
1100#ifdef DEBUG
1101/*
1102 * List all of the locked vnodes in the system.
1103 * Called when debugging the kernel.
1104 */
1105printlockedvnodes()
1106{
1107 register struct mount *mp;
1108 register struct vnode *vp;
1109
1110 printf("Locked vnodes\n");
1111 mp = rootfs;
1112 do {
1113 for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf)
1114 if (VOP_ISLOCKED(vp))
1115 vprint((char *)0, vp);
1116 mp = mp->mnt_next;
1117 } while (mp != rootfs);
1118}
1119#endif
1120
1121int kinfo_vdebug = 1;
1122int kinfo_vgetfailed;
1123#define KINFO_VNODESLOP 10
1124/*
1125 * Dump vnode list (via kinfo).
1126 * Copyout address of vnode followed by vnode.
1127 */
1128/* ARGSUSED */
1129kinfo_vnode(op, where, acopysize, arg, aneeded)
1130 int op;
1131 char *where;
1132 int *acopysize, arg, *aneeded;
1133{
1134 register struct mount *mp = rootfs;
1135 struct mount *omp;
1136 struct vnode *vp;
1137 register char *bp = where, *savebp;
1138 char *ewhere = where + *acopysize;
1139 int error;
1140
1141#define VPTRSZ sizeof (struct vnode *)
1142#define VNODESZ sizeof (struct vnode)
1143 if (where == NULL) {
1144 *aneeded = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ);
1145 return (0);
1146 }
1147
1148 do {
1149 if (vfs_busy(mp)) {
1150 mp = mp->mnt_next;
1151 continue;
1152 }
1153 savebp = bp;
1154again:
1155 for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) {
1156 /*
1157 * Check that the vp is still associated with
1158 * this filesystem. RACE: could have been
1159 * recycled onto the same filesystem.
1160 */
1161 if (vp->v_mount != mp) {
1162 if (kinfo_vdebug)
1163 printf("kinfo: vp changed\n");
1164 bp = savebp;
1165 goto again;
1166 }
1167 if ((bp + VPTRSZ + VNODESZ <= ewhere) &&
1168 ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) ||
1169 (error = copyout((caddr_t)vp, bp + VPTRSZ,
1170 VNODESZ))))
1171 return (error);
1172 bp += VPTRSZ + VNODESZ;
1173 }
1174 omp = mp;
1175 mp = mp->mnt_next;
1176 vfs_unbusy(omp);
1177 } while (mp != rootfs);
1178
1179 *aneeded = bp - where;
1180 if (bp > ewhere)
1181 *acopysize = ewhere - where;
1182 else
1183 *acopysize = bp - where;
1184 return (0);
1185}