zfs_main: create, clone, rename: accept -pp for non-mountable parents

Teach `zfs {create,clone,rename}` to accept a doubled `-p` flag (`-pp`)
to create non-existing ancestor datasets with `canmount=off`.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Rob Norris <robn@despairlabs.com>
Signed-off-by: Ivan Shapovalov <intelfx@intelfx.name>
Closes #17000
This commit is contained in:
Ivan Shapovalov 2025-01-28 12:11:18 +04:00 committed by Brian Behlendorf
parent 2f3f1ab1ba
commit 8531621aba
11 changed files with 373 additions and 23 deletions

View File

@ -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] ... "
"<snapshot> <filesystem|volume>\n"));
case HELP_CREATE:
return (gettext("\tcreate [-Pnpuv] [-o property=value] ... "
return (gettext("\tcreate [-Pnp[p]uv] [-o property=value] ... "
"<filesystem>\n"
"\tcreate [-Pnpsv] [-b blocksize] [-o property=value] ... "
"\tcreate [-Pnp[p]sv] [-b blocksize] "
"[-o property=value] ... "
"-V <size> <volume>\n"));
case HELP_DESTROY:
return (gettext("\tdestroy [-fnpRrv] <filesystem|volume>\n"
@ -338,7 +339,8 @@ get_usage(zfs_help_t idx)
case HELP_RENAME:
return (gettext("\trename [-f] <filesystem|volume|snapshot> "
"<filesystem|volume|snapshot>\n"
"\trename -p [-f] <filesystem|volume> <filesystem|volume>\n"
"\trename -p[p] [-f] <filesystem|volume> "
"<filesystem|volume>\n"
"\trename -u [-f] <filesystem> <filesystem>\n"
"\trename -r <snapshot> <snapshot>\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);
}

View File

@ -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));
}
/*

View File

@ -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

View File

@ -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.

View File

@ -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

View File

@ -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]

View File

@ -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

View File

@ -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 \

View File

@ -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 <intelfx@intelfx.name>
#
. $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."

View File

@ -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 <intelfx@intelfx.name>
#
. $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."

View File

@ -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 <intelfx@intelfx.name>
#
. $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."