Allow zfs unshare <protocol> -a

Allow `zfs unshare <protocol> -a` command to share or unshare all datasets
of a given protocol, nfs or smb.

Additionally, enable most of ZFS Test Suite zfs_share/zfs_unshare test cases.
To work around some Illumos-specific functionalities ($SHARE/$UNSHARE) some
function wrappers were added around them.

Finally, fix and issue in smb_is_share_active() that would leave SMB shares
exported when invoking 'zfs unshare -a'

Reviewed-by: Giuseppe Di Natale <dinatale2@llnl.gov>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Turbo Fredriksson <turbo@bayour.com>
Signed-off-by: loli10K <ezomori.nozomu@gmail.com>
Closes #3238 
Closes #5367
This commit is contained in:
LOLi 2016-11-29 20:22:38 +01:00 committed by Brian Behlendorf
parent 251cb8dfac
commit 2f71caf2d9
17 changed files with 289 additions and 48 deletions

View File

@ -270,7 +270,7 @@ get_usage(zfs_help_t idx)
return (gettext("\tset <property=value> ... "
"<filesystem|volume|snapshot> ...\n"));
case HELP_SHARE:
return (gettext("\tshare <-a | filesystem>\n"));
return (gettext("\tshare <-a [nfs|smb] | filesystem>\n"));
case HELP_SNAPSHOT:
return (gettext("\tsnapshot|snap [-r] [-o property=value] ... "
"<filesystem|volume>@<snap> ...\n"));
@ -279,7 +279,7 @@ get_usage(zfs_help_t idx)
"<-a | filesystem|mountpoint>\n"));
case HELP_UNSHARE:
return (gettext("\tunshare "
"<-a | filesystem|mountpoint>\n"));
"<-a [nfs|smb] | filesystem|mountpoint>\n"));
case HELP_ALLOW:
return (gettext("\tallow <filesystem|volume>\n"
"\tallow [-ldug] "
@ -6436,7 +6436,7 @@ unshare_unmount(int op, int argc, char **argv)
char sharesmb[ZFS_MAXPROPLEN];
/* check options */
while ((c = getopt(argc, argv, op == OP_SHARE ? "a" : "af")) != -1) {
while ((c = getopt(argc, argv, op == OP_SHARE ? ":a" : "af")) != -1) {
switch (c) {
case 'a':
do_all = 1;
@ -6444,6 +6444,11 @@ unshare_unmount(int op, int argc, char **argv)
case 'f':
flags = MS_FORCE;
break;
case ':':
(void) fprintf(stderr, gettext("missing argument for "
"'%c' option\n"), optopt);
usage(B_FALSE);
break;
case '?':
(void) fprintf(stderr, gettext("invalid option '%c'\n"),
optopt);
@ -6475,6 +6480,19 @@ unshare_unmount(int op, int argc, char **argv)
unshare_unmount_node_t *node;
uu_avl_index_t idx;
uu_avl_walk_t *walk;
char *protocol = NULL;
if (op == OP_SHARE && argc > 0) {
if (strcmp(argv[0], "nfs") != 0 &&
strcmp(argv[0], "smb") != 0) {
(void) fprintf(stderr, gettext("share type "
"must be 'nfs' or 'smb'\n"));
usage(B_FALSE);
}
protocol = argv[0];
argc--;
argv++;
}
if (argc != 0) {
(void) fprintf(stderr, gettext("too many arguments\n"));
@ -6567,8 +6585,8 @@ unshare_unmount(int op, int argc, char **argv)
switch (op) {
case OP_SHARE:
if (zfs_unshareall_bypath(node->un_zhp,
node->un_mountp) != 0)
if (zfs_unshareall_bytype(node->un_zhp,
node->un_mountp, protocol) != 0)
ret = 1;
break;

View File

@ -116,6 +116,7 @@ AC_DEFUN([ZFS_AC_CONFIG_USER_COMMANDS_LINUX], [
AC_PATH_TOOL(READLINK, readlink, "")
AC_PATH_TOOL(SETFACL, setfacl, "")
AC_PATH_TOOL(SHARE, exportfs, "")
AC_PATH_TOOL(NET, net, "")
AC_PATH_TOOL(SWAP, swapon, "")
AC_PATH_TOOL(SWAPADD, swapon, "")
AC_PATH_TOOL(UDEVADM, udevadm, "")

View File

@ -763,6 +763,7 @@ extern int zfs_unshare_smb(zfs_handle_t *, const char *);
extern int zfs_unshareall_nfs(zfs_handle_t *);
extern int zfs_unshareall_smb(zfs_handle_t *);
extern int zfs_unshareall_bypath(zfs_handle_t *, const char *);
extern int zfs_unshareall_bytype(zfs_handle_t *, const char *, const char *);
extern int zfs_unshareall(zfs_handle_t *);
extern int zfs_deleg_share_nfs(libzfs_handle_t *, char *, char *, char *,
void *, void *, int, zfs_share_op_t);

View File

@ -354,17 +354,19 @@ smb_validate_shareopts(const char *shareopts)
static boolean_t
smb_is_share_active(sa_share_impl_t impl_share)
{
smb_share_t *iter = smb_shares;
if (!smb_available())
return (B_FALSE);
/* Retrieve the list of (possible) active shares */
smb_retrieve_shares();
while (smb_shares != NULL) {
if (strcmp(impl_share->sharepath, smb_shares->path) == 0)
while (iter != NULL) {
if (strcmp(impl_share->sharepath, iter->path) == 0)
return (B_TRUE);
smb_shares = smb_shares->next;
iter = iter->next;
}
return (B_FALSE);

View File

@ -988,6 +988,20 @@ zfs_unshareall_bypath(zfs_handle_t *zhp, const char *mountpoint)
return (zfs_unshare_proto(zhp, mountpoint, share_all_proto));
}
int
zfs_unshareall_bytype(zfs_handle_t *zhp, const char *mountpoint,
const char *proto)
{
if (proto == NULL)
return (zfs_unshare_proto(zhp, mountpoint, share_all_proto));
if (strcmp(proto, "nfs") == 0)
return (zfs_unshare_proto(zhp, mountpoint, nfs_only));
else if (strcmp(proto, "smb") == 0)
return (zfs_unshare_proto(zhp, mountpoint, smb_only));
else
return (1);
}
/*
* Remove the mountpoint associated with the current dataset, if necessary.
* We only remove the underlying directory if:

View File

@ -160,12 +160,12 @@ zfs \- configures ZFS file systems
.LP
.nf
\fBzfs\fR \fBshare\fR \fB-a\fR | \fIfilesystem\fR
\fBzfs\fR \fBshare\fR [\fBnfs\fR|\fBsmb\fR] \fB-a\fR | \fIfilesystem\fR
.fi
.LP
.nf
\fBzfs\fR \fBunshare\fR \fB-a\fR \fIfilesystem\fR|\fImountpoint\fR
\fBzfs\fR \fBunshare\fR [\fBnfs\fR|\fBsmb\fR] \fB-a\fR | \fIfilesystem\fR|\fImountpoint\fR
.fi
.LP
@ -2646,7 +2646,7 @@ Unmount the specified filesystem. The command can also be given a path to a \fBZ
.sp
.ne 2
.na
\fB\fBzfs share\fR \fB-a\fR | \fIfilesystem\fR\fR
\fB\fBzfs share\fR [\fBnfs\fR|\fBsmb\fR] \fB-a\fR | \fIfilesystem\fR\fR
.ad
.sp .6
.RS 4n
@ -2658,7 +2658,7 @@ Shares available \fBZFS\fR file systems.
.ad
.sp .6
.RS 4n
Share all available \fBZFS\fR file systems. Invoked automatically as part of the boot process.
Share all available \fBZFS\fR file systems. Invoked automatically as part of the boot process. Additionally if one of \fBnfs\fR|\fBsmb\fR protocols is specified only share file systems whose \fBsharenfs\fR|\fBsharesmb\fR is set.
.RE
.sp
@ -2676,11 +2676,11 @@ Share the specified filesystem according to the \fBsharenfs\fR and \fBsharesmb\f
.sp
.ne 2
.na
\fB\fBzfs unshare\fR \fB-a\fR | \fIfilesystem\fR|\fImountpoint\fR\fR
\fB\fBzfs unshare\fR [\fBnfs\fR|\fBsmb\fR] \fB-a\fR | \fIfilesystem\fR|\fImountpoint\fR\fR
.ad
.sp .6
.RS 4n
Unshares currently shared \fBZFS\fR file systems. This is invoked automatically as part of the shutdown process.
Unshares currently shared \fBZFS\fR file systems. This is invoked automatically as part of the shutdown process. Additionally if one of \fBnfs\fR|\fBsmb\fR is specified unshare only file systems currently shared by that protocol.
.sp
.ne 2
.na

View File

@ -181,11 +181,12 @@ tests = ['cache_001_pos', 'cache_002_neg', 'canmount_001_pos',
'zfs_set_002_neg', 'zfs_set_003_neg', 'property_alias_001_pos']
# DISABLED: Tests need to be updated for Linux share behavior
#[tests/functional/cli_root/zfs_share]
#tests = ['zfs_share_001_pos', 'zfs_share_002_pos', 'zfs_share_003_pos',
# 'zfs_share_004_pos', 'zfs_share_005_pos', 'zfs_share_006_pos',
# 'zfs_share_007_neg', 'zfs_share_008_neg', 'zfs_share_009_neg',
# 'zfs_share_010_neg', 'zfs_share_011_pos']
# zfs_share_005_pos - needs investigation, probably unsupported NFS share format
[tests/functional/cli_root/zfs_share]
tests = ['zfs_share_001_pos', 'zfs_share_002_pos', 'zfs_share_003_pos',
'zfs_share_004_pos', 'zfs_share_006_pos',
'zfs_share_007_neg', 'zfs_share_008_neg', 'zfs_share_009_neg',
'zfs_share_010_neg', 'zfs_share_011_pos']
[tests/functional/cli_root/zfs_snapshot]
tests = ['zfs_snapshot_001_neg', 'zfs_snapshot_002_neg',
@ -203,9 +204,11 @@ tests = ['zfs_unmount_001_pos', 'zfs_unmount_002_pos', 'zfs_unmount_003_pos',
'zfs_unmount_007_neg', 'zfs_unmount_008_neg']
# DISABLED: Tests need to be updated for Linux unshare behavior
#[tests/functional/cli_root/zfs_unshare]
#tests = ['zfs_unshare_001_pos', 'zfs_unshare_002_pos', 'zfs_unshare_003_pos',
# 'zfs_unshare_004_neg', 'zfs_unshare_005_neg']
# zfs_unshare_002_pos - zfs set sharenfs=off won't unshare if it was already off
# zfs_unshare_006_pos - some distros come with Samba "user shares" disabled
[tests/functional/cli_root/zfs_unshare]
tests = ['zfs_unshare_001_pos', 'zfs_unshare_003_pos',
'zfs_unshare_004_neg', 'zfs_unshare_005_neg']
[tests/functional/cli_root/zfs_upgrade]
tests = ['zfs_upgrade_001_pos', 'zfs_upgrade_002_pos', 'zfs_upgrade_003_pos',

View File

@ -67,6 +67,7 @@ export MOUNT="@MOUNT@"
export MPSTAT="@MPSTAT@"
export MV="@MV@"
export NAWK="@AWK@"
export NET="@NET@"
export NEWFS="@NEWFS@"
export NPROC="@NPROC@"
export PAGESIZE="@PAGESIZE@"

View File

@ -1052,7 +1052,7 @@ function datasetnonexists
}
#
# Given a mountpoint, or a dataset name, determine if it is shared.
# Given a mountpoint, or a dataset name, determine if it is shared via NFS.
#
# Returns 0 if shared, 1 otherwise.
#
@ -1061,11 +1061,6 @@ function is_shared
typeset fs=$1
typeset mtpt
if is_linux; then
log_unsupported "Currently unsupported by the test framework"
return 1
fi
if [[ $fs != "/"* ]] ; then
if datasetnonexists "$fs" ; then
return 1
@ -1080,6 +1075,15 @@ function is_shared
fi
fi
if is_linux; then
for mtpt in `$SHARE | $AWK '{print $1}'` ; do
if [[ $mtpt == $fs ]] ; then
return 0
fi
done
return 1
fi
for mtpt in `$SHARE | $AWK '{print $2}'` ; do
if [[ $mtpt == $fs ]] ; then
return 0
@ -1095,7 +1099,36 @@ function is_shared
}
#
# Given a mountpoint, determine if it is not shared.
# Given a dataset name determine if it is shared via SMB.
#
# Returns 0 if shared, 1 otherwise.
#
function is_shared_smb
{
typeset fs=$1
typeset mtpt
if datasetnonexists "$fs" ; then
return 1
else
fs=$(echo $fs | sed 's@/@_@g')
fi
if is_linux; then
for mtpt in `$NET usershare list | $AWK '{print $1}'` ; do
if [[ $mtpt == $fs ]] ; then
return 0
fi
done
return 1
else
log_unsupported "Currently unsupported by the test framework"
return 1
fi
}
#
# Given a mountpoint, determine if it is not shared via NFS.
#
# Returns 0 if not shared, 1 otherwise.
#
@ -1103,12 +1136,24 @@ function not_shared
{
typeset fs=$1
if is_linux; then
log_unsupported "Currently unsupported by the test framework"
is_shared $fs
if (($? == 0)); then
return 1
fi
is_shared $fs
return 0
}
#
# Given a dataset determine if it is not shared via SMB.
#
# Returns 0 if not shared, 1 otherwise.
#
function not_shared_smb
{
typeset fs=$1
is_shared_smb $fs
if (($? == 0)); then
return 1
fi
@ -1123,12 +1168,7 @@ function unshare_fs #fs
{
typeset fs=$1
if is_linux; then
log_unsupported "Currently unsupported by the test framework"
return 1
fi
is_shared $fs
is_shared $fs || is_shared_smb $fs
if (($? == 0)); then
log_must $ZFS unshare $fs
fi
@ -1136,6 +1176,78 @@ function unshare_fs #fs
return 0
}
#
# Helper function to share a NFS mountpoint.
#
function share_nfs #fs
{
typeset fs=$1
if is_linux; then
is_shared $fs
if (($? != 0)); then
log_must $SHARE "*:$fs"
fi
else
is_shared $fs
if (($? != 0)); then
log_must $SHARE -F nfs $fs
fi
fi
return 0
}
#
# Helper function to unshare a NFS mountpoint.
#
function unshare_nfs #fs
{
typeset fs=$1
if is_linux; then
is_shared $fs
if (($? == 0)); then
log_must $UNSHARE -u "*:$fs"
fi
else
is_shared $fs
if (($? == 0)); then
log_must $UNSHARE -F nfs $fs
fi
fi
return 0
}
#
# Helper function to show NFS shares.
#
function showshares_nfs
{
if is_linux; then
$SHARE -v
else
$SHARE -F nfs
fi
return 0
}
#
# Helper function to show SMB shares.
#
function showshares_smb
{
if is_linux; then
$NET usershare list
else
$SHARE -F smb
fi
return 0
}
#
# Check NFS server status and trigger it online.
#
@ -1149,7 +1261,7 @@ function setup_nfs_server
fi
if is_linux; then
log_unsupported "Currently unsupported by the test framework"
log_note "NFS server must started prior to running test framework."
return
fi

View File

@ -68,7 +68,7 @@ do
log_fail "get sharenfs failed. ($option != ${shareopts[i]})"
fi
$SHARE | $GREP $option > /dev/null 2>&1
showshares_nfs | $GREP $option > /dev/null 2>&1
if (( $? != 0 )); then
log_fail "The '$option' option was not found in share output."
fi

View File

@ -59,7 +59,7 @@ do
log_note "Setting sharenfs=${badopts[i]} $i "
log_mustnot $ZFS set sharenfs="${badopts[i]}" $TESTPOOL/$TESTFS
$SHARE | $GREP $option > /dev/null 2>&1
showshares_nfs | $GREP $option > /dev/null 2>&1
if (( $? == 0 )); then
log_fail "An invalid setting '$option' was propagated."
fi

View File

@ -59,7 +59,7 @@ if [[ $sharenfs_val == off ]]; then
log_must $ZFS set sharenfs=on $fs
fi
$SHARE | $GREP $mpt >/dev/null 2>&1
showshares_nfs | $GREP $mpt >/dev/null 2>&1
if (( $? != 0 )); then
log_must $ZFS share $fs
fi

View File

@ -6,4 +6,5 @@ dist_pkgdata_SCRIPTS = \
zfs_unshare_002_pos.ksh \
zfs_unshare_003_pos.ksh \
zfs_unshare_004_neg.ksh \
zfs_unshare_005_neg.ksh
zfs_unshare_005_neg.ksh \
zfs_unshare_006_pos.ksh

View File

@ -88,7 +88,7 @@ function test_unshare # <mntp> <filesystem>
if [[ $prop_value == "off" ]]; then
not_shared $mntp ||
log_must $UNSHARE -F nfs $mntp
log_must eval "unshare_nfs $mntp"
log_must $ZFS set sharenfs=on $filesystem
is_shared $mntp || \
log_fail "'$ZFS set sharenfs=on' fails to make" \

View File

@ -45,7 +45,7 @@ function cleanup
typeset -i i=0
while (( i < ${#mntp_fs[*]} )); do
is_shared ${mntp_fs[i]} && \
log_must $UNSHARE -F nfs ${mntp_fs[i]}
log_must eval "unshare_nfs ${mntp_fs[i]}"
((i = i + 2))
done
@ -86,7 +86,7 @@ function test_legacy_unshare # <mntp> <filesystem>
log_fail "'zfs set sharenfs=off' fails to make ZFS " \
"filesystem $filesystem unshared."
log_must $SHARE -F nfs $mntp
log_must eval "share_nfs $mntp"
is_shared $mntp || \
log_fail "'share' command fails to share ZFS file system."
#
@ -150,7 +150,7 @@ done
#
i=0
while (( i < ${#mntp_fs[*]} )); do
$SHARE -F nfs ${mntp_fs[i]}
share_nfs ${mntp_fs[i]}
is_shared ${mntp_fs[i]} || \
log_fail "'$SHARE' shares ZFS filesystem failed."

View File

@ -68,7 +68,7 @@ function test_snap_unshare # <mntp> <filesystem>
prop_value=$(get_prop "sharenfs" $filesystem)
if [[ $prop_value == "off" ]]; then
is_shared $mntp || $UNSHARE -F nfs $mntp
is_shared $mntp || unshare_nfs $mntp
log_must $ZFS set sharenfs=on $filesystem
fi

View File

@ -0,0 +1,88 @@
#!/bin/ksh -p
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License (the "License").
# You may not use this file except in compliance with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
# Copyright 2016, loli10K. All rights reserved.
#
. $STF_SUITE/include/libtest.shlib
#
# DESCRIPTION:
# Verify that 'zfs unshare [nfs|smb] -a' unshares only filesystems shared by the
# specified protocol.
#
# STRATEGY:
# 1. Share filesystems with different protocols.
# 2. Invoke 'zfs unshare nfs -a' to unshare filesystems.
# 3. Verify that only nfs filesystems are unshared.
# 4. Share all filesystems again.
# 5. Invoke 'zfs unshare smb -a' and verify only smb filesystems are unshared.
#
verify_runnable "global"
function cleanup
{
log_must $ZFS unshare -a
log_must $ZFS destroy -f $TESTPOOL/$TESTFS/shared1
log_must $ZFS destroy -f $TESTPOOL/$TESTFS/shared2
log_must $ZFS destroy -f $TESTPOOL/$TESTFS/shared3
}
log_assert "Verify '$ZFS unshare [nfs|smb] -a' only works on the specified "\
"protocol."
log_onexit cleanup
# 1. Share filesystems with different protocols.
log_must $ZFS create $TESTPOOL/$TESTFS/shared1
log_must $ZFS create $TESTPOOL/$TESTFS/shared2
log_must $ZFS create $TESTPOOL/$TESTFS/shared3
log_must $ZFS set mountpoint=$TESTDIR/1 $TESTPOOL/$TESTFS/shared1
log_must $ZFS set mountpoint=$TESTDIR/2 $TESTPOOL/$TESTFS/shared2
log_must $ZFS set mountpoint=$TESTDIR/3 $TESTPOOL/$TESTFS/shared3
log_must $ZFS set sharenfs=on $TESTPOOL/$TESTFS/shared1
log_must $ZFS set sharenfs=on $TESTPOOL/$TESTFS/shared2
log_must $ZFS set sharesmb=on $TESTPOOL/$TESTFS/shared2
log_must $ZFS set sharesmb=on $TESTPOOL/$TESTFS/shared3
log_must $ZFS share -a
# 2. Invoke 'zfs unshare nfs -a' to unshare filesystems.
log_must $ZFS unshare nfs -a
# 3. Verify that only nfs filesystems are unshared.
log_must eval "not_shared $TESTPOOL/$TESTFS/shared1"
log_must eval "not_shared $TESTPOOL/$TESTFS/shared2"
log_must eval "is_shared_smb $TESTPOOL/$TESTFS/shared2"
log_must eval "is_shared_smb $TESTPOOL/$TESTFS/shared3"
# 4. Share all filesystems again.
log_must $ZFS share -a
# 5. Invoke 'zfs unshare smb -a' and verify only smb filesystems are unshared.
log_must $ZFS unshare smb -a
log_must eval "is_shared $TESTPOOL/$TESTFS/shared1"
log_must eval "is_shared $TESTPOOL/$TESTFS/shared2"
log_must eval "not_shared_smb $TESTPOOL/$TESTFS/shared2"
log_must eval "not_shared_smb $TESTPOOL/$TESTFS/shared3"
log_pass "'$ZFS unshare [nfs|smb] -a' only works on the specified protocol."