Print this page
8115 parallel zfs mount


  43 #include <stddef.h>
  44 #include <stdio.h>
  45 #include <stdlib.h>
  46 #include <strings.h>
  47 #include <unistd.h>
  48 #include <fcntl.h>
  49 #include <zone.h>
  50 #include <grp.h>
  51 #include <pwd.h>
  52 #include <signal.h>
  53 #include <sys/debug.h>
  54 #include <sys/list.h>
  55 #include <sys/mkdev.h>
  56 #include <sys/mntent.h>
  57 #include <sys/mnttab.h>
  58 #include <sys/mount.h>
  59 #include <sys/stat.h>
  60 #include <sys/fs/zfs.h>
  61 #include <sys/types.h>
  62 #include <time.h>

  63 
  64 #include <libzfs.h>
  65 #include <libzfs_core.h>
  66 #include <zfs_prop.h>
  67 #include <zfs_deleg.h>
  68 #include <libuutil.h>
  69 #include <aclutils.h>
  70 #include <directory.h>
  71 #include <idmap.h>
  72 #include <libshare.h>
  73 
  74 #include "zfs_iter.h"
  75 #include "zfs_util.h"
  76 #include "zfs_comutil.h"
  77 
  78 libzfs_handle_t *g_zfs;
  79 
  80 static FILE *mnttab_file;
  81 static char history_str[HIS_MAX_RECORD_LEN];
  82 static boolean_t log_history = B_TRUE;


5732                     holds_callback, &cb);
5733                 if (ret != 0)
5734                         ++errors;
5735         }
5736 
5737         /*
5738          *  2. print holds data
5739          */
5740         print_holds(scripted, cb.cb_max_namelen, cb.cb_max_taglen, nvl);
5741 
5742         if (nvlist_empty(nvl))
5743                 (void) printf(gettext("no datasets available\n"));
5744 
5745         nvlist_free(nvl);
5746 
5747         return (0 != errors);
5748 }
5749 
5750 #define CHECK_SPINNER 30
5751 #define SPINNER_TIME 3          /* seconds */
5752 #define MOUNT_TIME 5            /* seconds */
5753 





5754 static int
5755 get_one_dataset(zfs_handle_t *zhp, void *data)
5756 {
5757         static char *spin[] = { "-", "\\", "|", "/" };
5758         static int spinval = 0;
5759         static int spincheck = 0;
5760         static time_t last_spin_time = (time_t)0;
5761         get_all_cb_t *cbp = data;
5762         zfs_type_t type = zfs_get_type(zhp);
5763 
5764         if (cbp->cb_verbose) {
5765                 if (--spincheck < 0) {
5766                         time_t now = time(NULL);
5767                         if (last_spin_time + SPINNER_TIME < now) {
5768                                 update_progress(spin[spinval++ % 4]);
5769                                 last_spin_time = now;
5770                         }
5771                         spincheck = CHECK_SPINNER;
5772                 }
5773         }
5774 
5775         /*
5776          * Interate over any nested datasets.
5777          */
5778         if (zfs_iter_filesystems(zhp, get_one_dataset, data) != 0) {
5779                 zfs_close(zhp);
5780                 return (1);
5781         }
5782 
5783         /*
5784          * Skip any datasets whose type does not match.
5785          */
5786         if ((type & ZFS_TYPE_FILESYSTEM) == 0) {
5787                 zfs_close(zhp);
5788                 return (0);
5789         }
5790         libzfs_add_handle(cbp, zhp);
5791         assert(cbp->cb_used <= cbp->cb_alloc);
5792 
5793         return (0);
5794 }
5795 
5796 static void
5797 get_all_datasets(zfs_handle_t ***dslist, size_t *count, boolean_t verbose)
5798 {
5799         get_all_cb_t cb = { 0 };
5800         cb.cb_verbose = verbose;
5801         cb.cb_getone = get_one_dataset;

5802 
5803         if (verbose)
5804                 set_progress_header(gettext("Reading ZFS config"));
5805         (void) zfs_iter_root(g_zfs, get_one_dataset, &cb);
5806 
5807         *dslist = cb.cb_handles;
5808         *count = cb.cb_used;
5809 
5810         if (verbose)
5811                 finish_progress(gettext("done."));
5812 }
5813 
5814 /*
5815  * Generic callback for sharing or mounting filesystems.  Because the code is so
5816  * similar, we have a common function with an extra parameter to determine which
5817  * mode we are using.
5818  */
5819 #define OP_SHARE        0x1
5820 #define OP_MOUNT        0x2
5821 












