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