Print this page
6265 speed up mount/umount

*** 83,92 **** --- 83,93 ---- #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,144 **** --- 136,150 ---- 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,615 **** --- 612,663 ---- { 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,825 **** --- 864,881 ---- 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,3618 **** --- 3665,3686 ---- * 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,3641 **** --- 3700,3715 ---- 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,3746 **** int vfs_devismounted(dev_t dev) { struct vfs *vfsp; ! int found; vfs_list_read_lock(); ! vfsp = rootvfs; ! found = 0; ! do { ! if (vfsp->vfs_dev == dev) { found = 1; - break; - } - vfsp = vfsp->vfs_next; - } while (vfsp != rootvfs); vfs_list_unlock(); return (found); } --- 3799,3828 ---- int vfs_devismounted(dev_t dev) { struct vfs *vfsp; ! int found = 0; ! struct vfs search; ! avl_index_t index; ! ! search.vfs_dev = dev; ! search.vfs_mntix = 0; vfs_list_read_lock(); ! ! /* ! * 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); }
*** 3752,3784 **** struct vfs * vfs_dev2vfsp(dev_t dev) { struct vfs *vfsp; int found; vfs_list_read_lock(); ! vfsp = rootvfs; found = 0; ! do { /* * 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), curproc->p_zone)) { VFS_HOLD(vfsp); found = 1; break; } ! vfsp = vfsp->vfs_next; ! } while (vfsp != rootvfs); vfs_list_unlock(); ! 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 --- 3834,3879 ---- 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(); ! ! /* ! * 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; ! 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 (ZONE_PATH_VISIBLE(refstr_value(vfsp->vfs_mntpt), curproc->p_zone)) { VFS_HOLD(vfsp); found = 1; break; } ! vfsp = AVL_NEXT(&vfs_by_dev, vfsp); ! } vfs_list_unlock(); ! 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,3818 **** 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) { 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 { --- 3896,3925 ---- vfs_list_read_lock(); if (getzoneid() == GLOBAL_ZONEID) { /* * The global zone may see filesystems in any zone. */ ! 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; vfsp = list->vfs_zone_prev; do {