5822 /*
5823  * Share or mount a dataset.
5824  */
5825 static int
5826 share_mount_one(zfs_handle_t *zhp, int op, int flags, char *protocol,
5827     boolean_t explicit, const char *options)
5828 {
5829         char mountpoint[ZFS_MAXPROPLEN];
5830         char shareopts[ZFS_MAXPROPLEN];
5831         char smbshareopts[ZFS_MAXPROPLEN];
5832         const char *cmdname = op == OP_SHARE ? "share" : "mount";
5833         struct mnttab mnt;
5834         uint64_t zoned, canmount;
5835         boolean_t shared_nfs, shared_smb;
5836 
5837         assert(zfs_get_type(zhp) & ZFS_TYPE_FILESYSTEM);
5838 
5839         /*
5840          * Check to make sure we can mount/share this dataset.  If we
5841          * are in the global zone and the filesystem is exported to a


6042         ++current;
6043 
6044         /* display header if we're here for the first time */
6045         if (current == 1) {
6046                 set_progress_header(gettext("Mounting ZFS filesystems"));
6047         } else if (current != total && last_progress_time + MOUNT_TIME >= now) {
6048                 /* too soon to report again */
6049                 return;
6050         }
6051 
6052         last_progress_time = now;
6053 
6054         (void) sprintf(info, "(%d/%d)", current, total);
6055 
6056         if (current == total)
6057                 finish_progress(info);
6058         else
6059                 update_progress(info);
6060 }
6061 























6062 static void
6063 append_options(char *mntopts, char *newopts)
6064 {
6065         int len = strlen(mntopts);
6066 
6067         /* original length plus new string to append plus 1 for the comma */
6068         if (len + 1 + strlen(newopts) >= MNT_LINE_MAX) {
6069                 (void) fprintf(stderr, gettext("the opts argument for "
6070                     "'%c' option is too long (more than %d chars)\n"),
6071                     "-o", MNT_LINE_MAX);
6072                 usage(B_FALSE);
6073         }
6074 
6075         if (*mntopts)
6076                 mntopts[len++] = ',';
6077 
6078         (void) strcpy(&mntopts[len], newopts);
6079 }
6080 
6081 static int


6114                 case 'O':
6115                         flags |= MS_OVERLAY;
6116                         break;
6117                 case ':':
6118                         (void) fprintf(stderr, gettext("missing argument for "
6119                             "'%c' option\n"), optopt);
6120                         usage(B_FALSE);
6121                         break;
6122                 case '?':
6123                         (void) fprintf(stderr, gettext("invalid option '%c'\n"),
6124                             optopt);
6125                         usage(B_FALSE);
6126                 }
6127         }
6128 
6129         argc -= optind;
6130         argv += optind;
6131 
6132         /* check number of arguments */
6133         if (do_all) {
6134                 zfs_handle_t **dslist = NULL;
6135                 size_t i, count = 0;
6136                 char *protocol = NULL;
6137 
6138                 if (op == OP_SHARE && argc > 0) {
6139                         if (strcmp(argv[0], "nfs") != 0 &&
6140                             strcmp(argv[0], "smb") != 0) {
6141                                 (void) fprintf(stderr, gettext("share type "
6142                                     "must be 'nfs' or 'smb'\n"));
6143                                 usage(B_FALSE);
6144                         }
6145                         protocol = argv[0];
6146                         argc--;
6147                         argv++;
6148                 }
6149 
6150                 if (argc != 0) {
6151                         (void) fprintf(stderr, gettext("too many arguments\n"));
6152                         usage(B_FALSE);
6153                 }
6154 
6155                 start_progress_timer();
6156                 get_all_datasets(&dslist, &count, verbose);

6157 
6158                 if (count == 0)
6159                         return (0);
6160 
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);
6170                 }
6171 
6172                 for (i = 0; i < count; i++) {
6173                         if (verbose)
6174                                 report_mount_progress(i, count);
6175 
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);



















