* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
- * @(#)vfs_subr.c 7.23 (Berkeley) %G%
+ * @(#)vfs_subr.c 7.39 (Berkeley) %G%
*/
/*
#include "mount.h"
#include "time.h"
#include "vnode.h"
+#include "specdev.h"
#include "namei.h"
#include "ucred.h"
#include "errno.h"
mp = rootfs;
do {
- if (mp->m_fsid.val[0] == fsid->val[0] &&
- mp->m_fsid.val[1] == fsid->val[1]) {
+ if (mp->m_stat.f_fsid.val[0] == fsid->val[0] &&
+ mp->m_stat.f_fsid.val[1] == fsid->val[1]) {
return (mp);
}
mp = mp->m_next;
vap->va_type = VNON;
vap->va_mode = vap->va_nlink = vap->va_uid = vap->va_gid =
vap->va_fsid = vap->va_fileid = vap->va_size =
- vap->va_size1 = vap->va_blocksize = vap->va_rdev =
- vap->va_bytes = vap->va_bytes1 =
+ vap->va_size_rsv = vap->va_blocksize = vap->va_rdev =
+ vap->va_bytes = vap->va_bytes_rsv =
vap->va_atime.tv_sec = vap->va_atime.tv_usec =
vap->va_mtime.tv_sec = vap->va_mtime.tv_usec =
vap->va_ctime.tv_sec = vap->va_ctime.tv_usec =
struct vnode *vfreeh, **vfreet;
extern struct vnodeops dead_vnodeops, spec_vnodeops;
extern void vclean();
-
-#define SPECHSZ 64
-#if ((SPECHSZ&(SPECHSZ-1)) == 0)
-#define SPECHASH(rdev) (((rdev>>5)+(rdev))&(SPECHSZ-1))
-#else
-#define SPECHASH(rdev) (((unsigned)((rdev>>5)+(rdev)))%SPECHSZ)
-#endif
-struct vnode *speclisth[SPECHSZ];
+long numvnodes;
/*
* Initialize the vnode structures and initialize each file system type.
*/
vfsinit()
{
- register struct vnode *vp = vnode;
struct vfsops **vfsp;
- /*
- * Build vnode free list.
- */
- vfreeh = vp;
- vfreet = &vp->v_freef;
- vp->v_freeb = &vfreeh;
- vp->v_op = &dead_vnodeops;
- for (vp++; vp < vnodeNVNODE; vp++) {
- *vfreet = vp;
- vp->v_freeb = vfreet;
- vfreet = &vp->v_freef;
- vp->v_op = &dead_vnodeops;
- }
- vp--;
- vp->v_freef = NULL;
/*
* Initialize the vnode name cache
*/
{
register struct vnode *vp, *vq;
- if ((vp = vfreeh) == NULL) {
- tablefull("vnode");
- *vpp = 0;
- return (ENFILE);
+ if (numvnodes < desiredvnodes) {
+ vp = (struct vnode *)malloc(sizeof *vp, M_VNODE, M_WAITOK);
+ bzero((char *)vp, sizeof *vp);
+ numvnodes++;
+ } else {
+ if ((vp = vfreeh) == NULL) {
+ tablefull("vnode");
+ *vpp = 0;
+ return (ENFILE);
+ }
+ if (vp->v_usecount)
+ panic("free vnode isn't");
+ if (vq = vp->v_freef)
+ vq->v_freeb = &vfreeh;
+ else
+ vfreet = &vfreeh;
+ vfreeh = vq;
+ vp->v_freef = NULL;
+ vp->v_freeb = NULL;
+ if (vp->v_type != VBAD)
+ vgone(vp);
+ vp->v_flag = 0;
+ vp->v_shlockc = 0;
+ vp->v_exlockc = 0;
+ vp->v_lastr = 0;
+ vp->v_socket = 0;
}
- if (vp->v_usecount)
- panic("free vnode isn't");
- if (vq = vp->v_freef)
- vq->v_freeb = &vfreeh;
- vfreeh = vq;
- vp->v_freef = NULL;
- vp->v_freeb = NULL;
- if (vp->v_type != VNON && vp->v_type != VBAD)
- vgone(vp);
vp->v_type = VNON;
- vp->v_flag = 0;
- vp->v_shlockc = 0;
- vp->v_exlockc = 0;
- vp->v_lastr = 0;
- vp->v_socket = 0;
cache_purge(vp);
vp->v_tag = tag;
vp->v_op = vops;
break;
}
if (vp == NULL || vp->v_tag != VT_NON) {
- if (vp != NULL) {
- nvp->v_flag |= VALIASED;
- vp->v_flag |= VALIASED;
- vput(vp);
- }
MALLOC(nvp->v_specinfo, struct specinfo *,
sizeof(struct specinfo), M_VNODE, M_WAITOK);
nvp->v_rdev = nvp_rdev;
nvp->v_hashchain = vpp;
nvp->v_specnext = *vpp;
*vpp = nvp;
+ if (vp != NULL) {
+ nvp->v_flag |= VALIASED;
+ vp->v_flag |= VALIASED;
+ vput(vp);
+ }
return ((struct vnode *)0);
}
VOP_UNLOCK(vp);
{
register struct vnode *vq;
- while (vp->v_flag & VALIASED) {
- for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
- if (vq->v_rdev != vp->v_rdev || vp == vq)
- continue;
- vgone(vq);
- break;
+ if (vp->v_flag & VALIASED) {
+ /*
+ * If a vgone (or vclean) is already in progress,
+ * wait until it is done and return.
+ */
+ if (vp->v_flag & VXLOCK) {
+ vp->v_flag |= VXWANT;
+ sleep((caddr_t)vp, PINOD);
+ return;
}
+ /*
+ * Ensure that vp will not be vgone'd while we
+ * are eliminating its aliases.
+ */
+ vp->v_flag |= VXLOCK;
+ while (vp->v_flag & VALIASED) {
+ for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
+ if (vq->v_rdev != vp->v_rdev ||
+ vq->v_type != vp->v_type || vp == vq)
+ continue;
+ vgone(vq);
+ break;
+ }
+ }
+ /*
+ * Remove the lock so that vgone below will
+ * really eliminate the vnode after which time
+ * vgone will awaken any sleepers.
+ */
+ vp->v_flag &= ~VXLOCK;
}
vgone(vp);
}
struct vnode *vx;
long count;
+ /*
+ * If a vgone (or vclean) is already in progress,
+ * wait until it is done and return.
+ */
+ if (vp->v_flag & VXLOCK) {
+ vp->v_flag |= VXWANT;
+ sleep((caddr_t)vp, PINOD);
+ return;
+ }
/*
* Clean out the filesystem specific data.
*/
if (vp->v_flag & VALIASED) {
count = 0;
for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
- if (vq->v_rdev != vp->v_rdev)
+ if (vq->v_rdev != vp->v_rdev ||
+ vq->v_type != vp->v_type)
continue;
count++;
vx = vq;
return (vp->v_usecount);
loop:
for (count = 0, vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
- if (vq->v_rdev != vp->v_rdev)
+ if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type)
continue;
/*
* Alias, but not in use, so flush it out.
* Print out a description of a vnode.
*/
static char *typename[] =
- { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VBAD" };
+ { "VNON", "VREG", "VDIR", "VBLK", "VCHR", "VLNK", "VSOCK", "VFIFO", "VBAD" };
vprint(label, vp)
char *label;
VOP_PRINT(vp);
}
-strcat(src, append)
- register char *src, *append;
+int kinfo_vdebug = 1;
+int kinfo_vgetfailed;
+#define KINFO_VNODESLOP 10
+/*
+ * Dump vnode list (via kinfo).
+ * Copyout address of vnode followed by vnode.
+ */
+kinfo_vnode(op, where, acopysize, arg, aneeded)
+ char *where;
+ int *acopysize, *aneeded;
{
+ register struct mount *mp = rootfs;
+ register struct vnode *nextvp;
+ struct vnode *vp;
+ register needed = 0;
+ register char *bp = where, *savebp;
+ char *ewhere = where + *acopysize;
+ int error;
+
+#define VPTRSZ sizeof (struct vnode *)
+#define VNODESZ sizeof (struct vnode)
+ if (where == NULL) {
+ *aneeded = (numvnodes + KINFO_VNODESLOP) * (VPTRSZ + VNODESZ);
+ return (0);
+ }
+
+#define RETRY bp = savebp ; goto again
+ do {
+ /*
+ * A vget can fail if the vnode is being
+ * recycled. In this (rare) case, we have to start
+ * over with this filesystem. Also, have to
+ * check that nextvp is still associated
+ * with this filesystem. RACE: could have been
+ * recycled onto same filesystem.
+ */
+ savebp = bp;
+again:
+ nextvp = mp->m_mounth;
+ while (vp = nextvp) {
+ if (vget(vp)) {
+ if (kinfo_vdebug)
+ printf("kinfo: vget failed\n");
+ kinfo_vgetfailed++;
+ RETRY;
+ }
+ if (vp->v_mount != mp) {
+ if (kinfo_vdebug)
+ printf("kinfo: vp changed\n");
+ vput(vp);
+ RETRY;
+ }
+ if ((bp + VPTRSZ + VNODESZ <= ewhere) &&
+ ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) ||
+ (error = copyout((caddr_t)vp, bp + VPTRSZ,
+ VNODESZ)))) {
+ vput(vp);
+ return (error);
+ }
+ bp += VPTRSZ + VNODESZ;
+ nextvp = vp->v_mountf;
+ vput(vp);
+ }
+ mp = mp->m_next;
+ } while (mp != rootfs);
- for (; *src; ++src)
- /* void */;
- while (*src++ = *append++)
- /* void */;
+ *aneeded = bp - where;
+ if (bp > ewhere)
+ *acopysize = ewhere - where;
+ else
+ *acopysize = bp - where;
+ return (0);
}