|
|
1.1 root 1: /*
2: * Copyright (c) 1989 The Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution is only permitted until one year after the first shipment
6: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and
7: * binary forms are permitted provided that: (1) source distributions retain
8: * this entire copyright notice and comment, and (2) distributions including
9: * binaries display the following acknowledgement: This product includes
10: * software developed by the University of California, Berkeley and its
11: * contributors'' in the documentation or other materials provided with the
12: * distribution and in all advertising materials mentioning features or use
13: * of this software. Neither the name of the University nor the names of
14: * its contributors may be used to endorse or promote products derived from
15: * this software without specific prior written permission.
16: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
17: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
18: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19: *
20: * @(#)vfs_subr.c 7.47 (Berkeley) 6/28/90
21: */
22:
23: /*
24: * External virtual filesystem routines
25: */
26:
27: #include "param.h"
28: #include "mount.h"
29: #include "time.h"
30: #include "vnode.h"
31: #include "specdev.h"
32: #include "namei.h"
33: #include "ucred.h"
34: #include "errno.h"
35: #include "malloc.h"
36:
37: /*
38: * Remove a mount point from the list of mounted filesystems.
39: * Unmount of the root is illegal.
40: */
41: void
42: vfs_remove(mp)
43: register struct mount *mp;
44: {
45:
46: if (mp == rootfs)
47: panic("vfs_remove: unmounting root");
48: mp->mnt_prev->mnt_next = mp->mnt_next;
49: mp->mnt_next->mnt_prev = mp->mnt_prev;
50: mp->mnt_vnodecovered->v_mountedhere = (struct mount *)0;
51: vfs_unlock(mp);
52: }
53:
54: /*
55: * Lock a filesystem.
56: * Used to prevent access to it while mounting and unmounting.
57: */
58: vfs_lock(mp)
59: register struct mount *mp;
60: {
61:
62: while(mp->mnt_flag & MNT_MLOCK) {
63: mp->mnt_flag |= MNT_MWAIT;
64: sleep((caddr_t)mp, PVFS);
65: }
66: mp->mnt_flag |= MNT_MLOCK;
67: return (0);
68: }
69:
70: /*
71: * Unlock a locked filesystem.
72: * Panic if filesystem is not locked.
73: */
74: void
75: vfs_unlock(mp)
76: register struct mount *mp;
77: {
78:
79: if ((mp->mnt_flag & MNT_MLOCK) == 0)
80: panic("vfs_unlock: not locked");
81: mp->mnt_flag &= ~MNT_MLOCK;
82: if (mp->mnt_flag & MNT_MWAIT) {
83: mp->mnt_flag &= ~MNT_MWAIT;
84: wakeup((caddr_t)mp);
85: }
86: }
87:
88: /*
89: * Mark a mount point as busy.
90: * Used to synchronize access and to delay unmounting.
91: */
92: vfs_busy(mp)
93: register struct mount *mp;
94: {
95:
96: while(mp->mnt_flag & MNT_MPBUSY) {
97: mp->mnt_flag |= MNT_MPWANT;
98: sleep((caddr_t)&mp->mnt_flag, PVFS);
99: }
100: if (mp->mnt_flag & MNT_UNMOUNT)
101: return (1);
102: mp->mnt_flag |= MNT_MPBUSY;
103: return (0);
104: }
105:
106: /*
107: * Free a busy filesystem.
108: * Panic if filesystem is not busy.
109: */
110: void
111: vfs_unbusy(mp)
112: register struct mount *mp;
113: {
114:
115: if ((mp->mnt_flag & MNT_MPBUSY) == 0)
116: panic("vfs_unbusy: not busy");
117: mp->mnt_flag &= ~MNT_MPBUSY;
118: if (mp->mnt_flag & MNT_MPWANT) {
119: mp->mnt_flag &= ~MNT_MPWANT;
120: wakeup((caddr_t)&mp->mnt_flag);
121: }
122: }
123:
124: /*
125: * Lookup a mount point by filesystem identifier.
126: */
127: struct mount *
128: getvfs(fsid)
129: fsid_t *fsid;
130: {
131: register struct mount *mp;
132:
133: mp = rootfs;
134: do {
135: if (mp->mnt_stat.f_fsid.val[0] == fsid->val[0] &&
136: mp->mnt_stat.f_fsid.val[1] == fsid->val[1]) {
137: return (mp);
138: }
139: mp = mp->mnt_next;
140: } while (mp != rootfs);
141: return ((struct mount *)0);
142: }
143:
144: /*
145: * Set vnode attributes to VNOVAL
146: */
147: void vattr_null(vap)
148: register struct vattr *vap;
149: {
150:
151: vap->va_type = VNON;
152: vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid =
153: vap->va_fsid = vap->va_fileid = vap->va_size =
154: vap->va_size_rsv = vap->va_blocksize = vap->va_rdev =
155: vap->va_bytes = vap->va_bytes_rsv =
156: vap->va_atime.tv_sec = vap->va_atime.tv_usec =
157: vap->va_mtime.tv_sec = vap->va_mtime.tv_usec =
158: vap->va_ctime.tv_sec = vap->va_ctime.tv_usec =
159: vap->va_flags = vap->va_gen = VNOVAL;
160: }
161:
162: /*
163: * Initialize a nameidata structure
164: */
165: ndinit(ndp)
166: register struct nameidata *ndp;
167: {
168:
169: bzero((caddr_t)ndp, sizeof(struct nameidata));
170: ndp->ni_iov = &ndp->ni_nd.nd_iovec;
171: ndp->ni_iovcnt = 1;
172: ndp->ni_base = (caddr_t)&ndp->ni_dent;
173: ndp->ni_rw = UIO_WRITE;
174: ndp->ni_uioseg = UIO_SYSSPACE;
175: }
176:
177: /*
178: * Duplicate a nameidata structure
179: */
180: nddup(ndp, newndp)
181: register struct nameidata *ndp, *newndp;
182: {
183:
184: ndinit(newndp);
185: newndp->ni_cdir = ndp->ni_cdir;
186: VREF(newndp->ni_cdir);
187: newndp->ni_rdir = ndp->ni_rdir;
188: if (newndp->ni_rdir)
189: VREF(newndp->ni_rdir);
190: newndp->ni_cred = ndp->ni_cred;
191: crhold(newndp->ni_cred);
192: }
193:
194: /*
195: * Release a nameidata structure
196: */
197: ndrele(ndp)
198: register struct nameidata *ndp;
199: {
200:
201: vrele(ndp->ni_cdir);
202: if (ndp->ni_rdir)
203: vrele(ndp->ni_rdir);
204: crfree(ndp->ni_cred);
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: */
219: vfsinit()
220: {
221: struct vfsops **vfsp;
222:
223: /*
224: * Initialize the vnode name cache
225: */
226: nchinit();
227: /*
228: * Initialize each file system type.
229: */
230: vattr_null(&va_null);
231: for (vfsp = &vfssw[0]; vfsp <= &vfssw[MOUNT_MAXTYPE]; vfsp++) {
232: if (*vfsp == NULL)
233: continue;
234: (*(*vfsp)->vfs_init)();
235: }
236: }
237:
238: /*
239: * Return the next vnode from the free list.
240: */
241: getnewvnode(tag, mp, vops, vpp)
242: enum vtagtype tag;
243: struct mount *mp;
244: struct vnodeops *vops;
245: struct vnode **vpp;
246: {
247: register struct vnode *vp, *vq;
248:
249: if (numvnodes < desiredvnodes) {
250: vp = (struct vnode *)malloc(sizeof *vp, M_VNODE, M_WAITOK);
251: bzero((char *)vp, sizeof *vp);
252: numvnodes++;
253: } else {
254: if ((vp = vfreeh) == NULL) {
255: tablefull("vnode");
256: *vpp = 0;
257: return (ENFILE);
258: }
259: if (vp->v_usecount)
260: panic("free vnode isn't");
261: if (vq = vp->v_freef)
262: vq->v_freeb = &vfreeh;
263: else
264: vfreet = &vfreeh;
265: vfreeh = vq;
266: vp->v_freef = NULL;
267: vp->v_freeb = NULL;
268: if (vp->v_type != VBAD)
269: vgone(vp);
270: vp->v_flag = 0;
271: vp->v_shlockc = 0;
272: vp->v_exlockc = 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: 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 (mp->mnt_mounth) {
313: vp->v_mountf = mp->mnt_mounth;
314: vp->v_mountb = &mp->mnt_mounth;
315: mp->mnt_mounth->v_mountb = &vp->v_mountf;
316: mp->mnt_mounth = vp;
317: } else {
318: mp->mnt_mounth = vp;
319: vp->v_mountb = &mp->mnt_mounth;
320: vp->v_mountf = NULL;
321: }
322: }
323:
324: /*
325: * Create a vnode for a block device.
326: * Used for root filesystem, argdev, and swap areas.
327: * Also used for memory file system special devices.
328: */
329: bdevvp(dev, vpp)
330: dev_t dev;
331: struct vnode **vpp;
332: {
333: register struct vnode *vp;
334: struct vnode *nvp;
335: int error;
336:
337: error = getnewvnode(VT_NON, (struct mount *)0, &spec_vnodeops, &nvp);
338: if (error) {
339: *vpp = 0;
340: return (error);
341: }
342: vp = nvp;
343: vp->v_type = VBLK;
344: if (nvp = checkalias(vp, dev, (struct mount *)0)) {
345: vput(vp);
346: vp = nvp;
347: }
348: *vpp = vp;
349: return (0);
350: }
351:
352: /*
353: * Check to see if the new vnode represents a special device
354: * for which we already have a vnode (either because of
355: * bdevvp() or because of a different vnode representing
356: * the same block device). If such an alias exists, deallocate
357: * the existing contents and return the aliased vnode. The
358: * caller is responsible for filling it with its new contents.
359: */
360: struct vnode *
361: checkalias(nvp, nvp_rdev, mp)
362: register struct vnode *nvp;
363: dev_t nvp_rdev;
364: struct mount *mp;
365: {
366: register struct vnode *vp;
367: struct vnode **vpp;
368:
369: if (nvp->v_type != VBLK && nvp->v_type != VCHR)
370: return (NULLVP);
371:
372: vpp = &speclisth[SPECHASH(nvp_rdev)];
373: loop:
374: for (vp = *vpp; vp; vp = vp->v_specnext) {
375: if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type)
376: continue;
377: /*
378: * Alias, but not in use, so flush it out.
379: */
380: if (vp->v_usecount == 0) {
381: vgone(vp);
382: goto loop;
383: }
384: if (vget(vp))
385: goto loop;
386: break;
387: }
388: if (vp == NULL || vp->v_tag != VT_NON) {
389: MALLOC(nvp->v_specinfo, struct specinfo *,
390: sizeof(struct specinfo), M_VNODE, M_WAITOK);
391: nvp->v_rdev = nvp_rdev;
392: nvp->v_hashchain = vpp;
393: nvp->v_specnext = *vpp;
394: nvp->v_specflags = 0;
395: *vpp = nvp;
396: if (vp != NULL) {
397: nvp->v_flag |= VALIASED;
398: vp->v_flag |= VALIASED;
399: vput(vp);
400: }
401: return (NULLVP);
402: }
403: VOP_UNLOCK(vp);
404: vclean(vp, 0);
405: vp->v_op = nvp->v_op;
406: vp->v_tag = nvp->v_tag;
407: nvp->v_type = VNON;
408: insmntque(vp, mp);
409: return (vp);
410: }
411:
412: /*
413: * Grab a particular vnode from the free list, increment its
414: * reference count and lock it. The vnode lock bit is set the
415: * vnode is being eliminated in vgone. The process is awakened
416: * when the transition is completed, and an error returned to
417: * indicate that the vnode is no longer usable (possibly having
418: * been changed to a new file system type).
419: */
420: vget(vp)
421: register struct vnode *vp;
422: {
423: register struct vnode *vq;
424:
425: if (vp->v_flag & VXLOCK) {
426: vp->v_flag |= VXWANT;
427: sleep((caddr_t)vp, PINOD);
428: return (1);
429: }
430: if (vp->v_usecount == 0) {
431: if (vq = vp->v_freef)
432: vq->v_freeb = vp->v_freeb;
433: else
434: vfreet = vp->v_freeb;
435: *vp->v_freeb = vq;
436: vp->v_freef = NULL;
437: vp->v_freeb = NULL;
438: }
439: VREF(vp);
440: VOP_LOCK(vp);
441: return (0);
442: }
443:
444: /*
445: * Vnode reference, just increment the count
446: */
447: void vref(vp)
448: struct vnode *vp;
449: {
450:
451: vp->v_usecount++;
452: }
453:
454: /*
455: * vput(), just unlock and vrele()
456: */
457: void vput(vp)
458: register struct vnode *vp;
459: {
460: VOP_UNLOCK(vp);
461: vrele(vp);
462: }
463:
464: /*
465: * Vnode release.
466: * If count drops to zero, call inactive routine and return to freelist.
467: */
468: void vrele(vp)
469: register struct vnode *vp;
470: {
471:
472: if (vp == NULL)
473: panic("vrele: null vp");
474: vp->v_usecount--;
475: if (vp->v_usecount < 0)
476: vprint("vrele: bad ref count", vp);
477: if (vp->v_usecount > 0)
478: return;
479: if (vfreeh == NULLVP) {
480: /*
481: * insert into empty list
482: */
483: vfreeh = vp;
484: vp->v_freeb = &vfreeh;
485: } else {
486: /*
487: * insert at tail of list
488: */
489: *vfreet = vp;
490: vp->v_freeb = vfreet;
491: }
492: vp->v_freef = NULL;
493: vfreet = &vp->v_freef;
494: VOP_INACTIVE(vp);
495: }
496:
497: /*
498: * Page or buffer structure gets a reference.
499: */
500: vhold(vp)
501: register struct vnode *vp;
502: {
503:
504: vp->v_holdcnt++;
505: }
506:
507: /*
508: * Page or buffer structure frees a reference.
509: */
510: holdrele(vp)
511: register struct vnode *vp;
512: {
513:
514: if (vp->v_holdcnt <= 0)
515: panic("holdrele: holdcnt");
516: vp->v_holdcnt--;
517: }
518:
519: /*
520: * Remove any vnodes in the vnode table belonging to mount point mp.
521: *
522: * If MNT_NOFORCE is specified, there should not be any active ones,
523: * return error if any are found (nb: this is a user error, not a
524: * system error). If MNT_FORCE is specified, detach any active vnodes
525: * that are found.
526: */
527: int busyprt = 0; /* patch to print out busy vnodes */
528:
529: vflush(mp, skipvp, flags)
530: struct mount *mp;
531: struct vnode *skipvp;
532: int flags;
533: {
534: register struct vnode *vp, *nvp;
535: int busy = 0;
536:
537: if ((mp->mnt_flag & MNT_MPBUSY) == 0)
538: panic("vflush: not busy");
539: loop:
540: for (vp = mp->mnt_mounth; vp; vp = nvp) {
541: if (vp->v_mount != mp)
542: goto loop;
543: nvp = vp->v_mountf;
544: /*
545: * Skip over a selected vnode.
546: */
547: if (vp == skipvp)
548: continue;
549: /*
550: * Skip over a vnodes marked VSYSTEM.
551: */
552: if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM))
553: continue;
554: /*
555: * With v_usecount == 0, all we need to do is clear
556: * out the vnode data structures and we are done.
557: */
558: if (vp->v_usecount == 0) {
559: vgone(vp);
560: continue;
561: }
562: /*
563: * For block or character devices, revert to an
564: * anonymous device. For all other files, just kill them.
565: */
566: if (flags & FORCECLOSE) {
567: if (vp->v_type != VBLK && vp->v_type != VCHR) {
568: vgone(vp);
569: } else {
570: vclean(vp, 0);
571: vp->v_op = &spec_vnodeops;
572: insmntque(vp, (struct mount *)0);
573: }
574: continue;
575: }
576: if (busyprt)
577: vprint("vflush: busy vnode", vp);
578: busy++;
579: }
580: if (busy)
581: return (EBUSY);
582: return (0);
583: }
584:
585: /*
586: * Disassociate the underlying file system from a vnode.
587: */
588: void vclean(vp, flags)
589: register struct vnode *vp;
590: long flags;
591: {
592: struct vnodeops *origops;
593: int active;
594:
595: /*
596: * Check to see if the vnode is in use.
597: * If so we have to reference it before we clean it out
598: * so that its count cannot fall to zero and generate a
599: * race against ourselves to recycle it.
600: */
601: if (active = vp->v_usecount)
602: VREF(vp);
603: /*
604: * Prevent the vnode from being recycled or
605: * brought into use while we clean it out.
606: */
607: if (vp->v_flag & VXLOCK)
608: panic("vclean: deadlock");
609: vp->v_flag |= VXLOCK;
610: /*
611: * Even if the count is zero, the VOP_INACTIVE routine may still
612: * have the object locked while it cleans it out. The VOP_LOCK
613: * ensures that the VOP_INACTIVE routine is done with its work.
614: * For active vnodes, it ensures that no other activity can
615: * occur while the buffer list is being cleaned out.
616: */
617: VOP_LOCK(vp);
618: if (flags & DOCLOSE)
619: vinvalbuf(vp, 1);
620: /*
621: * Prevent any further operations on the vnode from
622: * being passed through to the old file system.
623: */
624: origops = vp->v_op;
625: vp->v_op = &dead_vnodeops;
626: vp->v_tag = VT_NON;
627: /*
628: * If purging an active vnode, it must be unlocked, closed,
629: * and deactivated before being reclaimed.
630: */
631: (*(origops->vn_unlock))(vp);
632: if (active) {
633: if (flags & DOCLOSE)
634: (*(origops->vn_close))(vp, 0, NOCRED);
635: (*(origops->vn_inactive))(vp);
636: }
637: /*
638: * Reclaim the vnode.
639: */
640: if ((*(origops->vn_reclaim))(vp))
641: panic("vclean: cannot reclaim");
642: if (active)
643: vrele(vp);
644: /*
645: * Done with purge, notify sleepers in vget of the grim news.
646: */
647: vp->v_flag &= ~VXLOCK;
648: if (vp->v_flag & VXWANT) {
649: vp->v_flag &= ~VXWANT;
650: wakeup((caddr_t)vp);
651: }
652: }
653:
654: /*
655: * Eliminate all activity associated with the requested vnode
656: * and with all vnodes aliased to the requested vnode.
657: */
658: void vgoneall(vp)
659: register struct vnode *vp;
660: {
661: register struct vnode *vq;
662:
663: if (vp->v_flag & VALIASED) {
664: /*
665: * If a vgone (or vclean) is already in progress,
666: * wait until it is done and return.
667: */
668: if (vp->v_flag & VXLOCK) {
669: vp->v_flag |= VXWANT;
670: sleep((caddr_t)vp, PINOD);
671: return;
672: }
673: /*
674: * Ensure that vp will not be vgone'd while we
675: * are eliminating its aliases.
676: */
677: vp->v_flag |= VXLOCK;
678: while (vp->v_flag & VALIASED) {
679: for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
680: if (vq->v_rdev != vp->v_rdev ||
681: vq->v_type != vp->v_type || vp == vq)
682: continue;
683: vgone(vq);
684: break;
685: }
686: }
687: /*
688: * Remove the lock so that vgone below will
689: * really eliminate the vnode after which time
690: * vgone will awaken any sleepers.
691: */
692: vp->v_flag &= ~VXLOCK;
693: }
694: vgone(vp);
695: }
696:
697: /*
698: * Eliminate all activity associated with a vnode
699: * in preparation for reuse.
700: */
701: void vgone(vp)
702: register struct vnode *vp;
703: {
704: register struct vnode *vq;
705: struct vnode *vx;
706: long count;
707:
708: /*
709: * If a vgone (or vclean) is already in progress,
710: * wait until it is done and return.
711: */
712: if (vp->v_flag & VXLOCK) {
713: vp->v_flag |= VXWANT;
714: sleep((caddr_t)vp, PINOD);
715: return;
716: }
717: /*
718: * Clean out the filesystem specific data.
719: */
720: vclean(vp, DOCLOSE);
721: /*
722: * Delete from old mount point vnode list, if on one.
723: */
724: if (vp->v_mountb) {
725: if (vq = vp->v_mountf)
726: vq->v_mountb = vp->v_mountb;
727: *vp->v_mountb = vq;
728: vp->v_mountf = NULL;
729: vp->v_mountb = NULL;
730: }
731: /*
732: * If special device, remove it from special device alias list.
733: */
734: if (vp->v_type == VBLK || vp->v_type == VCHR) {
735: if (*vp->v_hashchain == vp) {
736: *vp->v_hashchain = vp->v_specnext;
737: } else {
738: for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
739: if (vq->v_specnext != vp)
740: continue;
741: vq->v_specnext = vp->v_specnext;
742: break;
743: }
744: if (vq == NULL)
745: panic("missing bdev");
746: }
747: if (vp->v_flag & VALIASED) {
748: count = 0;
749: for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
750: if (vq->v_rdev != vp->v_rdev ||
751: vq->v_type != vp->v_type)
752: continue;
753: count++;
754: vx = vq;
755: }
756: if (count == 0)
757: panic("missing alias");
758: if (count == 1)
759: vx->v_flag &= ~VALIASED;
760: vp->v_flag &= ~VALIASED;
761: }
762: FREE(vp->v_specinfo, M_VNODE);
763: vp->v_specinfo = NULL;
764: }
765: /*
766: * If it is on the freelist, move it to the head of the list.
767: */
768: if (vp->v_freeb) {
769: if (vq = vp->v_freef)
770: vq->v_freeb = vp->v_freeb;
771: else
772: vfreet = vp->v_freeb;
773: *vp->v_freeb = vq;
774: vp->v_freef = vfreeh;
775: vp->v_freeb = &vfreeh;
776: vfreeh->v_freeb = &vp->v_freef;
777: vfreeh = vp;
778: }
779: vp->v_type = VBAD;
780: }
781:
782: /*
783: * Lookup a vnode by device number.
784: */
785: vfinddev(dev, type, vpp)
786: dev_t dev;
787: enum vtype type;
788: struct vnode **vpp;
789: {
790: register struct vnode *vp;
791:
792: for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) {
793: if (dev != vp->v_rdev || type != vp->v_type)
794: continue;
795: *vpp = vp;
796: return (0);
797: }
798: return (1);
799: }
800:
801: /*
802: * Calculate the total number of references to a special device.
803: */
804: vcount(vp)
805: register struct vnode *vp;
806: {
807: register struct vnode *vq;
808: int count;
809:
810: if ((vp->v_flag & VALIASED) == 0)
811: return (vp->v_usecount);
812: loop:
813: for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
814: if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type)
815: continue;
816: /*
817: * Alias, but not in use, so flush it out.
818: */
819: if (vq->v_usecount == 0) {
820: vgone(vq);
821: goto loop;
822: }
823: count += vq->v_usecount;
824: }
825: return (count);
826: }
827:
828: /*
829: * Print out a description of a vnode.
830: */
831: static char *typename[] =
832: { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" };
833:
834: vprint(label, vp)
835: char *label;
836: register struct vnode *vp;
837: {
838: char buf[64];
839:
840: if (label != NULL)
841: printf("%s: ", label);
842: printf("type %s, usecount %d, refcount %d,", typename[vp->v_type],
843: vp->v_usecount, vp->v_holdcnt);
844: buf[0] = '\0';
845: if (vp->v_flag & VROOT)
846: strcat(buf, "|VROOT");
847: if (vp->v_flag & VTEXT)
848: strcat(buf, "|VTEXT");
849: if (vp->v_flag & VSYSTEM)
850: strcat(buf, "|VSYSTEM");
851: if (vp->v_flag & VEXLOCK)
852: strcat(buf, "|VEXLOCK");
853: if (vp->v_flag & VSHLOCK)
854: strcat(buf, "|VSHLOCK");
855: if (vp->v_flag & VLWAIT)
856: strcat(buf, "|VLWAIT");
857: if (vp->v_flag & VXLOCK)
858: strcat(buf, "|VXLOCK");
859: if (vp->v_flag & VXWANT)
860: strcat(buf, "|VXWANT");
861: if (vp->v_flag & VBWAIT)
862: strcat(buf, "|VBWAIT");
863: if (vp->v_flag & VALIASED)
864: strcat(buf, "|VALIASED");
865: if (buf[0] != '\0')
866: printf(" flags (%s)", &buf[1]);
867: printf("\n\t");
868: VOP_PRINT(vp);
869: }
870:
871: int kinfo_vdebug = 1;
872: int kinfo_vgetfailed;
873: #define KINFO_VNODESLOP 10
874: /*
875: * Dump vnode list (via kinfo).
876: * Copyout address of vnode followed by vnode.
877: */
878: kinfo_vnode(op, where, acopysize, arg, aneeded)
879: char *where;
880: int *acopysize, *aneeded;
881: {
882: register struct mount *mp = rootfs;
883: struct mount *omp;
884: struct vnode *vp;
885: register needed = 0;
886: register char *bp = where, *savebp;
887: char *ewhere = where + *acopysize;
888: int error;
889:
890: #define VPTRSZ sizeof (struct vnode *)
891: #define VNODESZ sizeof (struct vnode)
892: if (where == NULL) {
893: *aneeded = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ);
894: return (0);
895: }
896:
897: do {
898: if (vfs_busy(mp)) {
899: mp = mp->mnt_next;
900: continue;
901: }
902: savebp = bp;
903: again:
904: for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) {
905: /*
906: * Check that the vp is still associated with
907: * this filesystem. RACE: could have been
908: * recycled onto the same filesystem.
909: */
910: if (vp->v_mount != mp) {
911: if (kinfo_vdebug)
912: printf("kinfo: vp changed\n");
913: bp = savebp;
914: goto again;
915: }
916: if ((bp + VPTRSZ + VNODESZ <= ewhere) &&
917: ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) ||
918: (error = copyout((caddr_t)vp, bp + VPTRSZ,
919: VNODESZ))))
920: return (error);
921: bp += VPTRSZ + VNODESZ;
922: }
923: omp = mp;
924: mp = mp->mnt_next;
925: vfs_unbusy(omp);
926: } while (mp != rootfs);
927:
928: *aneeded = bp - where;
929: if (bp > ewhere)
930: *acopysize = ewhere - where;
931: else
932: *acopysize = bp - where;
933: return (0);
934: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.