Print this page
6265 speed up mount/umount

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/fs/vfs.c
          +++ new/usr/src/uts/common/fs/vfs.c
↓ open down ↓ 77 lines elided ↑ open up ↑
  78   78  #include <sys/policy.h>
  79   79  #include <sys/ctfs.h>
  80   80  #include <sys/objfs.h>
  81   81  #include <sys/console.h>
  82   82  #include <sys/reboot.h>
  83   83  #include <sys/attr.h>
  84   84  #include <sys/zio.h>
  85   85  #include <sys/spa.h>
  86   86  #include <sys/lofi.h>
  87   87  #include <sys/bootprops.h>
       88 +#include <sys/avl.h>
  88   89  
  89   90  #include <vm/page.h>
  90   91  
  91   92  #include <fs/fs_subr.h>
  92   93  /* Private interfaces to create vopstats-related data structures */
  93   94  extern void             initialize_vopstats(vopstats_t *);
  94   95  extern vopstats_t       *get_fstype_vopstats(struct vfs *, struct vfssw *);
  95   96  extern vsk_anchor_t     *get_vskstat_anchor(struct vfs *);
  96   97  
  97   98  static void vfs_clearmntopt_nolock(mntopts_t *, const char *, int);
↓ open down ↓ 32 lines elided ↑ open up ↑
 130  131  vnode_t *devicesdir;            /* pointer to inode of devices root */
 131  132  vnode_t *devdir;                /* pointer to inode of dev root */
 132  133  
 133  134  char *server_rootpath;          /* root path for diskless clients */
 134  135  char *server_hostname;          /* hostname of diskless server */
 135  136  
 136  137  static struct vfs root;
 137  138  static struct vfs devices;
 138  139  static struct vfs dev;
 139  140  struct vfs *rootvfs = &root;    /* pointer to root vfs; head of VFS list. */
      141 +avl_tree_t vfs_by_dev;          /* avl tree to index mounted VFSs by dev */
      142 +avl_tree_t vfs_by_mntpnt;       /* avl tree to index mounted VFSs by mntpnt */
      143 +uint64_t vfs_curr_mntix;        /* counter to provide a unique mntix for
      144 +                                 * entries in the above avl trees.
      145 +                                 * protected by vfslist lock */
 140  146  rvfs_t *rvfs_list;              /* array of vfs ptrs for vfs hash list */
 141  147  int vfshsz = 512;               /* # of heads/locks in vfs hash arrays */
 142  148                                  /* must be power of 2!  */
 143  149  timespec_t vfs_mnttab_ctime;    /* mnttab created time */
 144  150  timespec_t vfs_mnttab_mtime;    /* mnttab last modified time */
 145  151  char *vfs_dummyfstype = "\0";
 146  152  struct pollhead vfs_pollhd;     /* for mnttab pollers */
 147  153  struct vnode *vfs_mntdummyvp;   /* to fake mnttab read/write for file events */
 148  154  int     mntfstype;              /* will be set once mnt fs is mounted */
 149  155  
↓ open down ↓ 451 lines elided ↑ open up ↑
 601  607          RUNLOCK_VFSSW();
 602  608  }
 603  609  
 604  610  void
 605  611  sync(void)
 606  612  {
 607  613          vfs_sync(0);
 608  614  }
 609  615  
 610  616  /*
      617 + * compare function for vfs_by_dev avl tree. compare dev first, then mntix
      618 + */
      619 +static int
      620 +vfs_cmp_dev(const void *aa, const void *bb)
      621 +{
      622 +        const vfs_t *a = aa;
      623 +        const vfs_t *b = bb;
      624 +
      625 +        if (a->vfs_dev < b->vfs_dev)
      626 +                return (-1);
      627 +        if (a->vfs_dev > b->vfs_dev)
      628 +                return (1);
      629 +        if (a->vfs_mntix < b->vfs_mntix)
      630 +                return (-1);
      631 +        if (a->vfs_mntix > b->vfs_mntix)
      632 +                return (1);
      633 +        return (0);
      634 +}
      635 +
      636 +/*
      637 + * compare function for vfs_by_mntpnt avl tree. compare mntpnt first, then mntix
      638 + */
      639 +static int
      640 +vfs_cmp_mntpnt(const void *aa, const void *bb)
      641 +{
      642 +        const vfs_t *a = aa;
      643 +        const vfs_t *b = bb;
      644 +        int ret;
      645 +
      646 +        ret = strcmp(refstr_value(a->vfs_mntpt), refstr_value(b->vfs_mntpt));
      647 +        if (ret < 0)
      648 +                return (-1);
      649 +        if (ret > 0)
      650 +                return (1);
      651 +        if (a->vfs_mntix < b->vfs_mntix)
      652 +                return (-1);
      653 +        if (a->vfs_mntix > b->vfs_mntix)
      654 +                return (1);
      655 +        return (0);
      656 +}
      657 +
      658 +/*
 611  659   * External routines.
 612  660   */
 613  661  
 614  662  krwlock_t vfssw_lock;   /* lock accesses to vfssw */
 615  663  
 616  664  /*
 617  665   * Lock for accessing the vfs linked list.  Initialized in vfs_mountroot(),
 618  666   * but otherwise should be accessed only via vfs_list_lock() and
 619  667   * vfs_list_unlock().  Also used to protect the timestamp for mods to the list.
 620  668   */
