Index: sys/miscfs/specfs/specdev.h
===================================================================
RCS file: /cvsroot/src/sys/miscfs/specfs/specdev.h,v
retrieving revision 1.39
diff -p -u -4 -r1.39 specdev.h
--- sys/miscfs/specfs/specdev.h	14 Nov 2009 18:36:57 -0000	1.39
+++ sys/miscfs/specfs/specdev.h	8 Feb 2013 10:53:53 -0000
@@ -90,19 +90,12 @@ typedef struct specdev {
 
 /*
  * Special device management
  */
-#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
-
-extern vnode_t	*specfs_hash[SPECHSZ];
-
 void	spec_node_init(vnode_t *, dev_t);
 void	spec_node_destroy(vnode_t *);
+int	spec_node_lookup_by_dev(enum vtype, dev_t, vnode_t **);
+int	spec_node_lookup_by_mount(struct mount *, vnode_t **);
 void	spec_node_revoke(vnode_t *);
 
 /*
  * Prototypes for special file operations on vnodes.
Index: sys/miscfs/specfs/spec_vnops.c
===================================================================
RCS file: /cvsroot/src/sys/miscfs/specfs/spec_vnops.c,v
retrieving revision 1.136
diff -p -u -4 -r1.136 spec_vnops.c
--- sys/miscfs/specfs/spec_vnops.c	20 Dec 2012 08:03:43 -0000	1.136
+++ sys/miscfs/specfs/spec_vnops.c	8 Feb 2013 10:53:53 -0000
@@ -92,9 +92,16 @@ const char	devin[] = "devin";
 const char	devout[] = "devout";
 const char	devioc[] = "devioc";
 const char	devcls[] = "devcls";
 
-vnode_t		*specfs_hash[SPECHSZ];
+#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
+
+static vnode_t	*specfs_hash[SPECHSZ];
 
 /*
  * This vnode operations vector is used for special device nodes
  * created from whole cloth by the kernel.  For the ops vector for
@@ -267,8 +274,84 @@ spec_node_init(vnode_t *vp, dev_t rdev)
 	}
 }
 
 /*
+ * Lookup a vnode by device number and return it referenced.
+ */
+int
+spec_node_lookup_by_dev(enum vtype type, dev_t dev, vnode_t **vpp)
+{
+	int error;
+	vnode_t *vp;
+
+	mutex_enter(&device_lock);
+	for (vp = specfs_hash[SPECHASH(dev)]; vp; vp = vp->v_specnext) {
+		if (type == vp->v_type && dev == vp->v_rdev) {
+			mutex_enter(vp->v_interlock);
+			/* If clean or being cleaned, then ignore it. */
+			if ((vp->v_iflag & (VI_CLEAN | VI_XLOCK)) == 0)
+				break;
+			mutex_exit(vp->v_interlock);
+		}
+	}
+	KASSERT(vp == NULL || mutex_owned(vp->v_interlock));
+	if (vp == NULL) {
+		mutex_exit(&device_lock);
+		return ENOENT;
+	}
+	/*
+	 * If it is an opened block device return the opened vnode.
+	 */
+	if (type == VBLK && vp->v_specnode->sn_dev->sd_bdevvp != NULL) {
+		mutex_exit(vp->v_interlock);
+		vp = vp->v_specnode->sn_dev->sd_bdevvp;
+		mutex_enter(vp->v_interlock);
+	}
+	mutex_exit(&device_lock);
+	error = vget(vp, 0);
+	if (error != 0)
+		return error;
+	*vpp = vp;
+
+	return 0;
+}
+
+/*
+ * Lookup a vnode by file system mounted on and return it referenced.
+ */
+int
+spec_node_lookup_by_mount(struct mount *mp, vnode_t **vpp)
+{
+	int i, error;
+	vnode_t *vp, *vq;
+
+	mutex_enter(&device_lock);
+	for (i = 0, vq = NULL; i < SPECHSZ && vq == NULL; i++) {
+		for (vp = specfs_hash[i]; vp; vp = vp->v_specnext) {
+			if (vp->v_type != VBLK)
+				continue;
+			vq = vp->v_specnode->sn_dev->sd_bdevvp;
+			if (vq != NULL && vq->v_specmountpoint == mp)
+				break;
+			vq = NULL;
+		}
+	}
+	if (vq == NULL) {
+		mutex_exit(&device_lock);
+		return ENOENT;
+	}
+	mutex_enter(vq->v_interlock);
+	mutex_exit(&device_lock);
+	error = vget(vq, 0);
+	if (error != 0)
+		return error;
+	*vpp = vq;
+
+	return 0;
+
+}
+
+/*
  * A vnode representing a special device is going away.  Close
  * the device if the vnode holds it open.
  */
 void
Index: sys/kern/vfs_mount.c
===================================================================
RCS file: /cvsroot/src/sys/kern/vfs_mount.c,v
retrieving revision 1.16
diff -p -u -4 -r1.16 vfs_mount.c
--- sys/kern/vfs_mount.c	14 Dec 2012 18:39:48 -0000	1.16
+++ sys/kern/vfs_mount.c	8 Feb 2013 10:53:52 -0000
@@ -1251,21 +1251,16 @@ vfs_mountedon(vnode_t *vp)
 
 	if (vp->v_type != VBLK)
 		return ENOTBLK;
 	if (vp->v_specmountpoint != NULL)
-		return (EBUSY);
-	mutex_enter(&device_lock);
-	for (vq = specfs_hash[SPECHASH(vp->v_rdev)]; vq != NULL;
-	    vq = vq->v_specnext) {
-		if (vq->v_type != vp->v_type || vq->v_rdev != vp->v_rdev)
-			continue;
-		if (vq->v_specmountpoint != NULL) {
+		return EBUSY;
+	if (spec_node_lookup_by_dev(vp->v_type, vp->v_rdev, &vq) == 0) {
+		if (vq->v_specmountpoint != NULL)
 			error = EBUSY;
-			break;
-		}
+		vrele(vq);
 	}
-	mutex_exit(&device_lock);
-	return (error);
+
+	return error;
 }
 
 /*
  * Check if a device pointed to by vp is mounted.
Index: sys/kern/vfs_subr.c
===================================================================
RCS file: /cvsroot/src/sys/kern/vfs_subr.c,v
retrieving revision 1.435
diff -p -u -4 -r1.435 vfs_subr.c
--- sys/kern/vfs_subr.c	12 May 2012 18:42:08 -0000	1.435
+++ sys/kern/vfs_subr.c	8 Feb 2013 10:53:52 -0000
@@ -512,25 +512,10 @@ getdevvp(dev_t dev, vnode_t **vpp, enum 
  */
 int
 vfinddev(dev_t dev, enum vtype type, vnode_t **vpp)
 {
-	vnode_t *vp;
 
-	mutex_enter(&device_lock);
-	for (vp = specfs_hash[SPECHASH(dev)]; vp; vp = vp->v_specnext) {
-		if (type == vp->v_type && dev == vp->v_rdev)
-			break;
-	}
-	if (vp == NULL) {
-		mutex_exit(&device_lock);
-		return 0;
-	}
-	mutex_enter(vp->v_interlock);
-	mutex_exit(&device_lock);
-	if (vget(vp, 0) != 0)
-		return 0;
-	*vpp = vp;
-	return 1;
+	return (spec_node_lookup_by_dev(type, dev, vpp) == 0);
 }
 
 /*
  * Revoke all the vnodes corresponding to the specified minor number
@@ -538,36 +523,19 @@ vfinddev(dev_t dev, enum vtype type, vno
  */
 void
 vdevgone(int maj, int minl, int minh, enum vtype type)
 {
-	vnode_t *vp, **vpp;
+	vnode_t *vp;
 	dev_t dev;
 	int mn;
 
-	vp = NULL;	/* XXX gcc */
-
-	mutex_enter(&device_lock);
 	for (mn = minl; mn <= minh; mn++) {
 		dev = makedev(maj, mn);
-		vpp = &specfs_hash[SPECHASH(dev)];
-		for (vp = *vpp; vp != NULL;) {
-			mutex_enter(vp->v_interlock);
-			if ((vp->v_iflag & VI_CLEAN) != 0 ||
-			    type != vp->v_type || dev != vp->v_rdev) {
-				mutex_exit(vp->v_interlock);
-				vp = vp->v_specnext;
-				continue;
-			}
-			mutex_exit(&device_lock);
-			if (vget(vp, 0) == 0) {
-				VOP_REVOKE(vp, REVOKEALL);
-				vrele(vp);
-			}
-			mutex_enter(&device_lock);
-			vp = *vpp;
+		while (spec_node_lookup_by_dev(type, dev, &vp) == 0) {
+			VOP_REVOKE(vp, REVOKEALL);
+			vrele(vp);
 		}
 	}
-	mutex_exit(&device_lock);
 }
 
 /*
  * sysctl helper routine to return list of supported fstypes
Index: sys/kern/vfs_vnode.c
===================================================================
RCS file: /cvsroot/src/sys/kern/vfs_vnode.c,v
retrieving revision 1.17
diff -p -u -4 -r1.17 vfs_vnode.c
--- sys/kern/vfs_vnode.c	12 Nov 2012 11:00:07 -0000	1.17
+++ sys/kern/vfs_vnode.c	8 Feb 2013 10:53:52 -0000
@@ -1109,9 +1109,9 @@ vrecycle(vnode_t *vp, kmutex_t *inter_lk
  */
 void
 vrevoke(vnode_t *vp)
 {
-	vnode_t *vq, **vpp;
+	vnode_t *vq;
 	enum vtype type;
 	dev_t dev;
 
 	KASSERT(vp->v_usecount > 0);
@@ -1130,32 +1130,13 @@ vrevoke(vnode_t *vp)
 		type = vp->v_type;
 		mutex_exit(vp->v_interlock);
 	}
 
-	vpp = &specfs_hash[SPECHASH(dev)];
-	mutex_enter(&device_lock);
-	for (vq = *vpp; vq != NULL;) {
-		/* If clean or being cleaned, then ignore it. */
+	while (spec_node_lookup_by_dev(type, dev, &vq) == 0) {
 		mutex_enter(vq->v_interlock);
-		if ((vq->v_iflag & (VI_CLEAN | VI_XLOCK)) != 0 ||
-		    vq->v_type != type || vq->v_rdev != dev) {
-			mutex_exit(vq->v_interlock);
-			vq = vq->v_specnext;
-			continue;
-		}
-		mutex_exit(&device_lock);
-		if (vq->v_usecount == 0) {
-			vremfree(vq);
-			vq->v_usecount = 1;
-		} else {
-			atomic_inc_uint(&vq->v_usecount);
-		}
 		vclean(vq, DOCLOSE);
 		vrelel(vq, 0);
-		mutex_enter(&device_lock);
-		vq = *vpp;
 	}
-	mutex_exit(&device_lock);
 }
 
 /*
  * Eliminate all activity associated with a vnode in preparation for
Index: sys/dev/fss.c
===================================================================
RCS file: /cvsroot/src/sys/dev/fss.c,v
retrieving revision 1.85
diff -p -u -4 -r1.85 fss.c
--- sys/dev/fss.c	6 Feb 2013 09:33:16 -0000	1.85
+++ sys/dev/fss.c	8 Feb 2013 10:53:47 -0000
@@ -619,9 +619,9 @@ fss_copy_on_write(void *v, struct buf *b
 static int
 fss_create_files(struct fss_softc *sc, struct fss_set *fss,
     off_t *bsize, struct lwp *l)
 {
-	int i, error, bits, fsbsize;
+	int error, bits, fsbsize;
 	uint64_t numsec;
 	unsigned int secsize;
 	struct timespec ts;
 	/* nd -> nd2 to reduce mistakes while updating only some namei calls */
@@ -693,26 +693,9 @@ fss_create_files(struct fss_softc *sc, s
 	/*
 	 * Get the block device it is mounted on and its size.
 	 */
 
-	mutex_enter(&device_lock);
-	for (i = 0; i < SPECHSZ; i++) {
-		for (vp = specfs_hash[i]; vp; vp = vp->v_specnext) {
-			if (vp->v_type == VBLK &&
-			    vp == vp->v_specnode->sn_dev->sd_bdevvp &&
-			    vp->v_specmountpoint == sc->sc_mount)
-				break;
-		}
-		if (vp != NULL)
-			break;
-	}
-	if (vp == NULL) {
-		mutex_exit(&device_lock);
-		return EINVAL;
-	}
-	mutex_enter(vp->v_interlock);
-	mutex_exit(&device_lock);
-	error = vget(vp, 0);
+	error = spec_node_lookup_by_mount(sc->sc_mount, &vp);
 	if (error)
 		return error;
 	sc->sc_bdev = vp->v_rdev;
 
