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