mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-22 02:27:36 +03:00
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:
committed by
Brian Behlendorf
parent
2f3f1ab1ba
commit
8531621aba
@@ -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
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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."
|
||||
+74
@@ -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."
|
||||
+86
@@ -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."
|
||||
Reference in New Issue
Block a user