6183         } else if (argc == 0) {
6184                 struct mnttab entry;
6185 
6186                 if ((op == OP_SHARE) || (options != NULL)) {
6187                         (void) fprintf(stderr, gettext("missing filesystem "
6188                             "argument (specify -a for all)\n"));
6189                         usage(B_FALSE);
6190                 }
6191 
6192                 /*
6193                  * When mount is given no arguments, go through /etc/mnttab and
6194                  * display any active ZFS mounts.  We hide any snapshots, since
6195                  * they are controlled automatically.
6196                  */
6197                 rewind(mnttab_file);
6198                 while (getmntent(mnttab_file, &entry) == 0) {
6199                         if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0 ||
6200                             strchr(entry.mnt_special, '@') != NULL)
6201                                 continue;
6202 




  43 #include <stddef.h>
  44 #include <stdio.h>
  45 #include <stdlib.h>
  46 #include <strings.h>
  47 #include <unistd.h>
  48 #include <fcntl.h>
  49 #include <zone.h>
  50 #include <grp.h>
  51 #include <pwd.h>
  52 #include <signal.h>
  53 #include <sys/debug.h>
  54 #include <sys/list.h>
  55 #include <sys/mkdev.h>
  56 #include <sys/mntent.h>
  57 #include <sys/mnttab.h>
  58 #include <sys/mount.h>
  59 #include <sys/stat.h>
  60 #include <sys/fs/zfs.h>
  61 #include <sys/types.h>
  62 #include <time.h>
  63 #include <synch.h>
  64 
  65 #include <libzfs.h>
  66 #include <libzfs_core.h>
  67 #include <zfs_prop.h>
  68 #include <zfs_deleg.h>
  69 #include <libuutil.h>
  70 #include <aclutils.h>
  71 #include <directory.h>
  72 #include <idmap.h>
  73 #include <libshare.h>
  74 
  75 #include "zfs_iter.h"
  76 #include "zfs_util.h"
  77 #include "zfs_comutil.h"
  78 
  79 libzfs_handle_t *g_zfs;
  80 
  81 static FILE *mnttab_file;
  82 static char history_str[HIS_MAX_RECORD_LEN];
  83 static boolean_t log_history = B_TRUE;


5733                     holds_callback, &cb);
5734                 if (ret != 0)
5735                         ++errors;
5736         }
5737 
5738         /*
5739          *  2. print holds data
5740          */
5741         print_holds(scripted, cb.cb_max_namelen, cb.cb_max_taglen, nvl);
5742 
5743         if (nvlist_empty(nvl))
5744                 (void) printf(gettext("no datasets available\n"));
5745 
5746         nvlist_free(nvl);
5747 
5748         return (0 != errors);
5749 }
5750 
5751 #define CHECK_SPINNER 30
5752 #define SPINNER_TIME 3          /* seconds */
5753 #define MOUNT_TIME 1            /* seconds */
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 
5760 static int
5761 get_one_dataset(zfs_handle_t *zhp, void *data)
5762 {
5763         static char *spin[] = { "-", "\\", "|", "/" };
5764         static int spinval = 0;
5765         static int spincheck = 0;
5766         static time_t last_spin_time = (time_t)0;
5767         get_all_state_t *state = data;
5768         zfs_type_t type = zfs_get_type(zhp);
5769 
5770         if (state->ga_verbose) {
5771                 if (--spincheck < 0) {
5772                         time_t now = time(NULL);
5773                         if (last_spin_time + SPINNER_TIME < now) {
5774                                 update_progress(spin[spinval++ % 4]);
5775                                 last_spin_time = now;
5776                         }
5777                         spincheck = CHECK_SPINNER;
5778                 }
5779         }
5780 
5781         /*
5782          * Interate over any nested datasets.
5783          */
5784         if (zfs_iter_filesystems(zhp, get_one_dataset, data) != 0) {
5785                 zfs_close(zhp);
5786                 return (1);
5787         }
5788 
5789         /*
5790          * Skip any datasets whose type does not match.
5791          */
5792         if ((type & ZFS_TYPE_FILESYSTEM) == 0) {
5793                 zfs_close(zhp);
5794                 return (0);
5795         }
5796         libzfs_add_handle(state->ga_cbp, zhp);
5797         assert(state->ga_cbp->cb_used <= state->ga_cbp->cb_alloc);
5798 
5799         return (0);
5800 }
5801 
5802 static void
5803 get_all_datasets(get_all_cb_t *cbp, boolean_t verbose)
5804 {
5805         get_all_state_t state = {
5806             .ga_verbose = verbose,
5807             .ga_cbp = cbp
5808         };
5809 
5810         if (verbose)
5811                 set_progress_header(gettext("Reading ZFS config"));
5812         (void) zfs_iter_root(g_zfs, get_one_dataset, &state);
5813 



5814         if (verbose)
5815                 finish_progress(gettext("done."));
5816 }
5817 
5818 /*
5819  * Generic callback for sharing or mounting filesystems.  Because the code is so
5820  * similar, we have a common function with an extra parameter to determine which
5821  * mode we are using.
5822  */
5823 typedef enum { OP_SHARE, OP_MOUNT } share_mount_op_t;

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 
5837 /*
5838  * Share or mount a dataset.
5839  */
5840 static int
5841 share_mount_one(zfs_handle_t *zhp, int op, int flags, char *protocol,
5842     boolean_t explicit, const char *options)
5843 {
5844         char mountpoint[ZFS_MAXPROPLEN];
5845         char shareopts[ZFS_MAXPROPLEN];
5846         char smbshareopts[ZFS_MAXPROPLEN];
5847         const char *cmdname = op == OP_SHARE ? "share" : "mount";
5848         struct mnttab mnt;
5849         uint64_t zoned, canmount;
5850         boolean_t shared_nfs, shared_smb;
5851 
5852         assert(zfs_get_type(zhp) & ZFS_TYPE_FILESYSTEM);
5853 
5854         /*
5855          * Check to make sure we can mount/share this dataset.  If we
5856          * are in the global zone and the filesystem is exported to a


6057         ++current;
6058 
6059         /* display header if we're here for the first time */
6060         if (current == 1) {
6061                 set_progress_header(gettext("Mounting ZFS filesystems"));
6062         } else if (current != total && last_progress_time + MOUNT_TIME >= now) {
6063                 /* too soon to report again */
6064                 return;
6065         }
6066 
6067         last_progress_time = now;
6068 
6069         (void) sprintf(info, "(%d/%d)", current, total);
6070 
6071         if (current == total)
6072                 finish_progress(info);
6073         else
6074                 update_progress(info);
6075 }
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 
6100 static void
6101 append_options(char *mntopts, char *newopts)
6102 {
6103         int len = strlen(mntopts);
6104 
6105         /* original length plus new string to append plus 1 for the comma */
6106         if (len + 1 + strlen(newopts) >= MNT_LINE_MAX) {
6107                 (void) fprintf(stderr, gettext("the opts argument for "
6108                     "'%c' option is too long (more than %d chars)\n"),
6109                     "-o", MNT_LINE_MAX);
6110                 usage(B_FALSE);
6111         }
6112 
6113         if (*mntopts)
6114                 mntopts[len++] = ',';
6115 
6116         (void) strcpy(&mntopts[len], newopts);
6117 }
6118 
6119 static int


