--- old/usr/src/uts/common/fs/vfs.c	2015-09-28 19:41:48.665638244 +0200
+++ new/usr/src/uts/common/fs/vfs.c	2015-09-28 19:41:48.670200922 +0200
@@ -85,6 +85,7 @@
 #include <sys/spa.h>
 #include <sys/lofi.h>
 #include <sys/bootprops.h>
+#include <sys/avl.h>
 
 #include <vm/page.h>
 
@@ -137,6 +138,11 @@
 static struct vfs devices;
 static struct vfs dev;
 struct vfs *rootvfs = &root;	/* pointer to root vfs; head of VFS list. */
+avl_tree_t vfs_by_dev;		/* avl tree to index mounted VFSs by dev */
+avl_tree_t vfs_by_mntpnt;	/* avl tree to index mounted VFSs by mntpnt */
+uint64_t vfs_curr_mntix;	/* counter to provide a unique mntix for
+				 * entries in the above avl trees.
+				 * protected by vfslist lock */
 rvfs_t *rvfs_list;		/* array of vfs ptrs for vfs hash list */
 int vfshsz = 512;		/* # of heads/locks in vfs hash arrays */
 				/* must be power of 2!	*/
@@ -608,6 +614,48 @@
 }
 
 /*
+ * compare function for vfs_by_dev avl tree. compare dev first, then mntix
+ */
+static int
+vfs_cmp_dev(const void *aa, const void *bb)
+{
+	const vfs_t *a = aa;
+	const vfs_t *b = bb;
+
+	if (a->vfs_dev < b->vfs_dev)
+		return (-1);
+	if (a->vfs_dev > b->vfs_dev)
+		return (1);
+	if (a->vfs_mntix < b->vfs_mntix)
+		return (-1);
+	if (a->vfs_mntix > b->vfs_mntix)
+		return (1);
+	return (0);
+}
+
+/*
+ * compare function for vfs_by_mntpnt avl tree. compare mntpnt first, then mntix
+ */
+static int
+vfs_cmp_mntpnt(const void *aa, const void *bb)
+{
+	const vfs_t *a = aa;
+	const vfs_t *b = bb;
+	int ret;
+
+	ret = strcmp(refstr_value(a->vfs_mntpt), refstr_value(b->vfs_mntpt));
+	if (ret < 0)
+		return (-1);
+	if (ret > 0)
+		return (1);
+	if (a->vfs_mntix < b->vfs_mntix)
+		return (-1);
+	if (a->vfs_mntix > b->vfs_mntix)
+		return (1);
+	return (0);
+}
+
+/*
  * External routines.
  */
 
@@ -818,6 +866,14 @@
 	rw_init(&vfslist, NULL, RW_DEFAULT, NULL);
 
 	/*
+	 * Alloc the avl trees for quick indexing via dev and mountpoint
+	 */
+	avl_create(&vfs_by_dev, vfs_cmp_dev, sizeof(vfs_t),
+	    offsetof(vfs_t, vfs_avldev));
+	avl_create(&vfs_by_mntpnt, vfs_cmp_mntpnt, sizeof(vfs_t),
+	    offsetof(vfs_t, vfs_avlmntpnt));
+
+	/*
 	 * Alloc the vfs hash bucket array and locks
 	 */
 	rvfs_list = kmem_zalloc(vfshsz * sizeof (rvfs_t), KM_SLEEP);
@@ -3611,6 +3667,18 @@
 	vfs_hash_add(vfsp, 0);
 
 	/*
+	 * Link into tree indexed by mntpoint, for vfs_mntpoint2vfsp
+	 * mntix discerns entries with the same key
+	 */
+	vfsp->vfs_mntix = ++vfs_curr_mntix;
+	avl_add(&vfs_by_dev, vfsp);
+
+	/*
+	 * Link into tree indexed by dev, for vfs_devismounted
+	 */
+	avl_add(&vfs_by_mntpnt, vfsp);
+
+	/*
 	 * update the mnttab modification time
 	 */
 	vfs_mnttab_modtimeupd();
@@ -3634,6 +3702,12 @@
 	vfs_list_lock();
 
 	/*
+	 * Remove from avl trees
+	 */
+	avl_remove(&vfs_by_mntpnt, vfsp);
+	avl_remove(&vfs_by_dev, vfsp);
+
+	/*
 	 * Remove from hash.
 	 */
 	vfs_hash_remove(vfsp);
@@ -3727,18 +3801,26 @@
 vfs_devismounted(dev_t dev)
 {
 	struct vfs *vfsp;
-	int found;
+	int found = 0;
+	struct vfs search;
+	avl_index_t index;
+
+	search.vfs_dev = dev;
+	search.vfs_mntix = 0;
 
 	vfs_list_read_lock();
-	vfsp = rootvfs;
-	found = 0;
-	do {
-		if (vfsp->vfs_dev == dev) {
-			found = 1;
-			break;
-		}
-		vfsp = vfsp->vfs_next;
-	} while (vfsp != rootvfs);
+
+	/*
+	 * there might be several entries with the same dev in the tree,
+	 * only discerned by mntix. To find the first, we start with a mntix
+	 * of 0. The search will fail. The following avl_nearest will give
+	 * us the actual first entry.
+	 */
+	VERIFY(avl_find(&vfs_by_dev, &search, &index) == NULL);
+	vfsp = avl_nearest(&vfs_by_dev, index, AVL_AFTER);
+
+	if (vfsp != NULL && vfsp->vfs_dev == dev)
+		found = 1;
 
 	vfs_list_unlock();
 	return (found);
@@ -3754,11 +3836,25 @@
 {
 	struct vfs *vfsp;
 	int found;
+	struct vfs search;
+	avl_index_t index;
+
+	search.vfs_dev = dev;
+	search.vfs_mntix = 0;
 
 	vfs_list_read_lock();
-	vfsp = rootvfs;
+
+	/*
+	 * there might be several entries with the same dev in the tree,
+	 * only discerned by mntix. To find the first, we start with a mntix
+	 * of 0. The search will fail. The following avl_nearest will give
+	 * us the actual first entry.
+	 */
+	VERIFY(avl_find(&vfs_by_dev, &search, &index) == NULL);
+	vfsp = avl_nearest(&vfs_by_dev, index, AVL_AFTER);
+
 	found = 0;
-	do {
+	while (vfsp != NULL && vfsp->vfs_dev == dev) {
 		/*
 		 * The following could be made more efficient by making
 		 * the entire loop use vfs_zone_next if the call is from
@@ -3766,17 +3862,16 @@
 		 * umount2(2), don't seem to justify the added
 		 * complexity at present.
 		 */
-		if (vfsp->vfs_dev == dev &&
-		    ZONE_PATH_VISIBLE(refstr_value(vfsp->vfs_mntpt),
+		if (ZONE_PATH_VISIBLE(refstr_value(vfsp->vfs_mntpt),
 		    curproc->p_zone)) {
 			VFS_HOLD(vfsp);
 			found = 1;
 			break;
 		}
-		vfsp = vfsp->vfs_next;
-	} while (vfsp != rootvfs);
+		vfsp = AVL_NEXT(&vfs_by_dev, vfsp);
+	}
 	vfs_list_unlock();
-	return (found ? vfsp: NULL);
+	return (found ? vfsp : NULL);
 }
 
 /*
@@ -3803,14 +3898,26 @@
 		/*
 		 * The global zone may see filesystems in any zone.
 		 */
-		vfsp = rootvfs->vfs_prev;
-		do {
-			if (strcmp(refstr_value(vfsp->vfs_mntpt), mp) == 0) {
-				retvfsp = vfsp;
-				break;
-			}
-			vfsp = vfsp->vfs_prev;
-		} while (vfsp != rootvfs->vfs_prev);
+		struct vfs search;
+		search.vfs_mntpt = refstr_alloc(mp);
+		search.vfs_mntix = UINT64_MAX;
+		avl_index_t index;
+
+		/*
+		 * there might be several entries with the same mntpnt in the
+		 * tree, only discerned by mntix. To find the last, we start
+		 * with a mntix of UINT64_MAX. The search will fail. The
+		 * following avl_nearest will give  us the actual last entry
+		 * matching the mntpnt.
+		 */
+		VERIFY(avl_find(&vfs_by_mntpnt, &search, &index) == 0);
+		vfsp = avl_nearest(&vfs_by_mntpnt, index, AVL_BEFORE);
+
+		refstr_rele(search.vfs_mntpt);
+
+		if (vfsp != NULL &&
+		    strcmp(refstr_value(vfsp->vfs_mntpt), mp) == 0)
+			retvfsp = vfsp;
 	} else if ((list = zone->zone_vfslist) != NULL) {
 		const char *mntpt;
 
