Print this page
8115 parallel zfs mount


   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  24  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  25  * Copyright (c) 2014, 2016 by Delphix. All rights reserved.
  26  * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
  27  * Copyright 2017 Joyent, Inc.
  28  * Copyright 2017 RackTop Systems.
  29  */
  30 
  31 /*
  32  * Routines to manage ZFS mounts.  We separate all the nasty routines that have
  33  * to deal with the OS.  The following functions are the main entry points --
  34  * they are used by mount and unmount and when changing a filesystem's
  35  * mountpoint.
  36  *
  37  *      zfs_is_mounted()
  38  *      zfs_mount()
  39  *      zfs_unmount()
  40  *      zfs_unmountall()
  41  *
  42  * This file also contains the functions used to manage sharing filesystems via
  43  * NFS and iSCSI:
  44  *
  45  *      zfs_is_shared()


  62  *
  63  *      zpool_enable_datasets()
  64  *      zpool_disable_datasets()
  65  */
  66 
  67 #include <dirent.h>
  68 #include <dlfcn.h>
  69 #include <errno.h>
  70 #include <fcntl.h>
  71 #include <libgen.h>
  72 #include <libintl.h>
  73 #include <stdio.h>
  74 #include <stdlib.h>
  75 #include <strings.h>
  76 #include <unistd.h>
  77 #include <zone.h>
  78 #include <sys/mntent.h>
  79 #include <sys/mount.h>
  80 #include <sys/stat.h>
  81 #include <sys/statvfs.h>

  82 
  83 #include <libzfs.h>
  84 
  85 #include "libzfs_impl.h"
  86 
  87 #include <libshare.h>
  88 #include <sys/systeminfo.h>
  89 #define MAXISALEN       257     /* based on sysinfo(2) man page */
  90 



  91 static int zfs_share_proto(zfs_handle_t *, zfs_share_proto_t *);
  92 zfs_share_type_t zfs_is_shared_proto(zfs_handle_t *, char **,
  93     zfs_share_proto_t);
  94 
  95 /*
  96  * The share protocols table must be in the same order as the zfs_share_proto_t
  97  * enum in libzfs_impl.h
  98  */
  99 typedef struct {
 100         zfs_prop_t p_prop;
 101         char *p_name;
 102         int p_share_err;
 103         int p_unshare_err;
 104 } proto_table_t;
 105 
 106 proto_table_t proto_table[PROTO_END] = {
 107         {ZFS_PROP_SHARENFS, "nfs", EZFS_SHARENFSFAILED, EZFS_UNSHARENFSFAILED},
 108         {ZFS_PROP_SHARESMB, "smb", EZFS_SHARESMBFAILED, EZFS_UNSHARESMBFAILED},
 109 };
 110 


1060 {
1061         char mountpoint[ZFS_MAXPROPLEN];
1062         zprop_source_t source;
1063 
1064         if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint),
1065             &source))
1066                 return;
1067 
1068         if (source == ZPROP_SRC_DEFAULT ||
1069             source == ZPROP_SRC_INHERITED) {
1070                 /*
1071                  * Try to remove the directory, silently ignoring any errors.
1072                  * The filesystem may have since been removed or moved around,
1073                  * and this error isn't really useful to the administrator in
1074                  * any way.
1075                  */
1076                 (void) rmdir(mountpoint);
1077         }
1078 }
1079 




1080 void
1081 libzfs_add_handle(get_all_cb_t *cbp, zfs_handle_t *zhp)
1082 {
1083         if (cbp->cb_alloc == cbp->cb_used) {
1084                 size_t newsz;
1085                 void *ptr;
1086 
1087                 newsz = cbp->cb_alloc ? cbp->cb_alloc * 2 : 64;
1088                 ptr = zfs_realloc(zhp->zfs_hdl,
1089                     cbp->cb_handles, cbp->cb_alloc * sizeof (void *),
1090                     newsz * sizeof (void *));
1091                 cbp->cb_handles = ptr;
1092                 cbp->cb_alloc = newsz;
1093         }
1094         cbp->cb_handles[cbp->cb_used++] = zhp;
1095 }
1096 



