Print this page
8115 parallel zfs mount
        
*** 58,67 ****
--- 58,68 ----
  #include <sys/mount.h>
  #include <sys/stat.h>
  #include <sys/fs/zfs.h>
  #include <sys/types.h>
  #include <time.h>
+ #include <synch.h>
  
  #include <libzfs.h>
  #include <libzfs_core.h>
  #include <zfs_prop.h>
  #include <zfs_deleg.h>
*** 5747,5769 ****
          return (0 != errors);
  }
  
  #define CHECK_SPINNER 30
  #define SPINNER_TIME 3          /* seconds */
! #define MOUNT_TIME 5            /* seconds */
  
  static int
  get_one_dataset(zfs_handle_t *zhp, void *data)
  {
          static char *spin[] = { "-", "\\", "|", "/" };
          static int spinval = 0;
          static int spincheck = 0;
          static time_t last_spin_time = (time_t)0;
!         get_all_cb_t *cbp = data;
          zfs_type_t type = zfs_get_type(zhp);
  
!         if (cbp->cb_verbose) {
                  if (--spincheck < 0) {
                          time_t now = time(NULL);
                          if (last_spin_time + SPINNER_TIME < now) {
                                  update_progress(spin[spinval++ % 4]);
                                  last_spin_time = now;
--- 5748,5775 ----
          return (0 != errors);
  }
  
  #define CHECK_SPINNER 30
  #define SPINNER_TIME 3          /* seconds */
! #define MOUNT_TIME 1            /* seconds */
  
+ typedef struct get_all_state {
+         boolean_t       ga_verbose;
+         get_all_cb_t    *ga_cbp;
+ } get_all_state_t;
+ 
  static int
  get_one_dataset(zfs_handle_t *zhp, void *data)
  {
          static char *spin[] = { "-", "\\", "|", "/" };
          static int spinval = 0;
          static int spincheck = 0;
          static time_t last_spin_time = (time_t)0;
!         get_all_state_t *state = data;
          zfs_type_t type = zfs_get_type(zhp);
  
!         if (state->ga_verbose) {
                  if (--spincheck < 0) {
                          time_t now = time(NULL);
                          if (last_spin_time + SPINNER_TIME < now) {
                                  update_progress(spin[spinval++ % 4]);
                                  last_spin_time = now;
*** 5785,5826 ****
           */
          if ((type & ZFS_TYPE_FILESYSTEM) == 0) {
                  zfs_close(zhp);
                  return (0);
          }
!         libzfs_add_handle(cbp, zhp);
!         assert(cbp->cb_used <= cbp->cb_alloc);
  
          return (0);
  }
  
  static void
! get_all_datasets(zfs_handle_t ***dslist, size_t *count, boolean_t verbose)
  {
!         get_all_cb_t cb = { 0 };
!         cb.cb_verbose = verbose;
!         cb.cb_getone = get_one_dataset;
  
          if (verbose)
                  set_progress_header(gettext("Reading ZFS config"));
!         (void) zfs_iter_root(g_zfs, get_one_dataset, &cb);
  
-         *dslist = cb.cb_handles;
-         *count = cb.cb_used;
- 
          if (verbose)
                  finish_progress(gettext("done."));
  }
  
  /*
   * Generic callback for sharing or mounting filesystems.  Because the code is so
   * similar, we have a common function with an extra parameter to determine which
   * mode we are using.
   */
! #define OP_SHARE        0x1
! #define OP_MOUNT        0x2
  
  /*
   * Share or mount a dataset.
   */
  static int
  share_mount_one(zfs_handle_t *zhp, int op, int flags, char *protocol,
--- 5791,5841 ----
           */
          if ((type & ZFS_TYPE_FILESYSTEM) == 0) {
                  zfs_close(zhp);
                  return (0);
          }
!         libzfs_add_handle(state->ga_cbp, zhp);
!         assert(state->ga_cbp->cb_used <= state->ga_cbp->cb_alloc);
  
          return (0);
  }
  
  static void
! get_all_datasets(get_all_cb_t *cbp, boolean_t verbose)
  {
!         get_all_state_t state = {
!             .ga_verbose = verbose,
!             .ga_cbp = cbp
!         };
  
          if (verbose)
                  set_progress_header(gettext("Reading ZFS config"));
!         (void) zfs_iter_root(g_zfs, get_one_dataset, &state);
  
          if (verbose)
                  finish_progress(gettext("done."));
  }
  
  /*
   * Generic callback for sharing or mounting filesystems.  Because the code is so
   * similar, we have a common function with an extra parameter to determine which
   * mode we are using.
   */
! typedef enum { OP_SHARE, OP_MOUNT } share_mount_op_t;
  
+ typedef struct share_mount_state {
+         share_mount_op_t sm_op;
+         boolean_t sm_verbose;
+         int     sm_flags;
+         char    *sm_options;
+         char    *sm_proto; /* only valid for OP_SHARE */
+         mutex_t sm_lock; /* protects the remaining fields */
+         uint_t  sm_total; /* number of filesystems to process */
+         uint_t  sm_done; /* number of filesystems processed */
+         int     sm_status; /* -1 if any of the share/mount operations failed */
+ } share_mount_state_t;
+ 
  /*
   * Share or mount a dataset.
   */
  static int
  share_mount_one(zfs_handle_t *zhp, int op, int flags, char *protocol,
*** 6057,6066 ****
--- 6072,6104 ----
                  finish_progress(info);
          else
                  update_progress(info);
  }
  
+ /*
+  * zfs_foreach_mountpoint() callback that mounts or shares one filesystem and
+  * updates the progress meter.
+  */
+ static int
+ share_mount_one_cb(zfs_handle_t *zhp, void *arg)
+ {
+         share_mount_state_t *sms = arg;
+         int ret;
+ 
+         ret = share_mount_one(zhp, sms->sm_op, sms->sm_flags, sms->sm_proto,
+             B_FALSE, sms->sm_options);
+ 
+         (void) mutex_lock(&sms->sm_lock);
+         if (ret != 0)
+                 sms->sm_status = ret;
+         sms->sm_done++;
+         if (sms->sm_verbose)
+                 report_mount_progress(sms->sm_done, sms->sm_total);
+         (void) mutex_unlock(&sms->sm_lock);
+         return (ret);
+ }
+ 
  static void
  append_options(char *mntopts, char *newopts)
  {
          int len = strlen(mntopts);
  
*** 6129,6140 ****
          argc -= optind;
          argv += optind;
  
          /* check number of arguments */
          if (do_all) {
-                 zfs_handle_t **dslist = NULL;
-                 size_t i, count = 0;
                  char *protocol = NULL;
  
                  if (op == OP_SHARE && argc > 0) {
                          if (strcmp(argv[0], "nfs") != 0 &&
                              strcmp(argv[0], "smb") != 0) {
--- 6167,6176 ----
*** 6151,6187 ****
                          (void) fprintf(stderr, gettext("too many arguments\n"));
                          usage(B_FALSE);
                  }
  
                  start_progress_timer();
!                 get_all_datasets(&dslist, &count, verbose);
  
!                 if (count == 0)
                          return (0);
  
!                 qsort(dslist, count, sizeof (void *), libzfs_dataset_cmp);
                  sa_init_selective_arg_t sharearg;
!                 sharearg.zhandle_arr = dslist;
!                 sharearg.zhandle_len = count;
!                 if ((ret = zfs_init_libshare_arg(zfs_get_handle(dslist[0]),
                      SA_INIT_SHARE_API_SELECTIVE, &sharearg)) != SA_OK) {
!                         (void) fprintf(stderr,
!                             gettext("Could not initialize libshare, %d"), ret);
                          return (ret);
                  }
- 
-                 for (i = 0; i < count; i++) {
-                         if (verbose)
-                                 report_mount_progress(i, count);
- 
-                         if (share_mount_one(dslist[i], op, flags, protocol,
-                             B_FALSE, options) != 0)
-                                 ret = 1;
-                         zfs_close(dslist[i]);
                  }
  
!                 free(dslist);
          } else if (argc == 0) {
                  struct mnttab entry;
  
                  if ((op == OP_SHARE) || (options != NULL)) {
                          (void) fprintf(stderr, gettext("missing filesystem "
--- 6187,6234 ----
                          (void) fprintf(stderr, gettext("too many arguments\n"));
                          usage(B_FALSE);
                  }
  
                  start_progress_timer();
!                 get_all_cb_t cb = { 0 };
!                 get_all_datasets(&cb, verbose);
  
!                 if (cb.cb_used == 0)
                          return (0);
  
!                 if (op == OP_SHARE) {
                          sa_init_selective_arg_t sharearg;
!                         sharearg.zhandle_arr = cb.cb_handles;
!                         sharearg.zhandle_len = cb.cb_used;
!                         if ((ret = zfs_init_libshare_arg(g_zfs,
                              SA_INIT_SHARE_API_SELECTIVE, &sharearg)) != SA_OK) {
!                                 (void) fprintf(stderr, gettext(
!                                     "Could not initialize libshare, %d"), ret);
                                  return (ret);
                          }
                  }
  
!                 share_mount_state_t share_mount_state = { 0 };
!                 share_mount_state.sm_op = op;
!                 share_mount_state.sm_verbose = verbose;
!                 share_mount_state.sm_flags = flags;
!                 share_mount_state.sm_options = options;
!                 share_mount_state.sm_proto = protocol;
!                 share_mount_state.sm_total = cb.cb_used;
!                 (void) mutex_init(&share_mount_state.sm_lock, USYNC_THREAD,
!                     NULL);
!                 /*
!                  * libshare isn't mt-safe, so only do the operation in parallel
!                  * if we're mounting.
!                  */
!                 zfs_foreach_mountpoint(g_zfs, cb.cb_handles, cb.cb_used,
!                     share_mount_one_cb, &share_mount_state, op == OP_MOUNT);
!                 ret = share_mount_state.sm_status;
! 
!                 for (int i = 0; i < cb.cb_used; i++)
!                         zfs_close(cb.cb_handles[i]);
!                 free(cb.cb_handles);
          } else if (argc == 0) {
                  struct mnttab entry;
  
                  if ((op == OP_SHARE) || (options != NULL)) {
                          (void) fprintf(stderr, gettext("missing filesystem "