↓ open down ↓ 190 lines elided ↑ open up ↑
 811  859          struct vnode    *rvp = NULL;
 812  860          char            *path;
 813  861          size_t          plen;
 814  862          struct vfssw    *vswp;
 815  863          proc_t          *p;
 816  864  
 817  865          rw_init(&vfssw_lock, NULL, RW_DEFAULT, NULL);
 818  866          rw_init(&vfslist, NULL, RW_DEFAULT, NULL);
 819  867  
 820  868          /*
      869 +         * Alloc the avl trees for quick indexing via dev and mountpoint
      870 +         */
      871 +        avl_create(&vfs_by_dev, vfs_cmp_dev, sizeof(vfs_t),
      872 +            offsetof(vfs_t, vfs_avldev));
      873 +        avl_create(&vfs_by_mntpnt, vfs_cmp_mntpnt, sizeof(vfs_t),
      874 +            offsetof(vfs_t, vfs_avlmntpnt));
      875 +
      876 +        /*
 821  877           * Alloc the vfs hash bucket array and locks
 822  878           */
 823  879          rvfs_list = kmem_zalloc(vfshsz * sizeof (rvfs_t), KM_SLEEP);
 824  880  
 825  881          /*
 826  882           * Call machine-dependent routine "rootconf" to choose a root
 827  883           * file system type.
 828  884           */
 829  885          if (rootconf())
 830  886                  panic("vfs_mountroot: cannot mount root");
