add mono_time for NFS leases
[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 *
24e9a81d 7 * @(#)vfs_subr.c 7.62 (Berkeley) %G%
3c4390e8
KM
8 */
9
10/*
11 * External virtual filesystem routines
12 */
13
cb796a23
KB
14#include <sys/param.h>
15#include <sys/proc.h>
16#include <sys/mount.h>
17#include <sys/time.h>
18#include <sys/vnode.h>
19#include <sys/specdev.h>
20#include <sys/namei.h>
21#include <sys/ucred.h>
22#include <sys/buf.h>
23#include <sys/errno.h>
24#include <sys/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)) {
24e9a81d
KM
416 dirty++;
417 (void) VOP_BWRITE(bp);
76429560
KM
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 672
65c3b3a8 673#ifdef DIAGNOSTIC
36d09cb1 674 if (vp == NULL)
ef24f6dd 675 panic("vrele: null vp");
65c3b3a8 676#endif
7f7b7d89 677 vp->v_usecount--;
7f7b7d89 678 if (vp->v_usecount > 0)
36d09cb1 679 return;
65c3b3a8
KM
680#ifdef DIAGNOSTIC
681 if (vp->v_usecount != 0 || vp->v_writecount != 0) {
682 vprint("vrele: bad ref count", vp);
683 panic("vrele: ref cnt");
684 }
685#endif
54fb9dc2 686 if (vfreeh == NULLVP) {
36d09cb1
KM
687 /*
688 * insert into empty list
689 */
690 vfreeh = vp;
691 vp->v_freeb = &vfreeh;
36d09cb1
KM
692 } else {
693 /*
694 * insert at tail of list
695 */
696 *vfreet = vp;
697 vp->v_freeb = vfreet;
36d09cb1 698 }
ef24f6dd
KM
699 vp->v_freef = NULL;
700 vfreet = &vp->v_freef;
c099667a 701 VOP_INACTIVE(vp, p);
ef24f6dd
KM
702}
703
7f7b7d89
KM
704/*
705 * Page or buffer structure gets a reference.
706 */
707vhold(vp)
708 register struct vnode *vp;
709{
710
711 vp->v_holdcnt++;
712}
713
714/*
715 * Page or buffer structure frees a reference.
716 */
717holdrele(vp)
718 register struct vnode *vp;
719{
720
721 if (vp->v_holdcnt <= 0)
722 panic("holdrele: holdcnt");
723 vp->v_holdcnt--;
724}
725
f0556f86
KM
726/*
727 * Remove any vnodes in the vnode table belonging to mount point mp.
728 *
729 * If MNT_NOFORCE is specified, there should not be any active ones,
730 * return error if any are found (nb: this is a user error, not a
731 * system error). If MNT_FORCE is specified, detach any active vnodes
732 * that are found.
733 */
734int busyprt = 0; /* patch to print out busy vnodes */
735
736vflush(mp, skipvp, flags)
737 struct mount *mp;
738 struct vnode *skipvp;
739 int flags;
740{
741 register struct vnode *vp, *nvp;
742 int busy = 0;
743
54fb9dc2 744 if ((mp->mnt_flag & MNT_MPBUSY) == 0)
36ef03ec 745 panic("vflush: not busy");
4597dd33 746loop:
54fb9dc2 747 for (vp = mp->mnt_mounth; vp; vp = nvp) {
4597dd33
KM
748 if (vp->v_mount != mp)
749 goto loop;
f0556f86
KM
750 nvp = vp->v_mountf;
751 /*
752 * Skip over a selected vnode.
f0556f86
KM
753 */
754 if (vp == skipvp)
755 continue;
36ef03ec
KM
756 /*
757 * Skip over a vnodes marked VSYSTEM.
758 */
759 if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM))
760 continue;
f0556f86 761 /*
7f7b7d89 762 * With v_usecount == 0, all we need to do is clear
f0556f86
KM
763 * out the vnode data structures and we are done.
764 */
7f7b7d89 765 if (vp->v_usecount == 0) {
f0556f86
KM
766 vgone(vp);
767 continue;
768 }
769 /*
770 * For block or character devices, revert to an
771 * anonymous device. For all other files, just kill them.
772 */
36ef03ec 773 if (flags & FORCECLOSE) {
f0556f86
KM
774 if (vp->v_type != VBLK && vp->v_type != VCHR) {
775 vgone(vp);
776 } else {
777 vclean(vp, 0);
778 vp->v_op = &spec_vnodeops;
779 insmntque(vp, (struct mount *)0);
780 }
781 continue;
782 }
783 if (busyprt)
0bf84b18 784 vprint("vflush: busy vnode", vp);
f0556f86
KM
785 busy++;
786 }
787 if (busy)
788 return (EBUSY);
789 return (0);
790}
791
ef24f6dd
KM
792/*
793 * Disassociate the underlying file system from a vnode.
ef24f6dd 794 */
36ef03ec 795void vclean(vp, flags)
ef24f6dd 796 register struct vnode *vp;
aacc1bff 797 int flags;
ef24f6dd
KM
798{
799 struct vnodeops *origops;
2bae1875 800 int active;
c099667a 801 struct proc *p = curproc; /* XXX */
ef24f6dd 802
2bae1875
KM
803 /*
804 * Check to see if the vnode is in use.
0bf84b18
KM
805 * If so we have to reference it before we clean it out
806 * so that its count cannot fall to zero and generate a
807 * race against ourselves to recycle it.
2bae1875 808 */
7f7b7d89 809 if (active = vp->v_usecount)
2bae1875 810 VREF(vp);
2bae1875
KM
811 /*
812 * Prevent the vnode from being recycled or
813 * brought into use while we clean it out.
814 */
0bf84b18
KM
815 if (vp->v_flag & VXLOCK)
816 panic("vclean: deadlock");
ef24f6dd 817 vp->v_flag |= VXLOCK;
0bf84b18
KM
818 /*
819 * Even if the count is zero, the VOP_INACTIVE routine may still
820 * have the object locked while it cleans it out. The VOP_LOCK
821 * ensures that the VOP_INACTIVE routine is done with its work.
822 * For active vnodes, it ensures that no other activity can
823 * occur while the buffer list is being cleaned out.
824 */
825 VOP_LOCK(vp);
36ef03ec 826 if (flags & DOCLOSE)
0bf84b18 827 vinvalbuf(vp, 1);
ef24f6dd
KM
828 /*
829 * Prevent any further operations on the vnode from
830 * being passed through to the old file system.
831 */
832 origops = vp->v_op;
833 vp->v_op = &dead_vnodeops;
834 vp->v_tag = VT_NON;
835 /*
2bae1875
KM
836 * If purging an active vnode, it must be unlocked, closed,
837 * and deactivated before being reclaimed.
ef24f6dd 838 */
20454d5a 839 (*(origops->vop_unlock))(vp);
2bae1875 840 if (active) {
36ef03ec 841 if (flags & DOCLOSE)
20454d5a
KM
842 (*(origops->vop_close))(vp, IO_NDELAY, NOCRED, p);
843 (*(origops->vop_inactive))(vp, p);
ef24f6dd
KM
844 }
845 /*
846 * Reclaim the vnode.
847 */
20454d5a 848 if ((*(origops->vop_reclaim))(vp))
ef24f6dd 849 panic("vclean: cannot reclaim");
2bae1875
KM
850 if (active)
851 vrele(vp);
ef24f6dd
KM
852 /*
853 * Done with purge, notify sleepers in vget of the grim news.
854 */
855 vp->v_flag &= ~VXLOCK;
856 if (vp->v_flag & VXWANT) {
857 vp->v_flag &= ~VXWANT;
858 wakeup((caddr_t)vp);
859 }
860}
861
ef62830d
KM
862/*
863 * Eliminate all activity associated with the requested vnode
864 * and with all vnodes aliased to the requested vnode.
865 */
866void vgoneall(vp)
867 register struct vnode *vp;
868{
7f7b7d89 869 register struct vnode *vq;
ef62830d 870
7a7b3a95
KM
871 if (vp->v_flag & VALIASED) {
872 /*
873 * If a vgone (or vclean) is already in progress,
874 * wait until it is done and return.
875 */
876 if (vp->v_flag & VXLOCK) {
877 vp->v_flag |= VXWANT;
878 sleep((caddr_t)vp, PINOD);
879 return;
880 }
881 /*
882 * Ensure that vp will not be vgone'd while we
883 * are eliminating its aliases.
884 */
885 vp->v_flag |= VXLOCK;
886 while (vp->v_flag & VALIASED) {
887 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
888 if (vq->v_rdev != vp->v_rdev ||
889 vq->v_type != vp->v_type || vp == vq)
890 continue;
891 vgone(vq);
892 break;
893 }
ef62830d 894 }
7a7b3a95
KM
895 /*
896 * Remove the lock so that vgone below will
897 * really eliminate the vnode after which time
898 * vgone will awaken any sleepers.
899 */
900 vp->v_flag &= ~VXLOCK;
ef62830d
KM
901 }
902 vgone(vp);
903}
904
ef24f6dd
KM
905/*
906 * Eliminate all activity associated with a vnode
907 * in preparation for reuse.
908 */
909void vgone(vp)
910 register struct vnode *vp;
911{
7f7b7d89 912 register struct vnode *vq;
c0de8792
KM
913 struct vnode *vx;
914 long count;
ef24f6dd 915
4f55e3ec
KM
916 /*
917 * If a vgone (or vclean) is already in progress,
918 * wait until it is done and return.
919 */
920 if (vp->v_flag & VXLOCK) {
921 vp->v_flag |= VXWANT;
922 sleep((caddr_t)vp, PINOD);
923 return;
924 }
ef24f6dd
KM
925 /*
926 * Clean out the filesystem specific data.
927 */
36ef03ec 928 vclean(vp, DOCLOSE);
ef24f6dd
KM
929 /*
930 * Delete from old mount point vnode list, if on one.
931 */
932 if (vp->v_mountb) {
933 if (vq = vp->v_mountf)
934 vq->v_mountb = vp->v_mountb;
935 *vp->v_mountb = vq;
936 vp->v_mountf = NULL;
937 vp->v_mountb = NULL;
938 }
939 /*
940 * If special device, remove it from special device alias list.
941 */
942 if (vp->v_type == VBLK || vp->v_type == VCHR) {
7f7b7d89
KM
943 if (*vp->v_hashchain == vp) {
944 *vp->v_hashchain = vp->v_specnext;
ef24f6dd 945 } else {
7f7b7d89 946 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
c0de8792 947 if (vq->v_specnext != vp)
ef24f6dd 948 continue;
c0de8792 949 vq->v_specnext = vp->v_specnext;
ef24f6dd
KM
950 break;
951 }
c0de8792 952 if (vq == NULL)
ef24f6dd
KM
953 panic("missing bdev");
954 }
c0de8792 955 if (vp->v_flag & VALIASED) {
7f7b7d89
KM
956 count = 0;
957 for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
de81e10c
KM
958 if (vq->v_rdev != vp->v_rdev ||
959 vq->v_type != vp->v_type)
c0de8792
KM
960 continue;
961 count++;
962 vx = vq;
963 }
964 if (count == 0)
965 panic("missing alias");
966 if (count == 1)
967 vx->v_flag &= ~VALIASED;
968 vp->v_flag &= ~VALIASED;
969 }
970 FREE(vp->v_specinfo, M_VNODE);
971 vp->v_specinfo = NULL;
ef24f6dd
KM
972 }
973 /*
974 * If it is on the freelist, move it to the head of the list.
975 */
976 if (vp->v_freeb) {
977 if (vq = vp->v_freef)
978 vq->v_freeb = vp->v_freeb;
979 else
980 vfreet = vp->v_freeb;
981 *vp->v_freeb = vq;
982 vp->v_freef = vfreeh;
983 vp->v_freeb = &vfreeh;
984 vfreeh->v_freeb = &vp->v_freef;
985 vfreeh = vp;
986 }
2bae1875 987 vp->v_type = VBAD;
36d09cb1 988}
ef62830d 989
2bcd6066
KM
990/*
991 * Lookup a vnode by device number.
992 */
993vfinddev(dev, type, vpp)
994 dev_t dev;
995 enum vtype type;
996 struct vnode **vpp;
997{
998 register struct vnode *vp;
999
1000 for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) {
1001 if (dev != vp->v_rdev || type != vp->v_type)
1002 continue;
1003 *vpp = vp;
1004 return (0);
1005 }
1006 return (1);
1007}
1008
ef62830d
KM
1009/*
1010 * Calculate the total number of references to a special device.
1011 */
1012vcount(vp)
1013 register struct vnode *vp;
1014{
7f7b7d89 1015 register struct vnode *vq;
ef62830d
KM
1016 int count;
1017
1018 if ((vp->v_flag & VALIASED) == 0)
7f7b7d89 1019 return (vp->v_usecount);
ef62830d 1020loop:
7f7b7d89 1021 for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
de81e10c 1022 if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type)
ef62830d
KM
1023 continue;
1024 /*
1025 * Alias, but not in use, so flush it out.
1026 */
7f7b7d89 1027 if (vq->v_usecount == 0) {
ef62830d
KM
1028 vgone(vq);
1029 goto loop;
1030 }
7f7b7d89 1031 count += vq->v_usecount;
ef62830d
KM
1032 }
1033 return (count);
1034}
0bf84b18
KM
1035
1036/*
1037 * Print out a description of a vnode.
1038 */
1039static char *typename[] =
61f846a8 1040 { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" };
0bf84b18
KM
1041
1042vprint(label, vp)
1043 char *label;
1044 register struct vnode *vp;
1045{
f2f730c6 1046 char buf[64];
0bf84b18
KM
1047
1048 if (label != NULL)
1049 printf("%s: ", label);
65c3b3a8
KM
1050 printf("type %s, usecount %d, writecount %d, refcount %d,",
1051 typename[vp->v_type], vp->v_usecount, vp->v_writecount,
1052 vp->v_holdcnt);
f2f730c6
KM
1053 buf[0] = '\0';
1054 if (vp->v_flag & VROOT)
1055 strcat(buf, "|VROOT");
1056 if (vp->v_flag & VTEXT)
1057 strcat(buf, "|VTEXT");
36ef03ec
KM
1058 if (vp->v_flag & VSYSTEM)
1059 strcat(buf, "|VSYSTEM");
36ef03ec
KM
1060 if (vp->v_flag & VXLOCK)
1061 strcat(buf, "|VXLOCK");
1062 if (vp->v_flag & VXWANT)
1063 strcat(buf, "|VXWANT");
f2f730c6
KM
1064 if (vp->v_flag & VBWAIT)
1065 strcat(buf, "|VBWAIT");
36ef03ec
KM
1066 if (vp->v_flag & VALIASED)
1067 strcat(buf, "|VALIASED");
f2f730c6
KM
1068 if (buf[0] != '\0')
1069 printf(" flags (%s)", &buf[1]);
1070 printf("\n\t");
0bf84b18
KM
1071 VOP_PRINT(vp);
1072}
985cbdd5 1073
34c62e18
KM
1074#ifdef DEBUG
1075/*
1076 * List all of the locked vnodes in the system.
1077 * Called when debugging the kernel.
1078 */
1079printlockedvnodes()
1080{
1081 register struct mount *mp;
1082 register struct vnode *vp;
1083
1084 printf("Locked vnodes\n");
1085 mp = rootfs;
1086 do {
1087 for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf)
1088 if (VOP_ISLOCKED(vp))
1089 vprint((char *)0, vp);
1090 mp = mp->mnt_next;
1091 } while (mp != rootfs);
1092}
1093#endif
1094
985cbdd5
MT
1095int kinfo_vdebug = 1;
1096int kinfo_vgetfailed;
1097#define KINFO_VNODESLOP 10
1098/*
1099 * Dump vnode list (via kinfo).
1100 * Copyout address of vnode followed by vnode.
1101 */
aacc1bff 1102/* ARGSUSED */
985cbdd5 1103kinfo_vnode(op, where, acopysize, arg, aneeded)
aacc1bff 1104 int op;
985cbdd5 1105 char *where;
aacc1bff 1106 int *acopysize, arg, *aneeded;
985cbdd5
MT
1107{
1108 register struct mount *mp = rootfs;
36ef03ec 1109 struct mount *omp;
985cbdd5 1110 struct vnode *vp;
985cbdd5
MT
1111 register char *bp = where, *savebp;
1112 char *ewhere = where + *acopysize;
1113 int error;
1114
1115#define VPTRSZ sizeof (struct vnode *)
1116#define VNODESZ sizeof (struct vnode)
1117 if (where == NULL) {
1118 *aneeded = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ);
1119 return (0);
1120 }
1121
985cbdd5 1122 do {
36ef03ec 1123 if (vfs_busy(mp)) {
54fb9dc2 1124 mp = mp->mnt_next;
36ef03ec
KM
1125 continue;
1126 }
985cbdd5
MT
1127 savebp = bp;
1128again:
4597dd33 1129 for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) {
41185b3b
KM
1130 /*
1131 * Check that the vp is still associated with
1132 * this filesystem. RACE: could have been
1133 * recycled onto the same filesystem.
1134 */
4597dd33
KM
1135 if (vp->v_mount != mp) {
1136 if (kinfo_vdebug)
1137 printf("kinfo: vp changed\n");
1138 bp = savebp;
1139 goto again;
1140 }
985cbdd5
MT
1141 if ((bp + VPTRSZ + VNODESZ <= ewhere) &&
1142 ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) ||
1143 (error = copyout((caddr_t)vp, bp + VPTRSZ,
41185b3b 1144 VNODESZ))))
985cbdd5 1145 return (error);
985cbdd5 1146 bp += VPTRSZ + VNODESZ;
985cbdd5 1147 }
36ef03ec 1148 omp = mp;
54fb9dc2 1149 mp = mp->mnt_next;
36ef03ec 1150 vfs_unbusy(omp);
985cbdd5
MT
1151 } while (mp != rootfs);
1152
1153 *aneeded = bp - where;
1154 if (bp > ewhere)
1155 *acopysize = ewhere - where;
1156 else
1157 *acopysize = bp - where;
1158 return (0);
1159}