diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index cebd09b..f5a9703 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -596,7 +596,7 @@ retry:
 	 * close() were performed on it).
 	 */
 	if (delfp) {
-		(void)closef(delfp, td);
+		closef(delfp, p);
 		if (holdleaders) {
 			spin_lock_wr(&fdp->fd_spin);
 			fdp->fd_holdleaderscount--;
@@ -830,7 +830,7 @@ kern_close(int fd)
 			knote_fdclose(p, fd);
 		rel_mplock();
 	}
-	error = closef(fp, td);
+	error = closef(fp, p);
 	if (holdleaders) {
 		spin_lock_wr(&fdp->fd_spin);
 		fdp->fd_holdleaderscount--;
@@ -1180,6 +1180,98 @@ fdavail(struct proc *p, int n)
 }
 
 /*
+ * Revoke open descriptors referencing (f_data, f_type)
+ *
+ * Any revoke executed within a prison is only able to
+ * revoke descriptors for processes within that prison.
+ *
+ * Returns 0 on success or an error code.
+ */
+struct fdrevoke_info {
+	void *data;
+	short type;
+	short unused;
+	int count;
+	int again;
+	struct ucred *cred;
+	struct file *nfp;
+};
+
+static int fdrevoke_callback(struct proc *p, void *vinfo);
+
+int
+fdrevoke(void *f_data, short f_type, struct ucred *cred)
+{
+	struct fdrevoke_info info;
+	int error;
+
+	bzero(&info, sizeof(info));
+	info.data = f_data;
+	info.type = f_type;
+	info.cred = cred;
+	error = falloc(NULL, &info.nfp, NULL);
+	if (error)
+		return (error);
+	do {
+		info.again = 0;
+		allproc_scan(fdrevoke_callback, &info);
+	} while (info.again != 0);
+	fdrop(info.nfp);
+	return(info.count);
+}
+
+static int
+fdrevoke_callback(struct proc *p, void *vinfo)
+{
+	struct fdrevoke_info *info = vinfo;
+	struct filedesc *fdp;
+	struct file *fp;
+	int n;
+
+	if (p->p_stat == SIDL || p->p_stat == SZOMB)
+		return(0);
+	if (info->cred->cr_prison &&
+	    info->cred->cr_prison != p->p_ucred->cr_prison) {
+		return(0);
+	}
+
+	/*
+	 * If the controlling terminal of the process matches the
+	 * vnode being revoked we clear the controlling terminal.
+	 *
+	 * The normal spec_close() may not catch this because it
+	 * uses curproc instead of p.
+	 */
+	if (p->p_session && info->type == DTYPE_VNODE &&
+	    info->data == p->p_session->s_ttyvp) {
+		p->p_session->s_ttyvp = NULL;
+		vrele(info->data);
+	}
+
+	/*
+	 * Locate and close any matching file descriptors.
+	 */
+	if ((fdp = p->p_fd) == NULL)
+		return(0);
+	spin_lock_wr(&fdp->fd_spin);
+	for (n = 0; n < fdp->fd_nfiles; ++n) {
+		if ((fp = fdp->fd_files[n].fp) == NULL)
+			continue;
+		if (info->data == fp->f_data && info->type == fp->f_type) {
+			fhold(info->nfp);
+			fdp->fd_files[n].fp = info->nfp;
+			spin_unlock_wr(&fdp->fd_spin);
+			closef(fp, p);
+			spin_lock_wr(&fdp->fd_spin);
+			++info->count;
+			info->again = 1;
+		}
+	}
+	spin_unlock_wr(&fdp->fd_spin);
+	return(0);
+}
+
+/*
  * falloc:
  *	Create a new open file structure and reserve a file decriptor
  *	for the process that refers to it.
@@ -1630,8 +1722,6 @@ again:
 void
 fdfree(struct proc *p)
 {
-	/* Take any thread of p */
-	struct thread *td = FIRST_LWP_IN_PROC(p)->lwp_thread;
 	struct filedesc *fdp = p->p_fd;
 	struct fdnode *fdnode;
 	int i;
@@ -1731,7 +1821,7 @@ fdfree(struct proc *p)
 	 */
 	for (i = 0; i <= fdp->fd_lastfile; ++i) {
 		if (fdp->fd_files[i].fp)
-			closef(fdp->fd_files[i].fp, td);
+			closef(fdp->fd_files[i].fp, p);
 	}
 	if (fdp->fd_files != fdp->fd_builtin_files)
 		kfree(fdp->fd_files, M_FILEDESC);
@@ -1879,8 +1969,6 @@ is_unsafe(struct file *fp)
 void
 setugidsafety(struct proc *p)
 {
-	/* Take any thread of p */
-	struct thread *td = FIRST_LWP_IN_PROC(p)->lwp_thread;
 	struct filedesc *fdp = p->p_fd;
 	int i;
 
@@ -1905,7 +1993,7 @@ setugidsafety(struct proc *p)
 			 * a race while close blocks.
 			 */
 			if ((fp = funsetfd_locked(fdp, i)) != NULL)
-				closef(fp, td);
+				closef(fp, p);
 		}
 	}
 }
@@ -1918,8 +2006,6 @@ setugidsafety(struct proc *p)
 void
 fdcloseexec(struct proc *p)
 {
-	/* Take any thread of p */
-	struct thread *td = FIRST_LWP_IN_PROC(p)->lwp_thread;
 	struct filedesc *fdp = p->p_fd;
 	int i;
 
@@ -1943,7 +2029,7 @@ fdcloseexec(struct proc *p)
 			 * a race while close blocks.
 			 */
 			if ((fp = funsetfd_locked(fdp, i)) != NULL)
-				closef(fp, td);
+				closef(fp, p);
 		}
 	}
 }
@@ -2010,21 +2096,15 @@ fdcheckstd(struct proc *p)
  * MPALMOSTSAFE - acquires mplock for VOP operations
  */
 int
-closef(struct file *fp, struct thread *td)
+closef(struct file *fp, struct proc *p)
 {
 	struct vnode *vp;
 	struct flock lf;
 	struct filedesc_to_leader *fdtol;
-	struct proc *p;
 
 	if (fp == NULL)
 		return (0);
-	if (td == NULL) {
-		td = curthread;
-		p = NULL;		/* allow no proc association */
-	} else {
-		p = td->td_proc;	/* can also be NULL */
-	}
+
 	/*
 	 * POSIX record locking dictates that any close releases ALL
 	 * locks owned by this process.  This is handled by setting
@@ -2323,9 +2403,7 @@ allfiles_scan_exclusive(int (*callback)(struct file *, void *), void *data)
 
 	spin_lock_wr(&filehead_spin);
 	LIST_FOREACH(fp, &filehead, f_list) {
-		spin_lock_wr(&fp->f_spin);
 		res = callback(fp, data);
-		spin_unlock_wr(&fp->f_spin);
 		if (res < 0)
 			break;
 	}
diff --git a/sys/kern/tty.c b/sys/kern/tty.c
index c252227..bcf94b6 100644
--- a/sys/kern/tty.c
+++ b/sys/kern/tty.c
@@ -341,9 +341,9 @@ retry:
 			vclrflags(vp, VCTTYISOPEN);
 			VOP_CLOSE(vp, FREAD|FWRITE);
 		}
-		if (dorevoke)
-			VOP_REVOKE(vp, REVOKEALL);
 		vn_unlock(vp);
+		if (dorevoke)
+			vrevoke(vp, proc0.p_ucred);
 		vdrop(vp);
 	} else {
 		sp->s_ttyvp = NULL;
diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c
index c12e78a..f30f340 100644
--- a/sys/kern/uipc_usrreq.c
+++ b/sys/kern/uipc_usrreq.c
@@ -1265,7 +1265,7 @@ unp_gc_checkrefs(struct file *fp, void *data)
 static int
 unp_gc_clearmarks(struct file *fp, void *data __unused)
 {
-	fp->f_flag &= ~(FMARK|FDEFER);
+	atomic_clear_int(&fp->f_flag, FMARK | FDEFER);
 	return(0);
 }
 
@@ -1289,7 +1289,7 @@ unp_gc_checkmarks(struct file *fp, void *data)
 	 * and un-mark it
 	 */
 	if (fp->f_flag & FDEFER) {
-		fp->f_flag &= ~FDEFER;
+		atomic_clear_int(&fp->f_flag, FDEFER);
 		--info->defer;
 	} else {
 		/*
@@ -1309,7 +1309,7 @@ unp_gc_checkmarks(struct file *fp, void *data)
 		 * If it got this far then it must be
 		 * externally accessible.
 		 */
-		fp->f_flag |= FMARK;
+		atomic_set_int(&fp->f_flag, FMARK);
 	}
 	/*
 	 * either it was defered, or it is externally 
@@ -1323,7 +1323,6 @@ unp_gc_checkmarks(struct file *fp, void *data)
 	    !(so->so_proto->pr_flags & PR_RIGHTS))
 		return(0);
 #ifdef notdef
-	XXX note: exclusive fp->f_spin lock held
 	if (so->so_rcv.sb_flags & SB_LOCK) {
 		/*
 		 * This is problematical; it's not clear
@@ -1406,14 +1405,10 @@ unp_mark(struct file *fp, void *data)
 {
 	struct unp_gc_info *info = data;
 
-	if (info->locked_fp != fp)
-		spin_lock_wr(&fp->f_spin);
 	if ((fp->f_flag & FMARK) == 0) {
 		++info->defer;
-		fp->f_flag |= (FMARK|FDEFER);
+		atomic_set_int(&fp->f_flag, FMARK | FDEFER);
 	}
-	if (info->locked_fp != fp)
-		spin_unlock_wr(&fp->f_spin);
 }
 
 static void
diff --git a/sys/kern/vfs_default.c b/sys/kern/vfs_default.c
index fe3c033..70ccdb5 100644
--- a/sys/kern/vfs_default.c
+++ b/sys/kern/vfs_default.c
@@ -88,7 +88,6 @@ struct vop_ops default_vnode_vops = {
 	.vop_poll		= vop_nopoll,
 	.vop_readlink		= (void *)vop_einval,
 	.vop_reallocblks	= (void *)vop_eopnotsupp,
-	.vop_revoke		= vop_stdrevoke,
 	.vop_strategy		= vop_nostrategy,
 	.vop_getacl		= (void *)vop_eopnotsupp,
 	.vop_setacl		= (void *)vop_eopnotsupp,
diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index 9a4c039..5c31d01 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -53,6 +53,7 @@
 #include <sys/domain.h>
 #include <sys/eventhandler.h>
 #include <sys/fcntl.h>
+#include <sys/file.h>
 #include <sys/kernel.h>
 #include <sys/kthread.h>
 #include <sys/malloc.h>
@@ -1200,26 +1201,15 @@ vclean_vxlocked(struct vnode *vp, int flags)
  * Eliminate all activity associated with the requested vnode
  * and with all vnodes aliased to the requested vnode.
  *
- * The vnode must be referenced and vx_lock()'d
- *
- * revoke { struct vnode *a_vp, int a_flags }
+ * The vnode must be referenced but should not be locked.
  */
 int
-vop_stdrevoke(struct vop_revoke_args *ap)
+vrevoke(struct vnode *vp, struct ucred *cred)
 {
-	struct vnode *vp, *vq;
+	struct vnode *vq;
 	lwkt_tokref ilock;
 	cdev_t dev;
-
-	KASSERT((ap->a_flags & REVOKEALL) != 0, ("vop_revoke"));
-
-	vp = ap->a_vp;
-
-	/*
-	 * If the vnode is already dead don't try to revoke it
-	 */
-	if (vp->v_flag & VRECLAIMED)
-		return (0);
+	int error;
 
 	/*
 	 * If the vnode has a device association, scrap all vnodes associated
@@ -1229,8 +1219,10 @@ vop_stdrevoke(struct vop_revoke_args *ap)
 	 * The passed vp will probably show up in the list, do not VX lock
 	 * it twice!
 	 */
-	if (vp->v_type != VCHR)
-		return(0);
+	if (vp->v_type != VCHR) {
+		error = fdrevoke(vp, DTYPE_VNODE, cred);
+		return (error);
+	}
 	if ((dev = vp->v_rdev) == NULL) {
 		if ((dev = get_dev(vp->v_umajor, vp->v_uminor)) == NULL)
 			return(0);
@@ -1238,12 +1230,10 @@ vop_stdrevoke(struct vop_revoke_args *ap)
 	reference_dev(dev);
 	lwkt_gettoken(&ilock, &spechash_token);
 	while ((vq = SLIST_FIRST(&dev->si_hlist)) != NULL) {
-		if (vp != vq)
-			vx_get(vq);
-		if (vq == SLIST_FIRST(&dev->si_hlist))
-			vgone_vxlocked(vq);
-		if (vp != vq)
-			vx_put(vq);
+		vref(vq);
+		fdrevoke(vq, DTYPE_VNODE, cred);
+		v_release_rdev(vq);
+		vrele(vq);
 	}
 	lwkt_reltoken(&ilock);
 	release_dev(dev);
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index d174c9a..9c5a40b 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -3560,17 +3560,15 @@ sys_revoke(struct revoke_args *uap)
 	cred = crhold(nd.nl_cred);
 	nlookup_done(&nd);
 	if (error == 0) {
-		if (vp->v_type != VCHR && vp->v_type != VBLK)
-			error = EINVAL;
 		if (error == 0)
 			error = VOP_GETATTR(vp, &vattr);
 		if (error == 0 && cred->cr_uid != vattr.va_uid)
 			error = priv_check_cred(cred, PRIV_ROOT, PRISON_ROOT);
-		if (error == 0 && count_udev(vp->v_umajor, vp->v_uminor) > 0) {
-			error = 0;
-			vx_lock(vp);
-			VOP_REVOKE(vp, REVOKEALL);
-			vx_unlock(vp);
+		if (error == 0 && (vp->v_type == VCHR || vp->v_type == VBLK)) {
+			if (count_udev(vp->v_umajor, vp->v_uminor) > 0)
+				error = vrevoke(vp, cred);
+		} else if (error == 0) {
+			error = vrevoke(vp, cred);
 		}
 		vrele(vp);
 	}
diff --git a/sys/kern/vfs_vopops.c b/sys/kern/vfs_vopops.c
index 89ce089..ec92b3e 100644
--- a/sys/kern/vfs_vopops.c
+++ b/sys/kern/vfs_vopops.c
@@ -97,7 +97,6 @@ VNODEOP_DESC_INIT(write);
 VNODEOP_DESC_INIT(ioctl);
 VNODEOP_DESC_INIT(poll);
 VNODEOP_DESC_INIT(kqfilter);
-VNODEOP_DESC_INIT(revoke);
 VNODEOP_DESC_INIT(mmap);
 VNODEOP_DESC_INIT(fsync);
 VNODEOP_DESC_INIT(old_remove);
@@ -406,21 +405,6 @@ vop_kqfilter(struct vop_ops *ops, struct vnode *vp, struct knote *kn)
 }
 
 int
-vop_revoke(struct vop_ops *ops, struct vnode *vp, int flags)
-{
-	struct vop_revoke_args ap;
-	int error;
-
-	ap.a_head.a_desc = &vop_revoke_desc;
-	ap.a_head.a_ops = ops;
-	ap.a_vp = vp;
-	ap.a_flags = flags;
-
-	DO_OPS(ops, error, &ap, vop_revoke);
-	return(error);
-}
-
-int
 vop_mmap(struct vop_ops *ops, struct vnode *vp, int fflags, struct ucred *cred)
 {
 	struct vop_mmap_args ap;
@@ -1415,15 +1399,6 @@ vop_kqfilter_ap(struct vop_kqfilter_args *ap)
 }
 
 int
-vop_revoke_ap(struct vop_revoke_args *ap)
-{
-	int error;
-
-	DO_OPS(ap->a_head.a_ops, error, ap, vop_revoke);
-	return(error);
-}
-
-int
 vop_mmap_ap(struct vop_mmap_args *ap)
 {
 	int error;
diff --git a/sys/sys/file.h b/sys/sys/file.h
index 646fcc2..cd5e7dd 100644
--- a/sys/sys/file.h
+++ b/sys/sys/file.h
@@ -118,7 +118,7 @@ struct file {
 	int	f_count;	/* reference count */
 	int	f_msgcount;	/* (U) reference count from message queue */
 	struct nchandle f_nchandle; /* namecache reference */
-	struct spinlock f_spin;
+	struct spinlock f_spin;	/* NOT USED */
 };
 
 #define	DTYPE_VNODE	1	/* file */
diff --git a/sys/sys/filedesc.h b/sys/sys/filedesc.h
index d57e9d8..c3deef5 100644
--- a/sys/sys/filedesc.h
+++ b/sys/sys/filedesc.h
@@ -170,7 +170,8 @@ struct	filedesc *fdinit (struct proc *p);
 struct	filedesc *fdshare (struct proc *p);
 struct	filedesc *fdcopy (struct proc *p);
 void	fdfree (struct proc *p);
-int	closef (struct file *fp, struct thread *td);
+int	fdrevoke(void *f_data, short f_type, struct ucred *cred);
+int	closef (struct file *fp, struct proc *p);
 void	fdcloseexec (struct proc *p);
 int	fdcheckstd (struct proc *p);
 struct	file *holdfp (struct filedesc *fdp, int fd, int flag);
diff --git a/sys/sys/vfsops.h b/sys/sys/vfsops.h
index b2ae193..6d80f34 100644
--- a/sys/sys/vfsops.h
+++ b/sys/sys/vfsops.h
@@ -193,12 +193,6 @@ struct vop_kqfilter_args {
 	struct knote *a_kn;
 };
 
-struct vop_revoke_args {
-	struct vop_generic_args a_head;
-	struct vnode *a_vp;
-	int a_flags;
-};
-
 struct vop_mmap_args {
 	struct vop_generic_args a_head;
 	struct vnode *a_vp;
@@ -593,7 +587,7 @@ struct vop_ops {
 	int	(*vop_ioctl)(struct vop_ioctl_args *);
 	int	(*vop_poll)(struct vop_poll_args *);
 	int	(*vop_kqfilter)(struct vop_kqfilter_args *);
-	int	(*vop_revoke)(struct vop_revoke_args *);
+	int	(*vop_unused01)(void *);	/* was vop_revoke */
 	int	(*vop_mmap)(struct vop_mmap_args *);
 	int	(*vop_fsync)(struct vop_fsync_args *);
 	int	(*vop_old_remove)(struct vop_old_remove_args *);
@@ -672,7 +666,6 @@ union vop_args_union {
 	struct vop_ioctl_args vu_ioctl;
 	struct vop_poll_args vu_poll;
 	struct vop_kqfilter_args vu_kqfilter;
-	struct vop_revoke_args vu_revoke;
 	struct vop_mmap_args vu_mmap;
 	struct vop_fsync_args vu_fsync;
 	struct vop_old_remove_args vu_remove;
@@ -753,7 +746,6 @@ int vop_ioctl(struct vop_ops *ops, struct vnode *vp, u_long command,
 int vop_poll(struct vop_ops *ops, struct vnode *vp, int events,
 		struct ucred *cred);
 int vop_kqfilter(struct vop_ops *ops, struct vnode *vp, struct knote *kn);
-int vop_revoke(struct vop_ops *ops, struct vnode *vp, int flags);
 int vop_mmap(struct vop_ops *ops, struct vnode *vp, int fflags,
 		struct ucred *cred);
 int vop_fsync(struct vop_ops *ops, struct vnode *vp, int waitfor);
@@ -864,7 +856,6 @@ int vop_write_ap(struct vop_write_args *ap);
 int vop_ioctl_ap(struct vop_ioctl_args *ap);
 int vop_poll_ap(struct vop_poll_args *ap);
 int vop_kqfilter_ap(struct vop_kqfilter_args *ap);
-int vop_revoke_ap(struct vop_revoke_args *ap);
 int vop_mmap_ap(struct vop_mmap_args *ap);
 int vop_fsync_ap(struct vop_fsync_args *ap);
 int vop_old_remove_ap(struct vop_old_remove_args *ap);
@@ -927,7 +918,6 @@ extern struct syslink_desc vop_write_desc;
 extern struct syslink_desc vop_ioctl_desc;
 extern struct syslink_desc vop_poll_desc;
 extern struct syslink_desc vop_kqfilter_desc;
-extern struct syslink_desc vop_revoke_desc;
 extern struct syslink_desc vop_mmap_desc;
 extern struct syslink_desc vop_fsync_desc;
 extern struct syslink_desc vop_old_remove_desc;
@@ -996,8 +986,6 @@ extern struct syslink_desc vop_nrename_desc;
 	vop_poll(*(vp)->v_ops, vp, events, cred)
 #define VOP_KQFILTER(vp, kn)				\
 	vop_kqfilter(*(vp)->v_ops, vp, kn)
-#define VOP_REVOKE(vp, flags)				\
-	vop_revoke(*(vp)->v_ops, vp, flags)
 #define VOP_MMAP(vp, fflags, cred)			\
 	vop_mmap(*(vp)->v_ops, vp, fflags, cred)
 #define VOP_FSYNC(vp, waitfor)				\
diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h
index 70c7ac4..f278cb8 100644
--- a/sys/sys/vnode.h
+++ b/sys/sys/vnode.h
@@ -358,7 +358,6 @@ extern	int		vttoif_tab[];
 #define	WRITECLOSE	0x0004		/* vflush: only close writable files */
 #define	DOCLOSE		0x0008		/* vclean: close active files */
 #define	V_SAVE		0x0001		/* vinvalbuf: sync file first */
-#define	REVOKEALL	0x0001		/* vop_revoke: revoke all aliases */
 
 #ifdef DIAGNOSTIC
 #define	VATTR_NULL(vap)	vattr_null(vap)
@@ -479,6 +478,7 @@ void	vclean_vxlocked (struct vnode *vp, int flags);
 void	vclean_unlocked (struct vnode *vp);
 void	vgone_vxlocked (struct vnode *vp);
 void	vupdatefsmid (struct vnode *vp);
+int	vrevoke (struct vnode *vp, struct ucred *cred);
 int	vinvalbuf (struct vnode *vp, int save, int slpflag, int slptimeo);
 int	vtruncbuf (struct vnode *vp, off_t length, int blksize);
 int	vfsync(struct vnode *vp, int waitfor, int passes,
@@ -528,7 +528,6 @@ int	vop_stdmarkatime(struct vop_markatime_args *ap);
 int	vop_nopoll (struct vop_poll_args *ap);
 int	vop_stdpathconf (struct vop_pathconf_args *ap);
 int	vop_stdpoll (struct vop_poll_args *ap);
-int	vop_stdrevoke (struct vop_revoke_args *ap);
 int	vop_eopnotsupp (struct vop_generic_args *ap);
 int	vop_ebadf (struct vop_generic_args *ap);
 int	vop_einval (struct vop_generic_args *ap);
diff --git a/sys/vfs/specfs/spec_vnops.c b/sys/vfs/specfs/spec_vnops.c
index 97b5cf9..91fbbfd 100644
--- a/sys/vfs/specfs/spec_vnops.c
+++ b/sys/vfs/specfs/spec_vnops.c
@@ -688,7 +688,7 @@ spec_bmap(struct vop_bmap_args *ap)
  *
  * spec_close(struct vnode *a_vp, int a_fflag)
  *
- * NOTE: the vnode may or may not be locked on call.
+ * NOTE: The vnode may or may not be locked on call.
  */
 /* ARGSUSED */
 static int
@@ -701,37 +701,35 @@ spec_close(struct vop_close_args *ap)
 	int needrelock;
 
 	/*
-	 * Hack: a tty device that is a controlling terminal
-	 * has a reference from the session structure.
-	 * We cannot easily tell that a character device is
-	 * a controlling terminal, unless it is the closing
-	 * process' controlling terminal.  In that case,
-	 * if the reference count is 2 (this last descriptor
-	 * plus the session), release the reference from the session.
+	 * A couple of hacks for devices and tty devices.  The
+	 * vnode ref count cannot be used to figure out the
+	 * last close, but we can use v_opencount now that
+	 * revoke works properly.
 	 *
-	 * It is possible for v_opencount to be 0 or 1 in this case, 0
-	 * because the tty might have been revoked.
+	 * Detect the last close on a controlling terminal and clear
+	 * the session (half-close).
 	 */
 	if (dev)
 		reference_dev(dev);
-	if (vcount(vp) == 2 && vp->v_opencount <= 1 && 
-	    p && vp == p->p_session->s_ttyvp) {
+
+	if (p && vp->v_opencount <= 1 && vp == p->p_session->s_ttyvp) {
 		p->p_session->s_ttyvp = NULL;
 		vrele(vp);
 	}
 
 	/*
-	 * Vnodes can be opened and close multiple times.  Do not really
+	 * Vnodes can be opened and closed multiple times.  Do not really
 	 * close the device unless (1) it is being closed forcibly,
 	 * (2) the device wants to track closes, or (3) this is the last
 	 * vnode doing its last close on the device.
 	 *
 	 * XXX the VXLOCK (force close) case can leave vnodes referencing
-	 * a closed device.
+	 * a closed device.  This might not occur now that our revoke is
+	 * fixed.
 	 */
 	if (dev && ((vp->v_flag & VRECLAIMED) ||
 	    (dev_dflags(dev) & D_TRACKCLOSE) ||
-	    (vcount(vp) <= 1 && vp->v_opencount == 1))) {
+	    (vp->v_opencount == 1))) {
 		needrelock = 0;
 		if (vn_islocked(vp)) {
 			needrelock = 1;
diff --git a/sys/vfs/union/union_vnops.c b/sys/vfs/union/union_vnops.c
index 60c7962..ae6378c 100644
--- a/sys/vfs/union/union_vnops.c
+++ b/sys/vfs/union/union_vnops.c
@@ -94,7 +94,6 @@ static int	union_readlink (struct vop_readlink_args *ap);
 static int	union_reclaim (struct vop_reclaim_args *ap);
 static int	union_remove (struct vop_old_remove_args *ap);
 static int	union_rename (struct vop_old_rename_args *ap);
-static int	union_revoke (struct vop_revoke_args *ap);
 static int	union_rmdir (struct vop_old_rmdir_args *ap);
 static int	union_poll (struct vop_poll_args *ap);
 static int	union_setattr (struct vop_setattr_args *ap);
@@ -1143,29 +1142,6 @@ union_poll(struct vop_poll_args *ap)
 }
 
 /*
- * union_revoke(struct vnode *a_vp, int a_flags, struct thread *a_td)
- */
-static int
-union_revoke(struct vop_revoke_args *ap)
-{
-	struct vnode *vp = ap->a_vp;
-	struct vnode *vx;
-
-	if ((vx = UPPERVP(vp)) != NULL) {
-		vx_get(vx);
-		VOP_REVOKE(vx, ap->a_flags);
-		vx_put(vx);
-	}
-	if ((vx = LOWERVP(vp)) != NULL) {
-		vx_get(vx);
-		VOP_REVOKE(vx, ap->a_flags);
-		vx_put(vx);
-	}
-	vgone_vxlocked(vp);
-	return (0);
-}
-
-/*
  * union_mmap(struct vnode *a_vp, int a_fflags, struct ucred *a_cred,
  *	      struct thread *a_td)
  */
@@ -1804,7 +1780,6 @@ struct vop_ops union_vnode_vops = {
 	.vop_reclaim =		union_reclaim,
 	.vop_old_remove =	union_remove,
 	.vop_old_rename =	union_rename,
-	.vop_revoke =		union_revoke,
 	.vop_old_rmdir =	union_rmdir,
 	.vop_setattr =		union_setattr,
 	.vop_strategy =		union_strategy,
