Print this page
8115 parallel zfs mount

Split Close
Expand all
Collapse all
          --- old/usr/src/cmd/zfs/zfs_main.c
          +++ new/usr/src/cmd/zfs/zfs_main.c
↓ open down ↓ 52 lines elided ↑ open up ↑
  53   53  #include <sys/debug.h>
  54   54  #include <sys/list.h>
  55   55  #include <sys/mkdev.h>
  56   56  #include <sys/mntent.h>
  57   57  #include <sys/mnttab.h>
  58   58  #include <sys/mount.h>
  59   59  #include <sys/stat.h>
  60   60  #include <sys/fs/zfs.h>
  61   61  #include <sys/types.h>
  62   62  #include <time.h>
       63 +#include <synch.h>
  63   64  
  64   65  #include <libzfs.h>
  65   66  #include <libzfs_core.h>
  66   67  #include <zfs_prop.h>
  67   68  #include <zfs_deleg.h>
  68   69  #include <libuutil.h>
  69   70  #include <aclutils.h>
  70   71  #include <directory.h>
  71   72  #include <idmap.h>
  72   73  #include <libshare.h>
↓ open down ↓ 5669 lines elided ↑ open up ↑
5742 5743          if (nvlist_empty(nvl))
5743 5744                  (void) printf(gettext("no datasets available\n"));
5744 5745  
5745 5746          nvlist_free(nvl);
5746 5747  
5747 5748          return (0 != errors);
5748 5749  }
5749 5750  
5750 5751  #define CHECK_SPINNER 30
5751 5752  #define SPINNER_TIME 3          /* seconds */
5752      -#define MOUNT_TIME 5            /* seconds */
     5753 +#define MOUNT_TIME 1            /* seconds */
5753 5754  
     5755 +typedef struct get_all_state {
     5756 +        boolean_t       ga_verbose;
     5757 +        get_all_cb_t    *ga_cbp;
     5758 +} get_all_state_t;
     5759 +
5754 5760  static int
5755 5761  get_one_dataset(zfs_handle_t *zhp, void *data)
5756 5762  {
5757 5763          static char *spin[] = { "-", "\\", "|", "/" };
5758 5764          static int spinval = 0;
5759 5765          static int spincheck = 0;
5760 5766          static time_t last_spin_time = (time_t)0;
5761      -        get_all_cb_t *cbp = data;
     5767 +        get_all_state_t *state = data;
5762 5768          zfs_type_t type = zfs_get_type(zhp);
5763 5769  
5764      -        if (cbp->cb_verbose) {
     5770 +        if (state->ga_verbose) {
5765 5771                  if (--spincheck < 0) {
5766 5772                          time_t now = time(NULL);
5767 5773                          if (last_spin_time + SPINNER_TIME < now) {
5768 5774                                  update_progress(spin[spinval++ % 4]);
5769 5775                                  last_spin_time = now;
5770 5776                          }
5771 5777                          spincheck = CHECK_SPINNER;
5772 5778                  }
5773 5779          }
5774 5780  
↓ open down ↓ 5 lines elided ↑ open up ↑
5780 5786                  return (1);
5781 5787          }
5782 5788  
5783 5789          /*
5784 5790           * Skip any datasets whose type does not match.
5785 5791           */
5786 5792          if ((type & ZFS_TYPE_FILESYSTEM) == 0) {
5787 5793                  zfs_close(zhp);
5788 5794                  return (0);
5789 5795          }
5790      -        libzfs_add_handle(cbp, zhp);
5791      -        assert(cbp->cb_used <= cbp->cb_alloc);
     5796 +        libzfs_add_handle(state->ga_cbp, zhp);
     5797 +        assert(state->ga_cbp->cb_used <= state->ga_cbp->cb_alloc);
5792 5798  
5793 5799          return (0);
5794 5800  }
5795 5801  
5796 5802  static void
5797      -get_all_datasets(zfs_handle_t ***dslist, size_t *count, boolean_t verbose)
     5803 +get_all_datasets(get_all_cb_t *cbp, boolean_t verbose)