6152                 case 'O':
6153                         flags |= MS_OVERLAY;
6154                         break;
6155                 case ':':
6156                         (void) fprintf(stderr, gettext("missing argument for "
6157                             "'%c' option\n"), optopt);
6158                         usage(B_FALSE);
6159                         break;
6160                 case '?':
6161                         (void) fprintf(stderr, gettext("invalid option '%c'\n"),
6162                             optopt);
6163                         usage(B_FALSE);
6164                 }
6165         }
6166 
6167         argc -= optind;
6168         argv += optind;
6169 
6170         /* check number of arguments */
6171         if (do_all) {


6172                 char *protocol = NULL;
6173 
6174                 if (op == OP_SHARE && argc > 0) {
6175                         if (strcmp(argv[0], "nfs") != 0 &&
6176                             strcmp(argv[0], "smb") != 0) {
6177                                 (void) fprintf(stderr, gettext("share type "
6178                                     "must be 'nfs' or 'smb'\n"));
6179                                 usage(B_FALSE);
6180                         }
6181                         protocol = argv[0];
6182                         argc--;
6183                         argv++;
6184                 }
6185 
6186                 if (argc != 0) {
6187                         (void) fprintf(stderr, gettext("too many arguments\n"));
6188                         usage(B_FALSE);
6189                 }
6190 
6191                 start_progress_timer();
6192                 get_all_cb_t cb = { 0 };
6193                 get_all_datasets(&cb, verbose);
6194 
6195                 if (cb.cb_used == 0)
6196                         return (0);
6197 
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                         }









6208                 }
6209 
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;
6226 
6227                 for (int i = 0; i < cb.cb_used; i++)
6228                         zfs_close(cb.cb_handles[i]);
6229                 free(cb.cb_handles);
6230         } else if (argc == 0) {
6231                 struct mnttab entry;
6232 
6233                 if ((op == OP_SHARE) || (options != NULL)) {
6234                         (void) fprintf(stderr, gettext("missing filesystem "
6235                             "argument (specify -a for all)\n"));
6236                         usage(B_FALSE);
6237                 }
6238 
6239                 /*
6240                  * When mount is given no arguments, go through /etc/mnttab and
6241                  * display any active ZFS mounts.  We hide any snapshots, since
6242                  * they are controlled automatically.
6243                  */
6244                 rewind(mnttab_file);
6245                 while (getmntent(mnttab_file, &entry) == 0) {
6246                         if (strcmp(entry.mnt_fstype, MNTTYPE_ZFS) != 0 ||
6247                             strchr(entry.mnt_special, '@') != NULL)
6248                                 continue;
6249