From 3cbe89b12a55a0ff350d7434834f4f48227896a3 Mon Sep 17 00:00:00 2001 From: LOLi Date: Tue, 1 May 2018 05:58:29 +0200 Subject: [PATCH] Fix zfs incremental send remove '-o' properties When receiving an incremental send stream with intermediary snapshots zfs_receive_one() does not correctly identify the top-level dataset: consequently we restore said snapshots as if they were children datasets in the hierarchy, forcing inheritance of any property received with 'zfs send -o' and effectively removing any locally set value. The test case did not correctly verify this situation because it uses adjacent snapshots, basically testing 'zfs send -i' instead of 'zfs send -I': this commit adds an additional intermediary snapshot to the test script. Reviewed-by: Paul Dagnelie Reviewed-by: Brian Behlendorf Signed-off-by: loli10K Closes #7478 --- lib/libzfs/libzfs_sendrecv.c | 2 +- .../receive-o-x_props_override.ksh | 22 +++++++++++-------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/lib/libzfs/libzfs_sendrecv.c b/lib/libzfs/libzfs_sendrecv.c index b138745b84..9a4f373a1e 100644 --- a/lib/libzfs/libzfs_sendrecv.c +++ b/lib/libzfs/libzfs_sendrecv.c @@ -4041,7 +4041,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, goto out; } - if (top_zfs && *top_zfs == NULL) + if (top_zfs && (*top_zfs == NULL || strcmp(*top_zfs, name) == 0)) toplevel = B_TRUE; if (drrb->drr_type == DMU_OST_ZVOL) { type = ZFS_TYPE_VOLUME; diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_receive/receive-o-x_props_override.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs_receive/receive-o-x_props_override.ksh index 3d5d08db20..3b77664c35 100755 --- a/tests/zfs-tests/tests/functional/cli_root/zfs_receive/receive-o-x_props_override.ksh +++ b/tests/zfs-tests/tests/functional/cli_root/zfs_receive/receive-o-x_props_override.ksh @@ -113,16 +113,17 @@ log_must eval "zfs send -R $orig@snap1 > $streamfile_repl" log_must eval "zfs recv $dest < $streamfile_repl" # Fill the datasets with properties and create an incremental replication stream log_must zfs snapshot -r $orig@snap2 +log_must zfs snapshot -r $orig@snap3 log_must eval "zfs set copies=2 $orig" log_must eval "zfs set '$userprop:orig'='$userval' $orig" log_must eval "zfs set '$userprop:orig'='$userval' $origsub" log_must eval "zfs set '$userprop:snap'='$userval' $orig@snap1" -log_must eval "zfs set '$userprop:snap'='$userval' $origsub@snap2" -log_must eval "zfs send -R -I $orig@snap1 $orig@snap2 > $streamfile_incr" +log_must eval "zfs set '$userprop:snap'='$userval' $origsub@snap3" +log_must eval "zfs send -R -I $orig@snap1 $orig@snap3 > $streamfile_incr" # Sets various combination of override and exclude options log_must eval "zfs recv -F -o atime=off -o '$userprop:dest2'='$userval' "\ "-o quota=123456789 -x compression -x '$userprop:orig' " \ - "-x '$userprop:snap2' $dest < $streamfile_incr" + "-x '$userprop:snap3' $dest < $streamfile_incr" # Verify we can correctly override and exclude properties log_must eval "check_prop_source $dest copies 2 received" log_must eval "check_prop_source $dest atime off local" @@ -138,9 +139,9 @@ log_must eval "check_prop_missing $destsub '$userprop:orig'" log_must eval "check_prop_source " \ "$dest@snap1 '$userprop:snap' '$userval' received" log_must eval "check_prop_source " \ - "$destsub@snap2 '$userprop:snap' '$userval' received" -log_must eval "check_prop_missing $dest@snap2 '$userprop:snap2'" -log_must eval "check_prop_missing $destsub@snap2 '$userprop:snap2'" + "$destsub@snap3 '$userprop:snap' '$userval' received" +log_must eval "check_prop_missing $dest@snap3 '$userprop:snap3'" +log_must eval "check_prop_missing $destsub@snap3 '$userprop:snap3'" # Cleanup log_must zfs destroy -r -f $orig log_must zfs destroy -r -f $dest @@ -171,7 +172,8 @@ log_must eval "zfs set compression=gzip $dest" log_must eval "zfs set '$userprop:dest'='localval' $dest" # Receive the new stream, verify we preserve locally set properties log_must zfs snapshot -r $orig@snap2 -log_must eval "zfs send -R -I $orig@snap1 $orig@snap2 > $streamfile_incr" +log_must zfs snapshot -r $orig@snap3 +log_must eval "zfs send -R -I $orig@snap1 $orig@snap3 > $streamfile_incr" log_must eval "zfs recv -F -x copies -x compression -x '$userprop:orig' " \ "-x '$userprop:dest' $dest < $streamfile_incr" log_must eval "check_prop_source $dest '$userprop:dest' 'localval' local" @@ -206,7 +208,8 @@ log_must eval "check_prop_source $destsub quota 0 default" log_must eval "zfs set quota=123456789 $dest" log_must eval "zfs set canmount=off $destsub" log_must zfs snapshot -r $orig@snap2 -log_must eval "zfs send -R -I $orig@snap1 $orig@snap2 > $streamfile_incr" +log_must zfs snapshot -r $orig@snap3 +log_must eval "zfs send -R -I $orig@snap1 $orig@snap3 > $streamfile_incr" log_must eval "zfs recv -F -x quota -x canmount $dest < $streamfile_incr" log_must eval "check_prop_source $dest quota 123456789 local" log_must eval "check_prop_source $destsub quota 0 default" @@ -233,7 +236,8 @@ log_must eval "zfs set '$userprop:origsub'='$userval' $destsub" mntpnt=$(get_prop mountpoint $orig) log_must eval "dd if=/dev/urandom of=$mntpnt/file bs=1024k count=10" log_must zfs snapshot -r $orig@snap2 -log_must eval "zfs send -R -I $orig@snap1 $orig@snap2 > $streamfile_incr" +log_must zfs snapshot -r $orig@snap3 +log_must eval "zfs send -R -I $orig@snap1 $orig@snap3 > $streamfile_incr" log_must eval "dd if=$streamfile_incr of=$streamfile_trun bs=1024k count=9" # Receive the truncated stream, verify original properties are kept log_mustnot eval "zfs recv -F -o copies=3 -o quota=987654321 "\