aboutsummaryrefslogtreecommitdiffstats
path: root/lib/libzfs/libzfs_mount.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libzfs/libzfs_mount.c')
-rw-r--r--lib/libzfs/libzfs_mount.c168
1 files changed, 142 insertions, 26 deletions
diff --git a/lib/libzfs/libzfs_mount.c b/lib/libzfs/libzfs_mount.c
index b257b6511..6d11016bc 100644
--- a/lib/libzfs/libzfs_mount.c
+++ b/lib/libzfs/libzfs_mount.c
@@ -22,7 +22,7 @@
/*
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2014, 2019 by Delphix. All rights reserved.
+ * Copyright (c) 2014, 2020 by Delphix. All rights reserved.
* Copyright 2016 Igor Kozhukhov <[email protected]>
* Copyright 2017 RackTop Systems.
* Copyright (c) 2018 Datto Inc.
@@ -593,10 +593,12 @@ zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags)
free(mntpt);
return (-1);
}
+ zfs_commit_all_shares();
if (unmount_one(hdl, mntpt, flags) != 0) {
free(mntpt);
(void) zfs_shareall(zhp);
+ zfs_commit_all_shares();
return (-1);
}
@@ -669,6 +671,94 @@ zfs_is_shared(zfs_handle_t *zhp)
return (rc ? B_TRUE : B_FALSE);
}
+/*
+ * Unshare a filesystem by mountpoint.
+ */
+int
+unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint,
+ zfs_share_proto_t proto)
+{
+ int err;
+
+ err = sa_disable_share(mountpoint, proto_table[proto].p_name);
+ if (err != SA_OK) {
+ return (zfs_error_fmt(hdl, proto_table[proto].p_unshare_err,
+ dgettext(TEXT_DOMAIN, "cannot unshare '%s': %s"),
+ name, sa_errorstr(err)));
+ }
+ return (0);
+}
+
+/*
+ * Query libshare for the given mountpoint and protocol, returning
+ * a zfs_share_type_t value.
+ */
+zfs_share_type_t
+is_shared(const char *mountpoint, zfs_share_proto_t proto)
+{
+ if (sa_is_shared(mountpoint, proto_table[proto].p_name)) {
+ switch (proto) {
+ case PROTO_NFS:
+ return (SHARED_NFS);
+ case PROTO_SMB:
+ return (SHARED_SMB);
+ default:
+ return (SHARED_NOT_SHARED);
+ }
+ }
+ return (SHARED_NOT_SHARED);
+}
+
+/*
+ * Share the given filesystem according to the options in the specified
+ * protocol specific properties (sharenfs, sharesmb). We rely
+ * on "libshare" to do the dirty work for us.
+ */
+int
+zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
+{
+ char mountpoint[ZFS_MAXPROPLEN];
+ char shareopts[ZFS_MAXPROPLEN];
+ char sourcestr[ZFS_MAXPROPLEN];
+ zfs_share_proto_t *curr_proto;
+ zprop_source_t sourcetype;
+ int err = 0;
+
+ if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL, 0))
+ return (0);
+
+ for (curr_proto = proto; *curr_proto != PROTO_END; curr_proto++) {
+ /*
+ * Return success if there are no share options.
+ */
+ if (zfs_prop_get(zhp, proto_table[*curr_proto].p_prop,
+ shareopts, sizeof (shareopts), &sourcetype, sourcestr,
+ ZFS_MAXPROPLEN, B_FALSE) != 0 ||
+ strcmp(shareopts, "off") == 0)
+ continue;
+
+ /*
+ * If the 'zoned' property is set, then zfs_is_mountable()
+ * will have already bailed out if we are in the global zone.
+ * But local zones cannot be NFS servers, so we ignore it for
+ * local zones as well.
+ */
+ if (zfs_prop_get_int(zhp, ZFS_PROP_ZONED))
+ continue;
+
+ err = sa_enable_share(zfs_get_name(zhp), mountpoint, shareopts,
+ proto_table[*curr_proto].p_name);
+ if (err != SA_OK) {
+ return (zfs_error_fmt(zhp->zfs_hdl,
+ proto_table[*curr_proto].p_share_err,
+ dgettext(TEXT_DOMAIN, "cannot share '%s: %s'"),
+ zfs_get_name(zhp), sa_errorstr(err)));
+ }
+
+ }
+ return (0);
+}
+
int
zfs_share(zfs_handle_t *zhp)
{
@@ -695,7 +785,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_impl(zhp->zfs_hdl, mountpoint, proto))
+ if ((rc = is_shared(mountpoint, proto))
!= SHARED_NOT_SHARED) {
if (where != NULL)
*where = mountpoint;
@@ -723,21 +813,6 @@ zfs_is_shared_smb(zfs_handle_t *zhp, char **where)
}
/*
- * zfs_uninit_libshare(zhandle)
- *
- * Uninitialize the libshare API if it hasn't already been
- * uninitialized. It is OK to call multiple times.
- */
-void
-zfs_uninit_libshare(libzfs_handle_t *zhandle)
-{
- if (zhandle != NULL && zhandle->libzfs_sharehdl != NULL) {
- sa_fini(zhandle->libzfs_sharehdl);
- zhandle->libzfs_sharehdl = NULL;
- }
-}
-
-/*
* zfs_parse_options(options, proto)
*
* Call the legacy parse interface to get the protocol specific
@@ -746,8 +821,45 @@ zfs_uninit_libshare(libzfs_handle_t *zhandle)
int
zfs_parse_options(char *options, zfs_share_proto_t proto)
{
- return (sa_parse_legacy_options(NULL, options,
- proto_table[proto].p_name));
+ return (sa_validate_shareopts(options, proto_table[proto].p_name));
+}
+
+void
+zfs_commit_proto(zfs_share_proto_t *proto)
+{
+ zfs_share_proto_t *curr_proto;
+ for (curr_proto = proto; *curr_proto != PROTO_END; curr_proto++) {
+ sa_commit_shares(proto_table[*curr_proto].p_name);
+ }
+}
+
+void
+zfs_commit_nfs_shares(void)
+{
+ zfs_commit_proto(nfs_only);
+}
+
+void
+zfs_commit_smb_shares(void)
+{
+ zfs_commit_proto(smb_only);
+}
+
+void
+zfs_commit_all_shares(void)
+{
+ zfs_commit_proto(share_all_proto);
+}
+
+void
+zfs_commit_shares(const char *proto)
+{
+ if (proto == NULL)
+ zfs_commit_proto(share_all_proto);
+ else if (strcmp(proto, "nfs") == 0)
+ zfs_commit_proto(nfs_only);
+ else if (strcmp(proto, "smb") == 0)
+ zfs_commit_proto(smb_only);
}
int
@@ -793,12 +905,13 @@ zfs_unshare_proto(zfs_handle_t *zhp, const char *mountpoint,
for (curr_proto = proto; *curr_proto != PROTO_END;
curr_proto++) {
- if (is_shared_impl(hdl, mntpt, *curr_proto) &&
- unshare_one(hdl, zhp->zfs_name,
- mntpt, *curr_proto) != 0) {
- if (mntpt != NULL)
- free(mntpt);
- return (-1);
+ if (is_shared(mntpt, *curr_proto)) {
+ if (unshare_one(hdl, zhp->zfs_name,
+ mntpt, *curr_proto) != 0) {
+ if (mntpt != NULL)
+ free(mntpt);
+ return (-1);
+ }
}
}
}
@@ -1338,6 +1451,8 @@ zpool_enable_datasets(zpool_handle_t *zhp, const char *mntopts, int flags)
zfs_share_one, &ms, B_FALSE);
if (ms.ms_mntstatus != 0)
ret = ms.ms_mntstatus;
+ else
+ zfs_commit_all_shares();
out:
for (int i = 0; i < cb.cb_used; i++)
@@ -1463,12 +1578,13 @@ zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force)
zfs_share_proto_t *curr_proto;
for (curr_proto = share_all_proto; *curr_proto != PROTO_END;
curr_proto++) {
- if (is_shared_impl(hdl, mountpoints[i], *curr_proto) &&
+ if (is_shared(mountpoints[i], *curr_proto) &&
unshare_one(hdl, mountpoints[i],
mountpoints[i], *curr_proto) != 0)
goto out;
}
}
+ zfs_commit_all_shares();
/*
* Now unmount everything, removing the underlying directories as