Print this page
11945 pool import performance regression due to repeated libshare initialization
Reviewed by: Sanjay Nadkarni <sanjay.nadkarni@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Dan McDonald <danmcd@joyent.com>
Reviewed by: Jason King <jason.brian.king@gmail.com>

Split Close
Expand all
Collapse all
          --- old/usr/src/lib/libzfs/common/libzfs_mount.c
          +++ new/usr/src/lib/libzfs/common/libzfs_mount.c
↓ open down ↓ 604 lines elided ↑ open up ↑
 605  605  }
 606  606  
 607  607  /*
 608  608   * Make sure things will work if libshare isn't installed by using
 609  609   * wrapper functions that check to see that the pointers to functions
 610  610   * initialized in _zfs_init_libshare() are actually present.
 611  611   */
 612  612  
 613  613  static sa_handle_t (*_sa_init)(int);
 614  614  static sa_handle_t (*_sa_init_arg)(int, void *);
      615 +static int (*_sa_service)(sa_handle_t);
 615  616  static void (*_sa_fini)(sa_handle_t);
 616  617  static sa_share_t (*_sa_find_share)(sa_handle_t, char *);
 617  618  static int (*_sa_enable_share)(sa_share_t, char *);
 618  619  static int (*_sa_disable_share)(sa_share_t, char *);
 619  620  static char *(*_sa_errorstr)(int);
 620  621  static int (*_sa_parse_legacy_options)(sa_group_t, char *, char *);
 621  622  static boolean_t (*_sa_needs_refresh)(sa_handle_t *);
 622  623  static libzfs_handle_t *(*_sa_get_zfs_handle)(sa_handle_t);
 623  624  static int (*_sa_zfs_process_share)(sa_handle_t, sa_group_t, sa_share_t,
 624  625      char *, char *, zprop_source_t, char *, char *, char *);
