Print this page
6265 speed up mount/umount
@@ -83,10 +83,11 @@
#include <sys/attr.h>
#include <sys/zio.h>
#include <sys/spa.h>
#include <sys/lofi.h>
#include <sys/bootprops.h>
+#include <sys/avl.h>
#include <vm/page.h>
#include <fs/fs_subr.h>
/* Private interfaces to create vopstats-related data structures */
@@ -135,10 +136,15 @@
static struct vfs root;
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! */
timespec_t vfs_mnttab_ctime; /* mnttab created time */
timespec_t vfs_mnttab_mtime; /* mnttab last modified time */
@@ -606,10 +612,52 @@
{
vfs_sync(0);
}
/*
+ * 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.
*/
krwlock_t vfssw_lock; /* lock accesses to vfssw */
@@ -816,10 +864,18 @@
rw_init(&vfssw_lock, NULL, RW_DEFAULT, NULL);
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);
/*
@@ -3609,10 +3665,22 @@
* the UFS.
*/
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();
vfs_list_unlock();
zone_rele(zone);
@@ -3632,10 +3700,16 @@
ASSERT(vfsp != rootvfs);
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);
/*
@@ -3725,22 +3799,30 @@
int
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) {
+
+ /*
+ * 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;
- break;
- }
- vfsp = vfsp->vfs_next;
- } while (vfsp != rootvfs);
vfs_list_unlock();
return (found);
}
@@ -3752,33 +3834,46 @@
struct vfs *
vfs_dev2vfsp(dev_t dev)
{
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
* a zone. The only callers, however, ustat(2) and
* 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);
}
/*
* Search the vfs list for a specified mntpoint. Returns a pointer to it
* or NULL if no suitable entry is found. The caller of this routine
@@ -3801,18 +3896,30 @@
vfs_list_read_lock();
if (getzoneid() == GLOBAL_ZONEID) {
/*
* The global zone may see filesystems in any zone.
*/
- vfsp = rootvfs->vfs_prev;
- do {
- if (strcmp(refstr_value(vfsp->vfs_mntpt), mp) == 0) {
+ 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;
- break;
- }
- vfsp = vfsp->vfs_prev;
- } while (vfsp != rootvfs->vfs_prev);
} else if ((list = zone->zone_vfslist) != NULL) {
const char *mntpt;
vfsp = list->vfs_zone_prev;
do {