1097 static int
1098 mount_cb(zfs_handle_t *zhp, void *data)
1099 {
1100         get_all_cb_t *cbp = data;
1101 
1102         if (!(zfs_get_type(zhp) & ZFS_TYPE_FILESYSTEM)) {
1103                 zfs_close(zhp);
1104                 return (0);
1105         }
1106 
1107         if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_NOAUTO) {
1108                 zfs_close(zhp);
1109                 return (0);
1110         }
1111 
1112         /*
1113          * If this filesystem is inconsistent and has a receive resume
1114          * token, we can not mount it.
1115          */
1116         if (zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) &&
1117             zfs_prop_get(zhp, ZFS_PROP_RECEIVE_RESUME_TOKEN,
1118             NULL, 0, NULL, NULL, 0, B_TRUE) == 0) {
1119                 zfs_close(zhp);
1120                 return (0);
1121         }
1122 
1123         libzfs_add_handle(cbp, zhp);
1124         if (zfs_iter_filesystems(zhp, mount_cb, cbp) != 0) {
1125                 zfs_close(zhp);
1126                 return (-1);
1127         }
1128         return (0);
1129 }
1130 















1131 int
1132 libzfs_dataset_cmp(const void *a, const void *b)
1133 {
1134         zfs_handle_t **za = (zfs_handle_t **)a;
1135         zfs_handle_t **zb = (zfs_handle_t **)b;


1136         char mounta[MAXPATHLEN];
1137         char mountb[MAXPATHLEN];


1138         boolean_t gota, gotb;
1139 
1140         if ((gota = (zfs_get_type(*za) == ZFS_TYPE_FILESYSTEM)) != 0)
1141                 verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta,

1142                     sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0);
1143         if ((gotb = (zfs_get_type(*zb) == ZFS_TYPE_FILESYSTEM)) != 0)
1144                 verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb,


1145                     sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0);

1146 
1147         if (gota && gotb)
1148                 return (strcmp(mounta, mountb));















1149 
1150         if (gota)
1151                 return (-1);
1152         if (gotb)
1153                 return (1);
1154 
1155         return (strcmp(zfs_get_name(a), zfs_get_name(b)));




