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