Skip to content

Commit 650258d

Browse files
loli10Kbehlendorf
authored andcommitted
zfs promote|rename .../%recv should be an error
If we are in the middle of an incremental 'zfs receive', the child .../%recv will exist. If we run 'zfs promote' .../%recv, it will "work", but then zfs gets confused about the status of the new dataset. Attempting to do this promote should be an error. Similarly renaming .../%recv datasets should not be allowed. Reviewed-by: Giuseppe Di Natale <[email protected]> Reviewed-by: Brian Behlendorf <[email protected]> Signed-off-by: loli10K <[email protected]> Closes openzfs#4843 Closes openzfs#6339
1 parent f06f53f commit 650258d

File tree

7 files changed

+70
-9
lines changed

7 files changed

+70
-9
lines changed

lib/libzfs/libzfs_dataset.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3751,6 +3751,9 @@ zfs_promote(zfs_handle_t *zhp)
37513751
return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
37523752
}
37533753

3754+
if (!zfs_validate_name(hdl, zhp->zfs_name, zhp->zfs_type, B_TRUE))
3755+
return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
3756+
37543757
ret = lzc_promote(zhp->zfs_name, snapname, sizeof (snapname));
37553758

37563759
if (ret != 0) {
@@ -4080,6 +4083,10 @@ zfs_rename(zfs_handle_t *zhp, const char *target, boolean_t recursive,
40804083
(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
40814084
"cannot rename to '%s'"), target);
40824085

4086+
/* make sure source name is valid */
4087+
if (!zfs_validate_name(hdl, zhp->zfs_name, zhp->zfs_type, B_TRUE))
4088+
return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
4089+
40834090
/*
40844091
* Make sure the target name is valid
40854092
*/

module/zfs/zfs_ioctl.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3738,9 +3738,12 @@ zfs_ioc_rename(zfs_cmd_t *zc)
37383738
boolean_t recursive = zc->zc_cookie & 1;
37393739
char *at;
37403740

3741+
/* "zfs rename" from and to ...%recv datasets should both fail */
3742+
zc->zc_name[sizeof (zc->zc_name) - 1] = '\0';
37413743
zc->zc_value[sizeof (zc->zc_value) - 1] = '\0';
3742-
if (dataset_namecheck(zc->zc_value, NULL, NULL) != 0 ||
3743-
strchr(zc->zc_value, '%'))
3744+
if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0 ||
3745+
dataset_namecheck(zc->zc_value, NULL, NULL) != 0 ||
3746+
strchr(zc->zc_name, '%') || strchr(zc->zc_value, '%'))
37443747
return (SET_ERROR(EINVAL));
37453748

37463749
at = strchr(zc->zc_name, '@');
@@ -5002,6 +5005,11 @@ zfs_ioc_promote(zfs_cmd_t *zc)
50025005
char *cp;
50035006
int error;
50045007

5008+
zc->zc_name[sizeof (zc->zc_name) - 1] = '\0';
5009+
if (dataset_namecheck(zc->zc_name, NULL, NULL) != 0 ||
5010+
strchr(zc->zc_name, '%'))
5011+
return (SET_ERROR(EINVAL));
5012+
50055013
error = dsl_pool_hold(zc->zc_name, FTAG, &dp);
50065014
if (error != 0)
50075015
return (error);

tests/zfs-tests/include/libtest.shlib

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,41 @@ function create_bookmark
351351
log_must zfs bookmark $fs_vol@$snap $fs_vol#$bkmark
352352
}
353353