↓ open down ↓ 22 lines elided ↑ open up ↑
 647  648          isa[0] = '\0';
 648  649  #endif
 649  650          (void) snprintf(path, MAXPATHLEN,
 650  651              "/usr/lib/%s/libshare.so.1", isa);
 651  652  
 652  653          if ((libshare = dlopen(path, RTLD_LAZY | RTLD_GLOBAL)) != NULL) {
 653  654                  _sa_init = (sa_handle_t (*)(int))dlsym(libshare, "sa_init");
 654  655                  _sa_init_arg = (sa_handle_t (*)(int, void *))dlsym(libshare,
 655  656                      "sa_init_arg");
 656  657                  _sa_fini = (void (*)(sa_handle_t))dlsym(libshare, "sa_fini");
      658 +                _sa_service = (int (*)(sa_handle_t))dlsym(libshare,
      659 +                    "sa_service");
 657  660                  _sa_find_share = (sa_share_t (*)(sa_handle_t, char *))
 658  661                      dlsym(libshare, "sa_find_share");
 659  662                  _sa_enable_share = (int (*)(sa_share_t, char *))dlsym(libshare,
 660  663                      "sa_enable_share");
 661  664                  _sa_disable_share = (int (*)(sa_share_t, char *))dlsym(libshare,
 662  665                      "sa_disable_share");
 663  666                  _sa_errorstr = (char *(*)(int))dlsym(libshare, "sa_errorstr");
 664  667                  _sa_parse_legacy_options = (int (*)(sa_group_t, char *, char *))
 665  668                      dlsym(libshare, "sa_parse_legacy_options");
 666  669                  _sa_needs_refresh = (boolean_t (*)(sa_handle_t *))
↓ open down ↓ 3 lines elided ↑ open up ↑
 670  673                  _sa_zfs_process_share = (int (*)(sa_handle_t, sa_group_t,
 671  674                      sa_share_t, char *, char *, zprop_source_t, char *,
 672  675                      char *, char *))dlsym(libshare, "sa_zfs_process_share");
 673  676                  _sa_update_sharetab_ts = (void (*)(sa_handle_t))
 674  677                      dlsym(libshare, "sa_update_sharetab_ts");
 675  678                  if (_sa_init == NULL || _sa_init_arg == NULL ||
 676  679                      _sa_fini == NULL || _sa_find_share == NULL ||
 677  680                      _sa_enable_share == NULL || _sa_disable_share == NULL ||
 678  681                      _sa_errorstr == NULL || _sa_parse_legacy_options == NULL ||
 679  682                      _sa_needs_refresh == NULL || _sa_get_zfs_handle == NULL ||
 680      -                    _sa_zfs_process_share == NULL ||
      683 +                    _sa_zfs_process_share == NULL || _sa_service == NULL ||
 681  684                      _sa_update_sharetab_ts == NULL) {
 682  685                          _sa_init = NULL;
 683  686                          _sa_init_arg = NULL;
      687 +                        _sa_service = NULL;
 684  688                          _sa_fini = NULL;
 685  689                          _sa_disable_share = NULL;
 686  690                          _sa_enable_share = NULL;
 687  691                          _sa_errorstr = NULL;
 688  692                          _sa_parse_legacy_options = NULL;
 689  693                          (void) dlclose(libshare);
 690  694                          _sa_needs_refresh = NULL;
 691  695                          _sa_get_zfs_handle = NULL;
 692  696                          _sa_zfs_process_share = NULL;
 693  697                          _sa_update_sharetab_ts = NULL;
↓ open down ↓ 138 lines elided ↑ open up ↑
 832  836  static int
 833  837  zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
 834  838  {
 835  839          char mountpoint[ZFS_MAXPROPLEN];
 836  840          char shareopts[ZFS_MAXPROPLEN];
 837  841          char sourcestr[ZFS_MAXPROPLEN];
 838  842          libzfs_handle_t *hdl = zhp->zfs_hdl;
 839  843          sa_share_t share;
 840  844          zfs_share_proto_t *curr_proto;
 841  845          zprop_source_t sourcetype;
      846 +        int service = SA_INIT_ONE_SHARE_FROM_HANDLE;
 842  847          int ret;
 843  848  
 844  849          if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
 845  850                  return (0);
 846  851  
      852 +        /*
      853 +         * Function may be called in a loop from higher up stack, with libshare
      854 +         * initialized for multiple shares (SA_INIT_SHARE_API_SELECTIVE).
      855 +         * zfs_init_libshare_arg will refresh the handle's cache if necessary.
      856 +         * In this case we do not want to switch to per share initialization.
      857 +         * Specify SA_INIT_SHARE_API to do full refresh, if refresh required.
      858 +         */
      859 +        if ((hdl->libzfs_sharehdl != NULL) && (_sa_service != NULL) &&
      860 +            (_sa_service(hdl->libzfs_sharehdl) ==
      861 +            SA_INIT_SHARE_API_SELECTIVE)) {
      862 +                service = SA_INIT_SHARE_API;
      863 +        }
      864 +
 847  865          for (curr_proto = proto; *curr_proto != PROTO_END; curr_proto++) {
 848  866                  /*
 849  867                   * Return success if there are no share options.
 850  868                   */
 851  869                  if (zfs_prop_get(zhp, proto_table[*curr_proto].p_prop,
 852  870                      shareopts, sizeof (shareopts), &sourcetype, sourcestr,
 853  871                      ZFS_MAXPROPLEN, B_FALSE) != 0 ||
 854  872                      strcmp(shareopts, "off") == 0)
 855  873                          continue;
 856      -                ret = zfs_init_libshare_arg(hdl, SA_INIT_ONE_SHARE_FROM_HANDLE,
 857      -                    zhp);
      874 +                ret = zfs_init_libshare_arg(hdl, service, zhp);
 858  875                  if (ret != SA_OK) {
 859  876                          (void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED,
 860  877                              dgettext(TEXT_DOMAIN, "cannot share '%s': %s"),
 861  878                              zfs_get_name(zhp), _sa_errorstr != NULL ?
 862  879                              _sa_errorstr(ret) : "");
 863  880                          return (-1);
 864  881                  }
 865  882  
 866  883                  /*
 867  884                   * If the 'zoned' property is set, then zfs_is_mountable()
↓ open down ↓ 73 lines elided ↑ open up ↑
 941  958  /*
 942  959   * Unshare a filesystem by mountpoint.
 943  960   */
 944  961  static int
 945  962  unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint,
 946  963      zfs_share_proto_t proto)
 947  964  {
 948  965          sa_share_t share;
 949  966          int err;
 950  967          char *mntpt;
      968 +        int service = SA_INIT_ONE_SHARE_FROM_NAME;
 951  969  
 952  970          /*
 953  971           * Mountpoint could get trashed if libshare calls getmntany
 954  972           * which it does during API initialization, so strdup the
 955  973           * value.
 956  974           */
 957  975          mntpt = zfs_strdup(hdl, mountpoint);
 958  976  
 959  977          /*
 960      -         * make sure libshare initialized, initialize everything because we
 961      -         * don't know what other unsharing may happen later. Functions up the
 962      -         * stack are allowed to initialize instead a subset of shares at the
 963      -         * time the set is known.
      978 +         * Function may be called in a loop from higher up stack, with libshare
      979 +         * initialized for multiple shares (SA_INIT_SHARE_API_SELECTIVE).
      980 +         * zfs_init_libshare_arg will refresh the handle's cache if necessary.
      981 +         * In this case we do not want to switch to per share initialization.
      982 +         * Specify SA_INIT_SHARE_API to do full refresh, if refresh required.
 964  983           */
 965      -        if ((err = zfs_init_libshare_arg(hdl, SA_INIT_ONE_SHARE_FROM_NAME,
 966      -            (void *)name)) != SA_OK) {
      984 +        if ((hdl->libzfs_sharehdl != NULL) && (_sa_service != NULL) &&
      985 +            (_sa_service(hdl->libzfs_sharehdl) ==
      986 +            SA_INIT_SHARE_API_SELECTIVE)) {
      987 +                service = SA_INIT_SHARE_API;
      988 +        }
      989 +
      990 +        err = zfs_init_libshare_arg(hdl, service, (void *)name);
      991 +        if (err != SA_OK) {
 967  992                  free(mntpt);    /* don't need the copy anymore */
 968  993                  return (zfs_error_fmt(hdl, proto_table[proto].p_unshare_err,
 969  994                      dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"),
 970  995                      name, _sa_errorstr(err)));
 971  996          }
 972  997  
 973  998          share = zfs_sa_find_share(hdl->libzfs_sharehdl, mntpt);
 974  999          free(mntpt);    /* don't need the copy anymore */
 975 1000  
 976 1001          if (share != NULL) {
↓ open down ↓ 548 lines elided ↑ open up ↑
1525 1550                  goto out;
1526 1551  
1527 1552          ms.ms_mntopts = mntopts;
1528 1553          ms.ms_mntflags = flags;
1529 1554          zfs_foreach_mountpoint(zhp->zpool_hdl, cb.cb_handles, cb.cb_used,
1530 1555              zfs_mount_one, &ms, B_TRUE);
1531 1556          if (ms.ms_mntstatus != 0)
1532 1557                  ret = ms.ms_mntstatus;
1533 1558  
1534 1559          /*
1535      -         * Share all filesystems that need to be shared. This needs to be
1536      -         * a separate pass because libshare is not mt-safe, and so we need
1537      -         * to share serially.
     1560 +         * Initialize libshare SA_INIT_SHARE_API_SELECTIVE here
     1561 +         * to avoid unnecessary load/unload of the libshare API
     1562 +         * per shared dataset downstream.
1538 1563           */
1539 1564          sharearg.zhandle_arr = cb.cb_handles;
1540 1565          sharearg.zhandle_len = cb.cb_used;
1541 1566          if ((ret = zfs_init_libshare_arg(zhp->zpool_hdl,
1542 1567              SA_INIT_SHARE_API_SELECTIVE, &sharearg)) != 0)
1543 1568                  goto out;
1544 1569  
1545 1570          ms.ms_mntstatus = 0;
1546 1571          zfs_foreach_mountpoint(zhp->zpool_hdl, cb.cb_handles, cb.cb_used,
1547 1572              zfs_share_one, &ms, B_FALSE);
↓ open down ↓ 164 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX