No point in rewind() mtab in zfs_unshare_proto(). We're not really
[zfs.git] / lib / libzfs / libzfs_mount.c
index 0668dea..bded1f0 100644 (file)
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
  *
  *     zfs_is_shared_nfs()
  *     zfs_is_shared_smb()
- *     zfs_is_shared_iscsi()
  *     zfs_share_proto()
  *     zfs_shareall();
- *     zfs_share_iscsi()
  *     zfs_unshare_nfs()
  *     zfs_unshare_smb()
  *     zfs_unshareall_nfs()
  *     zfs_unshareall_smb()
  *     zfs_unshareall()
  *     zfs_unshareall_bypath()
- *     zfs_unshare_iscsi()
  *
  * The following functions are available for pool consumers, and will
  * mount/unmount and share/unshare all datasets within pool:
@@ -89,11 +85,6 @@ static int zfs_share_proto(zfs_handle_t *, zfs_share_proto_t *);
 zfs_share_type_t zfs_is_shared_proto(zfs_handle_t *, char **,
     zfs_share_proto_t);
 
-static int (*iscsitgt_zfs_share)(const char *);
-static int (*iscsitgt_zfs_unshare)(const char *);
-static int (*iscsitgt_zfs_is_shared)(const char *);
-static int (*iscsitgt_svc_online)();
-
 /*
  * The share protocols table must be in the same order as the zfs_share_prot_t
  * enum in libzfs_impl.h
@@ -125,29 +116,6 @@ zfs_share_proto_t share_all_proto[] = {
        PROTO_END
 };
 
-#pragma init(zfs_iscsi_init)
-static void
-zfs_iscsi_init(void)
-{
-       void *libiscsitgt;
-
-       if ((libiscsitgt = dlopen("/lib/libiscsitgt.so.1",
-           RTLD_LAZY | RTLD_GLOBAL)) == NULL ||
-           (iscsitgt_zfs_share = (int (*)(const char *))dlsym(libiscsitgt,
-           "iscsitgt_zfs_share")) == NULL ||
-           (iscsitgt_zfs_unshare = (int (*)(const char *))dlsym(libiscsitgt,
-           "iscsitgt_zfs_unshare")) == NULL ||
-           (iscsitgt_zfs_is_shared = (int (*)(const char *))dlsym(libiscsitgt,
-           "iscsitgt_zfs_is_shared")) == NULL ||
-           (iscsitgt_svc_online = (int (*)(const char *))dlsym(libiscsitgt,
-           "iscsitgt_svc_online")) == NULL) {
-               iscsitgt_zfs_share = NULL;
-               iscsitgt_zfs_unshare = NULL;
-               iscsitgt_zfs_is_shared = NULL;
-               iscsitgt_svc_online = NULL;
-       }
-}
-
 /*
  * Search the sharetab for the given mountpoint and protocol, returning
  * a zfs_share_type_t value.
@@ -287,6 +255,128 @@ zfs_is_mountable(zfs_handle_t *zhp, char *buf, size_t buflen,
 }
 
 /*
+ * The filesystem is mounted by invoking the system mount utility rather
+ * than by the system call mount(2).  This ensures that the /etc/mtab
+ * file is correctly locked for the update.  Performing our own locking
+ * and /etc/mtab update requires making an unsafe assumption about how
+ * the mount utility performs its locking.  Unfortunately, this also means
+ * in the case of a mount failure we do not have the exact errno.  We must
+ * make due with return value from the mount process.
+ *
+ * In the long term a shared library called libmount is under development
+ * which provides a common API to address the locking and errno issues.
+ * Once the standard mount utility has been updated to use this library
+ * we can add an autoconf check to conditionally use it.
+ *
+ * http://www.kernel.org/pub/linux/utils/util-linux/libmount-docs/index.html
+ */
+
+static int
+do_mount(const char *src, const char *mntpt, char *opts)
+{
+       char *argv[8] = {
+           "/bin/mount",
+           "-t", MNTTYPE_ZFS,
+           "-o", opts,
+           (char *)src,
+            (char *)mntpt,
+           (char *)NULL };
+       int rc;
+
+       /* Return only the most critical mount error */
+       rc = libzfs_run_process(argv[0], argv, STDOUT_VERBOSE|STDERR_VERBOSE);
+       if (rc) {
+               if (rc & MOUNT_FILEIO)
+                       return EIO;
+               if (rc & MOUNT_USER)
+                       return EINTR;
+               if (rc & MOUNT_SOFTWARE)
+                       return EPIPE;
+               if (rc & MOUNT_SYSERR)
+                       return EAGAIN;
+               if (rc & MOUNT_USAGE)
+                       return EINVAL;
+
+               return ENXIO; /* Generic error */
+       }
+
+       return 0;
+}
+
+static int
+do_unmount(const char *mntpt, int flags)
+{
+       char force_opt[] = "-f";
+       char lazy_opt[] = "-l";
+       char *argv[7] = {
+           "/bin/umount",
+           "-t", MNTTYPE_ZFS,
+           NULL, NULL, NULL, NULL };
+       int rc, count = 3;
+
+       if (flags & MS_FORCE) {
+               argv[count] = force_opt;
+               count++;
+       }
+
+       if (flags & MS_DETACH) {
+               argv[count] = lazy_opt;
+               count++;
+       }
+
+       argv[count] = (char *)mntpt;
+       rc = libzfs_run_process(argv[0], argv, STDOUT_VERBOSE|STDERR_VERBOSE);
+
+       return (rc ? EINVAL : 0);
+}
+
+static int
+zfs_add_option(zfs_handle_t *zhp, char *options, int len,
+    zfs_prop_t prop, char *on, char *off)
+{
+       char *source;
+       uint64_t value;
+
+       /* Skip adding duplicate default options */
+       if ((strstr(options, on) != NULL) || (strstr(options, off) != NULL))
+               return (0);
+
+       /*
+        * zfs_prop_get_int() to not used to ensure our mount options
+        * are not influenced by the current /etc/mtab contents.
+        */
+       value = getprop_uint64(zhp, prop, &source);
+
+       (void) strlcat(options, ",", len);
+       (void) strlcat(options, value ? on : off, len);
+
+       return (0);
+}
+
+static int
+zfs_add_options(zfs_handle_t *zhp, char *options, int len)
+{
+       int error = 0;
+
+       error = zfs_add_option(zhp, options, len,
+           ZFS_PROP_ATIME, MNTOPT_ATIME, MNTOPT_NOATIME);
+       error = error ? error : zfs_add_option(zhp, options, len,
+           ZFS_PROP_DEVICES, MNTOPT_DEVICES, MNTOPT_NODEVICES);
+       error = error ? error : zfs_add_option(zhp, options, len,
+           ZFS_PROP_EXEC, MNTOPT_EXEC, MNTOPT_NOEXEC);
+       error = error ? error : zfs_add_option(zhp, options, len,
+           ZFS_PROP_READONLY, MNTOPT_RO, MNTOPT_RW);
+       error = error ? error : zfs_add_option(zhp, options, len,
+           ZFS_PROP_SETUID, MNTOPT_SETUID, MNTOPT_NOSETUID);
+       error = error ? error : zfs_add_option(zhp, options, len,
+           ZFS_PROP_XATTR, MNTOPT_XATTR, MNTOPT_NOXATTR);
+       error = error ? error : zfs_add_option(zhp, options, len,
+           ZFS_PROP_NBMAND, MNTOPT_NBMAND, MNTOPT_NONBMAND);
+
+       return (error);
+}
+
+/*
  * Mount the given filesystem.
  */
 int
@@ -296,11 +386,43 @@ zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
        char mountpoint[ZFS_MAXPROPLEN];
        char mntopts[MNT_LINE_MAX];
        libzfs_handle_t *hdl = zhp->zfs_hdl;
+       int remount = 0, rc;
 
-       if (options == NULL)
-               mntopts[0] = '\0';
-       else
+       if (options == NULL) {
+               (void) strlcpy(mntopts, MNTOPT_DEFAULTS, sizeof (mntopts));
+       } else {
                (void) strlcpy(mntopts, options, sizeof (mntopts));
+       }
+
+       if (strstr(mntopts, MNTOPT_REMOUNT) != NULL)
+               remount = 1;
+
+       /*
+        * If the pool is imported read-only then all mounts must be read-only
+        */
+       if (zpool_get_prop_int(zhp->zpool_hdl, ZPOOL_PROP_READONLY, NULL))
+               (void) strlcat(mntopts, "," MNTOPT_RO, sizeof (mntopts));
+
+       /*
+        * Append default mount options which apply to the mount point.
+        * This is done because under Linux (unlike Solaris) multiple mount
+        * points may reference a single super block.  This means that just
+        * given a super block there is no back reference to update the per
+        * mount point options.
+        */
+       rc = zfs_add_options(zhp, mntopts, sizeof (mntopts));
+       if (rc) {
+               zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+                   "default options unavailable"));
+               return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
+                   dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
+                   mountpoint));
+       }
+
+       /*
+        * Append zfsutil option so the mount helper allow the mount
+        */
+       strlcat(mntopts, "," MNTOPT_ZFSUTIL, sizeof (mntopts));
 
        if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
                return (0);
@@ -318,12 +440,10 @@ zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
 
        /*
         * Determine if the mountpoint is empty.  If so, refuse to perform the
-        * mount.  We don't perform this check if MS_OVERLAY is specified, which
-        * would defeat the point.  We also avoid this check if 'remount' is
-        * specified.
+        * mount.  We don't perform this check if 'remount' is
+        * specified or if overlay option(-O) is given
         */
-       if ((flags & MS_OVERLAY) == 0 &&
-           strstr(mntopts, MNTOPT_REMOUNT) == NULL &&
+       if ((flags & MS_OVERLAY) == 0 && !remount &&
            !dir_is_empty(mountpoint)) {
                zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
                    "directory is not empty"));
@@ -332,30 +452,45 @@ zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
        }
 
        /* perform the mount */
-       if (mount(zfs_get_name(zhp), mountpoint, MS_OPTIONSTR | flags,
-           MNTTYPE_ZFS, NULL, 0, mntopts, sizeof (mntopts)) != 0) {
+       rc = do_mount(zfs_get_name(zhp), mountpoint, mntopts);
+       if (rc) {
                /*
                 * Generic errors are nasty, but there are just way too many
                 * from mount(), and they're well-understood.  We pick a few
                 * common ones to improve upon.
                 */
-               if (errno == EBUSY) {
+               if (rc == EBUSY) {
                        zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
                            "mountpoint or dataset is busy"));
-               } else if (errno == EPERM) {
+               } else if (rc == EPERM) {
                        zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
                            "Insufficient privileges"));
+               } else if (rc == ENOTSUP) {
+                       char buf[256];
+                       int spa_version;
+
+                       VERIFY(zfs_spa_version(zhp, &spa_version) == 0);
+                       (void) snprintf(buf, sizeof (buf),
+                           dgettext(TEXT_DOMAIN, "Can't mount a version %lld "
+                           "file system on a version %d pool. Pool must be"
+                           " upgraded to mount this file system."),
+                           (u_longlong_t)zfs_prop_get_int(zhp,
+                           ZFS_PROP_VERSION), spa_version);
+                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, buf));
                } else {
-                       zfs_error_aux(hdl, strerror(errno));
+                       zfs_error_aux(hdl, strerror(rc));
                }
                return (zfs_error_fmt(hdl, EZFS_MOUNTFAILED,
                    dgettext(TEXT_DOMAIN, "cannot mount '%s'"),
                    zhp->zfs_name));
        }
 
+       /* remove the mounted entry before re-adding on remount */
+       if (remount)
+               libzfs_mnttab_remove(hdl, zhp->zfs_name);
+
        /* add the mounted entry into our cache */
-       libzfs_mnttab_add(hdl, zfs_get_name(zhp), mountpoint,
-           mntopts);
+       libzfs_mnttab_add(hdl, zfs_get_name(zhp), mountpoint, mntopts);
        return (0);
 }
 
@@ -365,8 +500,10 @@ zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
 static int
 unmount_one(libzfs_handle_t *hdl, const char *mountpoint, int flags)
 {
-       if (umount2(mountpoint, flags) != 0) {
-               zfs_error_aux(hdl, strerror(errno));
+       int error;
+
+       error = do_unmount(mountpoint, flags);
+       if (error != 0) {
                return (zfs_error_fmt(hdl, EZFS_UMOUNTFAILED,
                    dgettext(TEXT_DOMAIN, "cannot unmount '%s'"),
                    mountpoint));
@@ -445,7 +582,7 @@ zfs_is_shared(zfs_handle_t *zhp)
        zfs_share_proto_t *curr_proto;
 
        if (ZFS_IS_VOLUME(zhp))
-               return (zfs_is_shared_iscsi(zhp));
+               return (B_FALSE);
 
        for (curr_proto = share_all_proto; *curr_proto != PROTO_END;
            curr_proto++)
@@ -457,18 +594,14 @@ zfs_is_shared(zfs_handle_t *zhp)
 int
 zfs_share(zfs_handle_t *zhp)
 {
-       if (ZFS_IS_VOLUME(zhp))
-               return (zfs_share_iscsi(zhp));
-
+       assert(!ZFS_IS_VOLUME(zhp));
        return (zfs_share_proto(zhp, share_all_proto));
 }
 
 int
 zfs_unshare(zfs_handle_t *zhp)
 {
-       if (ZFS_IS_VOLUME(zhp))
-               return (zfs_unshare_iscsi(zhp));
-
+       assert(!ZFS_IS_VOLUME(zhp));
        return (zfs_unshareall(zhp));
 }
 
@@ -484,7 +617,7 @@ zfs_is_shared_proto(zfs_handle_t *zhp, char **where, zfs_share_proto_t proto)
        if (!zfs_is_mounted(zhp, &mountpoint))
                return (SHARED_NOT_SHARED);
 
-       if (rc = is_shared(zhp->zfs_hdl, mountpoint, proto)) {
+       if ((rc = is_shared(zhp->zfs_hdl, mountpoint, proto))) {
                if (where != NULL)
                        *where = mountpoint;
                else
@@ -511,93 +644,6 @@ zfs_is_shared_smb(zfs_handle_t *zhp, char **where)
 }
 
 /*
- * Make sure things will work if libshare isn't installed by using
- * wrapper functions that check to see that the pointers to functions
- * initialized in _zfs_init_libshare() are actually present.
- */
-
-static sa_handle_t (*_sa_init)(int);
-static void (*_sa_fini)(sa_handle_t);
-static sa_share_t (*_sa_find_share)(sa_handle_t, char *);
-static int (*_sa_enable_share)(sa_share_t, char *);
-static int (*_sa_disable_share)(sa_share_t, char *);
-static char *(*_sa_errorstr)(int);
-static int (*_sa_parse_legacy_options)(sa_group_t, char *, char *);
-static boolean_t (*_sa_needs_refresh)(sa_handle_t *);
-static libzfs_handle_t *(*_sa_get_zfs_handle)(sa_handle_t);
-static int (*_sa_zfs_process_share)(sa_handle_t, sa_group_t, sa_share_t,
-    char *, char *, zprop_source_t, char *, char *, char *);
-static void (*_sa_update_sharetab_ts)(sa_handle_t);
-
-/*
- * _zfs_init_libshare()
- *
- * Find the libshare.so.1 entry points that we use here and save the
- * values to be used later. This is triggered by the runtime loader.
- * Make sure the correct ISA version is loaded.
- */
-
-#pragma init(_zfs_init_libshare)
-static void
-_zfs_init_libshare(void)
-{
-       void *libshare;
-       char path[MAXPATHLEN];
-       char isa[MAXISALEN];
-
-#if defined(_LP64)
-       if (sysinfo(SI_ARCHITECTURE_64, isa, MAXISALEN) == -1)
-               isa[0] = '\0';
-#else
-       isa[0] = '\0';
-#endif
-       (void) snprintf(path, MAXPATHLEN,
-           "/usr/lib/%s/libshare.so.1", isa);
-
-       if ((libshare = dlopen(path, RTLD_LAZY | RTLD_GLOBAL)) != NULL) {
-               _sa_init = (sa_handle_t (*)(int))dlsym(libshare, "sa_init");
-               _sa_fini = (void (*)(sa_handle_t))dlsym(libshare, "sa_fini");
-               _sa_find_share = (sa_share_t (*)(sa_handle_t, char *))
-                   dlsym(libshare, "sa_find_share");
-               _sa_enable_share = (int (*)(sa_share_t, char *))dlsym(libshare,
-                   "sa_enable_share");
-               _sa_disable_share = (int (*)(sa_share_t, char *))dlsym(libshare,
-                   "sa_disable_share");
-               _sa_errorstr = (char *(*)(int))dlsym(libshare, "sa_errorstr");
-               _sa_parse_legacy_options = (int (*)(sa_group_t, char *, char *))
-                   dlsym(libshare, "sa_parse_legacy_options");
-               _sa_needs_refresh = (boolean_t (*)(sa_handle_t *))
-                   dlsym(libshare, "sa_needs_refresh");
-               _sa_get_zfs_handle = (libzfs_handle_t *(*)(sa_handle_t))
-                   dlsym(libshare, "sa_get_zfs_handle");
-               _sa_zfs_process_share = (int (*)(sa_handle_t, sa_group_t,
-                   sa_share_t, char *, char *, zprop_source_t, char *,
-                   char *, char *))dlsym(libshare, "sa_zfs_process_share");
-               _sa_update_sharetab_ts = (void (*)(sa_handle_t))
-                   dlsym(libshare, "sa_update_sharetab_ts");
-               if (_sa_init == NULL || _sa_fini == NULL ||
-                   _sa_find_share == NULL || _sa_enable_share == NULL ||
-                   _sa_disable_share == NULL || _sa_errorstr == NULL ||
-                   _sa_parse_legacy_options == NULL ||
-                   _sa_needs_refresh == NULL || _sa_get_zfs_handle == NULL ||
-                   _sa_zfs_process_share == NULL ||
-                   _sa_update_sharetab_ts == NULL) {
-                       _sa_init = NULL;
-                       _sa_fini = NULL;
-                       _sa_disable_share = NULL;
-                       _sa_enable_share = NULL;
-                       _sa_errorstr = NULL;
-                       _sa_parse_legacy_options = NULL;
-                       (void) dlclose(libshare);
-                       _sa_needs_refresh = NULL;
-                       _sa_get_zfs_handle = NULL;
-                       _sa_zfs_process_share = NULL;
-                       _sa_update_sharetab_ts = NULL;
-               }
-       }
-}
-
-/*
  * zfs_init_libshare(zhandle, service)
  *
  * Initialize the libshare API if it hasn't already been initialized.
@@ -610,9 +656,6 @@ zfs_init_libshare(libzfs_handle_t *zhandle, int service)
 {
        int ret = SA_OK;
 
-       if (_sa_init == NULL)
-               ret = SA_CONFIG_ERR;
-
        if (ret == SA_OK && zhandle->libzfs_shareflags & ZFSSHARE_MISS) {
                /*
                 * We had a cache miss. Most likely it is a new ZFS
@@ -623,15 +666,14 @@ zfs_init_libshare(libzfs_handle_t *zhandle, int service)
                 * internal cache.
                 */
                zhandle->libzfs_shareflags &= ~ZFSSHARE_MISS;
-               if (_sa_needs_refresh != NULL &&
-                   _sa_needs_refresh(zhandle->libzfs_sharehdl)) {
+               if (sa_needs_refresh(zhandle->libzfs_sharehdl)) {
                        zfs_uninit_libshare(zhandle);
-                       zhandle->libzfs_sharehdl = _sa_init(service);
+                       zhandle->libzfs_sharehdl = sa_init(service);
                }
        }
 
        if (ret == SA_OK && zhandle && zhandle->libzfs_sharehdl == NULL)
-               zhandle->libzfs_sharehdl = _sa_init(service);
+               zhandle->libzfs_sharehdl = sa_init(service);
 
        if (ret == SA_OK && zhandle->libzfs_sharehdl == NULL)
                ret = SA_NO_MEMORY;
@@ -649,8 +691,7 @@ void
 zfs_uninit_libshare(libzfs_handle_t *zhandle)
 {
        if (zhandle != NULL && zhandle->libzfs_sharehdl != NULL) {
-               if (_sa_fini != NULL)
-                       _sa_fini(zhandle->libzfs_sharehdl);
+               sa_fini(zhandle->libzfs_sharehdl);
                zhandle->libzfs_sharehdl = NULL;
        }
 }
@@ -664,59 +705,14 @@ zfs_uninit_libshare(libzfs_handle_t *zhandle)
 int
 zfs_parse_options(char *options, zfs_share_proto_t proto)
 {
-       if (_sa_parse_legacy_options != NULL) {
-               return (_sa_parse_legacy_options(NULL, options,
-                   proto_table[proto].p_name));
-       }
-       return (SA_CONFIG_ERR);
-}
-
-/*
- * zfs_sa_find_share(handle, path)
- *
- * wrapper around sa_find_share to find a share path in the
- * configuration.
- */
-static sa_share_t
-zfs_sa_find_share(sa_handle_t handle, char *path)
-{
-       if (_sa_find_share != NULL)
-               return (_sa_find_share(handle, path));
-       return (NULL);
-}
-
-/*
- * zfs_sa_enable_share(share, proto)
- *
- * Wrapper for sa_enable_share which enables a share for a specified
- * protocol.
- */
-static int
-zfs_sa_enable_share(sa_share_t share, char *proto)
-{
-       if (_sa_enable_share != NULL)
-               return (_sa_enable_share(share, proto));
-       return (SA_CONFIG_ERR);
-}
-
-/*
- * zfs_sa_disable_share(share, proto)
- *
- * Wrapper for sa_enable_share which disables a share for a specified
- * protocol.
- */
-static int
-zfs_sa_disable_share(sa_share_t share, char *proto)
-{
-       if (_sa_disable_share != NULL)
-               return (_sa_disable_share(share, proto));
-       return (SA_CONFIG_ERR);
+       return (sa_parse_legacy_options(NULL, options,
+           proto_table[proto].p_name));
 }
 
 /*
  * Share the given filesystem according to the options in the specified
  * protocol specific properties (sharenfs, sharesmb).  We rely
- * on "libshare" to the dirty work for us.
+ * on "libshare" to do the dirty work for us.
  */
 static int
 zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
@@ -736,8 +732,7 @@ zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
        if ((ret = zfs_init_libshare(hdl, SA_INIT_SHARE_API)) != SA_OK) {
                (void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED,
                    dgettext(TEXT_DOMAIN, "cannot share '%s': %s"),
-                   zfs_get_name(zhp), _sa_errorstr != NULL ?
-                   _sa_errorstr(ret) : "");
+                   zfs_get_name(zhp), sa_errorstr(ret));
                return (-1);
        }
 
@@ -760,7 +755,7 @@ zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
                if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED))
                        continue;
 
-               share = zfs_sa_find_share(hdl->libzfs_sharehdl, mountpoint);
+               share = sa_find_share(hdl->libzfs_sharehdl, mountpoint);
                if (share == NULL) {
                        /*
                         * This may be a new file system that was just
@@ -771,7 +766,7 @@ zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
                         * safe to add this to the internal
                         * configuration.
                         */
-                       if (_sa_zfs_process_share(hdl->libzfs_sharehdl,
+                       if (sa_zfs_process_share(hdl->libzfs_sharehdl,
                            NULL, NULL, mountpoint,
                            proto_table[*curr_proto].p_name, sourcetype,
                            shareopts, sourcestr, zhp->zfs_name) != SA_OK) {
@@ -782,12 +777,12 @@ zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
                                return (-1);
                        }
                        hdl->libzfs_shareflags |= ZFSSHARE_MISS;
-                       share = zfs_sa_find_share(hdl->libzfs_sharehdl,
+                       share = sa_find_share(hdl->libzfs_sharehdl,
                            mountpoint);
                }
                if (share != NULL) {
                        int err;
-                       err = zfs_sa_enable_share(share,
+                       err = sa_enable_share(share,
                            proto_table[*curr_proto].p_name);
                        if (err != SA_OK) {
                                (void) zfs_error_fmt(hdl,
@@ -849,18 +844,18 @@ unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint,
                free(mntpt);    /* don't need the copy anymore */
                return (zfs_error_fmt(hdl, EZFS_SHARENFSFAILED,
                    dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"),
-                   name, _sa_errorstr(err)));
+                   name, sa_errorstr(err)));
        }
 
-       share = zfs_sa_find_share(hdl->libzfs_sharehdl, mntpt);
+       share = sa_find_share(hdl->libzfs_sharehdl, mntpt);
        free(mntpt);    /* don't need the copy anymore */
 
        if (share != NULL) {
-               err = zfs_sa_disable_share(share, proto_table[proto].p_name);
+               err = sa_disable_share(share, proto_table[proto].p_name);
                if (err != SA_OK) {
                        return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED,
                            dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"),
-                           name, _sa_errorstr(err)));
+                           name, sa_errorstr(err)));
                }
        } else {
                return (zfs_error_fmt(hdl, EZFS_UNSHARENFSFAILED,
@@ -882,7 +877,6 @@ zfs_unshare_proto(zfs_handle_t *zhp, const char *mountpoint,
        char *mntpt = NULL;
 
        /* check to see if need to unmount the filesystem */
-       rewind(zhp->zfs_hdl->libzfs_mnttab);
        if (mountpoint != NULL)
                mountpoint = mntpt = zfs_strdup(hdl, mountpoint);
 
@@ -894,11 +888,11 @@ zfs_unshare_proto(zfs_handle_t *zhp, const char *mountpoint,
                        mntpt = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp);
 
                for (curr_proto = proto; *curr_proto != PROTO_END;
-                   curr_proto++) {
+                    curr_proto++) {
 
                        if (is_shared(hdl, mntpt, *curr_proto) &&
                            unshare_one(hdl, zhp->zfs_name,
-                           mntpt, *curr_proto) != 0) {
+                                       mntpt, *curr_proto) != 0) {
                                if (mntpt != NULL)
                                        free(mntpt);
                                return (-1);
@@ -999,93 +993,29 @@ remove_mountpoint(zfs_handle_t *zhp)
        }
 }
 
-boolean_t
-zfs_is_shared_iscsi(zfs_handle_t *zhp)
-{
-
-       /*
-        * If iscsi deamon isn't running then we aren't shared
-        */
-       if (iscsitgt_svc_online && iscsitgt_svc_online() == 1)
-               return (B_FALSE);
-       else
-               return (iscsitgt_zfs_is_shared != NULL &&
-                   iscsitgt_zfs_is_shared(zhp->zfs_name) != 0);
-}
-
-int
-zfs_share_iscsi(zfs_handle_t *zhp)
-{
-       char shareopts[ZFS_MAXPROPLEN];
-       const char *dataset = zhp->zfs_name;
-       libzfs_handle_t *hdl = zhp->zfs_hdl;
-
-       /*
-        * Return success if there are no share options.
-        */
-       if (zfs_prop_get(zhp, ZFS_PROP_SHAREISCSI, shareopts,
-           sizeof (shareopts), NULL, NULL, 0, B_FALSE) != 0 ||
-           strcmp(shareopts, "off") == 0)
-               return (0);
-
-       if (iscsitgt_zfs_share == NULL || iscsitgt_zfs_share(dataset) != 0) {
-               int error = EZFS_SHAREISCSIFAILED;
-
-               /*
-                * If service isn't availabele and EPERM was
-                * returned then use special error.
-                */
-               if (iscsitgt_svc_online && errno == EPERM &&
-                   (iscsitgt_svc_online() != 0))
-                       error = EZFS_ISCSISVCUNAVAIL;
-
-               return (zfs_error_fmt(hdl, error,
-                   dgettext(TEXT_DOMAIN, "cannot share '%s'"), dataset));
-       }
-
-       return (0);
-}
-
-int
-zfs_unshare_iscsi(zfs_handle_t *zhp)
+void
+libzfs_add_handle(get_all_cb_t *cbp, zfs_handle_t *zhp)
 {
-       const char *dataset = zfs_get_name(zhp);
-       libzfs_handle_t *hdl = zhp->zfs_hdl;
-
-       /*
-        * Return if the volume is not shared
-        */
-       if (zfs_is_shared_iscsi(zhp) != SHARED_ISCSI)
-               return (0);
+       if (cbp->cb_alloc == cbp->cb_used) {
+               size_t newsz;
+               void *ptr;
 
-       /*
-        * If this fails with ENODEV it indicates that zvol wasn't shared so
-        * we should return success in that case.
-        */
-       if (iscsitgt_zfs_unshare == NULL ||
-           (iscsitgt_zfs_unshare(dataset) != 0 && errno != ENODEV)) {
-               if (errno == EPERM)
-                       zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
-                           "Insufficient privileges to unshare iscsi"));
-               return (zfs_error_fmt(hdl, EZFS_UNSHAREISCSIFAILED,
-                   dgettext(TEXT_DOMAIN, "cannot unshare '%s'"), dataset));
+               newsz = cbp->cb_alloc ? cbp->cb_alloc * 2 : 64;
+               ptr = zfs_realloc(zhp->zfs_hdl,
+                   cbp->cb_handles, cbp->cb_alloc * sizeof (void *),
+                   newsz * sizeof (void *));
+               cbp->cb_handles = ptr;
+               cbp->cb_alloc = newsz;
        }
-
-       return (0);
+       cbp->cb_handles[cbp->cb_used++] = zhp;
 }
 
-typedef struct mount_cbdata {
-       zfs_handle_t    **cb_datasets;
-       int             cb_used;
-       int             cb_alloc;
-} mount_cbdata_t;
-
 static int
 mount_cb(zfs_handle_t *zhp, void *data)
 {
-       mount_cbdata_t *cbp = data;
+       get_all_cb_t *cbp = data;
 
-       if (!(zfs_get_type(zhp) & (ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME))) {
+       if (!(zfs_get_type(zhp) & ZFS_TYPE_FILESYSTEM)) {
                zfs_close(zhp);
                return (0);
        }
@@ -1095,25 +1025,16 @@ mount_cb(zfs_handle_t *zhp, void *data)
                return (0);
        }
 
-       if (cbp->cb_alloc == cbp->cb_used) {
-               void *ptr;
-
-               if ((ptr = zfs_realloc(zhp->zfs_hdl,
-                   cbp->cb_datasets, cbp->cb_alloc * sizeof (void *),
-                   cbp->cb_alloc * 2 * sizeof (void *))) == NULL)
-                       return (-1);
-               cbp->cb_datasets = ptr;
-
-               cbp->cb_alloc *= 2;
+       libzfs_add_handle(cbp, zhp);
+       if (zfs_iter_filesystems(zhp, mount_cb, cbp) != 0) {
+               zfs_close(zhp);
+               return (-1);
        }
-
-       cbp->cb_datasets[cbp->cb_used++] = zhp;
-
-       return (zfs_iter_filesystems(zhp, mount_cb, cbp));
+       return (0);
 }
 
-static int
-dataset_cmp(const void *a, const void *b)
+int
+libzfs_dataset_cmp(const void *a, const void *b)
 {
        zfs_handle_t **za = (zfs_handle_t **)a;
        zfs_handle_t **zb = (zfs_handle_t **)b;
@@ -1151,7 +1072,7 @@ dataset_cmp(const void *a, const void *b)
 int
 zpool_enable_datasets(zpool_handle_t *zhp, const char *mntopts, int flags)
 {
-       mount_cbdata_t cb = { 0 };
+       get_all_cb_t cb = { 0 };
        libzfs_handle_t *hdl = zhp->zpool_hdl;
        zfs_handle_t *zfsp;
        int i, ret = -1;
@@ -1160,33 +1081,29 @@ zpool_enable_datasets(zpool_handle_t *zhp, const char *mntopts, int flags)
        /*
         * Gather all non-snap datasets within the pool.
         */
-       if ((cb.cb_datasets = zfs_alloc(hdl, 4 * sizeof (void *))) == NULL)
-               return (-1);
-       cb.cb_alloc = 4;
-
        if ((zfsp = zfs_open(hdl, zhp->zpool_name, ZFS_TYPE_DATASET)) == NULL)
                goto out;
 
-       cb.cb_datasets[0] = zfsp;
-       cb.cb_used = 1;
-
+       libzfs_add_handle(&cb, zfsp);
        if (zfs_iter_filesystems(zfsp, mount_cb, &cb) != 0)
                goto out;
-
        /*
         * Sort the datasets by mountpoint.
         */
-       qsort(cb.cb_datasets, cb.cb_used, sizeof (void *), dataset_cmp);
+       qsort(cb.cb_handles, cb.cb_used, sizeof (void *),
+           libzfs_dataset_cmp);
 
        /*
         * And mount all the datasets, keeping track of which ones
-        * succeeded or failed. By using zfs_alloc(), the good pointer
-        * will always be non-NULL.
+        * succeeded or failed.
         */
-       good = zfs_alloc(zhp->zpool_hdl, cb.cb_used * sizeof (int));
+       if ((good = zfs_alloc(zhp->zpool_hdl,
+           cb.cb_used * sizeof (int))) == NULL)
+               goto out;
+
        ret = 0;
        for (i = 0; i < cb.cb_used; i++) {
-               if (zfs_mount(cb.cb_datasets[i], mntopts, flags) != 0)
+               if (zfs_mount(cb.cb_handles[i], mntopts, flags) != 0)
                        ret = -1;
                else
                        good[i] = 1;
@@ -1199,7 +1116,7 @@ zpool_enable_datasets(zpool_handle_t *zhp, const char *mntopts, int flags)
         * zfs_alloc is supposed to exit if memory isn't available.
         */
        for (i = 0; i < cb.cb_used; i++) {
-               if (good[i] && zfs_share(cb.cb_datasets[i]) != 0)
+               if (good[i] && zfs_share(cb.cb_handles[i]) != 0)
                        ret = -1;
        }
 
@@ -1207,34 +1124,12 @@ zpool_enable_datasets(zpool_handle_t *zhp, const char *mntopts, int flags)
 
 out:
        for (i = 0; i < cb.cb_used; i++)
-               zfs_close(cb.cb_datasets[i]);
-       free(cb.cb_datasets);
+               zfs_close(cb.cb_handles[i]);
+       free(cb.cb_handles);
 
        return (ret);
 }
 
-
-static int
-zvol_cb(const char *dataset, void *data)
-{
-       libzfs_handle_t *hdl = data;
-       zfs_handle_t *zhp;
-
-       /*
-        * Ignore snapshots and ignore failures from non-existant datasets.
-        */
-       if (strchr(dataset, '@') != NULL ||
-           (zhp = zfs_open(hdl, dataset, ZFS_TYPE_VOLUME)) == NULL)
-               return (0);
-
-       if (zfs_unshare_iscsi(zhp) != 0)
-               return (-1);
-
-       zfs_close(zhp);
-
-       return (0);
-}
-
 static int
 mountpoint_compare(const void *a, const void *b)
 {
@@ -1244,14 +1139,15 @@ mountpoint_compare(const void *a, const void *b)
        return (strcmp(mountb, mounta));
 }
 
+/* alias for 2002/240 */
+#pragma weak zpool_unmount_datasets = zpool_disable_datasets
 /*
  * Unshare and unmount all datasets within the given pool.  We don't want to
  * rely on traversing the DSL to discover the filesystems within the pool,
  * because this may be expensive (if not all of them are mounted), and can fail
- * arbitrarily (on I/O error, for example).  Instead, we walk /etc/mnttab and
+ * arbitrarily (on I/O error, for example).  Instead, we walk /etc/mtab and
  * gather all the filesystems that are currently mounted.
  */
-#pragma weak zpool_unmount_datasets = zpool_disable_datasets
 int
 zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force)
 {
@@ -1265,12 +1161,6 @@ zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force)
        int ret = -1;
        int flags = (force ? MS_FORCE : 0);
 
-       /*
-        * First unshare all zvols.
-        */
-       if (zpool_iter_zvol(zhp, zvol_cb, hdl) != 0)
-               return (-1);
-
        namelen = strlen(zhp->zpool_name);
 
        rewind(hdl->libzfs_mnttab);