354+
#
355+
# Create a temporary clone result of an interrupted resumable 'zfs receive'
356+
# $1 Destination filesystem name. Must not exist, will be created as the result
357+
# of this function along with its %recv temporary clone
358+
# $2 Source filesystem name. Must not exist, will be created and destroyed
359+
#
360+
function create_recv_clone
361+
{
362+
typeset recvfs="$1"
363+
typeset sendfs="${2:-$TESTPOOL/create_recv_clone}"
364+
typeset snap="$sendfs@snap1"
365+
typeset incr="$sendfs@snap2"
366+
typeset mountpoint="$TESTDIR/create_recv_clone"
367+
typeset sendfile="$TESTDIR/create_recv_clone.zsnap"
368+
369+
[[ -z $recvfs ]] && log_fail "Recv filesystem's name is undefined."
370+
371+
datasetexists $recvfs && log_fail "Recv filesystem must not exist."
372+
datasetexists $sendfs && log_fail "Send filesystem must not exist."
373+
374+
log_must zfs create -o mountpoint="$mountpoint" $sendfs
375+
log_must zfs snapshot $snap
376+
log_must eval "zfs send $snap | zfs recv -u $recvfs"
377+
log_must mkfile 1m "$mountpoint/data"
378+
log_must zfs snapshot $incr
379+
log_must eval "zfs send -i $snap $incr | dd bs=10K count=1 > $sendfile"
380+
log_mustnot eval "zfs recv -su $recvfs < $sendfile"
381+
log_must zfs destroy -r $sendfs
382+
log_must rm -f "$sendfile"
383+
384+
if [[ $(get_prop 'inconsistent' "$recvfs/%recv") -ne 1 ]]; then
385+
log_fail "Error creating temporary $recvfs/%recv clone"
386+
fi
387+
}
388+
354389
function default_mirror_setup
355390
{
356391
default_mirror_setup_noexit $1 $2 $3

tests/zfs-tests/tests/functional/cli_root/zfs_promote/zfs_promote_006_neg.ksh

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
# pool, fs, snapshot,volume
4141
# (4) too many arguments.
4242
# (5) invalid options
43+
# (6) temporary %recv datasets
4344
#
4445
# STRATEGY:
4546
# 1. Create an array of invalid arguments
@@ -50,18 +51,25 @@
5051
verify_runnable "both"
5152

5253
snap=$TESTPOOL/$TESTFS@$TESTSNAP
54+
clone=$TESTPOOL/$TESTCLONE
55+
recvfs=$TESTPOOL/recvfs
5356
set -A args "" \
5457
"$TESTPOOL/blah" \
5558
"$TESTPOOL" "$TESTPOOL/$TESTFS" "$snap" \
5659
"$TESTPOOL/$TESTVOL" "$TESTPOOL $TESTPOOL/$TESTFS" \
57-
"$clone $TESTPOOL/$TESTFS" "- $clone" "-? $clone"
60+
"$clone $TESTPOOL/$TESTFS" "- $clone" "-? $clone" \
61+
"$recvfs/%recv"
5862

5963
function cleanup
6064
{
6165
if datasetexists $clone; then
6266
log_must zfs destroy $clone
6367
fi
6468

69+
if datasetexists $recvfs; then
70+
log_must zfs destroy -r $recvfs
71+
fi
72+
6573
if snapexists $snap; then
6674
destroy_snapshot $snap
6775
fi
@@ -70,10 +78,7 @@ function cleanup
7078
log_assert "'zfs promote' will fail with invalid arguments. "
7179
log_onexit cleanup
7280

73-
snap=$TESTPOOL/$TESTFS@$TESTSNAP
74-
clone=$TESTPOOL/$TESTCLONE
75-
log_must zfs snapshot $snap
76-
log_must zfs clone $snap $clone
81+
create_recv_clone $recvfs
7782

7883
typeset -i i=0
7984
while (( i < ${#args[*]} )); do

tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,4 @@ export BS=512
3636
export CNT=2048
3737
export VOL_R_PATH=$ZVOL_RDEVDIR/$TESTPOOL/$TESTVOL
3838
export VOLDATA=$TESTDIR2/voldata.rename
39+
export RECVFS=recvfs

tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename.kshlib

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ function additional_setup
6363
log_must cp $DATA $(get_prop mountpoint $TESTPOOL/$TESTVOL)/$TESTFILE0
6464
fi
6565

66+
# Create temporary %recv clone
67+
create_recv_clone $TESTPOOL/$RECVFS
6668
}
6769

6870
function rename_dataset # src dest
@@ -110,6 +112,9 @@ function cleanup
110112
log_must zfs destroy -fR $TESTPOOL/$TESTFS@snapshot
111113
fi
112114

115+
if datasetexists $TESTPOOL/$RECVFS; then
116+
log_must zfs destroy -r $TESTPOOL/$RECVFS
117+
fi
113118
}
114119

115120
function cmp_data #<$1 src data, $2 tgt data>

tests/zfs-tests/tests/functional/cli_root/zfs_rename/zfs_rename_004_neg.ksh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,8 @@ set -A bad_dataset $TESTPOOL/$TESTFS1 $TESTPOOL/$TESTCTR1 \
7777
$TESTPOOL/$TESTFS1 $TESTPOOL/${TESTFS1}%x \
7878
$TESTPOOL/$TESTFS1 $TESTPOOL/${TESTFS1}%p \
7979
$TESTPOOL/$TESTFS1 $TESTPOOL/${TESTFS1}%s \
80-
$TESTPOOL/$TESTFS@snapshot \
81-
$TESTPOOL/$TESTFS@snapshot/fs
80+
$TESTPOOL/$TESTFS@snapshot $TESTPOOL/$TESTFS@snapshot/fs \
81+
$TESTPOOL/$RECVFS/%recv $TESTPOOL/renamed.$$
8282

8383
#
8484
# cleanup defined in zfs_rename.kshlib

0 commit comments

Comments
 (0)