Merge 64400c3308
into d98973dbdd
This commit is contained in:
commit
e3e45fe924
|
@ -309,7 +309,8 @@ get_usage(zfs_help_t idx)
|
||||||
"[filesystem|volume|snapshot] ...\n"));
|
"[filesystem|volume|snapshot] ...\n"));
|
||||||
case HELP_MOUNT:
|
case HELP_MOUNT:
|
||||||
return (gettext("\tmount\n"
|
return (gettext("\tmount\n"
|
||||||
"\tmount [-flvO] [-o opts] <-a | filesystem>\n"));
|
"\tmount [-flvO] [-o opts] "
|
||||||
|
"<-a [filesystem] | [-A] filesystem>\n"));
|
||||||
case HELP_PROMOTE:
|
case HELP_PROMOTE:
|
||||||
return (gettext("\tpromote <clone-filesystem>\n"));
|
return (gettext("\tpromote <clone-filesystem>\n"));
|
||||||
case HELP_RECEIVE:
|
case HELP_RECEIVE:
|
||||||
|
@ -348,7 +349,7 @@ get_usage(zfs_help_t idx)
|
||||||
"<filesystem|volume>@<snap> ...\n"));
|
"<filesystem|volume>@<snap> ...\n"));
|
||||||
case HELP_UNMOUNT:
|
case HELP_UNMOUNT:
|
||||||
return (gettext("\tunmount [-fu] "
|
return (gettext("\tunmount [-fu] "
|
||||||
"<-a | filesystem|mountpoint>\n"));
|
"<-a [filesystem] | [-A] filesystem|mountpoint>\n"));
|
||||||
case HELP_UNSHARE:
|
case HELP_UNSHARE:
|
||||||
return (gettext("\tunshare "
|
return (gettext("\tunshare "
|
||||||
"<-a [nfs|smb] | filesystem|mountpoint>\n"));
|
"<-a [nfs|smb] | filesystem|mountpoint>\n"));
|
||||||
|
@ -6756,6 +6757,7 @@ zfs_do_holds(int argc, char **argv)
|
||||||
typedef struct get_all_state {
|
typedef struct get_all_state {
|
||||||
boolean_t ga_verbose;
|
boolean_t ga_verbose;
|
||||||
get_all_cb_t *ga_cbp;
|
get_all_cb_t *ga_cbp;
|
||||||
|
const char *ga_parent;
|
||||||
} get_all_state_t;
|
} get_all_state_t;
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -6794,6 +6796,16 @@ get_one_dataset(zfs_handle_t *zhp, void *data)
|
||||||
zfs_close(zhp);
|
zfs_close(zhp);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Skip any dataset that's not related to ga_parent.
|
||||||
|
*/
|
||||||
|
if (state->ga_parent != NULL &&
|
||||||
|
!zfs_dataset_related(zhp, state->ga_parent)) {
|
||||||
|
zfs_close(zhp);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
libzfs_add_handle(state->ga_cbp, zhp);
|
libzfs_add_handle(state->ga_cbp, zhp);
|
||||||
assert(state->ga_cbp->cb_used <= state->ga_cbp->cb_alloc);
|
assert(state->ga_cbp->cb_used <= state->ga_cbp->cb_alloc);
|
||||||
|
|
||||||
|
@ -6801,11 +6813,12 @@ get_one_dataset(zfs_handle_t *zhp, void *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
get_all_datasets(get_all_cb_t *cbp, boolean_t verbose)
|
get_all_datasets(get_all_cb_t *cbp, boolean_t verbose, const char *parent)
|
||||||
{
|
{
|
||||||
get_all_state_t state = {
|
get_all_state_t state = {
|
||||||
.ga_verbose = verbose,
|
.ga_verbose = verbose,
|
||||||
.ga_cbp = cbp
|
.ga_cbp = cbp,
|
||||||
|
.ga_parent = parent
|
||||||
};
|
};
|
||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
|
@ -6833,6 +6846,7 @@ typedef struct share_mount_state {
|
||||||
uint_t sm_total; /* number of filesystems to process */
|
uint_t sm_total; /* number of filesystems to process */
|
||||||
uint_t sm_done; /* number of filesystems processed */
|
uint_t sm_done; /* number of filesystems processed */
|
||||||
int sm_status; /* -1 if any of the share/mount operations failed */
|
int sm_status; /* -1 if any of the share/mount operations failed */
|
||||||
|
boolean_t sm_mount_noauto; /* treat 'canmount=noauto' as 'on' */
|
||||||
} share_mount_state_t;
|
} share_mount_state_t;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -6840,7 +6854,7 @@ typedef struct share_mount_state {
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
share_mount_one(zfs_handle_t *zhp, int op, int flags, enum sa_protocol protocol,
|
share_mount_one(zfs_handle_t *zhp, int op, int flags, enum sa_protocol protocol,
|
||||||
boolean_t explicit, const char *options)
|
boolean_t explicit, const char *options, boolean_t mount_noauto)
|
||||||
{
|
{
|
||||||
char mountpoint[ZFS_MAXPROPLEN];
|
char mountpoint[ZFS_MAXPROPLEN];
|
||||||
char shareopts[ZFS_MAXPROPLEN];
|
char shareopts[ZFS_MAXPROPLEN];
|
||||||
|
@ -6930,13 +6944,14 @@ share_mount_one(zfs_handle_t *zhp, int op, int flags, enum sa_protocol protocol,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* canmount explicit outcome
|
* canmount explicit mount_noauto outcome
|
||||||
* on no pass through
|
* on no n/a pass through
|
||||||
* on yes pass through
|
* on yes n/a pass through
|
||||||
* off no return 0
|
* off no n/a return 0
|
||||||
* off yes display error, return 1
|
* off yes n/a display error, return 1
|
||||||
* noauto no return 0
|
* noauto no no return 0
|
||||||
* noauto yes pass through
|
* noauto no yes pass through
|
||||||
|
* noauto yes yes/no pass through
|
||||||
*/
|
*/
|
||||||
canmount = zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT);
|
canmount = zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT);
|
||||||
if (canmount == ZFS_CANMOUNT_OFF) {
|
if (canmount == ZFS_CANMOUNT_OFF) {
|
||||||
|
@ -6947,11 +6962,13 @@ share_mount_one(zfs_handle_t *zhp, int op, int flags, enum sa_protocol protocol,
|
||||||
"'canmount' property is set to 'off'\n"), cmdname,
|
"'canmount' property is set to 'off'\n"), cmdname,
|
||||||
zfs_get_name(zhp));
|
zfs_get_name(zhp));
|
||||||
return (1);
|
return (1);
|
||||||
} else if (canmount == ZFS_CANMOUNT_NOAUTO && !explicit) {
|
} else if (canmount == ZFS_CANMOUNT_NOAUTO &&
|
||||||
|
!explicit && !mount_noauto) {
|
||||||
/*
|
/*
|
||||||
* When performing a 'zfs mount -a', we skip any mounts for
|
* When performing a 'zfs mount -a', we skip any mounts for
|
||||||
* datasets that have 'noauto' set. Sharing a dataset with
|
* datasets that have 'noauto' set. However, 'zfs mount -A'
|
||||||
* 'noauto' set is only allowed if it's mounted.
|
* will mount datasets with 'noauto' set. Sharing a dataset
|
||||||
|
* with 'noauto' set is only allowed if it's mounted.
|
||||||
*/
|
*/
|
||||||
if (op == OP_MOUNT)
|
if (op == OP_MOUNT)
|
||||||
return (0);
|
return (0);
|
||||||
|
@ -7107,7 +7124,7 @@ share_mount_one_cb(zfs_handle_t *zhp, void *arg)
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = share_mount_one(zhp, sms->sm_op, sms->sm_flags, sms->sm_proto,
|
ret = share_mount_one(zhp, sms->sm_op, sms->sm_flags, sms->sm_proto,
|
||||||
B_FALSE, sms->sm_options);
|
B_FALSE, sms->sm_options, sms->sm_mount_noauto);
|
||||||
|
|
||||||
pthread_mutex_lock(&sms->sm_lock);
|
pthread_mutex_lock(&sms->sm_lock);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
|
@ -7157,18 +7174,22 @@ sa_protocol_decode(const char *protocol)
|
||||||
static int
|
static int
|
||||||
share_mount(int op, int argc, char **argv)
|
share_mount(int op, int argc, char **argv)
|
||||||
{
|
{
|
||||||
int do_all = 0;
|
boolean_t do_all = B_FALSE;
|
||||||
|
boolean_t do_noauto = B_FALSE;
|
||||||
boolean_t verbose = B_FALSE;
|
boolean_t verbose = B_FALSE;
|
||||||
int c, ret = 0;
|
int c, ret = 0;
|
||||||
char *options = NULL;
|
char *options = NULL;
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
|
|
||||||
/* check options */
|
/* check options */
|
||||||
while ((c = getopt(argc, argv, op == OP_MOUNT ? ":alvo:Of" : "al"))
|
while ((c = getopt(argc, argv, op == OP_MOUNT ? ":aAlvo:Of" : "al"))
|
||||||
!= -1) {
|
!= -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'a':
|
case 'a':
|
||||||
do_all = 1;
|
do_all = B_TRUE;
|
||||||
|
break;
|
||||||
|
case 'A':
|
||||||
|
do_noauto = B_TRUE;
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
verbose = B_TRUE;
|
verbose = B_TRUE;
|
||||||
|
@ -7211,7 +7232,7 @@ share_mount(int op, int argc, char **argv)
|
||||||
argv += optind;
|
argv += optind;
|
||||||
|
|
||||||
/* check number of arguments */
|
/* check number of arguments */
|
||||||
if (do_all) {
|
if (do_all || do_noauto) {
|
||||||
enum sa_protocol protocol = SA_NO_PROTOCOL;
|
enum sa_protocol protocol = SA_NO_PROTOCOL;
|
||||||
|
|
||||||
if (op == OP_SHARE && argc > 0) {
|
if (op == OP_SHARE && argc > 0) {
|
||||||
|
@ -7219,15 +7240,40 @@ share_mount(int op, int argc, char **argv)
|
||||||
argc--;
|
argc--;
|
||||||
argv++;
|
argv++;
|
||||||
}
|
}
|
||||||
|
/* check number of arguments */
|
||||||
if (argc != 0) {
|
if (do_noauto && argc < 1) {
|
||||||
|
(void) fprintf(stderr, gettext("missing "
|
||||||
|
"dataset argument\n"));
|
||||||
|
usage(B_FALSE);
|
||||||
|
}
|
||||||
|
if ((op == OP_SHARE && argc != 0) || argc > 1) {
|
||||||
(void) fprintf(stderr, gettext("too many arguments\n"));
|
(void) fprintf(stderr, gettext("too many arguments\n"));
|
||||||
usage(B_FALSE);
|
usage(B_FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Limit `-a filesystem` to mount only
|
||||||
|
*/
|
||||||
|
const char *filesystem = NULL;
|
||||||
|
if (op == OP_MOUNT)
|
||||||
|
filesystem = argv[0];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Validate filesystem is actually a valid zfs filesystem
|
||||||
|
*/
|
||||||
|
if (filesystem != NULL) {
|
||||||
|
zfs_handle_t *zhp = zfs_open(g_zfs, filesystem,
|
||||||
|
ZFS_TYPE_FILESYSTEM);
|
||||||
|
if (zhp == NULL) {
|
||||||
|
free(options);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
zfs_close(zhp);
|
||||||
|
}
|
||||||
|
|
||||||
start_progress_timer();
|
start_progress_timer();
|
||||||
get_all_cb_t cb = { 0 };
|
get_all_cb_t cb = { 0 };
|
||||||
get_all_datasets(&cb, verbose);
|
get_all_datasets(&cb, verbose, filesystem);
|
||||||
|
|
||||||
if (cb.cb_used == 0) {
|
if (cb.cb_used == 0) {
|
||||||
free(options);
|
free(options);
|
||||||
|
@ -7241,6 +7287,7 @@ share_mount(int op, int argc, char **argv)
|
||||||
share_mount_state.sm_options = options;
|
share_mount_state.sm_options = options;
|
||||||
share_mount_state.sm_proto = protocol;
|
share_mount_state.sm_proto = protocol;
|
||||||
share_mount_state.sm_total = cb.cb_used;
|
share_mount_state.sm_total = cb.cb_used;
|
||||||
|
share_mount_state.sm_mount_noauto = do_noauto;
|
||||||
pthread_mutex_init(&share_mount_state.sm_lock, NULL);
|
pthread_mutex_init(&share_mount_state.sm_lock, NULL);
|
||||||
|
|
||||||
/* For a 'zfs share -a' operation start with a clean slate. */
|
/* For a 'zfs share -a' operation start with a clean slate. */
|
||||||
|
@ -7309,7 +7356,7 @@ share_mount(int op, int argc, char **argv)
|
||||||
ret = 1;
|
ret = 1;
|
||||||
} else {
|
} else {
|
||||||
ret = share_mount_one(zhp, op, flags, SA_NO_PROTOCOL,
|
ret = share_mount_one(zhp, op, flags, SA_NO_PROTOCOL,
|
||||||
B_TRUE, options);
|
B_TRUE, options, B_FALSE);
|
||||||
zfs_commit_shares(NULL);
|
zfs_commit_shares(NULL);
|
||||||
zfs_close(zhp);
|
zfs_close(zhp);
|
||||||
}
|
}
|
||||||
|
@ -7467,7 +7514,8 @@ out:
|
||||||
static int
|
static int
|
||||||
unshare_unmount(int op, int argc, char **argv)
|
unshare_unmount(int op, int argc, char **argv)
|
||||||
{
|
{
|
||||||
int do_all = 0;
|
boolean_t do_all = B_FALSE;
|
||||||
|
boolean_t do_noauto = B_FALSE;
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int c;
|
int c;
|
||||||
|
@ -7476,10 +7524,13 @@ unshare_unmount(int op, int argc, char **argv)
|
||||||
char sharesmb[ZFS_MAXPROPLEN];
|
char sharesmb[ZFS_MAXPROPLEN];
|
||||||
|
|
||||||
/* check options */
|
/* check options */
|
||||||
while ((c = getopt(argc, argv, op == OP_SHARE ? ":a" : "afu")) != -1) {
|
while ((c = getopt(argc, argv, op == OP_SHARE ? ":a" : "aAfu")) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'a':
|
case 'a':
|
||||||
do_all = 1;
|
do_all = B_TRUE;
|
||||||
|
break;
|
||||||
|
case 'A':
|
||||||
|
do_noauto = B_TRUE;
|
||||||
break;
|
break;
|
||||||
case 'f':
|
case 'f':
|
||||||
flags |= MS_FORCE;
|
flags |= MS_FORCE;
|
||||||
|
@ -7502,7 +7553,7 @@ unshare_unmount(int op, int argc, char **argv)
|
||||||
argc -= optind;
|
argc -= optind;
|
||||||
argv += optind;
|
argv += optind;
|
||||||
|
|
||||||
if (do_all) {
|
if (do_all || do_noauto) {
|
||||||
/*
|
/*
|
||||||
* We could make use of zfs_for_each() to walk all datasets in
|
* We could make use of zfs_for_each() to walk all datasets in
|
||||||
* the system, but this would be very inefficient, especially
|
* the system, but this would be very inefficient, especially
|
||||||
|
@ -7534,11 +7585,31 @@ unshare_unmount(int op, int argc, char **argv)
|
||||||
argv++;
|
argv++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argc != 0) {
|
/* check number of arguments */
|
||||||
|
if (do_noauto && argc < 1) {
|
||||||
|
(void) fprintf(stderr, gettext("missing "
|
||||||
|
"dataset argument\n"));
|
||||||
|
usage(B_FALSE);
|
||||||
|
}
|
||||||
|
if ((op == OP_SHARE && argc != 0) || argc > 1) {
|
||||||
(void) fprintf(stderr, gettext("too many arguments\n"));
|
(void) fprintf(stderr, gettext("too many arguments\n"));
|
||||||
usage(B_FALSE);
|
usage(B_FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Limit `-a filesystem` to unmount only
|
||||||
|
*/
|
||||||
|
const char *filesystem = NULL;
|
||||||
|
if (op == OP_MOUNT)
|
||||||
|
filesystem = argv[0];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Validate filesystem is actually a valid zfs filesystem
|
||||||
|
*/
|
||||||
|
if (filesystem != NULL && (zhp = zfs_open(g_zfs,
|
||||||
|
filesystem, ZFS_TYPE_FILESYSTEM)) == NULL)
|
||||||
|
return (1);
|
||||||
|
|
||||||
if (((pool = uu_avl_pool_create("unmount_pool",
|
if (((pool = uu_avl_pool_create("unmount_pool",
|
||||||
sizeof (unshare_unmount_node_t),
|
sizeof (unshare_unmount_node_t),
|
||||||
offsetof(unshare_unmount_node_t, un_avlnode),
|
offsetof(unshare_unmount_node_t, un_avlnode),
|
||||||
|
@ -7600,15 +7671,25 @@ unshare_unmount(int op, int argc, char **argv)
|
||||||
NULL, NULL, 0, B_FALSE) == 0);
|
NULL, NULL, 0, B_FALSE) == 0);
|
||||||
if (strcmp(nfs_mnt_prop, "legacy") == 0)
|
if (strcmp(nfs_mnt_prop, "legacy") == 0)
|
||||||
continue;
|
continue;
|
||||||
/* Ignore canmount=noauto mounts */
|
/*
|
||||||
|
* Ignore canmount=noauto mounts if
|
||||||
|
* 'do_noauto' is set to false (default: false)
|
||||||
|
*/
|
||||||
if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) ==
|
if (zfs_prop_get_int(zhp, ZFS_PROP_CANMOUNT) ==
|
||||||
ZFS_CANMOUNT_NOAUTO)
|
ZFS_CANMOUNT_NOAUTO && !do_noauto)
|
||||||
continue;
|
continue;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Skip any dataset that's not related to filesystem.
|
||||||
|
*/
|
||||||
|
if (filesystem != NULL &&
|
||||||
|
!zfs_dataset_related(zhp, filesystem))
|
||||||
|
continue;
|
||||||
|
|
||||||
node = safe_malloc(sizeof (unshare_unmount_node_t));
|
node = safe_malloc(sizeof (unshare_unmount_node_t));
|
||||||
node->un_zhp = zhp;
|
node->un_zhp = zhp;
|
||||||
node->un_mountp = safe_strdup(entry.mnt_mountp);
|
node->un_mountp = safe_strdup(entry.mnt_mountp);
|
||||||
|
|
|
@ -909,6 +909,7 @@ _LIBZFS_H int zfs_name_valid(const char *, zfs_type_t);
|
||||||
_LIBZFS_H zfs_handle_t *zfs_path_to_zhandle(libzfs_handle_t *, const char *,
|
_LIBZFS_H zfs_handle_t *zfs_path_to_zhandle(libzfs_handle_t *, const char *,
|
||||||
zfs_type_t);
|
zfs_type_t);
|
||||||
_LIBZFS_H int zfs_parent_name(zfs_handle_t *, char *, size_t);
|
_LIBZFS_H int zfs_parent_name(zfs_handle_t *, char *, size_t);
|
||||||
|
_LIBZFS_H boolean_t zfs_dataset_related(zfs_handle_t *, const char *);
|
||||||
_LIBZFS_H boolean_t zfs_dataset_exists(libzfs_handle_t *, const char *,
|
_LIBZFS_H boolean_t zfs_dataset_exists(libzfs_handle_t *, const char *,
|
||||||
zfs_type_t);
|
zfs_type_t);
|
||||||
_LIBZFS_H int zfs_spa_version(zfs_handle_t *, int *);
|
_LIBZFS_H int zfs_spa_version(zfs_handle_t *, int *);
|
||||||
|
|
|
@ -3466,6 +3466,35 @@ is_descendant(const char *ds1, const char *ds2)
|
||||||
return (ds2[d1len] == '/' && (strncmp(ds1, ds2, d1len) == 0));
|
return (ds2[d1len] == '/' && (strncmp(ds1, ds2, d1len) == 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Is one dataset is related to another, including self-relation?
|
||||||
|
*
|
||||||
|
* Needs to handle these cases:
|
||||||
|
* Dataset 1 "a/foo" "a/foo" "a/foo" "a/foo"
|
||||||
|
* Dataset 2 "a/foo" "a/fo" "a/foobar" "a/foo/bar"
|
||||||
|
* Related? Yes. No. No. Yes.
|
||||||
|
*/
|
||||||
|
static boolean_t
|
||||||
|
dataset_related(const char *ds1, const char *ds2)
|
||||||
|
{
|
||||||
|
/* ds1 and ds2 are identical */
|
||||||
|
if (strcmp(ds1, ds2) == 0)
|
||||||
|
return (B_TRUE);
|
||||||
|
|
||||||
|
/* ds2 is a descendant of ds1 */
|
||||||
|
if (is_descendant(ds1, ds2))
|
||||||
|
return (B_TRUE);
|
||||||
|
|
||||||
|
/* dataset are not related. */
|
||||||
|
return (B_FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean_t
|
||||||
|
zfs_dataset_related(zfs_handle_t *zhp, const char *parent)
|
||||||
|
{
|
||||||
|
return (dataset_related(parent, zfs_get_name(zhp)));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Given a complete name, return just the portion that refers to the parent.
|
* Given a complete name, return just the portion that refers to the parent.
|
||||||
* Will return -1 if there is no parent (path is just the name of the
|
* Will return -1 if there is no parent (path is just the name of the
|
||||||
|
|
|
@ -43,11 +43,11 @@
|
||||||
.Cm mount
|
.Cm mount
|
||||||
.Op Fl Oflv
|
.Op Fl Oflv
|
||||||
.Op Fl o Ar options
|
.Op Fl o Ar options
|
||||||
.Fl a Ns | Ns Ar filesystem
|
.Fl a Oo filesystem Oc | Oo Fl A Oc Ar filesystem
|
||||||
.Nm zfs
|
.Nm zfs
|
||||||
.Cm unmount
|
.Cm unmount
|
||||||
.Op Fl fu
|
.Op Fl fu
|
||||||
.Fl a Ns | Ns Ar filesystem Ns | Ns Ar mountpoint
|
.Fl a Oo filesystem Oc | Oo Fl A Oc Ar filesystem | Ar mountpoint
|
||||||
.
|
.
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
.Bl -tag -width ""
|
.Bl -tag -width ""
|
||||||
|
@ -61,7 +61,7 @@ Displays all ZFS file systems currently mounted.
|
||||||
.Cm mount
|
.Cm mount
|
||||||
.Op Fl Oflv
|
.Op Fl Oflv
|
||||||
.Op Fl o Ar options
|
.Op Fl o Ar options
|
||||||
.Fl a Ns | Ns Ar filesystem
|
.Fl a Oo filesystem Oc | Oo Fl A Oc Ar filesystem
|
||||||
.Xc
|
.Xc
|
||||||
Mount ZFS filesystem on a path described by its
|
Mount ZFS filesystem on a path described by its
|
||||||
.Sy mountpoint
|
.Sy mountpoint
|
||||||
|
@ -80,9 +80,13 @@ Allows mounting in non-empty
|
||||||
See
|
See
|
||||||
.Xr mount 8
|
.Xr mount 8
|
||||||
for more information.
|
for more information.
|
||||||
.It Fl a
|
.It Fl a Op filesystem
|
||||||
Mount all available ZFS file systems.
|
Mount the specified filesystem and its children, provided they are available.
|
||||||
Invoked automatically as part of the boot process if configured.
|
If no filesystem is specified, then all available ZFS file systems are mounted;
|
||||||
|
may be invoked automatically as part of the boot process if configured.
|
||||||
|
.It Fl A Ar filesystem
|
||||||
|
Mount the specified filesystem and its children, provided they are available.
|
||||||
|
Note: datasets with the `canmount=noauto` property will also be mounted.
|
||||||
.It Ar filesystem
|
.It Ar filesystem
|
||||||
Mount the specified filesystem.
|
Mount the specified filesystem.
|
||||||
.It Fl o Ar options
|
.It Fl o Ar options
|
||||||
|
@ -111,21 +115,26 @@ be mounted (e.g. redacted datasets).
|
||||||
.Nm zfs
|
.Nm zfs
|
||||||
.Cm unmount
|
.Cm unmount
|
||||||
.Op Fl fu
|
.Op Fl fu
|
||||||
.Fl a Ns | Ns Ar filesystem Ns | Ns Ar mountpoint
|
.Fl a Oo filesystem Oc | Oo Fl A Oc Ar filesystem | Ar mountpoint
|
||||||
.Xc
|
.Xc
|
||||||
Unmounts currently mounted ZFS file systems.
|
Unmounts currently mounted ZFS file systems.
|
||||||
.Bl -tag -width "-a"
|
.Bl -tag -width "-a"
|
||||||
.It Fl a
|
.It Fl a Op filesystem
|
||||||
Unmount all available ZFS file systems.
|
Unmount the specified filesystem and its children, provided they are available.
|
||||||
|
If no filesystem is specified,
|
||||||
|
then all available ZFS file systems are unmounted.
|
||||||
Invoked automatically as part of the shutdown process.
|
Invoked automatically as part of the shutdown process.
|
||||||
.It Fl f
|
.It Fl A Ar filesystem
|
||||||
Forcefully unmount the file system, even if it is currently in use.
|
Unmount the specified filesystem and its children, provided they are available.
|
||||||
This option is not supported on Linux.
|
Note: datasets with the `canmount=noauto` property will also be unmounted.
|
||||||
.It Fl u
|
|
||||||
Unload keys for any encryption roots unmounted by this command.
|
|
||||||
.It Ar filesystem Ns | Ns Ar mountpoint
|
.It Ar filesystem Ns | Ns Ar mountpoint
|
||||||
Unmount the specified filesystem.
|
Unmount the specified filesystem.
|
||||||
The command can also be given a path to a ZFS file system mount point on the
|
The command can also be given a path to a ZFS file system mount point on the
|
||||||
system.
|
system.
|
||||||
|
.It Fl u
|
||||||
|
Unload keys for any encryption roots unmounted by this command.
|
||||||
|
.It Fl f
|
||||||
|
Forcefully unmount the file system, even if it is currently in use.
|
||||||
|
This option is not supported on Linux.
|
||||||
.El
|
.El
|
||||||
.El
|
.El
|
||||||
|
|
|
@ -250,9 +250,9 @@ tags = ['functional', 'cli_root', 'zfs_load-key']
|
||||||
tests = ['zfs_mount_001_pos', 'zfs_mount_002_pos', 'zfs_mount_003_pos',
|
tests = ['zfs_mount_001_pos', 'zfs_mount_002_pos', 'zfs_mount_003_pos',
|
||||||
'zfs_mount_004_pos', 'zfs_mount_005_pos', 'zfs_mount_007_pos',
|
'zfs_mount_004_pos', 'zfs_mount_005_pos', 'zfs_mount_007_pos',
|
||||||
'zfs_mount_009_neg', 'zfs_mount_010_neg', 'zfs_mount_011_neg',
|
'zfs_mount_009_neg', 'zfs_mount_010_neg', 'zfs_mount_011_neg',
|
||||||
'zfs_mount_012_pos', 'zfs_mount_all_001_pos', 'zfs_mount_encrypted',
|
'zfs_mount_012_pos', 'zfs_mount_all_001_pos', 'zfs_mount_all_002_pos',
|
||||||
'zfs_mount_remount', 'zfs_mount_all_fail', 'zfs_mount_all_mountpoints',
|
'zfs_mount_encrypted', 'zfs_mount_remount', 'zfs_mount_all_fail',
|
||||||
'zfs_mount_test_race']
|
'zfs_mount_all_mountpoints', 'zfs_mount_test_race']
|
||||||
tags = ['functional', 'cli_root', 'zfs_mount']
|
tags = ['functional', 'cli_root', 'zfs_mount']
|
||||||
|
|
||||||
[tests/functional/cli_root/zfs_program]
|
[tests/functional/cli_root/zfs_program]
|
||||||
|
@ -344,7 +344,8 @@ tags = ['functional', 'cli_root', 'zfs_unload-key']
|
||||||
tests = ['zfs_unmount_001_pos', 'zfs_unmount_002_pos', 'zfs_unmount_003_pos',
|
tests = ['zfs_unmount_001_pos', 'zfs_unmount_002_pos', 'zfs_unmount_003_pos',
|
||||||
'zfs_unmount_004_pos', 'zfs_unmount_005_pos', 'zfs_unmount_006_pos',
|
'zfs_unmount_004_pos', 'zfs_unmount_005_pos', 'zfs_unmount_006_pos',
|
||||||
'zfs_unmount_007_neg', 'zfs_unmount_008_neg', 'zfs_unmount_009_pos',
|
'zfs_unmount_007_neg', 'zfs_unmount_008_neg', 'zfs_unmount_009_pos',
|
||||||
'zfs_unmount_all_001_pos', 'zfs_unmount_nested', 'zfs_unmount_unload_keys']
|
'zfs_unmount_all_001_pos', 'zfs_unmount_all_002_pos', 'zfs_unmount_nested',
|
||||||
|
'zfs_unmount_unload_keys']
|
||||||
tags = ['functional', 'cli_root', 'zfs_unmount']
|
tags = ['functional', 'cli_root', 'zfs_unmount']
|
||||||
|
|
||||||
[tests/functional/cli_root/zfs_unshare]
|
[tests/functional/cli_root/zfs_unshare]
|
||||||
|
|
|
@ -767,6 +767,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
|
||||||
functional/cli_root/zfs_mount/zfs_mount_013_pos.ksh \
|
functional/cli_root/zfs_mount/zfs_mount_013_pos.ksh \
|
||||||
functional/cli_root/zfs_mount/zfs_mount_014_neg.ksh \
|
functional/cli_root/zfs_mount/zfs_mount_014_neg.ksh \
|
||||||
functional/cli_root/zfs_mount/zfs_mount_all_001_pos.ksh \
|
functional/cli_root/zfs_mount/zfs_mount_all_001_pos.ksh \
|
||||||
|
functional/cli_root/zfs_mount/zfs_mount_all_002_pos.ksh \
|
||||||
functional/cli_root/zfs_mount/zfs_mount_all_fail.ksh \
|
functional/cli_root/zfs_mount/zfs_mount_all_fail.ksh \
|
||||||
functional/cli_root/zfs_mount/zfs_mount_all_mountpoints.ksh \
|
functional/cli_root/zfs_mount/zfs_mount_all_mountpoints.ksh \
|
||||||
functional/cli_root/zfs_mount/zfs_mount_encrypted.ksh \
|
functional/cli_root/zfs_mount/zfs_mount_encrypted.ksh \
|
||||||
|
@ -952,6 +953,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
|
||||||
functional/cli_root/zfs_unmount/zfs_unmount_008_neg.ksh \
|
functional/cli_root/zfs_unmount/zfs_unmount_008_neg.ksh \
|
||||||
functional/cli_root/zfs_unmount/zfs_unmount_009_pos.ksh \
|
functional/cli_root/zfs_unmount/zfs_unmount_009_pos.ksh \
|
||||||
functional/cli_root/zfs_unmount/zfs_unmount_all_001_pos.ksh \
|
functional/cli_root/zfs_unmount/zfs_unmount_all_001_pos.ksh \
|
||||||
|
functional/cli_root/zfs_unmount/zfs_unmount_all_002_pos.ksh \
|
||||||
functional/cli_root/zfs_unmount/zfs_unmount_nested.ksh \
|
functional/cli_root/zfs_unmount/zfs_unmount_nested.ksh \
|
||||||
functional/cli_root/zfs_unmount/zfs_unmount_unload_keys.ksh \
|
functional/cli_root/zfs_unmount/zfs_unmount_unload_keys.ksh \
|
||||||
functional/cli_root/zfs_unshare/cleanup.ksh \
|
functional/cli_root/zfs_unshare/cleanup.ksh \
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
# DESCRIPTION:
|
# DESCRIPTION:
|
||||||
# Try each 'zfs mount' with inapplicable scenarios to make sure
|
# Try each 'zfs mount' with inapplicable scenarios to make sure
|
||||||
# it returns an error. include:
|
# it returns an error. include:
|
||||||
# * '-a', but also with a specific filesystem.
|
# * Multiple filesystems specified
|
||||||
#
|
#
|
||||||
# STRATEGY:
|
# STRATEGY:
|
||||||
# 1. Create an array of parameters
|
# 1. Create an array of parameters
|
||||||
|
@ -53,7 +53,8 @@ for fs in $multifs ; do
|
||||||
datasets="$datasets $TESTPOOL/$fs"
|
datasets="$datasets $TESTPOOL/$fs"
|
||||||
done
|
done
|
||||||
|
|
||||||
set -A args "$mountall $TESTPOOL/$TESTFS"
|
set -A args "$mountall $datasets" \
|
||||||
|
"$mountcmd $datasets"
|
||||||
|
|
||||||
function setup_all
|
function setup_all
|
||||||
{
|
{
|
||||||
|
|
|
@ -57,7 +57,7 @@ log_assert "zfs mount fails with bad parameters"
|
||||||
log_onexit cleanup
|
log_onexit cleanup
|
||||||
|
|
||||||
fs=$TESTPOOL/$TESTFS
|
fs=$TESTPOOL/$TESTFS
|
||||||
set -A badargs "A" "-A" "-" "-x" "-?" "=" "-o *" "-a"
|
set -A badargs "A" "-" "-x" "-?" "=" "-o *"
|
||||||
|
|
||||||
for arg in "${badargs[@]}"; do
|
for arg in "${badargs[@]}"; do
|
||||||
log_mustnot eval "zfs mount $arg $fs >/dev/null 2>&1"
|
log_mustnot eval "zfs mount $arg $fs >/dev/null 2>&1"
|
||||||
|
|
|
@ -0,0 +1,209 @@
|
||||||
|
#!/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 https://opensource.org/licenses/CDDL-1.0.
|
||||||
|
# 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 2007 Sun Microsystems, Inc. All rights reserved.
|
||||||
|
# Use is subject to license terms.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016 by Delphix. All rights reserved.
|
||||||
|
#
|
||||||
|
|
||||||
|
. $STF_SUITE/include/libtest.shlib
|
||||||
|
. $STF_SUITE/tests/functional/cli_root/zfs_mount/zfs_mount.kshlib
|
||||||
|
|
||||||
|
#
|
||||||
|
# DESCRIPTION:
|
||||||
|
# Verify that 'zfs mount -a filesystem' succeeds as root.
|
||||||
|
#
|
||||||
|
# STRATEGY:
|
||||||
|
# 1. Create a group of pools with specified vdev.
|
||||||
|
# 2. Create zfs filesystems within the given pools.
|
||||||
|
# 3. Unmount all the filesystems.
|
||||||
|
# 4. Verify that 'zfs mount -a filesystem' command succeed,
|
||||||
|
# and the related available ZFS filesystems are mounted,
|
||||||
|
# and the unrelated ZFS filesystems remain unmounted
|
||||||
|
# 5. Verify that 'zfs mount' is identical with 'df -F zfs'
|
||||||
|
#
|
||||||
|
|
||||||
|
verify_runnable "both"
|
||||||
|
|
||||||
|
set -A fs "$TESTFS" "$TESTFS1"
|
||||||
|
set -A ctr "" "$TESTCTR" "$TESTCTR/$TESTCTR1" "$TESTCTR1"
|
||||||
|
set -A vol "$TESTVOL" "$TESTVOL1"
|
||||||
|
|
||||||
|
# Test the mounted state of root dataset (testpool/testctr)
|
||||||
|
typeset mnt=$TESTCTR
|
||||||
|
|
||||||
|
function setup_all
|
||||||
|
{
|
||||||
|
typeset -i i=0
|
||||||
|
typeset -i j=0
|
||||||
|
typeset path
|
||||||
|
|
||||||
|
while (( i < ${#ctr[*]} )); do
|
||||||
|
|
||||||
|
path=${TEST_BASE_DIR%%/}/testroot$$/$TESTPOOL
|
||||||
|
if [[ -n ${ctr[i]} ]]; then
|
||||||
|
path=$path/${ctr[i]}
|
||||||
|
|
||||||
|
setup_filesystem "$DISKS" "$TESTPOOL" \
|
||||||
|
"${ctr[i]}" "$path" \
|
||||||
|
"ctr"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if is_global_zone ; then
|
||||||
|
j=0
|
||||||
|
while (( j < ${#vol[*]} )); do
|
||||||
|
setup_filesystem "$DISKS" "$TESTPOOL" \
|
||||||
|
"${ctr[i]}/${vol[j]}" \
|
||||||
|
"$path/${vol[j]}" \
|
||||||
|
"vol"
|
||||||
|
((j = j + 1))
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
j=0
|
||||||
|
while (( j < ${#fs[*]} )); do
|
||||||
|
setup_filesystem "$DISKS" "$TESTPOOL" \
|
||||||
|
"${ctr[i]}/${fs[j]}" \
|
||||||
|
"$path/${fs[j]}"
|
||||||
|
((j = j + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
((i = i + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanup_all
|
||||||
|
{
|
||||||
|
typeset -i i=0
|
||||||
|
typeset -i j=0
|
||||||
|
typeset path
|
||||||
|
|
||||||
|
((i = ${#ctr[*]} - 1))
|
||||||
|
|
||||||
|
while (( i >= 0 )); do
|
||||||
|
if is_global_zone ; then
|
||||||
|
j=0
|
||||||
|
while (( j < ${#vol[*]} )); do
|
||||||
|
cleanup_filesystem "$TESTPOOL" \
|
||||||
|
"${ctr[i]}/${vol[j]}"
|
||||||
|
((j = j + 1))
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
j=0
|
||||||
|
while (( j < ${#fs[*]} )); do
|
||||||
|
cleanup_filesystem "$TESTPOOL" \
|
||||||
|
"${ctr[i]}/${fs[j]}"
|
||||||
|
((j = j + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
[[ -n ${ctr[i]} ]] && \
|
||||||
|
cleanup_filesystem "$TESTPOOL" "${ctr[i]}"
|
||||||
|
|
||||||
|
((i = i - 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
[[ -d ${TEST_BASE_DIR%%/}/testroot$$ ]] && \
|
||||||
|
rm -rf ${TEST_BASE_DIR%%/}/testroot$$
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# This function takes a single true/false argument:
|
||||||
|
# - true: it verifies that the $mnt file system is mounted.
|
||||||
|
# - false: it verifies that the $mnt file system is unmounted.
|
||||||
|
#
|
||||||
|
# In both scenarios, it ensures that the file systems in fs remain unmounted.
|
||||||
|
#
|
||||||
|
function verify_related
|
||||||
|
{
|
||||||
|
typeset -i i=0
|
||||||
|
typeset -i j=0
|
||||||
|
typeset path
|
||||||
|
typeset logfunc
|
||||||
|
|
||||||
|
while (( i < ${#ctr[*]} )); do
|
||||||
|
|
||||||
|
if $1 && { [[ ${ctr[i]} == $mnt ]] || [[ ${ctr[i]} == $mnt/* ]] }; then
|
||||||
|
logfunc=log_must
|
||||||
|
else
|
||||||
|
logfunc=log_mustnot
|
||||||
|
fi
|
||||||
|
|
||||||
|
path=$TESTPOOL
|
||||||
|
[[ -n ${ctr[i]} ]] && \
|
||||||
|
path=$path/${ctr[i]}
|
||||||
|
|
||||||
|
if is_global_zone ; then
|
||||||
|
j=0
|
||||||
|
while (( j < ${#vol[*]} )); do
|
||||||
|
log_mustnot mounted "$path/${vol[j]}"
|
||||||
|
((j = j + 1))
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
j=0
|
||||||
|
while (( j < ${#fs[*]} )); do
|
||||||
|
$logfunc mounted "$path/${fs[j]}"
|
||||||
|
((j = j + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
$logfunc mounted "$path"
|
||||||
|
|
||||||
|
((i = i + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
log_assert "Verify that 'zfs $mountall $TESTPOOL/$mnt' succeeds as root, " \
|
||||||
|
"and all the related available ZFS filesystems are mounted."
|
||||||
|
|
||||||
|
log_onexit cleanup_all
|
||||||
|
|
||||||
|
log_must setup_all
|
||||||
|
|
||||||
|
export __ZFS_POOL_RESTRICT="$TESTPOOL"
|
||||||
|
log_must zfs $unmountall
|
||||||
|
unset __ZFS_POOL_RESTRICT
|
||||||
|
|
||||||
|
verify_related false
|
||||||
|
|
||||||
|
export __ZFS_POOL_RESTRICT="$TESTPOOL"
|
||||||
|
log_must zfs $mountall $TESTPOOL/$mnt
|
||||||
|
unset __ZFS_POOL_RESTRICT
|
||||||
|
|
||||||
|
verify_related true
|
||||||
|
|
||||||
|
log_note "Verify that 'zfs $mountcmd' will display " \
|
||||||
|
"all available ZFS filesystems related to '$TESTPOOL/$mnt' are mounted."
|
||||||
|
|
||||||
|
verify_mount_display
|
||||||
|
|
||||||
|
log_pass "'zfs $mountall $TESTPOOL/$mnt' succeeds as root, " \
|
||||||
|
"and all the related available ZFS filesystems are mounted."
|
|
@ -37,7 +37,6 @@
|
||||||
# Try each 'zfs unmount' with inapplicable scenarios to make sure
|
# Try each 'zfs unmount' with inapplicable scenarios to make sure
|
||||||
# it returns an error. include:
|
# it returns an error. include:
|
||||||
# * Multiple filesystem|mountpoint specified
|
# * Multiple filesystem|mountpoint specified
|
||||||
# * '-a', but also with a specific filesystem|mountpoint.
|
|
||||||
#
|
#
|
||||||
# STRATEGY:
|
# STRATEGY:
|
||||||
# 1. Create an array of parameters
|
# 1. Create an array of parameters
|
||||||
|
@ -54,7 +53,7 @@ for fs in $multifs ; do
|
||||||
datasets="$datasets $TESTPOOL/$fs"
|
datasets="$datasets $TESTPOOL/$fs"
|
||||||
done
|
done
|
||||||
|
|
||||||
set -A args "$unmountall $TESTPOOL/$TESTFS" \
|
set -A args "$unmountall $datasets" \
|
||||||
"$unmountcmd $datasets"
|
"$unmountcmd $datasets"
|
||||||
|
|
||||||
function setup_all
|
function setup_all
|
||||||
|
|
|
@ -73,7 +73,7 @@ log_onexit cleanup
|
||||||
fs=$TESTPOOL/$TESTFS
|
fs=$TESTPOOL/$TESTFS
|
||||||
vol=$TESTPOOL/vol.$$
|
vol=$TESTPOOL/vol.$$
|
||||||
snap=$TESTPOOL/$TESTFS@snap.$$
|
snap=$TESTPOOL/$TESTFS@snap.$$
|
||||||
set -A badargs "A" "-A" "F" "-F" "-" "-x" "-?"
|
set -A badargs "A" "F" "-F" "-" "-x" "-?"
|
||||||
|
|
||||||
if ! ismounted $fs; then
|
if ! ismounted $fs; then
|
||||||
log_must zfs mount $fs
|
log_must zfs mount $fs
|
||||||
|
|
|
@ -0,0 +1,203 @@
|
||||||
|
#!/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 https://opensource.org/licenses/CDDL-1.0.
|
||||||
|
# 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 2007 Sun Microsystems, Inc. All rights reserved.
|
||||||
|
# Use is subject to license terms.
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright (c) 2016 by Delphix. All rights reserved.
|
||||||
|
#
|
||||||
|
|
||||||
|
. $STF_SUITE/tests/functional/cli_root/zfs_mount/zfs_mount.kshlib
|
||||||
|
. $STF_SUITE/tests/functional/cli_root/zfs_unmount/zfs_unmount.kshlib
|
||||||
|
|
||||||
|
#
|
||||||
|
# DESCRIPTION:
|
||||||
|
# Verify that 'zfs unmount -a[f]' succeeds as root.
|
||||||
|
#
|
||||||
|
# STRATEGY:
|
||||||
|
# 1. Create a group of pools with specified vdev.
|
||||||
|
# 2. Create zfs filesystems within the given pools.
|
||||||
|
# 3. Mount all the filesystems.
|
||||||
|
# 4. Verify that 'zfs unmount -a filesystem' command succeed,
|
||||||
|
# and the related available ZFS filesystems are unmounted,
|
||||||
|
# and the unrelated ZFS filesystems remain mounted
|
||||||
|
# 5. Verify that 'zfs mount' is identical with 'df -F zfs'
|
||||||
|
#
|
||||||
|
|
||||||
|
verify_runnable "both"
|
||||||
|
|
||||||
|
set -A fs "$TESTFS" "$TESTFS1"
|
||||||
|
set -A ctr "" "$TESTCTR" "$TESTCTR1" "$TESTCTR/$TESTCTR1"
|
||||||
|
set -A vol "$TESTVOL" "$TESTVOL1"
|
||||||
|
|
||||||
|
# Test the mounted state of root dataset (testpool/testctr)
|
||||||
|
typeset mnt=$TESTCTR
|
||||||
|
|
||||||
|
function setup_all
|
||||||
|
{
|
||||||
|
typeset -i i=0
|
||||||
|
typeset -i j=0
|
||||||
|
typeset path
|
||||||
|
|
||||||
|
while (( i < ${#ctr[*]} )); do
|
||||||
|
|
||||||
|
path=${TEST_BASE_DIR%%/}/testroot$$/$TESTPOOL
|
||||||
|
if [[ -n ${ctr[i]} ]]; then
|
||||||
|
path=$path/${ctr[i]}
|
||||||
|
|
||||||
|
setup_filesystem "$DISKS" "$TESTPOOL" \
|
||||||
|
"${ctr[i]}" "$path" \
|
||||||
|
"ctr"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if is_global_zone ; then
|
||||||
|
j=0
|
||||||
|
while (( j < ${#vol[*]} )); do
|
||||||
|
setup_filesystem "$DISKS" "$TESTPOOL" \
|
||||||
|
"${ctr[i]}/${vol[j]}" \
|
||||||
|
"$path/${vol[j]}" \
|
||||||
|
"vol"
|
||||||
|
((j = j + 1))
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
j=0
|
||||||
|
while (( j < ${#fs[*]} )); do
|
||||||
|
setup_filesystem "$DISKS" "$TESTPOOL" \
|
||||||
|
"${ctr[i]}/${fs[j]}" \
|
||||||
|
"$path/${fs[j]}"
|
||||||
|
((j = j + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
((i = i + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanup_all
|
||||||
|
{
|
||||||
|
typeset -i i=0
|
||||||
|
typeset -i j=0
|
||||||
|
|
||||||
|
((i = ${#ctr[*]} - 1))
|
||||||
|
|
||||||
|
while (( i >= 0 )); do
|
||||||
|
if is_global_zone ; then
|
||||||
|
j=0
|
||||||
|
while (( j < ${#vol[*]} )); do
|
||||||
|
cleanup_filesystem "$TESTPOOL" \
|
||||||
|
"${ctr[i]}/${vol[j]}"
|
||||||
|
((j = j + 1))
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
j=0
|
||||||
|
while (( j < ${#fs[*]} )); do
|
||||||
|
cleanup_filesystem "$TESTPOOL" \
|
||||||
|
"${ctr[i]}/${fs[j]}"
|
||||||
|
((j = j + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
[[ -n ${ctr[i]} ]] && \
|
||||||
|
cleanup_filesystem "$TESTPOOL" "${ctr[i]}"
|
||||||
|
|
||||||
|
((i = i - 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
[[ -d ${TEST_BASE_DIR%%/}/testroot$$ ]] && \
|
||||||
|
rm -rf ${TEST_BASE_DIR%%/}/testroot$$
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# This function verifies that the file systems in $mnt are unmounted.
|
||||||
|
# Next, it ensures that all other file systems in remain mounted.
|
||||||
|
#
|
||||||
|
function verify_related
|
||||||
|
{
|
||||||
|
typeset -i i=0
|
||||||
|
typeset -i j=0
|
||||||
|
typeset path
|
||||||
|
|
||||||
|
while (( i < ${#ctr[*]} )); do
|
||||||
|
|
||||||
|
if { [[ ${ctr[i]} == $mnt ]] || [[ ${ctr[i]} == $mnt/* ]] }; then
|
||||||
|
logfunc=log_must
|
||||||
|
else
|
||||||
|
logfunc=log_mustnot
|
||||||
|
fi
|
||||||
|
|
||||||
|
path=$TESTPOOL
|
||||||
|
[[ -n ${ctr[i]} ]] && \
|
||||||
|
path=$path/${ctr[i]}
|
||||||
|
|
||||||
|
if is_global_zone ; then
|
||||||
|
j=0
|
||||||
|
while (( j < ${#vol[*]} )); do
|
||||||
|
log_must unmounted "$path/${vol[j]}"
|
||||||
|
((j = j + 1))
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
j=0
|
||||||
|
while (( j < ${#fs[*]} )); do
|
||||||
|
$logfunc unmounted "$path/${fs[j]}"
|
||||||
|
((j = j + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
$logfunc unmounted "$path"
|
||||||
|
|
||||||
|
((i = i + 1))
|
||||||
|
done
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
log_assert "Verify that 'zfs $unmountall $TESTPOOL/$mnt' succeeds as root, " \
|
||||||
|
"and all the related available ZFS filesystems are unmounted."
|
||||||
|
|
||||||
|
log_onexit cleanup_all
|
||||||
|
|
||||||
|
log_must setup_all
|
||||||
|
|
||||||
|
typeset opt
|
||||||
|
for opt in "-a" "-fa"; do
|
||||||
|
export __ZFS_POOL_RESTRICT="$TESTPOOL"
|
||||||
|
log_must zfs $mountall
|
||||||
|
unset __ZFS_POOL_RESTRICT
|
||||||
|
|
||||||
|
export __ZFS_POOL_RESTRICT="$TESTPOOL"
|
||||||
|
log_must zfs unmount $opt $TESTPOOL/$mnt
|
||||||
|
unset __ZFS_POOL_RESTRICT
|
||||||
|
|
||||||
|
log_must verify_related
|
||||||
|
log_note "Verify that 'zfs $mountcmd' will display " \
|
||||||
|
"all available ZFS filesystems related to '$TESTPOOL/$mnt' are unmounted."
|
||||||
|
log_must verify_mount_display
|
||||||
|
|
||||||
|
done
|
||||||
|
|
||||||
|
log_pass "'zfs mount -[f]a $TESTPOOL/$mnt' succeeds as root, " \
|
||||||
|
"and all the related available ZFS filesystems are unmounted."
|
Loading…
Reference in New Issue