add vrecycle and vop_nolock* functions
SCCS-vsn: sys/kern/vfs_subr.c 8.24
*
* %sccs.include.redist.c%
*
*
* %sccs.include.redist.c%
*
- * @(#)vfs_subr.c 8.23 (Berkeley) %G%
+ * @(#)vfs_subr.c 8.24 (Berkeley) %G%
}
TAILQ_HEAD(freelst, vnode) vnode_free_list; /* vnode free list */
struct mntlist mountlist; /* mounted filesystem list */
}
TAILQ_HEAD(freelst, vnode) vnode_free_list; /* vnode free list */
struct mntlist mountlist; /* mounted filesystem list */
+static struct simplelock mntid_slock;
+struct simplelock mntvnode_slock;
+static struct simplelock spechash_slock;
+static struct simplelock vnode_free_list_slock;
/*
* Initialize the vnode management data structures.
/*
* Initialize the vnode management data structures.
+ simple_lock_init(&mntvnode_slock);
+ simple_lock_init(&mntid_slock);
+ simple_lock_init(&spechash_slock);
TAILQ_INIT(&vnode_free_list);
TAILQ_INIT(&vnode_free_list);
+ simple_lock_init(&vnode_free_list_slock);
CIRCLEQ_INIT(&mountlist);
}
CIRCLEQ_INIT(&mountlist);
}
+ simple_lock(&mntid_slock);
mtype = mp->mnt_vfc->vfc_typenum;
mp->mnt_stat.f_fsid.val[0] = makedev(nblkdev + mtype, 0);
mp->mnt_stat.f_fsid.val[1] = mtype;
mtype = mp->mnt_vfc->vfc_typenum;
mp->mnt_stat.f_fsid.val[0] = makedev(nblkdev + mtype, 0);
mp->mnt_stat.f_fsid.val[1] = mtype;
}
}
mp->mnt_stat.f_fsid.val[0] = tfsid.val[0];
}
}
mp->mnt_stat.f_fsid.val[0] = tfsid.val[0];
+ simple_unlock(&mntid_slock);
* Routines having to do with the management of the vnode table.
*/
extern int (**dead_vnodeop_p)();
* Routines having to do with the management of the vnode table.
*/
extern int (**dead_vnodeop_p)();
+static void vclean __P((struct vnode *vp, int flag, struct proc *p));
+extern void vgonel __P((struct vnode *vp, struct proc *p));
long numvnodes;
extern struct vattr va_null;
int newnodes = 0;
long numvnodes;
extern struct vattr va_null;
int newnodes = 0;
int (**vops)();
struct vnode **vpp;
{
int (**vops)();
struct vnode **vpp;
{
- register struct vnode *vp;
+ struct proc *p = curproc; /* XXX */
+ struct vnode *vp;
+top:
+ simple_lock(&vnode_free_list_slock);
newnodes++;
if ((vnode_free_list.tqh_first == NULL &&
numvnodes < 2 * desiredvnodes) ||
numvnodes < desiredvnodes) {
newnodes++;
if ((vnode_free_list.tqh_first == NULL &&
numvnodes < 2 * desiredvnodes) ||
numvnodes < desiredvnodes) {
+ simple_unlock(&vnode_free_list_slock);
vp = (struct vnode *)malloc((u_long)sizeof *vp,
M_VNODE, M_WAITOK);
bzero((char *)vp, sizeof *vp);
vp = (struct vnode *)malloc((u_long)sizeof *vp,
M_VNODE, M_WAITOK);
bzero((char *)vp, sizeof *vp);
numvnodes++;
vp->v_spare[0] = numvnodes;
} else {
numvnodes++;
vp->v_spare[0] = numvnodes;
} else {
- if ((vp = vnode_free_list.tqh_first) == NULL) {
+ for (vp = vnode_free_list.tqh_first;
+ vp != NULLVP; vp = vp->v_freelist.tqe_next) {
+ if (simple_lock_try(&vp->v_interlock))
+ break;
+ }
+ /*
+ * Unless this is a bad time of the month, at most
+ * the first NCPUS items on the free list are
+ * locked, so this is close enough to being empty.
+ */
+ if (vp == NULLVP) {
+ simple_unlock(&vnode_free_list_slock);
tablefull("vnode");
*vpp = 0;
return (ENFILE);
tablefull("vnode");
*vpp = 0;
return (ENFILE);
vp->v_freelist.tqe_next = (struct vnode *)0xdeadf;
/* see comment on why 0xdeadb is set at end of vgone (below) */
vp->v_freelist.tqe_prev = (struct vnode **)0xdeadb;
vp->v_freelist.tqe_next = (struct vnode *)0xdeadf;
/* see comment on why 0xdeadb is set at end of vgone (below) */
vp->v_freelist.tqe_prev = (struct vnode **)0xdeadb;
+ simple_unlock(&vnode_free_list_slock);
vp->v_lease = NULL;
if (vp->v_type != VBAD)
vp->v_lease = NULL;
if (vp->v_type != VBAD)
+ vgonel(vp, p);
+ else
+ simple_unlock(&vp->v_interlock);
#ifdef DIAGNOSTIC
if (vp->v_data)
panic("cleaned vnode isn't");
#ifdef DIAGNOSTIC
if (vp->v_data)
panic("cleaned vnode isn't");
*/
void
insmntque(vp, mp)
*/
void
insmntque(vp, mp)
- register struct vnode *vp;
- register struct mount *mp;
+ struct vnode *vp;
+ struct mount *mp;
+ simple_lock(&mntvnode_slock);
/*
* Delete from old mount point vnode list, if on one.
*/
/*
* Delete from old mount point vnode list, if on one.
*/
/*
* Insert into list of vnodes for the new mount point, if available.
*/
/*
* Insert into list of vnodes for the new mount point, if available.
*/
- if ((vp->v_mount = mp) == NULL)
- return;
- if (vp->v_mntvnodes.le_next != (struct vnode *)0xdeadf ||
- vp->v_mntvnodes.le_prev != (struct vnode **)0xdeadb)
- panic("insmntque: already on queue");
- LIST_INSERT_HEAD(&mp->mnt_vnodelist, vp, v_mntvnodes);
+ if ((vp->v_mount = mp) != NULL)
+ LIST_INSERT_HEAD(&mp->mnt_vnodelist, vp, v_mntvnodes);
+ simple_unlock(&mntvnode_slock);
dev_t nvp_rdev;
struct mount *mp;
{
dev_t nvp_rdev;
struct mount *mp;
{
- register struct vnode *vp;
+ struct proc *p = curproc; /* XXX */
+ struct vnode *vp;
struct vnode **vpp;
if (nvp->v_type != VBLK && nvp->v_type != VCHR)
struct vnode **vpp;
if (nvp->v_type != VBLK && nvp->v_type != VCHR)
vpp = &speclisth[SPECHASH(nvp_rdev)];
loop:
vpp = &speclisth[SPECHASH(nvp_rdev)];
loop:
+ simple_lock(&spechash_slock);
for (vp = *vpp; vp; vp = vp->v_specnext) {
if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type)
continue;
/*
* Alias, but not in use, so flush it out.
*/
for (vp = *vpp; vp; vp = vp->v_specnext) {
if (nvp_rdev != vp->v_rdev || nvp->v_type != vp->v_type)
continue;
/*
* Alias, but not in use, so flush it out.
*/
+ simple_lock(&vp->v_interlock);
if (vp->v_usecount == 0) {
if (vp->v_usecount == 0) {
+ simple_unlock(&spechash_slock);
+ vgonel(vp, p);
+ if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p)) {
+ simple_unlock(&spechash_slock);
break;
}
if (vp == NULL || vp->v_tag != VT_NON) {
break;
}
if (vp == NULL || vp->v_tag != VT_NON) {
nvp->v_hashchain = vpp;
nvp->v_specnext = *vpp;
nvp->v_specflags = 0;
nvp->v_hashchain = vpp;
nvp->v_specnext = *vpp;
nvp->v_specflags = 0;
+ simple_unlock(&spechash_slock);
nvp->v_flag |= VALIASED;
vp->v_flag |= VALIASED;
vput(vp);
}
return (NULLVP);
}
nvp->v_flag |= VALIASED;
vp->v_flag |= VALIASED;
vput(vp);
}
return (NULLVP);
}
- VOP_UNLOCK(vp);
- vclean(vp, 0);
+ simple_unlock(&spechash_slock);
+ VOP_UNLOCK(vp, 0, p);
+ simple_lock(&vp->v_interlock);
+ vclean(vp, 0, p);
vp->v_op = nvp->v_op;
vp->v_tag = nvp->v_tag;
nvp->v_type = VNON;
vp->v_op = nvp->v_op;
vp->v_tag = nvp->v_tag;
nvp->v_type = VNON;
* been changed to a new file system type).
*/
int
* been changed to a new file system type).
*/
int
-vget(vp, lockflag)
- register struct vnode *vp;
- int lockflag;
+vget(vp, flags, p)
+ struct vnode *vp;
+ int flags;
+ struct proc *p;
{
/*
* If the vnode is in the process of being cleaned out for
* another use, we wait for the cleaning to finish and then
{
/*
* If the vnode is in the process of being cleaned out for
* another use, we wait for the cleaning to finish and then
- * return failure. Cleaning is determined either by checking
- * that the VXLOCK flag is set, or that the use count is
- * zero with the back pointer set to show that it has been
- * removed from the free list by getnewvnode. The VXLOCK
- * flag may not have been set yet because vclean is blocked in
- * the VOP_LOCK call waiting for the VOP_INACTIVE to complete.
+ * return failure. Cleaning is determined by checking that
+ * the VXLOCK flag is set.
- if ((vp->v_flag & VXLOCK) ||
- (vp->v_usecount == 0 &&
- vp->v_freelist.tqe_prev == (struct vnode **)0xdeadb)) {
+ if ((flags & LK_INTERLOCK) == 0)
+ simple_lock(&vp->v_interlock);
+ if (vp->v_flag & VXLOCK) {
+ simple_unlock(&vp->v_interlock);
tsleep((caddr_t)vp, PINOD, "vget", 0);
tsleep((caddr_t)vp, PINOD, "vget", 0);
}
if (vp->v_usecount == 0) {
if (vp->v_freelist.tqe_next == (struct vnode *)0xdeadf ||
vp->v_freelist.tqe_prev == (struct vnode **)0xdeadb)
panic("vget: not on queue");
TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
}
if (vp->v_usecount == 0) {
if (vp->v_freelist.tqe_next == (struct vnode *)0xdeadf ||
vp->v_freelist.tqe_prev == (struct vnode **)0xdeadb)
panic("vget: not on queue");
TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
+ simple_unlock(&vnode_free_list_slock);
+ }
vp->v_freelist.tqe_next = (struct vnode *)0xdeadf;
vp->v_freelist.tqe_prev = (struct vnode **)0xdeadb;
}
vp->v_usecount++;
vp->v_freelist.tqe_next = (struct vnode *)0xdeadf;
vp->v_freelist.tqe_prev = (struct vnode **)0xdeadb;
}
vp->v_usecount++;
- if (lockflag)
- VOP_LOCK(vp);
+ if (flags & LK_TYPE_MASK)
+ return (vn_lock(vp, flags | LK_INTERLOCK, p));
+ simple_unlock(&vp->v_interlock);
if (printcnt-- > 0) vprint("vget got", vp);
return (0);
}
if (printcnt-- > 0) vprint("vget got", vp);
return (0);
}
- * Vnode reference, just increment the count
+ * Stubs to use when there is no locking to be done on the underlying object.
+ *
+ * Getting a lock just clears the interlock if necessary.
+ */
+int
+vop_nolock(ap)
+ struct vop_lock_args /* {
+ struct vnode *a_vp;
+ int a_flags;
+ struct proc *a_p;
+ } */ *ap;
+{
+ struct vnode *vp = ap->a_vp;
+
+ /*
+ * Since we are not using the lock manager, we must clear
+ * the interlock here.
+ */
+ if (ap->a_flags & LK_INTERLOCK)
+ simple_unlock(&vp->v_interlock);
+ return (0);
+}
+
+/*
+ * Unlock has nothing to do.
+ */
+int
+vop_nounlock(ap)
+ struct vop_unlock_args /* {
+ struct vnode *a_vp;
+ int a_flags;
+ struct proc *a_p;
+ } */ *ap;
+{
+
+ return (0);
+}
+
+/*
+ * Nothing is ever locked.
+ */
+int
+vop_noislocked(ap)
+ struct vop_islocked_args /* {
+ struct vnode *a_vp;
+ } */ *ap;
+{
+
+ return (0);
+}
+
+/*
+ * Vnode reference.
*/
void
vref(vp)
struct vnode *vp;
{
*/
void
vref(vp)
struct vnode *vp;
{
+ simple_lock(&vp->v_interlock);
if (vp->v_usecount <= 0)
panic("vref used where vget required");
if (vp->v_freelist.tqe_next != (struct vnode *)0xdeadf ||
vp->v_freelist.tqe_prev != (struct vnode **)0xdeadb)
panic("vref: not free");
vp->v_usecount++;
if (vp->v_usecount <= 0)
panic("vref used where vget required");
if (vp->v_freelist.tqe_next != (struct vnode *)0xdeadf ||
vp->v_freelist.tqe_prev != (struct vnode **)0xdeadb)
panic("vref: not free");
vp->v_usecount++;
+ simple_unlock(&vp->v_interlock);
if (printcnt-- > 0) vprint("vref get", vp);
if (vp->v_type != VBLK && curproc)
curproc->p_spare[0]++;
if (printcnt-- > 0) vprint("vref get", vp);
if (vp->v_type != VBLK && curproc)
curproc->p_spare[0]++;
- register struct vnode *vp;
+ struct proc *p = curproc; /* XXX */
- register struct vnode *vp;
+ struct proc *p = curproc; /* XXX */
#ifdef DIAGNOSTIC
if (vp == NULL)
panic("vrele: null vp");
#endif
#ifdef DIAGNOSTIC
if (vp == NULL)
panic("vrele: null vp");
#endif
+ simple_lock(&vp->v_interlock);
vp->v_usecount--;
if (printcnt-- > 0) vprint("vrele put", vp);
if (vp->v_type != VBLK && curproc)
curproc->p_spare[0]--;
if (bug_refs)
vprint("vref: ");
vp->v_usecount--;
if (printcnt-- > 0) vprint("vrele put", vp);
if (vp->v_type != VBLK && curproc)
curproc->p_spare[0]--;
if (bug_refs)
vprint("vref: ");
- if (vp->v_usecount > 0)
+ if (vp->v_usecount > 0) {
+ simple_unlock(&vp->v_interlock);
- if (vp->v_usecount != 0 || vp->v_writecount != 0) {
+ if (vp->v_usecount < 0 || vp->v_writecount != 0) {
vprint("vrele: bad ref count", vp);
panic("vrele: ref cnt");
}
vprint("vrele: bad ref count", vp);
panic("vrele: ref cnt");
}
/*
* insert at tail of LRU list
*/
/*
* insert at tail of LRU list
*/
+ simple_lock(&vnode_free_list_slock);
if (vp->v_freelist.tqe_next != (struct vnode *)0xdeadf ||
vp->v_freelist.tqe_prev != (struct vnode **)0xdeadb)
panic("vrele: not free");
TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_freelist);
if (vp->v_freelist.tqe_next != (struct vnode *)0xdeadf ||
vp->v_freelist.tqe_prev != (struct vnode **)0xdeadb)
panic("vrele: not free");
TAILQ_INSERT_TAIL(&vnode_free_list, vp, v_freelist);
+ simple_unlock(&vnode_free_list_slock);
+ if (vn_lock(vp, LK_EXCLUSIVE | LK_INTERLOCK, p) == 0)
+ VOP_INACTIVE(vp, p);
/*
* Page or buffer structure gets a reference.
*/
/*
* Page or buffer structure gets a reference.
*/
register struct vnode *vp;
{
register struct vnode *vp;
{
+ simple_lock(&vp->v_interlock);
+ simple_unlock(&vp->v_interlock);
register struct vnode *vp;
{
register struct vnode *vp;
{
+ simple_lock(&vp->v_interlock);
if (vp->v_holdcnt <= 0)
panic("holdrele: holdcnt");
vp->v_holdcnt--;
if (vp->v_holdcnt <= 0)
panic("holdrele: holdcnt");
vp->v_holdcnt--;
+ simple_unlock(&vp->v_interlock);
/*
* Remove any vnodes in the vnode table belonging to mount point mp.
/*
* Remove any vnodes in the vnode table belonging to mount point mp.
struct vnode *skipvp;
int flags;
{
struct vnode *skipvp;
int flags;
{
- register struct vnode *vp, *nvp;
+ struct proc *p = curproc; /* XXX */
+ struct vnode *vp, *nvp;
if ((mp->mnt_flag & MNT_MPBUSY) == 0)
panic("vflush: not busy");
if ((mp->mnt_flag & MNT_MPBUSY) == 0)
panic("vflush: not busy");
+#endif
+
+ simple_lock(&mntvnode_slock);
loop:
for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) {
if (vp->v_mount != mp)
loop:
for (vp = mp->mnt_vnodelist.lh_first; vp; vp = nvp) {
if (vp->v_mount != mp)
*/
if (vp == skipvp)
continue;
*/
if (vp == skipvp)
continue;
+
+ simple_lock(&vp->v_interlock);
/*
* Skip over a vnodes marked VSYSTEM.
*/
/*
* Skip over a vnodes marked VSYSTEM.
*/
- if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM))
+ if ((flags & SKIPSYSTEM) && (vp->v_flag & VSYSTEM)) {
+ simple_unlock(&vp->v_interlock);
/*
* If WRITECLOSE is set, only flush out regular file
* vnodes open for writing.
*/
if ((flags & WRITECLOSE) &&
/*
* If WRITECLOSE is set, only flush out regular file
* vnodes open for writing.
*/
if ((flags & WRITECLOSE) &&
- (vp->v_writecount == 0 || vp->v_type != VREG))
+ (vp->v_writecount == 0 || vp->v_type != VREG)) {
+ simple_unlock(&vp->v_interlock);
/*
* With v_usecount == 0, all we need to do is clear
* out the vnode data structures and we are done.
*/
if (vp->v_usecount == 0) {
/*
* With v_usecount == 0, all we need to do is clear
* out the vnode data structures and we are done.
*/
if (vp->v_usecount == 0) {
+ simple_unlock(&mntvnode_slock);
+ vgonel(vp, p);
+ simple_lock(&mntvnode_slock);
* anonymous device. For all other files, just kill them.
*/
if (flags & FORCECLOSE) {
* anonymous device. For all other files, just kill them.
*/
if (flags & FORCECLOSE) {
+ simple_unlock(&mntvnode_slock);
if (vp->v_type != VBLK && vp->v_type != VCHR) {
if (vp->v_type != VBLK && vp->v_type != VCHR) {
vp->v_op = spec_vnodeop_p;
insmntque(vp, (struct mount *)0);
}
vp->v_op = spec_vnodeop_p;
insmntque(vp, (struct mount *)0);
}
+ simple_lock(&mntvnode_slock);
continue;
}
#ifdef DIAGNOSTIC
if (busyprt)
vprint("vflush: busy vnode", vp);
#endif
continue;
}
#ifdef DIAGNOSTIC
if (busyprt)
vprint("vflush: busy vnode", vp);
#endif
+ simple_unlock(&vp->v_interlock);
+ simple_unlock(&mntvnode_slock);
if (busy)
return (EBUSY);
return (0);
if (busy)
return (EBUSY);
return (0);
/*
* Disassociate the underlying file system from a vnode.
/*
* Disassociate the underlying file system from a vnode.
+ * The vnode interlock is held on entry.
-void
-vclean(vp, flags)
- register struct vnode *vp;
+static void
+vclean(vp, flags, p)
+ struct vnode *vp;
* race against ourselves to recycle it.
*/
if (active = vp->v_usecount)
* race against ourselves to recycle it.
*/
if (active = vp->v_usecount)
- VREF(vp);
- /*
- * Even if the count is zero, the VOP_INACTIVE routine may still
- * have the object locked while it cleans it out. The VOP_LOCK
- * ensures that the VOP_INACTIVE routine is done with its work.
- * For active vnodes, it ensures that no other activity can
- * occur while the underlying object is being cleaned out.
- */
- VOP_LOCK(vp);
/*
* Prevent the vnode from being recycled or
* brought into use while we clean it out.
/*
* Prevent the vnode from being recycled or
* brought into use while we clean it out.
if (vp->v_flag & VXLOCK)
panic("vclean: deadlock");
vp->v_flag |= VXLOCK;
if (vp->v_flag & VXLOCK)
panic("vclean: deadlock");
vp->v_flag |= VXLOCK;
+ /*
+ * Even if the count is zero, the VOP_INACTIVE routine may still
+ * have the object locked while it cleans it out. The VOP_LOCK
+ * ensures that the VOP_INACTIVE routine is done with its work.
+ * For active vnodes, it ensures that no other activity can
+ * occur while the underlying object is being cleaned out.
+ */
+ VOP_LOCK(vp, LK_DRAIN | LK_INTERLOCK, p);
/*
* Clean out any buffers associated with the vnode.
*/
if (flags & DOCLOSE)
vinvalbuf(vp, V_SAVE, NOCRED, NULL, 0, 0);
/*
* Clean out any buffers associated with the vnode.
*/
if (flags & DOCLOSE)
vinvalbuf(vp, V_SAVE, NOCRED, NULL, 0, 0);
- /*
- * Any other processes trying to obtain this lock must first
- * wait for VXLOCK to clear, then call the new lock operation.
- */
- VOP_UNLOCK(vp);
/*
* If purging an active vnode, it must be closed and
/*
* If purging an active vnode, it must be closed and
- * deactivated before being reclaimed.
+ * deactivated before being reclaimed. Note that the
+ * VOP_INACTIVE will unlock the vnode.
*/
if (active) {
if (flags & DOCLOSE)
*/
if (active) {
if (flags & DOCLOSE)
- VOP_CLOSE(vp, IO_NDELAY, NOCRED, NULL);
- VOP_INACTIVE(vp);
+ VOP_CLOSE(vp, IO_NDELAY, NOCRED, p);
+ VOP_INACTIVE(vp, p);
+ } else {
+ /*
+ * Any other processes trying to obtain this lock must first
+ * wait for VXLOCK to clear, then call the new lock operation.
+ */
+ VOP_UNLOCK(vp, 0, p);
}
/*
* Reclaim the vnode.
*/
}
/*
* Reclaim the vnode.
*/
+ if (VOP_RECLAIM(vp, p))
panic("vclean: cannot reclaim");
if (active)
vrele(vp);
panic("vclean: cannot reclaim");
if (active)
vrele(vp);
- register struct vnode *vp, *vq;
+ struct vnode *vp, *vq;
+ struct proc *p = curproc; /* XXX */
+
+#ifdef DIAGNOSTIC
+ if ((ap->a_flags & REVOKEALL) == 0)
+ panic("vop_revoke");
+#endif
- if ((ap->a_flags & REVOKEALL) && (vp->v_flag & VALIASED)) {
+ simple_lock(&vp->v_interlock);
+
+ 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;
/*
* 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;
+ simple_unlock(&vp->v_interlock);
tsleep((caddr_t)vp, PINOD, "vop_revokeall", 0);
return (0);
}
tsleep((caddr_t)vp, PINOD, "vop_revokeall", 0);
return (0);
}
* are eliminating its aliases.
*/
vp->v_flag |= VXLOCK;
* are eliminating its aliases.
*/
vp->v_flag |= VXLOCK;
+ simple_unlock(&vp->v_interlock);
while (vp->v_flag & VALIASED) {
while (vp->v_flag & VALIASED) {
+ simple_lock(&spechash_slock);
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;
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;
+ simple_unlock(&spechash_slock);
+ if (vq == NULLVP)
+ simple_unlock(&spechash_slock);
}
/*
* Remove the lock so that vgone below will
* really eliminate the vnode after which time
* vgone will awaken any sleepers.
*/
}
/*
* Remove the lock so that vgone below will
* really eliminate the vnode after which time
* vgone will awaken any sleepers.
*/
+ simple_lock(&vp->v_interlock);
+ vgonel(vp, p);
+ return (0);
+}
+
+/*
+ * Recycle an unused vnode to the front of the free list.
+ * Release the passed interlock if the vnode will be recycled.
+ */
+int
+vrecycle(vp, inter_lkp, p)
+ struct vnode *vp;
+ struct simplelock *inter_lkp;
+ struct proc *p;
+{
+
+ simple_lock(&vp->v_interlock);
+ if (vp->v_usecount == 0) {
+ if (inter_lkp)
+ simple_unlock(inter_lkp);
+ vgonel(vp, p);
+ return (1);
+ }
+ simple_unlock(&vp->v_interlock);
- register struct vnode *vp;
+ struct vnode *vp;
+{
+ struct proc *p = curproc; /* XXX */
+
+ simple_lock(&vp->v_interlock);
+ vgonel(vp, p);
+}
+
+/*
+ * vgone, with the vp interlock held.
+ */
+void
+vgonel(vp, p)
+ struct vnode *vp;
+ struct proc *p;
- register struct vnode *vq;
*/
if (vp->v_flag & VXLOCK) {
vp->v_flag |= VXWANT;
*/
if (vp->v_flag & VXLOCK) {
vp->v_flag |= VXWANT;
+ simple_unlock(&vp->v_interlock);
tsleep((caddr_t)vp, PINOD, "vgone", 0);
return;
}
/*
* Clean out the filesystem specific data.
*/
tsleep((caddr_t)vp, PINOD, "vgone", 0);
return;
}
/*
* Clean out the filesystem specific data.
*/
+ vclean(vp, DOCLOSE, p);
/*
* Delete from old mount point vnode list, if on one.
*/
/*
* Delete from old mount point vnode list, if on one.
*/
- if (vp->v_mount != NULL) {
- if (vp->v_mntvnodes.le_next == (struct vnode *)0xdeadf ||
- vp->v_mntvnodes.le_prev == (struct vnode **)0xdeadb)
- panic("vgone: not on queue");
- LIST_REMOVE(vp, v_mntvnodes);
- vp->v_mntvnodes.le_next = (struct vnode *)0xdeadf;
- vp->v_mntvnodes.le_prev = (struct vnode **)0xdeadb;
- vp->v_mount = NULL;
- }
+ if (vp->v_mount != NULL)
+ insmntque(vp, (struct mount *)0);
/*
* If special device, remove it from special device alias list
* if it is on one.
*/
if ((vp->v_type == VBLK || vp->v_type == VCHR) && vp->v_specinfo != 0) {
/*
* If special device, remove it from special device alias list
* if it is on one.
*/
if ((vp->v_type == VBLK || vp->v_type == VCHR) && vp->v_specinfo != 0) {
+ simple_lock(&spechash_slock);
if (*vp->v_hashchain == vp) {
*vp->v_hashchain = vp->v_specnext;
} else {
if (*vp->v_hashchain == vp) {
*vp->v_hashchain = vp->v_specnext;
} else {
vx->v_flag &= ~VALIASED;
vp->v_flag &= ~VALIASED;
}
vx->v_flag &= ~VALIASED;
vp->v_flag &= ~VALIASED;
}
+ simple_unlock(&spechash_slock);
FREE(vp->v_specinfo, M_VNODE);
vp->v_specinfo = NULL;
}
FREE(vp->v_specinfo, M_VNODE);
vp->v_specinfo = NULL;
}
* getnewvnode after removing it from the freelist to ensure
* that we do not try to move it here.
*/
* getnewvnode after removing it from the freelist to ensure
* that we do not try to move it here.
*/
- if (vp->v_usecount == 0 &&
- vp->v_freelist.tqe_prev != (struct vnode **)0xdeadb &&
- vnode_free_list.tqh_first != vp) {
- if (vp->v_freelist.tqe_next == (struct vnode *)0xdeadf)
- panic("vgone: use 0, not free");
- TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
- TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist);
+ if (vp->v_usecount == 0) {
+ simple_lock(&vnode_free_list_slock);
+ if ((vp->v_freelist.tqe_prev != (struct vnode **)0xdeadb) &&
+ vnode_free_list.tqh_first != vp) {
+ TAILQ_REMOVE(&vnode_free_list, vp, v_freelist);
+ TAILQ_INSERT_HEAD(&vnode_free_list, vp, v_freelist);
+ }
+ simple_unlock(&vnode_free_list_slock);
enum vtype type;
struct vnode **vpp;
{
enum vtype type;
struct vnode **vpp;
{
- register struct vnode *vp;
+ struct vnode *vp;
+ int rc = 0;
+ simple_lock(&spechash_slock);
for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) {
if (dev != vp->v_rdev || type != vp->v_type)
continue;
*vpp = vp;
for (vp = speclisth[SPECHASH(dev)]; vp; vp = vp->v_specnext) {
if (dev != vp->v_rdev || type != vp->v_type)
continue;
*vpp = vp;
+ simple_unlock(&spechash_slock);
+ return (rc);
- register struct vnode *vp;
- register struct vnode *vq, *vnext;
+ struct vnode *vq, *vnext;
int count;
loop:
if ((vp->v_flag & VALIASED) == 0)
return (vp->v_usecount);
int count;
loop:
if ((vp->v_flag & VALIASED) == 0)
return (vp->v_usecount);
+ simple_lock(&spechash_slock);
for (count = 0, vq = *vp->v_hashchain; vq; vq = vnext) {
vnext = vq->v_specnext;
if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type)
for (count = 0, vq = *vp->v_hashchain; vq; vq = vnext) {
vnext = vq->v_specnext;
if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type)
* Alias, but not in use, so flush it out.
*/
if (vq->v_usecount == 0 && vq != vp) {
* Alias, but not in use, so flush it out.
*/
if (vq->v_usecount == 0 && vq != vp) {
+ simple_unlock(&spechash_slock);
vgone(vq);
goto loop;
}
count += vq->v_usecount;
}
vgone(vq);
goto loop;
}
count += vq->v_usecount;
}
+ simple_unlock(&spechash_slock);
size_t *sizep;
{
register struct mount *mp, *nmp;
size_t *sizep;
{
register struct mount *mp, *nmp;
+ struct vnode *nvp, *vp;
register char *bp = where, *savebp;
char *ewhere;
int error;
register char *bp = where, *savebp;
char *ewhere;
int error;
continue;
savebp = bp;
again:
continue;
savebp = bp;
again:
+ simple_lock(&mntvnode_slock);
for (vp = mp->mnt_vnodelist.lh_first;
vp != NULL;
for (vp = mp->mnt_vnodelist.lh_first;
vp != NULL;
- vp = vp->v_mntvnodes.le_next) {
/*
* Check that the vp is still associated with
* this filesystem. RACE: could have been
* recycled onto the same filesystem.
*/
if (vp->v_mount != mp) {
/*
* Check that the vp is still associated with
* this filesystem. RACE: could have been
* recycled onto the same filesystem.
*/
if (vp->v_mount != mp) {
+ simple_unlock(&mntvnode_slock);
if (kinfo_vdebug)
printf("kinfo: vp changed\n");
bp = savebp;
goto again;
}
if (kinfo_vdebug)
printf("kinfo: vp changed\n");
bp = savebp;
goto again;
}
+ nvp = vp->v_mntvnodes.le_next;
if (bp + VPTRSZ + VNODESZ > ewhere) {
if (bp + VPTRSZ + VNODESZ > ewhere) {
+ simple_unlock(&mntvnode_slock);
*sizep = bp - where;
return (ENOMEM);
}
*sizep = bp - where;
return (ENOMEM);
}
+ simple_unlock(&mntvnode_slock);
if ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) ||
(error = copyout((caddr_t)vp, bp + VPTRSZ, VNODESZ)))
return (error);
bp += VPTRSZ + VNODESZ;
if ((error = copyout((caddr_t)&vp, bp, VPTRSZ)) ||
(error = copyout((caddr_t)vp, bp + VPTRSZ, VNODESZ)))
return (error);
bp += VPTRSZ + VNODESZ;
+ simple_lock(&mntvnode_slock);
+ simple_unlock(&mntvnode_slock);
- register struct vnode *vp;
- register struct vnode *vq;
+ struct vnode *vq;
+ int error = 0;
if (vp->v_specflags & SI_MOUNTEDON)
return (EBUSY);
if (vp->v_flag & VALIASED) {
if (vp->v_specflags & SI_MOUNTEDON)
return (EBUSY);
if (vp->v_flag & VALIASED) {
+ simple_lock(&spechash_slock);
for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
if (vq->v_rdev != vp->v_rdev ||
vq->v_type != vp->v_type)
continue;
for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) {
if (vq->v_rdev != vp->v_rdev ||
vq->v_type != vp->v_type)
continue;
- if (vq->v_specflags & SI_MOUNTEDON)
- return (EBUSY);
+ if (vq->v_specflags & SI_MOUNTEDON) {
+ error = EBUSY;
+ break;
+ }
+ simple_unlock(&spechash_slock);