summaryrefslogtreecommitdiff
path: root/usr/src/lib/libzfs/common/libzfs_mount.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libzfs/common/libzfs_mount.c')
-rw-r--r--usr/src/lib/libzfs/common/libzfs_mount.c313
1 files changed, 239 insertions, 74 deletions
diff --git a/usr/src/lib/libzfs/common/libzfs_mount.c b/usr/src/lib/libzfs/common/libzfs_mount.c
index d7dd227bc8..6810f7efdc 100644
--- a/usr/src/lib/libzfs/common/libzfs_mount.c
+++ b/usr/src/lib/libzfs/common/libzfs_mount.c
@@ -45,11 +45,17 @@
* zfs_unshare()
*
* zfs_is_shared_nfs()
- * zfs_share_nfs()
- * zfs_unshare_nfs()
- * zfs_unshareall_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
@@ -82,11 +88,46 @@
#include <sys/systeminfo.h>
#define MAXISALEN 257 /* based on sysinfo(2) man page */
+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
+ */
+typedef struct {
+ zfs_prop_t p_prop;
+ char *p_name;
+ int p_share_err;
+ int p_unshare_err;
+} proto_table_t;
+
+proto_table_t proto_table[PROTO_END] = {
+ {ZFS_PROP_SHARENFS, "nfs", EZFS_SHARENFSFAILED, EZFS_UNSHARENFSFAILED},
+ {ZFS_PROP_SHARESMB, "smb", EZFS_SHARESMBFAILED, EZFS_UNSHARESMBFAILED},
+};
+
+zfs_share_proto_t nfs_only[] = {
+ PROTO_NFS,
+ PROTO_END
+};
+
+zfs_share_proto_t smb_only[] = {
+ PROTO_SMB,
+ PROTO_END
+};
+zfs_share_proto_t share_all_proto[] = {
+ PROTO_NFS,
+ PROTO_SMB,
+ PROTO_END
+};
+
#pragma init(zfs_iscsi_init)
static void
zfs_iscsi_init(void)
@@ -111,29 +152,54 @@ zfs_iscsi_init(void)
}
/*
- * Search the sharetab for the given mountpoint, returning true if it is found.
+ * Search the sharetab for the given mountpoint and protocol, returning
+ * a zfs_share_type_t value.
*/
-static boolean_t
-is_shared(libzfs_handle_t *hdl, const char *mountpoint)
+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 (0);
+ return (SHARED_NOT_SHARED);
(void) fseek(hdl->libzfs_sharetab, 0, SEEK_SET);
while (fgets(buf, sizeof (buf), hdl->libzfs_sharetab) != NULL) {
/* the mountpoint is the first entry on each line */
- if ((tab = strchr(buf, '\t')) != NULL) {
+ if ((tab = strchr(buf, '\t')) == NULL)
+ continue;
+
+ *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(buf, mountpoint) == 0)
- return (B_TRUE);
+ 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);
+ }
+ }
}
}
- return (B_FALSE);
+ return (SHARED_NOT_SHARED);
}
/*
@@ -349,12 +415,12 @@ zfs_unmount(zfs_handle_t *zhp, const char *mountpoint, int flags)
/*
* Unshare and unmount the filesystem
*/
- if (zfs_unshare_nfs(zhp, mntpt) != 0)
+ if (zfs_unshare_proto(zhp, mntpt, share_all_proto) != 0)
return (-1);
if (unmount_one(zhp->zfs_hdl, mntpt, flags) != 0) {
free(mntpt);
- (void) zfs_share_nfs(zhp);
+ (void) zfs_shareall(zhp);
return (-1);
}
free(mntpt);
@@ -387,10 +453,17 @@ zfs_unmountall(zfs_handle_t *zhp, int flags)
boolean_t
zfs_is_shared(zfs_handle_t *zhp)
{
+ zfs_share_type_t rc = 0;
+ zfs_share_proto_t *curr_proto;
+
if (ZFS_IS_VOLUME(zhp))
return (zfs_is_shared_iscsi(zhp));
- return (zfs_is_shared_nfs(zhp, NULL));
+ for (curr_proto = share_all_proto; *curr_proto != PROTO_END;
+ curr_proto++)
+ rc |= zfs_is_shared_proto(zhp, NULL, *curr_proto);
+
+ return (rc ? B_TRUE : B_FALSE);
}
int
@@ -399,7 +472,7 @@ zfs_share(zfs_handle_t *zhp)
if (ZFS_IS_VOLUME(zhp))
return (zfs_share_iscsi(zhp));
- return (zfs_share_nfs(zhp));
+ return (zfs_share_proto(zhp, share_all_proto));
}
int
@@ -408,32 +481,47 @@ zfs_unshare(zfs_handle_t *zhp)
if (ZFS_IS_VOLUME(zhp))
return (zfs_unshare_iscsi(zhp));
- return (zfs_unshare_nfs(zhp, NULL));
+ return (zfs_unshareall(zhp));
}
/*
* Check to see if the filesystem is currently shared.
*/
-boolean_t
-zfs_is_shared_nfs(zfs_handle_t *zhp, char **where)
+zfs_share_type_t
+zfs_is_shared_proto(zfs_handle_t *zhp, char **where, zfs_share_proto_t proto)
{
char *mountpoint;
+ zfs_share_type_t rc;
if (!zfs_is_mounted(zhp, &mountpoint))
- return (B_FALSE);
+ return (SHARED_NOT_SHARED);
- if (is_shared(zhp->zfs_hdl, mountpoint)) {
+ if (rc = is_shared(zhp->zfs_hdl, mountpoint, proto)) {
if (where != NULL)
*where = mountpoint;
else
free(mountpoint);
- return (B_TRUE);
+ return (rc);
} else {
free(mountpoint);
- return (B_FALSE);
+ return (SHARED_NOT_SHARED);
}
}
+boolean_t
+zfs_is_shared_nfs(zfs_handle_t *zhp, char **where)
+{
+ return (zfs_is_shared_proto(zhp, where,
+ PROTO_NFS) != SHARED_NOT_SHARED);
+}
+
+boolean_t
+zfs_is_shared_smb(zfs_handle_t *zhp, char **where)
+{
+ return (zfs_is_shared_proto(zhp, where,
+ PROTO_SMB) != SHARED_NOT_SHARED);
+}
+
/*
* Make sure things will work if libshare isn't installed by using
* wrapper functions that check to see that the pointers to functions
@@ -552,12 +640,13 @@ zfs_uninit_libshare(libzfs_handle_t *zhandle)
*/
int
-zfs_parse_options(char *options, char *proto)
+zfs_parse_options(char *options, zfs_share_proto_t proto)
{
int ret;
if (_sa_parse_legacy_options != NULL)
- ret = _sa_parse_legacy_options(NULL, options, proto);
+ ret = _sa_parse_legacy_options(NULL, options,
+ proto_table[proto].p_name);
else
ret = SA_CONFIG_ERR;
return (ret);
@@ -609,74 +698,102 @@ zfs_sa_disable_share(sa_share_t share, char *proto)
}
/*
- * Share the given filesystem according to the options in 'sharenfs'. We rely
+ * 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.
*/
-int
-zfs_share_nfs(zfs_handle_t *zhp)
+static int
+zfs_share_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
{
char mountpoint[ZFS_MAXPROPLEN];
char shareopts[ZFS_MAXPROPLEN];
libzfs_handle_t *hdl = zhp->zfs_hdl;
sa_share_t share;
+ zfs_share_proto_t *curr_proto;
int ret;
if (!zfs_is_mountable(zhp, mountpoint, sizeof (mountpoint), NULL))
return (0);
- /*
- * Return success if there are no share options.
- */
- if (zfs_prop_get(zhp, ZFS_PROP_SHARENFS, shareopts, sizeof (shareopts),
- NULL, NULL, 0, B_FALSE) != 0 ||
- strcmp(shareopts, "off") == 0)
- return (0);
-
- /*
- * 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))
- return (0);
-
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(ret));
return (-1);
}
- share = zfs_sa_find_share(hdl->libzfs_sharehdl, mountpoint);
- if (share != NULL) {
- int err;
- err = zfs_sa_enable_share(share, "nfs");
- if (err != SA_OK) {
- (void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED,
+
+ 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), NULL, NULL,
+ 0, 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;
+
+ share = zfs_sa_find_share(hdl->libzfs_sharehdl, mountpoint);
+ if (share != NULL) {
+ int err;
+ err = zfs_sa_enable_share(share,
+ proto_table[*curr_proto].p_name);
+ if (err != SA_OK) {
+ (void) zfs_error_fmt(hdl,
+ proto_table[*curr_proto].p_share_err,
+ dgettext(TEXT_DOMAIN, "cannot share '%s'"),
+ zfs_get_name(zhp));
+ return (-1);
+ }
+ } else {
+ (void) zfs_error_fmt(hdl,
+ proto_table[*curr_proto].p_share_err,
dgettext(TEXT_DOMAIN, "cannot share '%s'"),
zfs_get_name(zhp));
return (-1);
}
- } else {
- (void) zfs_error_fmt(hdl, EZFS_SHARENFSFAILED,
- dgettext(TEXT_DOMAIN, "cannot share '%s'"),
- zfs_get_name(zhp));
- return (-1);
- }
+ }
return (0);
}
+
+int
+zfs_share_nfs(zfs_handle_t *zhp)
+{
+ return (zfs_share_proto(zhp, nfs_only));
+}
+
+int
+zfs_share_smb(zfs_handle_t *zhp)
+{
+ return (zfs_share_proto(zhp, smb_only));
+}
+
+int
+zfs_shareall(zfs_handle_t *zhp)
+{
+ return (zfs_share_proto(zhp, share_all_proto));
+}
+
/*
* Unshare a filesystem by mountpoint.
*/
static int
-unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint)
+unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint,
+ zfs_share_proto_t proto)
{
sa_share_t share;
int err;
char *mntpt;
-
/*
* Mountpoint could get trashed if libshare calls getmntany
* which id does during API initialization, so strdup the
@@ -696,7 +813,7 @@ unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint)
free(mntpt); /* don't need the copy anymore */
if (share != NULL) {
- err = zfs_sa_disable_share(share, "nfs");
+ err = zfs_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"),
@@ -714,7 +831,8 @@ unshare_one(libzfs_handle_t *hdl, const char *name, const char *mountpoint)
* Unshare the given filesystem.
*/
int
-zfs_unshare_nfs(zfs_handle_t *zhp, const char *mountpoint)
+zfs_unshare_proto(zfs_handle_t *zhp, const char *mountpoint,
+ zfs_share_proto_t *proto)
{
struct mnttab search = { 0 }, entry;
char *mntpt = NULL;
@@ -724,19 +842,25 @@ zfs_unshare_nfs(zfs_handle_t *zhp, const char *mountpoint)
search.mnt_fstype = MNTTYPE_ZFS;
rewind(zhp->zfs_hdl->libzfs_mnttab);
if (mountpoint != NULL)
- mountpoint = mntpt = zfs_strdup(zhp->zfs_hdl, mountpoint);
+ mntpt = zfs_strdup(zhp->zfs_hdl, mountpoint);
if (mountpoint != NULL || ((zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) &&
getmntany(zhp->zfs_hdl->libzfs_mnttab, &entry, &search) == 0)) {
+ zfs_share_proto_t *curr_proto;
if (mountpoint == NULL)
- mountpoint = entry.mnt_mountp;
+ mntpt = zfs_strdup(zhp->zfs_hdl, entry.mnt_mountp);
- if (is_shared(zhp->zfs_hdl, mountpoint) &&
- unshare_one(zhp->zfs_hdl, zhp->zfs_name, mountpoint) != 0) {
- if (mntpt != NULL)
- free(mntpt);
- return (-1);
+ for (curr_proto = proto; *curr_proto != PROTO_END;
+ curr_proto++) {
+
+ if (is_shared(zhp->zfs_hdl, mntpt, *curr_proto) &&
+ unshare_one(zhp->zfs_hdl, zhp->zfs_name,
+ mntpt, *curr_proto) != 0) {
+ if (mntpt != NULL)
+ free(mntpt);
+ return (-1);
+ }
}
}
if (mntpt != NULL)
@@ -745,11 +869,23 @@ zfs_unshare_nfs(zfs_handle_t *zhp, const char *mountpoint)
return (0);
}
+int
+zfs_unshare_nfs(zfs_handle_t *zhp, const char *mountpoint)
+{
+ return (zfs_unshare_proto(zhp, mountpoint, nfs_only));
+}
+
+int
+zfs_unshare_smb(zfs_handle_t *zhp, const char *mountpoint)
+{
+ return (zfs_unshare_proto(zhp, mountpoint, smb_only));
+}
+
/*
- * Same as zfs_unmountall(), but for NFS unshares.
+ * Same as zfs_unmountall(), but for NFS and SMB unshares.
*/
int
-zfs_unshareall_nfs(zfs_handle_t *zhp)
+zfs_unshareall_proto(zfs_handle_t *zhp, zfs_share_proto_t *proto)
{
prop_changelist_t *clp;
int ret;
@@ -758,12 +894,36 @@ zfs_unshareall_nfs(zfs_handle_t *zhp)
if (clp == NULL)
return (-1);
- ret = changelist_unshare(clp);
+ ret = changelist_unshare(clp, proto);
changelist_free(clp);
return (ret);
}
+int
+zfs_unshareall_nfs(zfs_handle_t *zhp)
+{
+ return (zfs_unshareall_proto(zhp, nfs_only));
+}
+
+int
+zfs_unshareall_smb(zfs_handle_t *zhp)
+{
+ return (zfs_unshareall_proto(zhp, smb_only));
+}
+
+int
+zfs_unshareall(zfs_handle_t *zhp)
+{
+ return (zfs_unshareall_proto(zhp, share_all_proto));
+}
+
+int
+zfs_unshareall_bypath(zfs_handle_t *zhp, const char *mountpoint)
+{
+ return (zfs_unshare_proto(zhp, mountpoint, share_all_proto));
+}
+
/*
* Remove the mountpoint associated with the current dataset, if necessary.
* We only remove the underlying directory if:
@@ -805,7 +965,7 @@ 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 (0);
+ return (B_FALSE);
else
return (iscsitgt_zfs_is_shared != NULL &&
iscsitgt_zfs_is_shared(zhp->zfs_name) != 0);
@@ -853,7 +1013,7 @@ zfs_unshare_iscsi(zfs_handle_t *zhp)
/*
* Return if the volume is not shared
*/
- if (!zfs_is_shared_iscsi(zhp))
+ if (zfs_is_shared_iscsi(zhp) != SHARED_ISCSI)
return (0);
/*
@@ -1143,9 +1303,14 @@ zpool_disable_datasets(zpool_handle_t *zhp, boolean_t force)
* Walk through and first unshare everything.
*/
for (i = 0; i < used; i++) {
- if (is_shared(hdl, mountpoints[i]) &&
- unshare_one(hdl, mountpoints[i], mountpoints[i]) != 0)
- goto out;
+ zfs_share_proto_t *curr_proto;
+ for (curr_proto = share_all_proto; *curr_proto != PROTO_END;
+ curr_proto++) {
+ if (is_shared(hdl, mountpoints[i], *curr_proto) &&
+ unshare_one(hdl, mountpoints[i],
+ mountpoints[i], *curr_proto) != 0)
+ goto out;
+ }
}
/*