5798 5804  {
5799      -        get_all_cb_t cb = { 0 };
5800      -        cb.cb_verbose = verbose;
5801      -        cb.cb_getone = get_one_dataset;
     5805 +        get_all_state_t state = {
     5806 +            .ga_verbose = verbose,
     5807 +            .ga_cbp = cbp
     5808 +        };
5802 5809  
5803 5810          if (verbose)
5804 5811                  set_progress_header(gettext("Reading ZFS config"));
5805      -        (void) zfs_iter_root(g_zfs, get_one_dataset, &cb);
     5812 +        (void) zfs_iter_root(g_zfs, get_one_dataset, &state);
5806 5813  
5807      -        *dslist = cb.cb_handles;
5808      -        *count = cb.cb_used;
5809      -
5810 5814          if (verbose)
5811 5815                  finish_progress(gettext("done."));
5812 5816  }
5813 5817  
5814 5818  /*
5815 5819   * Generic callback for sharing or mounting filesystems.  Because the code is so
5816 5820   * similar, we have a common function with an extra parameter to determine which
5817 5821   * mode we are using.
5818 5822   */
5819      -#define OP_SHARE        0x1
5820      -#define OP_MOUNT        0x2
     5823 +typedef enum { OP_SHARE, OP_MOUNT } share_mount_op_t;
5821 5824  
     5825 +typedef struct share_mount_state {
     5826 +        share_mount_op_t sm_op;
     5827 +        boolean_t sm_verbose;
     5828 +        int     sm_flags;
     5829 +        char    *sm_options;
     5830 +        char    *sm_proto; /* only valid for OP_SHARE */
     5831 +        mutex_t sm_lock; /* protects the remaining fields */
     5832 +        uint_t  sm_total; /* number of filesystems to process */
     5833 +        uint_t  sm_done; /* number of filesystems processed */
     5834 +        int     sm_status; /* -1 if any of the share/mount operations failed */
     5835 +} share_mount_state_t;
     5836 +
5822 5837  /*
5823 5838   * Share or mount a dataset.
5824 5839   */
5825 5840  static int
5826 5841  share_mount_one(zfs_handle_t *zhp, int op, int flags, char *protocol,
5827 5842      boolean_t explicit, const char *options)
5828 5843  {
5829 5844          char mountpoint[ZFS_MAXPROPLEN];
5830 5845          char shareopts[ZFS_MAXPROPLEN];
5831 5846          char smbshareopts[ZFS_MAXPROPLEN];
↓ open down ↓ 220 lines elided ↑ open up ↑
6052 6067          last_progress_time = now;
6053 6068  
6054 6069          (void) sprintf(info, "(%d/%d)", current, total);
6055 6070  
6056 6071          if (current == total)
6057 6072                  finish_progress(info);
6058 6073          else
6059 6074                  update_progress(info);
6060 6075  }
6061 6076  
     6077 +/*
     6078 + * zfs_foreach_mountpoint() callback that mounts or shares one filesystem and
     6079 + * updates the progress meter.
     6080 + */
     6081 +static int
     6082 +share_mount_one_cb(zfs_handle_t *zhp, void *arg)
     6083 +{
     6084 +        share_mount_state_t *sms = arg;
     6085 +        int ret;
     6086 +
     6087 +        ret = share_mount_one(zhp, sms->sm_op, sms->sm_flags, sms->sm_proto,
     6088 +            B_FALSE, sms->sm_options);
     6089 +
     6090 +        (void) mutex_lock(&sms->sm_lock);
     6091 +        if (ret != 0)
     6092 +                sms->sm_status = ret;
     6093 +        sms->sm_done++;
     6094 +        if (sms->sm_verbose)
     6095 +                report_mount_progress(sms->sm_done, sms->sm_total);
     6096 +        (void) mutex_unlock(&sms->sm_lock);
     6097 +        return (ret);
     6098 +}
     6099 +
