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