diff --git a/cmd/zfs/zfs_main.c b/cmd/zfs/zfs_main.c index 920243579..9e75b4aa4 100644 --- a/cmd/zfs/zfs_main.c +++ b/cmd/zfs/zfs_main.c @@ -292,12 +292,13 @@ get_usage(zfs_help_t idx) { switch (idx) { case HELP_CLONE: - return (gettext("\tclone [-pu] [-o property=value] ... " + return (gettext("\tclone [-p[p]u] [-o property=value] ... " " \n")); case HELP_CREATE: - return (gettext("\tcreate [-Pnpuv] [-o property=value] ... " + return (gettext("\tcreate [-Pnp[p]uv] [-o property=value] ... " "\n" - "\tcreate [-Pnpsv] [-b blocksize] [-o property=value] ... " + "\tcreate [-Pnp[p]sv] [-b blocksize] " + "[-o property=value] ... " "-V \n")); case HELP_DESTROY: return (gettext("\tdestroy [-fnpRrv] \n" @@ -338,7 +339,8 @@ get_usage(zfs_help_t idx) case HELP_RENAME: return (gettext("\trename [-f] " "\n" - "\trename -p [-f] \n" + "\trename -p[p] [-f] " + "\n" "\trename -u [-f] \n" "\trename -r \n")); case HELP_ROLLBACK: @@ -766,6 +768,26 @@ finish_progress(const char *done) pt_header = NULL; } +static void +makeprops_parents(nvlist_t **ptr, boolean_t parents_nomount) +{ + nvlist_t *props = NULL; + + if (parents_nomount) { + if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0) + nomem(); + + if (nvlist_add_string(props, + zfs_prop_to_name(ZFS_PROP_CANMOUNT), + "off") != 0) { + nvlist_free(props); + nomem(); + } + } + + *ptr = props; +} + static int zfs_mount_and_share(libzfs_handle_t *hdl, const char *dataset, zfs_type_t type) { @@ -826,6 +848,7 @@ zfs_mount_and_share(libzfs_handle_t *hdl, const char *dataset, zfs_type_t type) * the clone exists. * * The '-p' flag creates all the non-existing ancestors of the target first. + * If repeated twice, the ancestors are created with `canmount=off`. * * The '-u' flag prevents the newly created file system from being mounted. */ @@ -834,8 +857,10 @@ zfs_do_clone(int argc, char **argv) { zfs_handle_t *zhp = NULL; boolean_t parents = B_FALSE; + boolean_t parents_nomount = B_FALSE; boolean_t nomount = B_FALSE; nvlist_t *props; + nvlist_t *props_parents = NULL; int ret = 1; int c; @@ -852,7 +877,10 @@ zfs_do_clone(int argc, char **argv) } break; case 'p': - parents = B_TRUE; + if (!parents) + parents = B_TRUE; + else + parents_nomount = B_TRUE; break; case 'u': nomount = B_TRUE; @@ -900,9 +928,11 @@ zfs_do_clone(int argc, char **argv) ret = 0; goto error; } - if (zfs_create_ancestors(g_zfs, argv[1]) != 0) { + + makeprops_parents(&props_parents, parents_nomount); + if (zfs_create_ancestors_props(g_zfs, argv[1], + props_parents) != 0) goto error; - } } /* pass to libzfs */ @@ -930,11 +960,13 @@ error: zfs_close(zhp); error_open: nvlist_free(props); + nvlist_free(props_parents); return (!!ret); usage: ASSERT0P(zhp); nvlist_free(props); + nvlist_free(props_parents); usage(B_FALSE); return (-1); } @@ -1068,6 +1100,7 @@ default_volblocksize(zpool_handle_t *zhp, nvlist_t *props) * SPA_VERSION_REFRESERVATION, we set a refreservation instead. * * The '-p' flag creates all the non-existing ancestors of the target first. + * If repeated twice, the ancestors are created with `canmount=off`. * * The '-n' flag is no-op (dry run) mode. This will perform a user-space sanity * check of arguments and properties, but does not check for permissions, @@ -1090,12 +1123,14 @@ zfs_do_create(int argc, char **argv) boolean_t noreserve = B_FALSE; boolean_t bflag = B_FALSE; boolean_t parents = B_FALSE; + boolean_t parents_nomount = B_FALSE; boolean_t dryrun = B_FALSE; boolean_t nomount = B_FALSE; boolean_t verbose = B_FALSE; boolean_t parseable = B_FALSE; int ret = 1; nvlist_t *props; + nvlist_t *props_parents = NULL; uint64_t intval; const char *strval; @@ -1124,7 +1159,10 @@ zfs_do_create(int argc, char **argv) parseable = B_TRUE; break; case 'p': - parents = B_TRUE; + if (!parents) + parents = B_TRUE; + else + parents_nomount = B_TRUE; break; case 'b': bflag = B_TRUE; @@ -1274,6 +1312,8 @@ zfs_do_create(int argc, char **argv) } if (parents && zfs_name_valid(argv[0], type)) { + makeprops_parents(&props_parents, parents_nomount); + /* * Now create the ancestors of target dataset. If the target * already exists and '-p' option was used we should not @@ -1289,7 +1329,8 @@ zfs_do_create(int argc, char **argv) "create ancestors of %s\n", argv[0]); } if (!dryrun) { - if (zfs_create_ancestors(g_zfs, argv[0]) != 0) { + if (zfs_create_ancestors_props(g_zfs, argv[0], + props_parents) != 0) { goto error; } } @@ -1348,9 +1389,11 @@ zfs_do_create(int argc, char **argv) (void) zfs_mount_and_share(g_zfs, argv[0], ZFS_TYPE_DATASET); error: nvlist_free(props); + nvlist_free(props_parents); return (ret); badusage: nvlist_free(props); + nvlist_free(props_parents); usage(B_FALSE); return (2); } @@ -4039,6 +4082,8 @@ found3:; * Renames the given dataset to another of the same type. * * The '-p' flag creates all the non-existing ancestors of the target first. + * If repeated twice, the ancestors are created with `canmount=off`. + * * The '-u' flag prevents file systems from being remounted during rename. */ static int @@ -4050,12 +4095,17 @@ zfs_do_rename(int argc, char **argv) int ret = 1; int types; boolean_t parents = B_FALSE; + boolean_t parents_nomount = B_FALSE; + nvlist_t *props_parents = NULL; /* check options */ while ((c = getopt(argc, argv, "pruf")) != -1) { switch (c) { case 'p': - parents = B_TRUE; + if (parents) + parents_nomount = B_TRUE; + else + parents = B_TRUE; break; case 'r': flags.recursive = B_TRUE; @@ -4122,9 +4172,13 @@ zfs_do_rename(int argc, char **argv) goto error_open; /* If we were asked and the name looks good, try to create ancestors. */ - if (parents && zfs_name_valid(argv[1], zfs_get_type(zhp)) && - zfs_create_ancestors(g_zfs, argv[1]) != 0) { - goto error; + if (parents && zfs_name_valid(argv[1], zfs_get_type(zhp))) { + + makeprops_parents(&props_parents, parents_nomount); + if (zfs_create_ancestors_props(g_zfs, argv[1], + props_parents) != 0) { + goto error; + } } ret = (zfs_rename(zhp, argv[1], flags) != 0); @@ -4132,6 +4186,7 @@ zfs_do_rename(int argc, char **argv) error: zfs_close(zhp); error_open: + nvlist_free(props_parents); return (ret); } diff --git a/lib/libzfs/libzfs_dataset.c b/lib/libzfs/libzfs_dataset.c index a86c4d0c0..9349af477 100644 --- a/lib/libzfs/libzfs_dataset.c +++ b/lib/libzfs/libzfs_dataset.c @@ -3657,7 +3657,7 @@ ancestorerr: int zfs_create_ancestors(libzfs_handle_t *hdl, const char *path) { - return zfs_create_ancestors_props(hdl, path, NULL); + return (zfs_create_ancestors_props(hdl, path, NULL)); } /* diff --git a/man/man8/zfs-clone.8 b/man/man8/zfs-clone.8 index 786b17521..dc7283fe2 100644 --- a/man/man8/zfs-clone.8 +++ b/man/man8/zfs-clone.8 @@ -62,6 +62,10 @@ Creates all the non-existing parent datasets. Datasets created in this manner are automatically mounted according to the .Sy mountpoint property inherited from their parent. +If the +.Fl p +option is specified multiple times, parent datasets are created with +.Sy canmount Ns = Ns Ar off . If the target filesystem or volume already exists, the operation completes successfully. .It Fl u diff --git a/man/man8/zfs-create.8 b/man/man8/zfs-create.8 index b9d013e88..b96a1c94a 100644 --- a/man/man8/zfs-create.8 +++ b/man/man8/zfs-create.8 @@ -85,6 +85,10 @@ property inherited from their parent. Any property specified on the command line using the .Fl o option is ignored. +If the +.Fl p +option is specified multiple times, parent datasets are created with +.Sy canmount Ns = Ns Ar off . If the target filesystem already exists, the operation completes successfully. .It Fl n Do a dry-run @@ -177,6 +181,10 @@ property inherited from their parent. Any property specified on the command line using the .Fl o option is ignored. +If the +.Fl p +option is specified multiple times, parent datasets are created with +.Sy canmount Ns = Ns Ar off . If the target filesystem already exists, the operation completes successfully. .It Fl s Creates a sparse volume with no reservation. diff --git a/man/man8/zfs-rename.8 b/man/man8/zfs-rename.8 index b32987f19..fc9349303 100644 --- a/man/man8/zfs-rename.8 +++ b/man/man8/zfs-rename.8 @@ -103,6 +103,10 @@ Creates all the non-existing parent datasets. Datasets created in this manner are automatically mounted according to the .Sy mountpoint property inherited from their parent. +Alernatively, if the +.Fl p +option is specified multiple times, parent datasets are created with +.Sy canmount Ns = Ns Ar off . .It Fl u Do not remount file systems during rename. If a file system's diff --git a/tests/runfiles/common.run b/tests/runfiles/common.run index 7b0bfa90e..0ad81335d 100644 --- a/tests/runfiles/common.run +++ b/tests/runfiles/common.run @@ -196,8 +196,8 @@ tags = ['functional', 'cli_root', 'zfs_change-key'] tests = ['zfs_clone_001_neg', 'zfs_clone_002_pos', 'zfs_clone_003_pos', 'zfs_clone_004_pos', 'zfs_clone_005_pos', 'zfs_clone_006_pos', 'zfs_clone_007_pos', 'zfs_clone_008_neg', 'zfs_clone_009_neg', - 'zfs_clone_010_pos', 'zfs_clone_encrypted', 'zfs_clone_deeply_nested', - 'zfs_clone_rm_nested', 'zfs_clone_nomount'] + 'zfs_clone_010_pos', 'zfs_clone_011_pos', 'zfs_clone_encrypted', + 'zfs_clone_deeply_nested', 'zfs_clone_rm_nested', 'zfs_clone_nomount'] tags = ['functional', 'cli_root', 'zfs_clone'] [tests/functional/cli_root/zfs_copies] @@ -210,9 +210,9 @@ tests = ['zfs_create_001_pos', 'zfs_create_002_pos', 'zfs_create_003_pos', 'zfs_create_004_pos', 'zfs_create_005_pos', 'zfs_create_006_pos', 'zfs_create_007_pos', 'zfs_create_008_neg', 'zfs_create_009_neg', 'zfs_create_010_neg', 'zfs_create_011_pos', 'zfs_create_012_pos', - 'zfs_create_013_pos', 'zfs_create_014_pos', 'zfs_create_encrypted', - 'zfs_create_crypt_combos', 'zfs_create_dryrun', 'zfs_create_nomount', - 'zfs_create_verbose'] + 'zfs_create_013_pos', 'zfs_create_014_pos', 'zfs_create_015_pos', + 'zfs_create_encrypted', 'zfs_create_crypt_combos', 'zfs_create_dryrun', + 'zfs_create_nomount', 'zfs_create_verbose'] tags = ['functional', 'cli_root', 'zfs_create'] [tests/functional/cli_root/zpool_prefetch] @@ -300,8 +300,9 @@ tests = ['zfs_rename_001_pos', 'zfs_rename_002_pos', 'zfs_rename_003_pos', 'zfs_rename_004_neg', 'zfs_rename_005_neg', 'zfs_rename_006_pos', 'zfs_rename_007_pos', 'zfs_rename_008_pos', 'zfs_rename_009_neg', 'zfs_rename_010_neg', 'zfs_rename_011_pos', 'zfs_rename_012_neg', - 'zfs_rename_013_pos', 'zfs_rename_014_neg', 'zfs_rename_encrypted_child', - 'zfs_rename_to_encrypted', 'zfs_rename_mountpoint', 'zfs_rename_nounmount'] + 'zfs_rename_013_pos', 'zfs_rename_014_neg', 'zfs_rename_015_pos', + 'zfs_rename_encrypted_child', 'zfs_rename_to_encrypted', 'zfs_rename_mountpoint', + 'zfs_rename_nounmount'] tags = ['functional', 'cli_root', 'zfs_rename'] [tests/functional/cli_root/zfs_reservation] diff --git a/tests/zfs-tests/include/libtest.shlib b/tests/zfs-tests/include/libtest.shlib index d979d6874..913d23d13 100644 --- a/tests/zfs-tests/include/libtest.shlib +++ b/tests/zfs-tests/include/libtest.shlib @@ -1171,6 +1171,22 @@ function datasetnonexists return 0 } +# Check if the specified dataset property has the expected value or fail +function dataset_has_prop # property expected_value dataset +{ + typeset prop=$1 + typeset expected=$2 + typeset dataset=$3 + + typeset value="" + + value="$(get_prop "$prop" "$dataset")" + [[ "$value" == "$expected" ]] || { + log_note "dataset $dataset: property $prop == $value (!= $expected)" + return 1 + } +} + # FreeBSD breaks exports(5) at whitespace and doesn't process escapes # Solaris just breaks # @@ -2629,11 +2645,16 @@ function verify_opt_p_ops typeset datatype=$2 typeset dataset=$3 typeset newdataset=$4 + typeset popt=$5 if [[ $datatype != "fs" && $datatype != "vol" ]]; then log_fail "$datatype is not supported." fi + if [[ -z "$popt" ]]; then + popt=-p + fi + # check parameters accordingly case $ops in create) @@ -2671,7 +2692,7 @@ function verify_opt_p_ops log_mustnot datasetexists $newdataset ${newdataset%/*} # with -p option, operation should succeed - log_must zfs $ops -p $dataset $newdataset + log_must zfs $ops $popt $dataset $newdataset block_device_wait if ! datasetexists $newdataset ; then @@ -2680,7 +2701,7 @@ function verify_opt_p_ops # when $ops is create or clone, redo the operation still return zero if [[ $ops != "rename" ]]; then - log_must zfs $ops -p $dataset $newdataset + log_must zfs $ops $popt $dataset $newdataset fi return 0 diff --git a/tests/zfs-tests/tests/Makefile.am b/tests/zfs-tests/tests/Makefile.am index 1fc158f80..d87dc8697 100644 --- a/tests/zfs-tests/tests/Makefile.am +++ b/tests/zfs-tests/tests/Makefile.am @@ -677,6 +677,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \ functional/cli_root/zfs_clone/zfs_clone_008_neg.ksh \ functional/cli_root/zfs_clone/zfs_clone_009_neg.ksh \ functional/cli_root/zfs_clone/zfs_clone_010_pos.ksh \ + functional/cli_root/zfs_clone/zfs_clone_011_pos.ksh \ functional/cli_root/zfs_clone/zfs_clone_deeply_nested.ksh \ functional/cli_root/zfs_clone/zfs_clone_encrypted.ksh \ functional/cli_root/zfs_clone/zfs_clone_nomount.ksh \ @@ -705,6 +706,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \ functional/cli_root/zfs_create/zfs_create_012_pos.ksh \ functional/cli_root/zfs_create/zfs_create_013_pos.ksh \ functional/cli_root/zfs_create/zfs_create_014_pos.ksh \ + functional/cli_root/zfs_create/zfs_create_015_pos.ksh \ functional/cli_root/zfs_create/zfs_create_crypt_combos.ksh \ functional/cli_root/zfs_create/zfs_create_dryrun.ksh \ functional/cli_root/zfs_create/zfs_create_encrypted.ksh \ @@ -864,6 +866,7 @@ nobase_dist_datadir_zfs_tests_tests_SCRIPTS += \ functional/cli_root/zfs_rename/zfs_rename_012_neg.ksh \ functional/cli_root/zfs_rename/zfs_rename_013_pos.ksh \ functional/cli_root/zfs_rename/zfs_rename_014_neg.ksh \ + functional/cli_root/zfs_rename/zfs_rename_015_pos.ksh \ functional/cli_root/zfs_rename/zfs_rename_encrypted_child.ksh \ functional/cli_root/zfs_rename/zfs_rename_mountpoint.ksh \ functional/cli_root/zfs_rename/zfs_rename_nounmount.ksh \ diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_011_pos.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_011_pos.ksh new file mode 100755 index 000000000..9e71db317 --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zfs_clone/zfs_clone_011_pos.ksh @@ -0,0 +1,94 @@ +#!/bin/ksh -p +# SPDX-License-Identifier: CDDL-1.0 +# +# 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 (c) 2026 Ivan Shapovalov +# + +. $STF_SUITE/include/libtest.shlib + +# +# DESCRIPTION: +# `zfs clone -pp` should create the parent of the new filesystem with `canmount=off`. +# +# STRATEGY: +# 1. Prepare snapshots +# 2. Make sure the parent of the clone target does not exist +# 3. Make sure that `zfs clone -pp` works the same as `-p` +# 4. Make sure that the newly created parent has `canmount=off` +# + +verify_runnable "both" + +function setup +{ + log_note "Create snapshots and mount them..." + + for snap in $SNAPFS $SNAPFS1 ; do + if ! snapexists "$snap" ; then + log_must zfs snapshot "$snap" + fi + done + + return 0 +} + +function cleanup +{ + + datasetexists "$TESTPOOL/notexist" && destroy_dataset "$TESTPOOL/notexist" -rRf + + for snap in $SNAPFS $SNAPFS1 ; do + snapexists "$snap" && destroy_dataset "$snap" -Rf + done + + return 0 +} + +log_onexit cleanup + +log_assert "'zfs clone -pp' should work as expected." + +setup + +log_mustnot datasetexists "$TESTPOOL/notexist" +log_mustnot datasetexists "$TESTPOOL/notexist/new" +log_mustnot datasetexists "$TESTPOOL/notexist/new2" + +log_must verify_opt_p_ops "clone" "fs" "$SNAPFS" \ + "$TESTPOOL/notexist/new/clonefs$$" "-pp" + +log_must dataset_has_prop canmount off "$TESTPOOL/notexist" +log_must dataset_has_prop canmount off "$TESTPOOL/notexist/new" +log_mustnot ismounted "$TESTPOOL/notexist" +log_mustnot ismounted "$TESTPOOL/notexist/new" + +if is_global_zone ; then + log_must verify_opt_p_ops "clone" "vol" "$SNAPFS1" \ + "$TESTPOOL/notexist/new2/clonevol$$" "-pp" + + log_must dataset_has_prop canmount off "$TESTPOOL/notexist/new2" + log_mustnot ismounted "$TESTPOOL/notexist/new2" +fi + +log_pass "'zfs clone -pp' works as expected." diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_015_pos.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_015_pos.ksh new file mode 100755 index 000000000..d4c009c22 --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zfs_create/zfs_create_015_pos.ksh @@ -0,0 +1,74 @@ +#!/bin/ksh -p +# SPDX-License-Identifier: CDDL-1.0 +# +# 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 (c) 2026 Ivan Shapovalov +# + +. $STF_SUITE/include/libtest.shlib + +# +# DESCRIPTION: +# `zfs create -pp` should create the parent of the new filesystem with `canmount=off`. +# +# STRATEGY: +# 1. Make sure the parent of the dataset to be created does not exist +# 2. Make sure that `zfs create -pp` works the same as `-p` +# 3. Make sure that the newly created parent has `canmount=off` + +verify_runnable "both" + +function cleanup +{ + datasetexists "$TESTPOOL/notexist" && \ + destroy_dataset "$TESTPOOL/notexist" -rRf + + return 0 +} + +log_onexit cleanup + +log_assert "'zfs create -p' should work as expected." + +log_mustnot datasetexists "$TESTPOOL/notexist" +log_mustnot datasetexists "$TESTPOOL/notexist/new" +log_mustnot datasetexists "$TESTPOOL/notexist/new2" + +log_must verify_opt_p_ops "create" "fs" \ + "$TESTPOOL/notexist/new/create$$" "" "-pp" + +log_must dataset_has_prop canmount off "$TESTPOOL/notexist" +log_must dataset_has_prop canmount off "$TESTPOOL/notexist/new" +log_mustnot ismounted "$TESTPOOL/notexist" +log_mustnot ismounted "$TESTPOOL/notexist/new" + +# verify volume creation +if is_global_zone; then + log_must verify_opt_p_ops "create" "vol" \ + "$TESTPOOL/notexist/new2/volume$$" "" "-pp" + + log_must dataset_has_prop canmount off "$TESTPOOL/notexist/new2" + log_mustnot ismounted "$TESTPOOL/notexist/new2" +fi + +log_pass "'zfs create -p' works as expected." diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_015_pos.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_015_pos.ksh new file mode 100755 index 000000000..124c3eed7 --- /dev/null +++ b/tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_015_pos.ksh @@ -0,0 +1,86 @@ +#!/bin/ksh -p +# SPDX-License-Identifier: CDDL-1.0 +# +# 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 (c) 2026 Ivan Shapovalov +# + +. $STF_SUITE/include/libtest.shlib + +# +# DESCRIPTION +# `zfs rename -pp` should create the parent of the new filesystem with `canmount=off`. +# +# STRATEGY: +# 1. Make sure the parent of the rename target does not exist +# 2. Make sure that `zfs rename -pp` works the same as `-p` +# 3. Make sure that the newly created parent has `canmount=off` +# + +verify_runnable "both" + +function cleanup +{ + datasetexists "$TESTPOOL/notexist" && \ + destroy_dataset "$TESTPOOL/notexist" -Rf + + datasetexists "$TESTPOOL/$TESTFS" && \ + destroy_dataset "$TESTPOOL/$TESTFS" -Rf + + log_must zfs create "$TESTPOOL/$TESTFS" + + if is_global_zone ; then + datasetexists "$TESTPOOL/$TESTVOL" && \ + destroy_dataset "$TESTPOOL/$TESTVOL" -Rf + + log_must zfs create -V "$VOLSIZE" "$TESTPOOL/$TESTVOL" + fi + + return 0 +} + +log_onexit cleanup + +log_assert "'zfs rename -pp' should work as expected." + +log_must_not datasetexists "$TESTPOOL/notexist" +log_must_not datasetexists "$TESTPOOL/notexist/new" +log_must_not datasetexists "$TESTPOOL/notexist/new2" + +log_must verify_opt_p_ops "rename" "fs" "$TESTPOOL/$TESTFS" \ + "$TESTPOOL/notexist/new/$TESTFS1" "-pp" + +log_must dataset_has_prop canmount off "$TESTPOOL/notexist" +log_must dataset_has_prop canmount off "$TESTPOOL/notexist/new" +log_mustnot ismounted "$TESTPOOL/notexist" +log_mustnot ismounted "$TESTPOOL/notexist/new" + +if is_global_zone; then + log_must verify_opt_p_ops "rename" "vol" "$TESTPOOL/$TESTVOL" \ + "$TESTPOOL/notexist/new2/$TESTVOL1" "-pp" + + log_must dataset_has_prop canmount off "$TESTPOOL/notexist/new2" + log_mustnot ismounted "$TESTPOOL/notexist/new2" +fi + +log_pass "'zfs rename -pp' works as expected."