Add support for zfs mount -R <filesystem>
This commit adds support for mounting a dataset along with all of it's children with '-R' flag for zfs mount. There can be scenarios where we want to mount all datasets under one hierarchy instead of mounting all datasets present on system with '-a' flag. '-R' flag should work on all root and non-root datasets. Usage information and man page has been updated for zfs mount. A test for verifying the behavior for '-R' flag is also added. Reviewed-by: Ameer Hamza <ahamza@ixsystems.com> Reviewed-by: Alexander Motin <mav@FreeBSD.org> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Umer Saleem <usaleem@ixsystems.com> Closes #16015
This commit is contained in:
parent
9a7ef02f4d
commit
8a56047135
|
@ -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|-R filesystem|"
|
||||||
|
"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:
|
||||||
|
@ -6750,6 +6751,8 @@ zfs_do_holds(int argc, char **argv)
|
||||||
#define MOUNT_TIME 1 /* seconds */
|
#define MOUNT_TIME 1 /* seconds */
|
||||||
|
|
||||||
typedef struct get_all_state {
|
typedef struct get_all_state {
|
||||||
|
char **ga_datasets;
|
||||||
|
int ga_count;
|
||||||
boolean_t ga_verbose;
|
boolean_t ga_verbose;
|
||||||
get_all_cb_t *ga_cbp;
|
get_all_cb_t *ga_cbp;
|
||||||
} get_all_state_t;
|
} get_all_state_t;
|
||||||
|
@ -6796,19 +6799,35 @@ get_one_dataset(zfs_handle_t *zhp, void *data)
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static int
|
||||||
get_all_datasets(get_all_cb_t *cbp, boolean_t verbose)
|
get_recursive_datasets(zfs_handle_t *zhp, void *data)
|
||||||
{
|
{
|
||||||
get_all_state_t state = {
|
get_all_state_t *state = data;
|
||||||
.ga_verbose = verbose,
|
int len = strlen(zfs_get_name(zhp));
|
||||||
.ga_cbp = cbp
|
for (int i = 0; i < state->ga_count; ++i) {
|
||||||
};
|
if (strcmp(state->ga_datasets[i], zfs_get_name(zhp)) == 0)
|
||||||
|
return (get_one_dataset(zhp, data));
|
||||||
|
else if ((strncmp(state->ga_datasets[i], zfs_get_name(zhp),
|
||||||
|
len) == 0) && state->ga_datasets[i][len] == '/') {
|
||||||
|
(void) zfs_iter_filesystems_v2(zhp, 0,
|
||||||
|
get_recursive_datasets, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
zfs_close(zhp);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
if (verbose)
|
static void
|
||||||
|
get_all_datasets(get_all_state_t *state)
|
||||||
|
{
|
||||||
|
if (state->ga_verbose)
|
||||||
set_progress_header(gettext("Reading ZFS config"));
|
set_progress_header(gettext("Reading ZFS config"));
|
||||||
(void) zfs_iter_root(g_zfs, get_one_dataset, &state);
|
if (state->ga_datasets == NULL)
|
||||||
|
(void) zfs_iter_root(g_zfs, get_one_dataset, state);
|
||||||
|
else
|
||||||
|
(void) zfs_iter_root(g_zfs, get_recursive_datasets, state);
|
||||||
|
|
||||||
if (verbose)
|
if (state->ga_verbose)
|
||||||
finish_progress(gettext("done."));
|
finish_progress(gettext("done."));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7154,18 +7173,22 @@ static int
|
||||||
share_mount(int op, int argc, char **argv)
|
share_mount(int op, int argc, char **argv)
|
||||||
{
|
{
|
||||||
int do_all = 0;
|
int do_all = 0;
|
||||||
|
int recursive = 0;
|
||||||
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 ? ":aRlvo:Of" : "al"))
|
||||||
!= -1) {
|
!= -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'a':
|
case 'a':
|
||||||
do_all = 1;
|
do_all = 1;
|
||||||
break;
|
break;
|
||||||
|
case 'R':
|
||||||
|
recursive = 1;
|
||||||
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
verbose = B_TRUE;
|
verbose = B_TRUE;
|
||||||
break;
|
break;
|
||||||
|
@ -7207,7 +7230,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 || recursive) {
|
||||||
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) {
|
||||||
|
@ -7216,14 +7239,38 @@ share_mount(int op, int argc, char **argv)
|
||||||
argv++;
|
argv++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argc != 0) {
|
if (argc != 0 && do_all) {
|
||||||
(void) fprintf(stderr, gettext("too many arguments\n"));
|
(void) fprintf(stderr, gettext("too many arguments\n"));
|
||||||
usage(B_FALSE);
|
usage(B_FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (argc == 0 && recursive) {
|
||||||
|
(void) fprintf(stderr,
|
||||||
|
gettext("no dataset provided\n"));
|
||||||
|
usage(B_FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
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_state_t state = { 0 };
|
||||||
|
if (argc == 0) {
|
||||||
|
state.ga_datasets = NULL;
|
||||||
|
state.ga_count = -1;
|
||||||
|
} else {
|
||||||
|
zfs_handle_t *zhp;
|
||||||
|
for (int i = 0; i < argc; i++) {
|
||||||
|
zhp = zfs_open(g_zfs, argv[i],
|
||||||
|
ZFS_TYPE_FILESYSTEM);
|
||||||
|
if (zhp == NULL)
|
||||||
|
usage(B_FALSE);
|
||||||
|
zfs_close(zhp);
|
||||||
|
}
|
||||||
|
state.ga_datasets = argv;
|
||||||
|
state.ga_count = argc;
|
||||||
|
}
|
||||||
|
state.ga_verbose = verbose;
|
||||||
|
state.ga_cbp = &cb;
|
||||||
|
get_all_datasets(&state);
|
||||||
|
|
||||||
if (cb.cb_used == 0) {
|
if (cb.cb_used == 0) {
|
||||||
free(options);
|
free(options);
|
||||||
|
|
|
@ -43,7 +43,7 @@
|
||||||
.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 Ns | Ns Fl R Ar filesystem Ns | Ns Ar filesystem
|
||||||
.Nm zfs
|
.Nm zfs
|
||||||
.Cm unmount
|
.Cm unmount
|
||||||
.Op Fl fu
|
.Op Fl fu
|
||||||
|
@ -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 Ns | Ns Fl R Ar filesystem Ns | Ns 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
|
||||||
|
@ -83,6 +83,8 @@ for more information.
|
||||||
.It Fl a
|
.It Fl a
|
||||||
Mount all available ZFS file systems.
|
Mount all available ZFS file systems.
|
||||||
Invoked automatically as part of the boot process if configured.
|
Invoked automatically as part of the boot process if configured.
|
||||||
|
.It Fl R
|
||||||
|
Mount the specified filesystems along with all their children.
|
||||||
.It Ar filesystem
|
.It Ar filesystem
|
||||||
Mount the specified filesystem.
|
Mount the specified filesystem.
|
||||||
.It Fl o Ar options
|
.It Fl o Ar options
|
||||||
|
|
|
@ -246,7 +246,7 @@ tests = ['zfs_mount_001_pos', 'zfs_mount_002_pos', 'zfs_mount_003_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_encrypted',
|
||||||
'zfs_mount_remount', 'zfs_mount_all_fail', 'zfs_mount_all_mountpoints',
|
'zfs_mount_remount', 'zfs_mount_all_fail', 'zfs_mount_all_mountpoints',
|
||||||
'zfs_mount_test_race']
|
'zfs_mount_test_race', 'zfs_mount_recursive']
|
||||||
tags = ['functional', 'cli_root', 'zfs_mount']
|
tags = ['functional', 'cli_root', 'zfs_mount']
|
||||||
|
|
||||||
[tests/functional/cli_root/zfs_program]
|
[tests/functional/cli_root/zfs_program]
|
||||||
|
|
|
@ -155,7 +155,8 @@ 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_encrypted', 'zfs_mount_remount',
|
'zfs_mount_012_pos', 'zfs_mount_encrypted', 'zfs_mount_remount',
|
||||||
'zfs_mount_all_fail', 'zfs_mount_all_mountpoints', 'zfs_mount_test_race']
|
'zfs_mount_all_fail', 'zfs_mount_all_mountpoints',
|
||||||
|
'zfs_mount_test_race', 'zfs_mount_recursive']
|
||||||
tags = ['functional', 'cli_root', 'zfs_mount']
|
tags = ['functional', 'cli_root', 'zfs_mount']
|
||||||
|
|
||||||
[tests/functional/cli_root/zfs_program]
|
[tests/functional/cli_root/zfs_program]
|
||||||
|
|
|
@ -769,6 +769,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \
|
||||||
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 \
|
||||||
|
functional/cli_root/zfs_mount/zfs_mount_recursive.ksh \
|
||||||
functional/cli_root/zfs_mount/zfs_mount_remount.ksh \
|
functional/cli_root/zfs_mount/zfs_mount_remount.ksh \
|
||||||
functional/cli_root/zfs_mount/zfs_mount_test_race.ksh \
|
functional/cli_root/zfs_mount/zfs_mount_test_race.ksh \
|
||||||
functional/cli_root/zfs_mount/zfs_multi_mount.ksh \
|
functional/cli_root/zfs_mount/zfs_multi_mount.ksh \
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
export mountcmd=mount
|
export mountcmd=mount
|
||||||
export mountforce="$mountcmd -f"
|
export mountforce="$mountcmd -f"
|
||||||
export mountall="$mountcmd -a"
|
export mountall="$mountcmd -a"
|
||||||
|
export mountrecursive="$mountcmd -R"
|
||||||
|
|
||||||
export unmountcmd=unmount
|
export unmountcmd=unmount
|
||||||
export unmountforce="$unmountcmd -f"
|
export unmountforce="$unmountcmd -f"
|
||||||
|
|
|
@ -0,0 +1,146 @@
|
||||||
|
#!/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 2024, iXsystems Inc. All rights reserved.
|
||||||
|
#
|
||||||
|
|
||||||
|
. $STF_SUITE/include/libtest.shlib
|
||||||
|
. $STF_SUITE/tests/functional/cli_root/zfs_mount/zfs_mount.kshlib
|
||||||
|
|
||||||
|
#
|
||||||
|
# DESCRIPTION:
|
||||||
|
# Verify zfs mount -R <filesystems/s> functionality.
|
||||||
|
#
|
||||||
|
# STRATEGY:
|
||||||
|
# 1. Create nested datasets
|
||||||
|
# 2. Unmount all datasets
|
||||||
|
# 3. Recusrively mount root datasets, this should mount all datasets
|
||||||
|
# present in a pool
|
||||||
|
# 4. Unmount all datasets
|
||||||
|
# 5. Recusrsively mount child datasets with children. This should mount
|
||||||
|
# child datasets, but not the root dataset or parent datasets
|
||||||
|
# 6. Unmount all datasets
|
||||||
|
# 7. Mount root dataset recursively again and confirm all child
|
||||||
|
# datasets are mounted.
|
||||||
|
#
|
||||||
|
|
||||||
|
verify_runnable "both"
|
||||||
|
|
||||||
|
function cleanup
|
||||||
|
{
|
||||||
|
log_must datasetexists $TESTPOOL/$TESTFS1 && \
|
||||||
|
destroy_dataset $TESTPOOL/$TESTFS1 -R
|
||||||
|
log_must datasetexists $TESTPOOL/$TESTFS2 && \
|
||||||
|
destroy_dataset $TESTPOOL/$TESTFS2 -R
|
||||||
|
log_must datasetexists $TESTPOOL/$TESTFS3 && \
|
||||||
|
destroy_dataset $TESTPOOL/$TESTFS3 -R
|
||||||
|
}
|
||||||
|
|
||||||
|
function setup_all
|
||||||
|
{
|
||||||
|
log_must datasetexists $TESTPOOL/$TESTFS || zfs create $TESTPOOL/$TESTFS
|
||||||
|
log_must zfs create $TESTPOOL/$TESTFS1
|
||||||
|
log_must zfs create $TESTPOOL/$TESTFS2
|
||||||
|
log_must zfs create $TESTPOOL/$TESTFS3
|
||||||
|
log_must zfs create $TESTPOOL/$TESTFS2/child1
|
||||||
|
log_must zfs create $TESTPOOL/$TESTFS2/child2
|
||||||
|
log_must zfs create $TESTPOOL/$TESTFS2/child3
|
||||||
|
log_must zfs create $TESTPOOL/$TESTFS2/child2/subchild
|
||||||
|
log_must zfs create $TESTPOOL/$TESTFS3/child
|
||||||
|
}
|
||||||
|
|
||||||
|
log_assert "Verify that 'zfs $mountrecursive' successfully, " \
|
||||||
|
"mounts the dataset along with all its children."
|
||||||
|
|
||||||
|
log_onexit cleanup
|
||||||
|
|
||||||
|
log_must setup_all
|
||||||
|
|
||||||
|
log_must zfs $unmountall
|
||||||
|
|
||||||
|
log_must zfs $mountrecursive $TESTPOOL
|
||||||
|
|
||||||
|
log_must mounted $TESTPOOL
|
||||||
|
log_must mounted $TESTPOOL/$TESTFS
|
||||||
|
log_must mounted $TESTPOOL/$TESTFS1
|
||||||
|
log_must mounted $TESTPOOL/$TESTFS2
|
||||||
|
log_must mounted $TESTPOOL/$TESTFS3
|
||||||
|
log_must mounted $TESTPOOL/$TESTFS2/child1
|
||||||
|
log_must mounted $TESTPOOL/$TESTFS2/child2
|
||||||
|
log_must mounted $TESTPOOL/$TESTFS2/child3
|
||||||
|
log_must mounted $TESTPOOL/$TESTFS2/child2/subchild
|
||||||
|
log_must mounted $TESTPOOL/$TESTFS3/child
|
||||||
|
|
||||||
|
log_must zfs $unmountall
|
||||||
|
|
||||||
|
log_mustnot mounted $TESTPOOL
|
||||||
|
log_mustnot mounted $TESTPOOL/$TESTFS
|
||||||
|
log_mustnot mounted $TESTPOOL/$TESTFS1
|
||||||
|
log_mustnot mounted $TESTPOOL/$TESTFS2
|
||||||
|
log_mustnot mounted $TESTPOOL/$TESTFS3
|
||||||
|
log_mustnot mounted $TESTPOOL/$TESTFS2/child1
|
||||||
|
log_mustnot mounted $TESTPOOL/$TESTFS2/child2
|
||||||
|
log_mustnot mounted $TESTPOOL/$TESTFS2/child3
|
||||||
|
log_mustnot mounted $TESTPOOL/$TESTFS2/child2/subchild
|
||||||
|
log_mustnot mounted $TESTPOOL/$TESTFS3/child
|
||||||
|
|
||||||
|
log_must zfs $mountrecursive $TESTPOOL/$TESTFS2 $TESTPOOL/$TESTFS3
|
||||||
|
|
||||||
|
log_mustnot mounted $TESTPOOL
|
||||||
|
log_mustnot mounted $TESTPOOL/$TESTFS
|
||||||
|
log_mustnot mounted $TESTPOOL/$TESTFS1
|
||||||
|
log_must mounted $TESTPOOL/$TESTFS2
|
||||||
|
log_must mounted $TESTPOOL/$TESTFS3
|
||||||
|
log_must mounted $TESTPOOL/$TESTFS2/child1
|
||||||
|
log_must mounted $TESTPOOL/$TESTFS2/child2
|
||||||
|
log_must mounted $TESTPOOL/$TESTFS2/child3
|
||||||
|
log_must mounted $TESTPOOL/$TESTFS2/child2/subchild
|
||||||
|
log_must mounted $TESTPOOL/$TESTFS3/child
|
||||||
|
|
||||||
|
log_must zfs $unmountall
|
||||||
|
|
||||||
|
log_mustnot mounted $TESTPOOL
|
||||||
|
log_mustnot mounted $TESTPOOL/$TESTFS
|
||||||
|
log_mustnot mounted $TESTPOOL/$TESTFS1
|
||||||
|
log_mustnot mounted $TESTPOOL/$TESTFS2
|
||||||
|
log_mustnot mounted $TESTPOOL/$TESTFS3
|
||||||
|
log_mustnot mounted $TESTPOOL/$TESTFS2/child1
|
||||||
|
log_mustnot mounted $TESTPOOL/$TESTFS2/child2
|
||||||
|
log_mustnot mounted $TESTPOOL/$TESTFS2/child3
|
||||||
|
log_mustnot mounted $TESTPOOL/$TESTFS2/child2/subchild
|
||||||
|
log_mustnot mounted $TESTPOOL/$TESTFS3/child
|
||||||
|
|
||||||
|
log_must zfs $mountrecursive $TESTPOOL/$TESTFS2/child2
|
||||||
|
|
||||||
|
log_must mounted $TESTPOOL/$TESTFS2/child2
|
||||||
|
log_must mounted $TESTPOOL/$TESTFS2/child2/subchild
|
||||||
|
log_mustnot mounted $TESTPOOL
|
||||||
|
log_mustnot mounted $TESTPOOL/$TESTFS
|
||||||
|
log_mustnot mounted $TESTPOOL/$TESTFS1
|
||||||
|
log_mustnot mounted $TESTPOOL/$TESTFS2
|
||||||
|
log_mustnot mounted $TESTPOOL/$TESTFS3
|
||||||
|
log_mustnot mounted $TESTPOOL/$TESTFS2/child1
|
||||||
|
log_mustnot mounted $TESTPOOL/$TESTFS2/child3
|
||||||
|
log_mustnot mounted $TESTPOOL/$TESTFS3/child
|
||||||
|
|
||||||
|
log_pass "'zfs $mountrecursive' behaves as expected."
|
Loading…
Reference in New Issue