X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/f2f730c6da1419eaec22e7751d1dd56a14423979..17c2edaa6c498fa46f4add2c758d9c5e4a46e4e1:/usr/src/sys/kern/vfs_subr.c diff --git a/usr/src/sys/kern/vfs_subr.c b/usr/src/sys/kern/vfs_subr.c index 0b3098c78b..52d5ee5eec 100644 --- a/usr/src/sys/kern/vfs_subr.c +++ b/usr/src/sys/kern/vfs_subr.c @@ -14,7 +14,7 @@ * 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% */ /* @@ -25,6 +25,7 @@ #include "mount.h" #include "time.h" #include "vnode.h" +#include "specdev.h" #include "namei.h" #include "ucred.h" #include "errno.h" @@ -92,8 +93,8 @@ getvfs(fsid) 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; @@ -111,8 +112,8 @@ void vattr_null(vap) 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 = @@ -170,38 +171,15 @@ ndrele(ndp) 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 */ @@ -227,26 +205,34 @@ getnewvnode(tag, mp, vops, vpp) { 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; @@ -359,17 +345,17 @@ loop: 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); @@ -623,13 +609,36 @@ void vgoneall(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); } @@ -645,6 +654,15 @@ void 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. */ @@ -678,7 +696,8 @@ void vgone(vp) 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; @@ -741,7 +760,7 @@ vcount(vp) 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. @@ -759,7 +778,7 @@ loop: * 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; @@ -796,12 +815,76 @@ vprint(label, vp) 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); }