* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
- * @(#)vfs_subr.c 7.30 (Berkeley) %G%
+ * @(#)vfs_subr.c 7.38 (Berkeley) %G%
*/
/*
#include "mount.h"
#include "time.h"
#include "vnode.h"
+#include "specdev.h"
#include "namei.h"
#include "ucred.h"
#include "errno.h"
#include "malloc.h"
-/*
- * Shorthand notation.
- */
-#define v_hashchain v_specinfo->si_hashchain
-#define v_specnext v_specinfo->si_specnext
-
/*
* Remove a mount point from the list of mounted filesystems.
* Unmount of the root is illegal.
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;
- vp->v_type = VBAD;
- for (vp++; vp < vnodeNVNODE; vp++) {
- *vfreet = vp;
- vp->v_freeb = vfreet;
- vfreet = &vp->v_freef;
- vp->v_op = &dead_vnodeops;
- vp->v_type = VBAD;
- }
- 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 != 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 ||
- vq->v_type != vp->v_type || 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.
*/