↓ open down ↓ 2773 lines elided ↑ open up ↑
3604 3660          }
3605 3661  
3606 3662          /*
3607 3663           * Link into the hash table, inserting it at the end, so that LOFS
3608 3664           * with the same fsid as UFS (or other) file systems will not hide
3609 3665           * the UFS.
3610 3666           */
3611 3667          vfs_hash_add(vfsp, 0);
3612 3668  
3613 3669          /*
     3670 +         * Link into tree indexed by mntpoint, for vfs_mntpoint2vfsp
     3671 +         * mntix discerns entries with the same key
     3672 +         */
     3673 +        vfsp->vfs_mntix = ++vfs_curr_mntix;
     3674 +        avl_add(&vfs_by_dev, vfsp);
     3675 +
     3676 +        /*
     3677 +         * Link into tree indexed by dev, for vfs_devismounted
     3678 +         */
     3679 +        avl_add(&vfs_by_mntpnt, vfsp);
     3680 +
     3681 +        /*
3614 3682           * update the mnttab modification time
3615 3683           */
3616 3684          vfs_mnttab_modtimeupd();
3617 3685          vfs_list_unlock();
3618 3686          zone_rele(zone);
3619 3687  }
3620 3688  
3621 3689  void
3622 3690  vfs_list_remove(struct vfs *vfsp)
3623 3691  {
↓ open down ↓ 3 lines elided ↑ open up ↑
3627 3695          ASSERT(zone != NULL);
3628 3696          /*
3629 3697           * Callers are responsible for preventing attempts to unmount the
3630 3698           * root.
3631 3699           */
3632 3700          ASSERT(vfsp != rootvfs);
3633 3701  
3634 3702          vfs_list_lock();
3635 3703  
3636 3704          /*
     3705 +         * Remove from avl trees
     3706 +         */
     3707 +        avl_remove(&vfs_by_mntpnt, vfsp);
     3708 +        avl_remove(&vfs_by_dev, vfsp);
     3709 +
     3710 +        /*
3637 3711           * Remove from hash.
3638 3712           */
3639 3713          vfs_hash_remove(vfsp);
3640 3714  
3641 3715          /*
3642 3716           * Remove from vfs list.
3643 3717           */
3644 3718          vfsp->vfs_prev->vfs_next = vfsp->vfs_next;
3645 3719          vfsp->vfs_next->vfs_prev = vfsp->vfs_prev;
3646 3720          vfsp->vfs_next = vfsp->vfs_prev = NULL;
↓ open down ↓ 73 lines elided ↑ open up ↑
3720 3794  
3721 3795  /*
3722 3796   * Search the vfs list for a specified device.  Returns 1, if entry is found
3723 3797   * or 0 if no suitable entry is found.
3724 3798   */
3725 3799  
3726 3800  int
3727 3801  vfs_devismounted(dev_t dev)
3728 3802  {
3729 3803          struct vfs *vfsp;
3730      -        int found;
     3804 +        int found = 0;
     3805 +        struct vfs search;
     3806 +        avl_index_t index;
     3807 +
     3808 +        search.vfs_dev = dev;
     3809 +        search.vfs_mntix = 0;
3731 3810  
3732 3811          vfs_list_read_lock();
3733      -        vfsp = rootvfs;
3734      -        found = 0;
3735      -        do {
3736      -                if (vfsp->vfs_dev == dev) {
3737      -                        found = 1;
3738      -                        break;
3739      -                }
3740      -                vfsp = vfsp->vfs_next;
3741      -        } while (vfsp != rootvfs);
     3812 +
     3813 +        /*
     3814 +         * there might be several entries with the same dev in the tree,
     3815 +         * only discerned by mntix. To find the first, we start with a mntix
     3816 +         * of 0. The search will fail. The following avl_nearest will give
     3817 +         * us the actual first entry.
     3818 +         */
     3819 +        VERIFY(avl_find(&vfs_by_dev, &search, &index) == NULL);
     3820 +        vfsp = avl_nearest(&vfs_by_dev, index, AVL_AFTER);
     3821 +
     3822 +        if (vfsp != NULL && vfsp->vfs_dev == dev)
     3823 +                found = 1;
3742 3824  
3743 3825          vfs_list_unlock();
3744 3826          return (found);
3745 3827  }
3746 3828  
3747 3829  /*
3748 3830   * Search the vfs list for a specified device.  Returns a pointer to it
3749 3831   * or NULL if no suitable entry is found. The caller of this routine
3750 3832   * is responsible for releasing the returned vfs pointer.
3751 3833   */
3752 3834  struct vfs *
3753 3835  vfs_dev2vfsp(dev_t dev)
3754 3836  {
3755 3837          struct vfs *vfsp;
3756 3838          int found;
     3839 +        struct vfs search;
     3840 +        avl_index_t index;
     3841 +
     3842 +        search.vfs_dev = dev;
     3843 +        search.vfs_mntix = 0;
3757 3844  
3758 3845          vfs_list_read_lock();
3759      -        vfsp = rootvfs;
     3846 +
     3847 +        /*
     3848 +         * there might be several entries with the same dev in the tree,
     3849 +         * only discerned by mntix. To find the first, we start with a mntix
     3850 +         * of 0. The search will fail. The following avl_nearest will give
     3851 +         * us the actual first entry.
     3852 +         */
     3853 +        VERIFY(avl_find(&vfs_by_dev, &search, &index) == NULL);
     3854 +        vfsp = avl_nearest(&vfs_by_dev, index, AVL_AFTER);
     3855 +
3760 3856          found = 0;
3761      -        do {
     3857 +        while (vfsp != NULL && vfsp->vfs_dev == dev) {
3762 3858                  /*
3763 3859                   * The following could be made more efficient by making
3764 3860                   * the entire loop use vfs_zone_next if the call is from
3765 3861                   * a zone.  The only callers, however, ustat(2) and
3766 3862                   * umount2(2), don't seem to justify the added
3767 3863                   * complexity at present.
3768 3864                   */
3769      -                if (vfsp->vfs_dev == dev &&
3770      -                    ZONE_PATH_VISIBLE(refstr_value(vfsp->vfs_mntpt),
     3865 +                if (ZONE_PATH_VISIBLE(refstr_value(vfsp->vfs_mntpt),
3771 3866                      curproc->p_zone)) {
3772 3867                          VFS_HOLD(vfsp);
3773 3868                          found = 1;
3774 3869                          break;
3775 3870                  }
3776      -                vfsp = vfsp->vfs_next;
3777      -        } while (vfsp != rootvfs);
     3871 +                vfsp = AVL_NEXT(&vfs_by_dev, vfsp);
     3872 +        }
3778 3873          vfs_list_unlock();
3779      -        return (found ? vfsp: NULL);
     3874 +        return (found ? vfsp : NULL);
3780 3875  }
3781 3876  
3782 3877  /*
3783 3878   * Search the vfs list for a specified mntpoint.  Returns a pointer to it
3784 3879   * or NULL if no suitable entry is found. The caller of this routine
3785 3880   * is responsible for releasing the returned vfs pointer.
3786 3881   *
3787 3882   * Note that if multiple mntpoints match, the last one matching is
3788 3883   * returned in an attempt to return the "top" mount when overlay
3789 3884   * mounts are covering the same mount point.  This is accomplished by starting
↓ open down ↓ 6 lines elided ↑ open up ↑
3796 3891          struct vfs *vfsp;
3797 3892          struct vfs *retvfsp = NULL;
3798 3893          zone_t *zone = curproc->p_zone;
3799 3894          struct vfs *list;
3800 3895  
3801 3896          vfs_list_read_lock();
3802 3897          if (getzoneid() == GLOBAL_ZONEID) {
3803 3898                  /*
3804 3899                   * The global zone may see filesystems in any zone.
3805 3900                   */
3806      -                vfsp = rootvfs->vfs_prev;
3807      -                do {
3808      -                        if (strcmp(refstr_value(vfsp->vfs_mntpt), mp) == 0) {
3809      -                                retvfsp = vfsp;
3810      -                                break;
3811      -                        }
3812      -                        vfsp = vfsp->vfs_prev;
3813      -                } while (vfsp != rootvfs->vfs_prev);
     3901 +                struct vfs search;
     3902 +                search.vfs_mntpt = refstr_alloc(mp);
     3903 +                search.vfs_mntix = UINT64_MAX;
     3904 +                avl_index_t index;
     3905 +
     3906 +                /*
     3907 +                 * there might be several entries with the same mntpnt in the
     3908 +                 * tree, only discerned by mntix. To find the last, we start
     3909 +                 * with a mntix of UINT64_MAX. The search will fail. The
     3910 +                 * following avl_nearest will give  us the actual last entry
     3911 +                 * matching the mntpnt.
     3912 +                 */
     3913 +                VERIFY(avl_find(&vfs_by_mntpnt, &search, &index) == 0);
     3914 +                vfsp = avl_nearest(&vfs_by_mntpnt, index, AVL_BEFORE);
     3915 +
     3916 +                refstr_rele(search.vfs_mntpt);
     3917 +
     3918 +                if (vfsp != NULL &&
     3919 +                    strcmp(refstr_value(vfsp->vfs_mntpt), mp) == 0)
     3920 +                        retvfsp = vfsp;
3814 3921          } else if ((list = zone->zone_vfslist) != NULL) {
3815 3922                  const char *mntpt;
3816 3923  
3817 3924                  vfsp = list->vfs_zone_prev;
3818 3925                  do {
3819 3926                          mntpt = refstr_value(vfsp->vfs_mntpt);
3820 3927                          mntpt = ZONE_PATH_TRANSLATE(mntpt, zone);
3821 3928                          if (strcmp(mntpt, mp) == 0) {
3822 3929                                  retvfsp = vfsp;
3823 3930                                  break;
↓ open down ↓ 1006 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX