From bdce0c55d7b377ef23cb5ef6d0675fdf6a5bf98f Mon Sep 17 00:00:00 2001 From: loli10K Date: Tue, 10 Jan 2017 00:26:23 +0100 Subject: [PATCH] Don't inherit locally set properties --- lib/libzfs/libzfs_sendrecv.c | 24 ++++++++++++++----- .../zfs_receive/zfs_receive_014_pos.ksh | 18 ++++++++++---- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/lib/libzfs/libzfs_sendrecv.c b/lib/libzfs/libzfs_sendrecv.c index 10b2fc460494..4f22bd87fe35 100644 --- a/lib/libzfs/libzfs_sendrecv.c +++ b/lib/libzfs/libzfs_sendrecv.c @@ -3073,13 +3073,14 @@ recv_ecksum_set_aux(libzfs_handle_t *hdl, const char *target_snap, /* * Prepare a new nvlist of properties that are to override (-o) or be excluded * (-x) from the received dataset - * cmdprops: input properties from command line (nvlist) - * oxprops: output properties (nvlist) + * cmdprops: input properties from command line + * origprops: original properties if the destination exists, NULL otherwise + * oxprops: output override (-o) and excluded (-x) properties */ static int zfs_setup_cmdline_props(libzfs_handle_t *hdl, zfs_type_t type, boolean_t zoned, boolean_t recursive, boolean_t toplevel, nvlist_t *cmdprops, - nvlist_t **oxprops, const char *errbuf) + nvlist_t *origprops, nvlist_t **oxprops, const char *errbuf) { nvpair_t *nvp; nvlist_t *oprops, *voprops; @@ -3124,7 +3125,8 @@ zfs_setup_cmdline_props(libzfs_handle_t *hdl, zfs_type_t type, boolean_t zoned, switch (nvpair_type(nvp)) { case DATA_TYPE_BOOLEAN: /* -x property */ - fnvlist_add_nvpair(*oxprops, nvp); + if (!nvlist_exists(origprops, name)) + fnvlist_add_nvpair(*oxprops, nvp); break; case DATA_TYPE_STRING: /* -o property=value */ fnvlist_add_nvpair(oprops, nvp); @@ -3197,7 +3199,8 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, char origin[MAXNAMELEN]; char name[MAXPATHLEN]; nvlist_t *rcvprops = NULL; /* props received from the send stream */ - nvlist_t *oxprops = NULL; /* props passed via the cli (-o|-x) */ + nvlist_t *oxprops = NULL; /* override (-o) and exclude (-x) props */ + nvlist_t *origprops = NULL; /* original props (if destination exists) */ zfs_type_t type; boolean_t toplevel; boolean_t zoned = B_FALSE; @@ -3482,6 +3485,12 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, /* we want to know if we're zoned when validating -o|-x props */ zoned = zfs_prop_get_int(zhp, ZFS_PROP_ZONED); + /* gather existing properties on destination dataset */ + (void) zfs_refresh_properties(zhp); + origprops = fnvlist_alloc(); + (void) fnvlist_merge(origprops, zhp->zfs_props); + (void) fnvlist_merge(origprops, zhp->zfs_user_props); + zfs_close(zhp); } else { /* @@ -3534,7 +3543,7 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, else type = ZFS_TYPE_FILESYSTEM; if ((err = zfs_setup_cmdline_props(hdl, type, zoned, recursive, - toplevel, cmdprops, &oxprops, errbuf)) != 0) + toplevel, cmdprops, origprops, &oxprops, errbuf)) != 0) goto out; err = ioctl_err = lzc_receive_one(destsnap, rcvprops, oxprops, origin, @@ -3755,6 +3764,9 @@ zfs_receive_one(libzfs_handle_t *hdl, int infd, const char *tosnap, if (newprops) nvlist_free(rcvprops); + if (origprops != NULL) + nvlist_free(origprops); + return (err); } diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_014_pos.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_014_pos.ksh index 7b2154d5c69d..caa08e0df411 100755 --- a/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_014_pos.ksh +++ b/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_014_pos.ksh @@ -42,12 +42,14 @@ destsub=$dest/sub typeset userprop=$(valid_user_property 8) typeset userval=$(user_property_value 8) typeset streamfile_full=/var/tmp/streamfile_full.$$ -typeset streamfile_repl=/var/tmp/streamfile_repl.$$ +typeset streamfile_repl1=/var/tmp/streamfile_repl1.$$ +typeset streamfile_repl2=/var/tmp/streamfile_repl2.$$ function cleanup { log_must $RM $streamfile_full - log_must $RM $streamfile_repl + log_must $RM $streamfile_repl1 + log_must $RM $streamfile_repl2 log_must $ZFS destroy -rf $orig log_must $ZFS destroy -rf $dest } @@ -147,6 +149,7 @@ log_must $ZFS create $origsub # 2. Snapshot the filesystems. log_must $ZFS snapshot $orig@snap1 log_must $ZFS snapshot -r $orig@snap2 +log_must $ZFS snapshot -r $orig@snap3 # 3. Create a full stream without properties. log_must eval "$ZFS send $orig@snap1 > $streamfile_full" @@ -156,7 +159,8 @@ 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_repl" +log_must eval "$ZFS send -R -I $orig@snap1 $orig@snap2 > $streamfile_repl1" +log_must eval "$ZFS send -R -I $orig@snap2 $orig@snap3 > $streamfile_repl2" # 5. Receive the send streams and verify we can override properties. # 5.1 Error results if the same property is specified in multiple -o or @@ -179,7 +183,7 @@ log_must eval "check_prop_source $dest '$userprop:dest1' '$userval' local" # properties for an incremental replication send stream. 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_repl" + "$dest < $streamfile_repl1" log_must eval "check_prop_source $dest atime off local" log_must eval "check_prop_source $dest '$userprop:dest2' '$userval' local" log_must eval "check_prop_source $dest quota 123456789 local" @@ -194,4 +198,10 @@ log_must eval "check_prop_received $destsub@snap2 '$userprop:snap'" log_must eval "check_prop_missing $dest@snap2 '$userprop:snap2'" log_must eval "check_prop_missing $destsub@snap2 '$userprop:snap2'" + +# 5.4 Verify -x property does not remove existing local properties +log_must eval "$ZFS set '$userprop:orig'='newval' $destsub" +log_must eval "$ZFS recv -F -x '$userprop:orig' $dest < $streamfile_repl2" +log_must eval "check_prop_source $destsub '$userprop:orig' 'newval' local" + log_pass "ZFS receive property override options passed."