1156 }
1157 
1158 /*





















































































































































































































1159  * Mount and share all datasets within the given pool.  This assumes that no
1160  * datasets within the pool are currently mounted.  Because users can create
1161  * complicated nested hierarchies of mountpoints, we first gather all the
1162  * datasets and mountpoints within the pool, and sort them by mountpoint.  Once
1163  * we have the list of all filesystems, we iterate over them in order and mount
1164  * and/or share each one.
1165  */
1166 #pragma weak zpool_mount_datasets = zpool_enable_datasets
1167 int
1168 zpool_enable_datasets(zpool_handle_t *zhp, const char *mntopts, int flags)
1169 {
1170         get_all_cb_t cb = { 0 };
1171         libzfs_handle_t *hdl = zhp->zpool_hdl;
1172         zfs_handle_t *zfsp;
1173         int i, ret = -1;
1174         int *good;
1175 
1176         /*
1177          * Gather all non-snap datasets within the pool.
1178          */
1179         if ((zfsp = zfs_open(hdl, zhp->zpool_name, ZFS_TYPE_DATASET)) == NULL)
1180                 goto out;
1181 
1182         libzfs_add_handle(&cb, zfsp);
1183         if (zfs_iter_filesystems(zfsp, mount_cb, &cb) != 0)
1184                 goto out;
1185         /*
1186          * Sort the datasets by mountpoint.
1187          */
1188         qsort(cb.cb_handles, cb.cb_used, sizeof (void *),
1189             libzfs_dataset_cmp);
1190 
1191         /*
1192          * And mount all the datasets, keeping track of which ones
1193          * succeeded or failed.

1194          */
1195         if ((good = zfs_alloc(zhp->zpool_hdl,
1196             cb.cb_used * sizeof (int))) == NULL)
1197                 goto out;
1198 
1199         ret = 0;
1200         for (i = 0; i < cb.cb_used; i++) {
1201                 if (zfs_mount(cb.cb_handles[i], mntopts, flags) != 0)
1202                         ret = -1;
1203                 else
1204                         good[i] = 1;
1205         }
1206 
1207         /*
1208          * Then share all the ones that need to be shared. This needs
1209          * to be a separate pass in order to avoid excessive reloading
1210          * of the configuration. Good should never be NULL since
1211          * zfs_alloc is supposed to exit if memory isn't available.
1212          */
1213         for (i = 0; i < cb.cb_used; i++) {
1214                 if (good[i] && zfs_share(cb.cb_handles[i]) != 0)
1215                         ret = -1;
1216         }

1217 
1218         free(good);




1219 
1220 out:
1221         for (i = 0; i < cb.cb_used; i++)
1222                 zfs_close(cb.cb_handles[i]);
1223         free(cb.cb_handles);
1224 
1225         return (ret);
1226 }
1227 
1228 static int
1229 mountpoint_compare(const void *a, const void *b)
1230 {
1231         const char *mounta = *((char **)a);
1232         const char *mountb = *((char **)b);
1233 
1234         return (strcmp(mountb, mounta));
1235 }
1236 
1237 /* alias for 2002/240 */
1238 #pragma weak zpool_unmount_datasets = zpool_disable_datasets
1239 /*
1240  * Unshare and unmount all datasets within the given pool.  We don't want to
1241  * rely on traversing the DSL to discover the filesystems within the pool,




   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  24  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  25  * Copyright (c) 2014, 2017 by Delphix. All rights reserved.
  26  * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
  27  * Copyright 2017 Joyent, Inc.
  28  * Copyright 2017 RackTop Systems.
  29  */
  30 
  31 /*
  32  * Routines to manage ZFS mounts.  We separate all the nasty routines that have
  33  * to deal with the OS.  The following functions are the main entry points --
  34  * they are used by mount and unmount and when changing a filesystem's
  35  * mountpoint.
  36  *
  37  *      zfs_is_mounted()
  38  *      zfs_mount()
  39  *      zfs_unmount()
  40  *      zfs_unmountall()
  41  *
  42  * This file also contains the functions used to manage sharing filesystems via
  43  * NFS and iSCSI:
  44  *
  45  *      zfs_is_shared()


  62  *
  63  *      zpool_enable_datasets()
  64  *      zpool_disable_datasets()
  65  */
  66 
  67 #include <dirent.h>
  68 #include <dlfcn.h>
  69 #include <errno.h>
  70 #include <fcntl.h>
  71 #include <libgen.h>
  72 #include <libintl.h>
  73 #include <stdio.h>
  74 #include <stdlib.h>
  75 #include <strings.h>
  76 #include <unistd.h>
  77 #include <zone.h>
  78 #include <sys/mntent.h>
  79 #include <sys/mount.h>
  80 #include <sys/stat.h>
  81 #include <sys/statvfs.h>
  82 #include <sys/taskq.h>
  83 
  84 #include <libzfs.h>
  85 
  86 #include "libzfs_impl.h"
  87 
  88 #include <libshare.h>
  89 #include <sys/systeminfo.h>
  90 #define MAXISALEN       257     /* based on sysinfo(2) man page */
  91 
  92 static int mount_tq_nthr = 512; /* taskq threads for multi-threaded mounting */
  93 
  94 static void zfs_mount_task(void *);
  95 static int zfs_share_proto(zfs_handle_t *, zfs_share_proto_t *);
  96 zfs_share_type_t zfs_is_shared_proto(zfs_handle_t *, char **,
  97     zfs_share_proto_t);
  98 
  99 /*
 100  * The share protocols table must be in the same order as the zfs_share_proto_t
 101  * enum in libzfs_impl.h
 102  */
 103 typedef struct {
 104         zfs_prop_t p_prop;
 105         char *p_name;
 106         int p_share_err;
 107         int p_unshare_err;
 108 } proto_table_t;
 109 
 110 proto_table_t proto_table[PROTO_END] = {
 111         {ZFS_PROP_SHARENFS, "nfs", EZFS_SHARENFSFAILED, EZFS_UNSHARENFSFAILED},
 112         {ZFS_PROP_SHARESMB, "smb", EZFS_SHARESMBFAILED, EZFS_UNSHARESMBFAILED},
 113 };
 114 


1064 {
1065         char mountpoint[ZFS_MAXPROPLEN];
1066         zprop_source_t source;
1067 
1068         if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint),
1069             &source))
1070                 return;
1071 
1072         if (source == ZPROP_SRC_DEFAULT ||
1073             source == ZPROP_SRC_INHERITED) {
1074                 /*
1075                  * Try to remove the directory, silently ignoring any errors.
1076                  * The filesystem may have since been removed or moved around,
1077                  * and this error isn't really useful to the administrator in
1078                  * any way.
1079                  */
1080                 (void) rmdir(mountpoint);
1081         }
1082 }
1083 
1084 /*
1085  * Add the given zfs handle to the cb_handles array, dynamically reallocating
1086  * the array if it is out of space.
1087  */
1088 void
1089 libzfs_add_handle(get_all_cb_t *cbp, zfs_handle_t *zhp)
1090 {
1091         if (cbp->cb_alloc == cbp->cb_used) {
1092                 size_t newsz;
1093                 zfs_handle_t **newhandles;
1094 
1095                 newsz = cbp->cb_alloc != 0 ? cbp->cb_alloc * 2 : 64;
1096                 newhandles = zfs_realloc(zhp->zfs_hdl,
1097                     cbp->cb_handles, cbp->cb_alloc * sizeof (zfs_handle_t *),
1098                     newsz * sizeof (zfs_handle_t *));
1099                 cbp->cb_handles = newhandles;
1100                 cbp->cb_alloc = newsz;
1101         }
1102         cbp->cb_handles[cbp->cb_used++] = zhp;
1103 }
1104 
1105 /*
1106  * Recursive helper function used during file system enumeration
1107  */
1108 static int
1109 zfs_iter_cb(zfs_handle_t *zhp, void *data)
1110 {
1111         get_all_cb_t *cbp = data;
1112 
1113         if (!(zfs_get_type(zhp) & ZFS_TYPE_FILESYSTEM)) {
1114                 zfs_close(zhp);
1115                 return (0);
1116         }
1117 
1118         if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) == ZFS_CANMOUNT_NOAUTO) {
1119                 zfs_close(zhp);
1120                 return (0);
1121         }
1122 
1123         /*
1124          * If this filesystem is inconsistent and has a receive resume
1125          * token, we can not mount it.
1126          */
1127         if (zfs_prop_get_int(zhp, ZFS_PROP_INCONSISTENT) &&
1128             zfs_prop_get(zhp, ZFS_PROP_RECEIVE_RESUME_TOKEN,
1129             NULL, 0, NULL, NULL, 0, B_TRUE) == 0) {
1130                 zfs_close(zhp);
1131                 return (0);
1132         }
1133 
1134         libzfs_add_handle(cbp, zhp);
1135         if (zfs_iter_filesystems(zhp, zfs_iter_cb, cbp) != 0) {
1136                 zfs_close(zhp);
1137                 return (-1);
1138         }
1139         return (0);
1140 }
1141 
1142 /*
1143  * Sort comparator that compares two mountpoint paths. We sort these paths so
1144  * that subdirectories immediately follow their parents. This means that we
1145  * effectively treat the '/' character as the lowest value non-nul char. An
1146  * example sorted list using this comparator would look like:
1147  *
1148  * /foo
1149  * /foo/bar
1150  * /foo/bar/baz
1151  * /foo/baz
1152  * /foo.bar
1153  *
1154  * The mounting code depends on this ordering to deterministically iterate
1155  * over filesystems in order to spawn parallel mount tasks.
1156  */
1157 int
1158 mountpoint_cmp(const void *arga, const void *argb)
1159 {
1160         zfs_handle_t *const *zap = arga;
1161         zfs_handle_t *za = *zap;
1162         zfs_handle_t *const *zbp = argb;
1163         zfs_handle_t *zb = *zbp;
1164         char mounta[MAXPATHLEN];
1165         char mountb[MAXPATHLEN];
1166         const char *a = mounta;
1167         const char *b = mountb;
1168         boolean_t gota, gotb;
1169 
1170         gota = (zfs_get_type(za) == ZFS_TYPE_FILESYSTEM);
1171         if (gota) {
1172                 verify(zfs_prop_get(za, ZFS_PROP_MOUNTPOINT, mounta,
1173                     sizeof (mounta), NULL, NULL, 0, B_FALSE) == 0);
1174         }
1175         gotb = (zfs_get_type(zb) == ZFS_TYPE_FILESYSTEM);
1176         if (gotb) {
1177                 verify(zfs_prop_get(zb, ZFS_PROP_MOUNTPOINT, mountb,
1178                     sizeof (mountb), NULL, NULL, 0, B_FALSE) == 0);
1179         }
1180 
1181         if (gota && gotb) {
1182                 while (*a != '\0' && (*a == *b)) {
1183                         a++;
1184                         b++;
1185                 }
1186                 if (*a == *b)
1187                         return (0);
1188                 if (*a == '\0')
1189                         return (-1);
1190                 if (*b == '\0')
1191                         return (1);
1192                 if (*a == '/')
1193                         return (-1);
1194                 if (*b == '/')
1195                         return (1);
1196                 return (*a < *b ? -1 : *a > *b);
1197         }
1198 
1199         if (gota)
1200                 return (-1);
1201         if (gotb)
1202                 return (1);
1203 
1204         /*
1205          * If neither filesystem has a mountpoint, revert to sorting by
1206          * dataset name.
1207          */
1208         return (strcmp(zfs_get_name(za), zfs_get_name(zb)));
1209 }
1210 
1211 /*
1212  * Return true if path2 is a child of path1.
1213  */
1214 static boolean_t
1215 libzfs_path_contains(const char *path1, const char *path2)
1216 {
1217         return (strstr(path2, path1) == path2 && path2[strlen(path1)] == '/');
1218 }
1219 
1220 /*
1221  * Given a mountpoint specified by idx in the handles array, find the first
1222  * non-descendent of that mountpoint and return its index. Descendant paths
1223  * start with the parent's path. This function relies on the ordering
1224  * enforced by mountpoint_cmp().
1225  */
1226 static int
1227 non_descendant_idx(zfs_handle_t **handles, size_t num_handles, int idx)
1228 {
1229         char parent[ZFS_MAXPROPLEN];
1230         char child[ZFS_MAXPROPLEN];
1231         int i;
1232 
1233         verify(zfs_prop_get(handles[idx], ZFS_PROP_MOUNTPOINT, parent,
1234             sizeof (parent), NULL, NULL, 0, B_FALSE) == 0);
1235 
1236         for (i = idx + 1; i < num_handles; i++) {
1237                 verify(zfs_prop_get(handles[i], ZFS_PROP_MOUNTPOINT, child,
1238                     sizeof (child), NULL, NULL, 0, B_FALSE) == 0);
1239                 if (!libzfs_path_contains(parent, child))
1240                         break;
1241         }
1242         return (i);
1243 }
1244 
1245 typedef struct mnt_param {
1246         libzfs_handle_t *mnt_hdl;
1247         taskq_t         *mnt_tq;
1248         zfs_handle_t    **mnt_zhps; /* filesystems to mount */
1249         size_t          mnt_num_handles;
1250         int             mnt_idx;        /* Index of selected entry to mount */
1251         zfs_iter_f      mnt_func;
1252         void            *mnt_data;
1253 } mnt_param_t;
1254 
1255 /*
1256  * Allocate and populate the parameter struct for mount function, and
1257  * schedule mounting of the entry selected by idx.
1258  */
1259 static void
1260 zfs_dispatch_mount(libzfs_handle_t *hdl, zfs_handle_t **handles,
1261     size_t num_handles, int idx, zfs_iter_f func, void *data, taskq_t *tq)
1262 {
1263         mnt_param_t *mnt_param = zfs_alloc(hdl, sizeof (mnt_param_t));
1264 
1265         mnt_param->mnt_hdl = hdl;
1266         mnt_param->mnt_tq = tq;
1267         mnt_param->mnt_zhps = handles;
1268         mnt_param->mnt_num_handles = num_handles;
1269         mnt_param->mnt_idx = idx;
1270         mnt_param->mnt_func = func;
1271         mnt_param->mnt_data = data;
1272 
1273         (void) taskq_dispatch(tq, zfs_mount_task, (void*)mnt_param, TQ_SLEEP);
1274 }
1275 
1276 /*
1277  * This is the structure used to keep state of mounting or sharing operations
1278  * during a call to zpool_enable_datasets().
1279  */
1280 typedef struct mount_state {
1281         /*
1282          * ms_mntstatus is set to -1 if any mount fails. While multiple threads
1283          * could update this variable concurrently, no synchronization is
1284          * needed as it's only ever set to -1.
1285          */
1286         int             ms_mntstatus;
1287         int             ms_mntflags;
1288         const char      *ms_mntopts;
1289 } mount_state_t;
1290 
1291 static int
1292 zfs_mount_one(zfs_handle_t *zhp, void *arg)
1293 {
1294         mount_state_t *ms = arg;
1295         int ret = 0;
1296 
1297         if (zfs_mount(zhp, ms->ms_mntopts, ms->ms_mntflags) != 0)
1298                 ret = ms->ms_mntstatus = -1;
1299         return (ret);
1300 }
1301 
1302 static int
1303 zfs_share_one(zfs_handle_t *zhp, void *arg)
1304 {
1305         mount_state_t *ms = arg;
1306         int ret = 0;
1307 
1308         if (zfs_share(zhp) != 0)
1309                 ret = ms->ms_mntstatus = -1;
1310         return (ret);
1311 }
1312 
1313 /*
1314  * Task queue function to mount one file system. On completion, it finds and
1315  * schedules its children to be mounted. This depends on the sorting done in
1316  * zfs_foreach_mountpoint(). Note that the degenerate case (chain of entries
1317  * each descending from the previous) will have no parallelism since we always
1318  * have to wait for the parent to finish mounting before we can schedule
1319  * its children.
1320  */
1321 static void
1322 zfs_mount_task(void *arg)
1323 {
1324         mnt_param_t *mp = arg;
1325         int idx = mp->mnt_idx;
1326         zfs_handle_t **handles = mp->mnt_zhps;
1327         size_t num_handles = mp->mnt_num_handles;
1328         char mountpoint[ZFS_MAXPROPLEN];
1329 
1330         verify(zfs_prop_get(handles[idx], ZFS_PROP_MOUNTPOINT, mountpoint,
1331             sizeof (mountpoint), NULL, NULL, 0, B_FALSE) == 0);
1332 
1333         if (mp->mnt_func(handles[idx], mp->mnt_data) != 0)
1334                 return;
1335 
1336         /*
1337          * We dispatch tasks to mount filesystems with mountpoints underneath
1338          * this one. We do this by dispatching the next filesystem with a
1339          * descendant mountpoint of the one we just mounted, then skip all of
1340          * its descendants, dispatch the next descendant mountpoint, and so on.
1341          * The non_descendant_idx() function skips over filesystems that are
1342          * descendants of the filesystem we just dispatched.
1343          */
1344         for (int i = idx + 1; i < num_handles;
1345             i = non_descendant_idx(handles, num_handles, i)) {
1346                 char child[ZFS_MAXPROPLEN];
1347                 verify(zfs_prop_get(handles[i], ZFS_PROP_MOUNTPOINT,
1348                     child, sizeof (child), NULL, NULL, 0, B_FALSE) == 0);
1349 
1350                 if (!libzfs_path_contains(mountpoint, child))
1351                         break; /* not a descendant, return */
1352                 zfs_dispatch_mount(mp->mnt_hdl, handles, num_handles, i,
1353                     mp->mnt_func, mp->mnt_data, mp->mnt_tq);
1354         }
1355         free(mp);
1356 }
1357 
1358 /*
1359  * Issue the func callback for each ZFS handle contained in the handles
1360  * array. This function is used to mount all datasets, and so this function
1361  * guarantees that filesystems for parent mountpoints are called before their
1362  * children. As such, before issuing any callbacks, we first sort the array
1363  * of handles by mountpoint.
1364  *
1365  * Callbacks are issued in one of two ways:
1366  *
1367  * 1. Sequentially: If the parallel argument is B_FALSE or the ZFS_SERIAL_MOUNT
1368  *    environment variable is set, then we issue callbacks sequentially.
1369  *
1370  * 2. In parallel: If the parallel argument is B_TRUE and the ZFS_SERIAL_MOUNT
1371  *    environment variable is not set, then we use a taskq to dispatch threads
1372  *    to mount filesystems is parallel. This function dispatches tasks to mount
1373  *    the filesystems at the top-level mountpoints, and these tasks in turn
1374  *    are responsible for recursively mounting filesystems in their children
1375  *    mountpoints.
1376  */
1377 void
1378 zfs_foreach_mountpoint(libzfs_handle_t *hdl, zfs_handle_t **handles,
1379     size_t num_handles, zfs_iter_f func, void *data, boolean_t parallel)
1380 {
1381         /*
1382          * The ZFS_SERIAL_MOUNT environment variable is an undocumented
1383          * variable that can be used as a convenience to do a/b comparison
1384          * of serial vs. parallel mounting.
1385          */
1386         boolean_t serial_mount = !parallel ||
1387             (getenv("ZFS_SERIAL_MOUNT") != NULL);
1388 
1389         /*
1390          * Sort the datasets by mountpoint. See mountpoint_cmp for details
1391          * of how these are sorted.
1392          */
1393         qsort(handles, num_handles, sizeof (zfs_handle_t *), mountpoint_cmp);
1394 
1395         if (serial_mount) {
1396                 for (int i = 0; i < num_handles; i++) {
1397                         func(handles[i], data);
1398                 }
1399                 return;
1400         }
1401 
1402         /*
1403          * Issue the callback function for each dataset using a parallel
1404          * algorithm that uses a taskq to manage threads.
1405          */
1406         taskq_t *tq = taskq_create("mount_taskq", mount_tq_nthr, 0,
1407             mount_tq_nthr, mount_tq_nthr, TASKQ_DYNAMIC | TASKQ_PREPOPULATE);
1408 
1409         /*
1410          * There may be multiple "top level" mountpoints outside of the pool's
1411          * root mountpoint, e.g.: /foo /bar. Dispatch a mount task for each of
1412          * these.
1413          */
1414         for (int i = 0; i < num_handles;
1415             i = non_descendant_idx(handles, num_handles, i)) {
1416                 zfs_dispatch_mount(hdl, handles, num_handles, i, func, data,
1417                     tq);
1418         }
1419 
1420         taskq_wait(tq); /* wait for all scheduled mounts to complete */
1421         taskq_destroy(tq);
1422 }
1423 
1424 /*
1425  * Mount and share all datasets within the given pool.  This assumes that no
1426  * datasets within the pool are currently mounted.




1427  */
1428 #pragma weak zpool_mount_datasets = zpool_enable_datasets
1429 int
1430 zpool_enable_datasets(zpool_handle_t *zhp, const char *mntopts, int flags)
1431 {
1432         get_all_cb_t cb = { 0 };
1433         mount_state_t ms = { 0 };
1434         zfs_handle_t *zfsp;
1435         sa_init_selective_arg_t sharearg;
1436         int ret = 0;
1437 
1438         if ((zfsp = zfs_open(zhp->zpool_hdl, zhp->zpool_name,
1439             ZFS_TYPE_DATASET)) == NULL)


1440                 goto out;
1441 








1442 
1443         /*
1444          * Gather all non-snapshot datasets within the pool. Start by adding
1445          * the root filesystem for this pool to the list, and then iterate
1446          * over all child filesystems.
1447          */
1448         libzfs_add_handle(&cb, zfsp);
1449         if (zfs_iter_filesystems(zfsp, zfs_iter_cb, &cb) != 0)
1450                 goto out;
1451 
1452         ms.ms_mntopts = mntopts;
1453         ms.ms_mntflags = flags;
1454         zfs_foreach_mountpoint(zhp->zpool_hdl, cb.cb_handles, cb.cb_used,
1455             zfs_mount_one, &ms, B_TRUE);
1456         if (ms.ms_mntstatus != 0)
1457                 ret = ms.ms_mntstatus;

1458 
1459         /*
1460          * Share all filesystems that need to be shared. This needs to be
1461          * a separate pass because libshare is not mt-safe, and so we need
1462          * to share serially.

1463          */
1464         sharearg.zhandle_arr = cb.cb_handles;
1465         sharearg.zhandle_len = cb.cb_used;
1466         if ((ret = zfs_init_libshare_arg(zhp->zpool_hdl,
1467             SA_INIT_SHARE_API_SELECTIVE, &sharearg)) != 0)
1468                 goto out;
1469 
1470         ms.ms_mntstatus = 0;
1471         zfs_foreach_mountpoint(zhp->zpool_hdl, cb.cb_handles, cb.cb_used,
1472             zfs_share_one, &ms, B_FALSE);
1473         if (ms.ms_mntstatus != 0)
1474                 ret = ms.ms_mntstatus;
1475 
1476 out:
1477         for (int i = 0; i < cb.cb_used; i++)
1478                 zfs_close(cb.cb_handles[i]);
1479         free(cb.cb_handles);
1480 
1481         return (ret);
1482 }
1483 
1484 static int
1485 mountpoint_compare(const void *a, const void *b)
1486 {
1487         const char *mounta = *((char **)a);
1488         const char *mountb = *((char **)b);
1489 
1490         return (strcmp(mountb, mounta));
1491 }
1492 
1493 /* alias for 2002/240 */
1494 #pragma weak zpool_unmount_datasets = zpool_disable_datasets
1495 /*
1496  * Unshare and unmount all datasets within the given pool.  We don't want to
1497  * rely on traversing the DSL to discover the filesystems within the pool,