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