6062 6100  static void
6063 6101  append_options(char *mntopts, char *newopts)
6064 6102  {
6065 6103          int len = strlen(mntopts);
6066 6104  
6067 6105          /* original length plus new string to append plus 1 for the comma */
6068 6106          if (len + 1 + strlen(newopts) >= MNT_LINE_MAX) {
6069 6107                  (void) fprintf(stderr, gettext("the opts argument for "
6070 6108                      "'%c' option is too long (more than %d chars)\n"),
6071 6109                      "-o", MNT_LINE_MAX);
↓ open down ↓ 52 lines elided ↑ open up ↑
6124 6162                              optopt);
6125 6163                          usage(B_FALSE);
6126 6164                  }
6127 6165          }
6128 6166  
6129 6167          argc -= optind;
6130 6168          argv += optind;
6131 6169  
6132 6170          /* check number of arguments */
6133 6171          if (do_all) {
6134      -                zfs_handle_t **dslist = NULL;
6135      -                size_t i, count = 0;
6136 6172                  char *protocol = NULL;
6137 6173  
6138 6174                  if (op == OP_SHARE && argc > 0) {
6139 6175                          if (strcmp(argv[0], "nfs") != 0 &&
6140 6176                              strcmp(argv[0], "smb") != 0) {
6141 6177                                  (void) fprintf(stderr, gettext("share type "
6142 6178                                      "must be 'nfs' or 'smb'\n"));
6143 6179                                  usage(B_FALSE);
6144 6180                          }
6145 6181                          protocol = argv[0];
6146 6182                          argc--;
6147 6183                          argv++;
6148 6184                  }
6149 6185  
6150 6186                  if (argc != 0) {
6151 6187                          (void) fprintf(stderr, gettext("too many arguments\n"));
6152 6188                          usage(B_FALSE);
6153 6189                  }
6154 6190  
6155 6191                  start_progress_timer();
6156      -                get_all_datasets(&dslist, &count, verbose);
     6192 +                get_all_cb_t cb = { 0 };
     6193 +                get_all_datasets(&cb, verbose);
6157 6194  
6158      -                if (count == 0)
     6195 +                if (cb.cb_used == 0)
6159 6196                          return (0);
6160 6197  
6161      -                qsort(dslist, count, sizeof (void *), libzfs_dataset_cmp);
6162      -                sa_init_selective_arg_t sharearg;
6163      -                sharearg.zhandle_arr = dslist;
6164      -                sharearg.zhandle_len = count;
6165      -                if ((ret = zfs_init_libshare_arg(zfs_get_handle(dslist[0]),
6166      -                    SA_INIT_SHARE_API_SELECTIVE, &sharearg)) != SA_OK) {
6167      -                        (void) fprintf(stderr,
6168      -                            gettext("Could not initialize libshare, %d"), ret);
6169      -                        return (ret);
     6198 +                if (op == OP_SHARE) {
     6199 +                        sa_init_selective_arg_t sharearg;
     6200 +                        sharearg.zhandle_arr = cb.cb_handles;
     6201 +                        sharearg.zhandle_len = cb.cb_used;
     6202 +                        if ((ret = zfs_init_libshare_arg(g_zfs,
     6203 +                            SA_INIT_SHARE_API_SELECTIVE, &sharearg)) != SA_OK) {
     6204 +                                (void) fprintf(stderr, gettext(
     6205 +                                    "Could not initialize libshare, %d"), ret);
     6206 +                                return (ret);
     6207 +                        }
6170 6208                  }
6171 6209  
6172      -                for (i = 0; i < count; i++) {
6173      -                        if (verbose)
6174      -                                report_mount_progress(i, count);
     6210 +                share_mount_state_t share_mount_state = { 0 };
     6211 +                share_mount_state.sm_op = op;
     6212 +                share_mount_state.sm_verbose = verbose;
     6213 +                share_mount_state.sm_flags = flags;
     6214 +                share_mount_state.sm_options = options;
     6215 +                share_mount_state.sm_proto = protocol;
     6216 +                share_mount_state.sm_total = cb.cb_used;
     6217 +                (void) mutex_init(&share_mount_state.sm_lock, USYNC_THREAD,
     6218 +                    NULL);
     6219 +                /*
     6220 +                 * libshare isn't mt-safe, so only do the operation in parallel
     6221 +                 * if we're mounting.
     6222 +                 */
     6223 +                zfs_foreach_mountpoint(g_zfs, cb.cb_handles, cb.cb_used,
     6224 +                    share_mount_one_cb, &share_mount_state, op == OP_MOUNT);
     6225 +                ret = share_mount_state.sm_status;
6175 6226  
6176      -                        if (share_mount_one(dslist[i], op, flags, protocol,
6177      -                            B_FALSE, options) != 0)
6178      -                                ret = 1;
6179      -                        zfs_close(dslist[i]);
6180      -                }
6181      -
6182      -                free(dslist);
     6227 +                for (int i = 0; i < cb.cb_used; i++)
     6228 +                        zfs_close(cb.cb_handles[i]);
     6229 +                free(cb.cb_handles);
6183 6230          } else if (argc == 0) {
6184 6231                  struct mnttab entry;
6185 6232  
6186 6233                  if ((op == OP_SHARE) || (options != NULL)) {
6187 6234                          (void) fprintf(stderr, gettext("missing filesystem "
6188 6235                              "argument (specify -a for all)\n"));
6189 6236                          usage(B_FALSE);
6190 6237                  }
6191 6238  
6192 6239                  /*
↓ open down ↓ 1103 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX