Documentation updates
[zfs.git] / lib / libzfs / libzfs_mount.c
index 0668dea..977b2ee 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:
@@ -76,6 +72,9 @@
 #include <sys/mntent.h>
 #include <sys/mount.h>
 #include <sys/stat.h>
+#ifdef HAVE_LIBSELINUX
+#include <selinux/selinux.h>
+#endif /* HAVE_LIBSELINUX */
 
 #include <libzfs.h>
 
 #include <sys/systeminfo.h>
 #define        MAXISALEN       257     /* based on sysinfo(2) man page */
 
+#ifdef HAVE_ZPL
 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,44 +120,22 @@ 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
+ * Search for NFS and SMB exports for the given mountpoint and protocol, returning
  * a zfs_share_type_t value.
  */
 static zfs_share_type_t
 is_shared(libzfs_handle_t *hdl, const char *mountpoint, zfs_share_proto_t proto)
 {
        char buf[MAXPATHLEN], *tab;
-       char *ptr;
 
        if (hdl->libzfs_sharetab == NULL)
                return (SHARED_NOT_SHARED);
 
        (void) fseek(hdl->libzfs_sharetab, 0, SEEK_SET);
 
+       /* Search /etc/exports for NFS exports */
+       /* FIXME: Assumes the file is tab delimited. */
        while (fgets(buf, sizeof (buf), hdl->libzfs_sharetab) != NULL) {
 
                /* the mountpoint is the first entry on each line */
@@ -171,31 +144,15 @@ is_shared(libzfs_handle_t *hdl, const char *mountpoint, zfs_share_proto_t proto)
 
                *tab = '\0';
                if (strcmp(buf, mountpoint) == 0) {
-                       /*
-                        * the protocol field is the third field
-                        * skip over second field
-                        */
-                       ptr = ++tab;
-                       if ((tab = strchr(ptr, '\t')) == NULL)
-                               continue;
-                       ptr = ++tab;
-                       if ((tab = strchr(ptr, '\t')) == NULL)
-                               continue;
-                       *tab = '\0';
-                       if (strcmp(ptr,
-                           proto_table[proto].p_name) == 0) {
-                               switch (proto) {
-                               case PROTO_NFS:
-                                       return (SHARED_NFS);
-                               case PROTO_SMB:
-                                       return (SHARED_SMB);
-                               default:
-                                       return (0);
-                               }
-                       }
+                       if (proto == PROTO_NFS)
+                               return (SHARED_NFS);
+                       else
+                               return (SHARED_NOT_SHARED);
                }
        }
 
+       /* XXX: Search /etc/samba/smb.conf for SMB exports, return SHARED_SMB */
+
        return (SHARED_NOT_SHARED);
 }
 
@@ -287,6 +244,82 @@ 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);
+       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);
+
+       return (rc ? EINVAL : 0);
+}
+
+/*
  * Mount the given filesystem.
  */
 int
@@ -296,12 +329,30 @@ 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 rc;
 
        if (options == NULL)
-               mntopts[0] = '\0';
+               (void) strlcpy(mntopts, MNTOPT_DEFAULTS, sizeof (mntopts));
        else
                (void) strlcpy(mntopts, options, sizeof (mntopts));
 
+       /*
+        * 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 zfsutil option so the mount helper allow the mount
+        */
+       strlcat(mntopts, "," MNTOPT_ZFSUTIL, sizeof (mntopts));
+
+#ifdef HAVE_LIBSELINUX
+       if (is_selinux_enabled())
+               (void) strlcat(mntopts, ",context=\"system_u:"
+                   "object_r:file_t:s0\"", sizeof (mntopts));
+#endif /* HAVE_LIBSELINUX */
+
        if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
                return (0);
 
@@ -318,12 +369,9 @@ 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.
         */
-       if ((flags & MS_OVERLAY) == 0 &&
-           strstr(mntopts, MNTOPT_REMOUNT) == NULL &&
+       if (strstr(mntopts, MNTOPT_REMOUNT) == NULL &&
            !dir_is_empty(mountpoint)) {
                zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
                    "directory is not empty"));
@@ -332,21 +380,33 @@ 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'"),
@@ -354,8 +414,7 @@ zfs_mount(zfs_handle_t *zhp, const char *options, int flags)
        }
 
        /* 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,7 +424,7 @@ 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) {
+       if (do_unmount(mountpoint, flags) != 0) {
                zfs_error_aux(hdl, strerror(errno));
                return (zfs_error_fmt(hdl, EZFS_UMOUNTFAILED,
                    dgettext(TEXT_DOMAIN, "cannot unmount '%s'"),
@@ -445,7 +504,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 +516,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 +539,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
@@ -536,8 +591,12 @@ static void (*_sa_update_sharetab_ts)(sa_handle_t);
  * values to be used later. This is triggered by the runtime loader.
  * Make sure the correct ISA version is loaded.
  */
-
+#ifdef __GNUC__
+static void
+_zfs_init_libshare(void) __attribute__((constructor));
+#else
 #pragma init(_zfs_init_libshare)
+#endif
 static void
 _zfs_init_libshare(void)
 {
@@ -734,10 +793,12 @@ zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
                return (0);
 
        if ((ret = zfs_init_libshare(hdl, SA_INIT_SHARE_API)) != SA_OK) {
+#ifdef HAVE_SHARE
                (void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED,
                    dgettext(TEXT_DOMAIN, "cannot share '%s': %s"),
                    zfs_get_name(zhp), _sa_errorstr != NULL ?
                    _sa_errorstr(ret) : "");
+#endif /* HAVE_SHARE */
                return (-1);
        }
 
@@ -999,93 +1060,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 +1092,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 +1139,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 +1148,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 +1183,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 +1191,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 +1206,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 +1228,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);
@@ -1386,3 +1343,53 @@ out:
 
        return (ret);
 }
+
+#else  /* HAVE_ZPL */
+
+int
+zfs_unshare_iscsi(zfs_handle_t *zhp)
+{
+       return 0;
+}
+
+int
+zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags)
+{
+       return 0;
+}
+
+void
+remove_mountpoint(zfs_handle_t *zhp) {
+       return;
+}
+
+boolean_t
+is_mounted(libzfs_handle_t *zfs_hdl, const char *special, char **where)
+{
+       return B_FALSE;
+}
+
+boolean_t
+zfs_is_mounted(zfs_handle_t *zhp, char **where)
+{
+       return is_mounted(zhp->zfs_hdl, zfs_get_name(zhp), where);
+}
+
+boolean_t
+zfs_is_shared(zfs_handle_t *zhp)
+{
+       return B_FALSE;
+}
+
+int
+zpool_enable_datasets(zpool_handle_t *zhp, const char *mntopts, int flags)
+{
+       return B_FALSE;
+}
+
+int
+zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force)
+{
+       return B_FALSE;
+}
+#endif /* HAVE_ZPL */