5 # This file and its contents are supplied under the terms of the
6 # Common Development and Distribution License ("CDDL"), version 1.0.
7 # You may only use this file in accordance with the terms of version
10 # A full copy of the text of the CDDL should have accompanied this
11 # source. A copy of the CDDL is also available via the Internet at
12 # http://www.illumos.org/license/CDDL.
18 # Copyright 2017, loli10K <ezomori.nozomu@gmail.com>. All rights reserved.
21 .
$STF_SUITE/include
/libtest.shlib
22 .
$STF_SUITE/tests
/functional
/cli_root
/zfs_set
/zfs_set_common.kshlib
26 # Verify ZFS property override (-o) and exclude (-x) options work when
27 # receiving a send stream
30 # 1. Create a filesystem with children.
31 # 2. Snapshot the filesystems.
32 # 3. Create various send streams (full, incremental, replication) and verify
33 # we can both override and exclude native and user properties.
36 verify_runnable
"both"
40 log_must
rm -f $streamfile_full
41 log_must
rm -f $streamfile_incr
42 log_must
rm -f $streamfile_repl
43 log_must
rm -f $streamfile_trun
44 log_must zfs destroy
-r -f $orig
45 log_must zfs destroy
-r -f $dest
49 # Verify property $2 is set from source $4 on dataset $1 and has value $3.
56 function check_prop_source
62 typeset chk_value
=$
(get_prop
"$prop" "$dataset")
63 typeset chk_source
=$
(get_source
"$prop" "$dataset")
65 if [[ "$chk_value" != "$value" ||
"$chk_source" != "$4" ]]
74 # Verify target dataset $1 inherit property $2 from dataset $3.
78 # $3 inherited dataset
80 function check_prop_inherit
82 typeset checked_dtst
="$1"
84 typeset inherited_dtst
="$3"
85 typeset inherited_value
=$
(get_prop
"$prop" "$inherited_dtst")
86 typeset value
=$
(get_prop
"$prop" "$checked_dtst")
87 typeset
source=$
(get_source
"$prop" "$checked_dtst")
89 if [[ "$value" != "$inherited_value" || \
90 "$source" != "inherited from $inherited_dtst" ]]
99 # Verify property $2 received value on dataset $1 has value $3
105 function check_prop_received
111 received
=$
(zfs get
-H -o received
"$prop" "$dataset")
113 log_fail
"Unable to get $prop received value for dataset " \
116 if [[ "$received" == "$value" ]]
125 # Verify user property $2 is not set on dataset $1
130 function check_prop_missing
135 value
=$
(zfs get
-H -o value
"$prop" "$dataset")
137 log_fail
"Unable to get $prop value for dataset $dataset"
139 if [[ "-" == "$value" ]]
147 log_assert
"ZFS receive property override and exclude options work as expected."
150 orig
=$TESTPOOL/$TESTFS1
152 dest
=$TESTPOOL/$TESTFS2
154 typeset userprop
=$
(valid_user_property
8)
155 typeset userval
=$
(user_property_value
8)
156 typeset streamfile_full
=$TESTDIR/streamfile_full.$$
157 typeset streamfile_incr
=$TESTDIR/streamfile_incr.$$
158 typeset streamfile_repl
=$TESTDIR/streamfile_repl.$$
159 typeset streamfile_trun
=$TESTDIR/streamfile_trun.$$
162 # 3.1 Verify we can't specify the same property in multiple -o or -x options
163 # or an invalid value was specified.
165 # Create a full send stream
166 log_must zfs create
$orig
167 log_must zfs snapshot
$orig@snap1
168 log_must
eval "zfs send $orig@snap1 > $streamfile_full"
169 # Verify we reject invalid options
170 log_mustnot
eval "zfs recv $dest -o atime < $streamfile_full"
171 log_mustnot
eval "zfs recv $dest -x atime=off < $streamfile_full"
172 log_mustnot
eval "zfs recv $dest -o atime=off -x atime < $streamfile_full"
173 log_mustnot
eval "zfs recv $dest -o atime=off -o atime=on < $streamfile_full"
174 log_mustnot
eval "zfs recv $dest -x atime -x atime < $streamfile_full"
175 log_mustnot
eval "zfs recv $dest -o version=1 < $streamfile_full"
176 log_mustnot
eval "zfs recv $dest -x version < $streamfile_full"
177 log_mustnot
eval "zfs recv $dest -x normalization < $streamfile_full"
178 # Verify we also reject invalid ZVOL options
179 log_must zfs create
-V 32K
-s $orig/zvol
180 log_must
eval "zfs send $orig@snap1 > $streamfile_full"
181 log_mustnot
eval "zfs recv $dest -x volsize < $streamfile_full"
182 log_mustnot
eval "zfs recv $dest -o volsize=32K < $streamfile_full"
185 log_must_busy zfs destroy
-r -f $orig
188 # 3.2 Verify -o property=value works on streams without properties.
190 # Create a full send stream
191 log_must zfs create
$orig
192 log_must zfs snapshot
$orig@snap1
193 log_must
eval "zfs send $orig@snap1 > $streamfile_full"
194 # Receive the full stream, override some properties
195 log_must
eval "zfs recv -o compression=on -o '$userprop:dest'='$userval' "\
196 "$dest < $streamfile_full"
197 log_must
eval "check_prop_source $dest compression on local"
198 log_must
eval "check_prop_source $dest '$userprop:dest' '$userval' local"
200 log_must zfs destroy
-r -f $orig
201 log_must zfs destroy
-r -f $dest
204 # 3.3 Verify -o property=value and -x work on both native and user properties
205 # for an incremental replication send stream.
207 # Create a dataset tree and receive it
208 log_must zfs create
$orig
209 log_must zfs create
$origsub
210 log_must zfs snapshot
-r $orig@snap1
211 log_must
eval "zfs send -R $orig@snap1 > $streamfile_repl"
212 log_must
eval "zfs recv $dest < $streamfile_repl"
213 # Fill the datasets with properties and create an incremental replication stream
214 log_must zfs snapshot
-r $orig@snap2
215 log_must
eval "zfs set copies=2 $orig"
216 log_must
eval "zfs set '$userprop:orig'='$userval' $orig"
217 log_must
eval "zfs set '$userprop:orig'='$userval' $origsub"
218 log_must
eval "zfs set '$userprop:snap'='$userval' $orig@snap1"
219 log_must
eval "zfs set '$userprop:snap'='$userval' $origsub@snap2"
220 log_must
eval "zfs send -R -I $orig@snap1 $orig@snap2 > $streamfile_incr"
221 # Sets various combination of override and exclude options
222 log_must
eval "zfs recv -F -o atime=off -o '$userprop:dest2'='$userval' "\
223 "-o quota=123456789 -x compression -x '$userprop:orig' " \
224 "-x '$userprop:snap2' $dest < $streamfile_incr"
225 # Verify we can correctly override and exclude properties
226 log_must
eval "check_prop_source $dest copies 2 received"
227 log_must
eval "check_prop_source $dest atime off local"
228 log_must
eval "check_prop_source $dest '$userprop:dest2' '$userval' local"
229 log_must
eval "check_prop_source $dest quota 123456789 local"
230 log_must
eval "check_prop_inherit $destsub copies $dest"
231 log_must
eval "check_prop_inherit $destsub atime $dest"
232 log_must
eval "check_prop_inherit $destsub '$userprop:dest2' $dest"
233 log_must
eval "check_prop_source $destsub quota 0 default"
234 log_must
eval "check_prop_source $destsub compression off default"
235 log_must
eval "check_prop_missing $dest '$userprop:orig'"
236 log_must
eval "check_prop_missing $destsub '$userprop:orig'"
237 log_must
eval "check_prop_source " \
238 "$dest@snap1 '$userprop:snap' '$userval' received"
239 log_must
eval "check_prop_source " \
240 "$destsub@snap2 '$userprop:snap' '$userval' received"
241 log_must
eval "check_prop_missing $dest@snap2 '$userprop:snap2'"
242 log_must
eval "check_prop_missing $destsub@snap2 '$userprop:snap2'"
244 log_must zfs destroy
-r -f $orig
245 log_must zfs destroy
-r -f $dest
248 # 3.4 Verify '-x property' does not remove existing local properties and a
249 # modified sent property is received and updated to the new value but can
252 # Create a dataset tree
253 log_must zfs create
$orig
254 log_must zfs create
$origsub
255 log_must zfs snapshot
-r $orig@snap1
256 log_must
eval "zfs set copies=2 $orig"
257 log_must
eval "zfs set '$userprop:orig'='oldval' $orig"
258 log_must
eval "zfs set '$userprop:orig'='oldsubval' $origsub"
259 log_must
eval "zfs send -R $orig@snap1 > $streamfile_repl"
260 log_must
eval "zfs receive $dest < $streamfile_repl"
261 log_must
eval "check_prop_source $dest copies 2 received"
262 log_must
eval "check_prop_inherit $destsub copies $dest"
263 log_must
eval "check_prop_source $dest '$userprop:orig' 'oldval' received"
264 log_must
eval "check_prop_source $destsub '$userprop:orig' 'oldsubval' received"
265 # Set new custom properties on both source and destination
266 log_must
eval "zfs set copies=3 $orig"
267 log_must
eval "zfs set '$userprop:orig'='newval' $orig"
268 log_must
eval "zfs set '$userprop:orig'='newsubval' $origsub"
269 log_must
eval "zfs set compression=gzip $dest"
270 log_must
eval "zfs set '$userprop:dest'='localval' $dest"
271 # Receive the new stream, verify we preserve locally set properties
272 log_must zfs snapshot
-r $orig@snap2
273 log_must
eval "zfs send -R -I $orig@snap1 $orig@snap2 > $streamfile_incr"
274 log_must
eval "zfs recv -F -x copies -x compression -x '$userprop:orig' " \
275 "-x '$userprop:dest' $dest < $streamfile_incr"
276 log_must
eval "check_prop_source $dest '$userprop:dest' 'localval' local"
277 log_must
eval "check_prop_received $dest '$userprop:orig' 'newval'"
278 log_must
eval "check_prop_received $destsub '$userprop:orig' 'newsubval'"
279 log_must
eval "check_prop_missing $dest '$userprop:orig'"
280 log_must
eval "check_prop_missing $destsub '$userprop:orig'"
281 log_must
eval "check_prop_source $dest copies 1 default"
282 log_must
eval "check_prop_received $dest copies 3"
283 log_must
eval "check_prop_source $destsub copies 1 default"
284 log_must
eval "check_prop_received $destsub copies '-'"
285 log_must
eval "check_prop_source $dest compression gzip local"
286 log_must
eval "check_prop_inherit $destsub compression $dest"
288 log_must zfs destroy
-r -f $orig
289 log_must zfs destroy
-r -f $dest
292 # 3.5 Verify we can exclude non-inheritable properties from a send stream
294 # Create a dataset tree and replication stream
295 log_must zfs create
$orig
296 log_must zfs create
$origsub
297 log_must zfs snapshot
-r $orig@snap1
298 log_must
eval "zfs set quota=123456789 $orig"
299 log_must
eval "zfs send -R $orig@snap1 > $streamfile_repl"
300 # Receive the stream excluding non-inheritable properties
301 log_must
eval "zfs recv -F -x quota $dest < $streamfile_repl"
302 log_must
eval "check_prop_source $dest quota 0 default"
303 log_must
eval "check_prop_source $destsub quota 0 default"
304 # Set some non-inheritable properties on the destination, verify we keep them
305 log_must
eval "zfs set quota=123456789 $dest"
306 log_must
eval "zfs set canmount=off $destsub"
307 log_must zfs snapshot
-r $orig@snap2
308 log_must
eval "zfs send -R -I $orig@snap1 $orig@snap2 > $streamfile_incr"
309 log_must
eval "zfs recv -F -x quota -x canmount $dest < $streamfile_incr"
310 log_must
eval "check_prop_source $dest quota 123456789 local"
311 log_must
eval "check_prop_source $destsub quota 0 default"
312 log_must
eval "check_prop_source $destsub canmount off local"
314 log_must zfs destroy
-r -f $orig
315 log_must zfs destroy
-r -f $dest
318 # 3.6 Verify we correctly restore existing properties on a failed receive
320 # Receive a "clean" dataset tree
321 log_must zfs create
$orig
322 log_must zfs create
$origsub
323 log_must zfs snapshot
-r $orig@snap1
324 log_must
eval "zfs send -R $orig@snap1 > $streamfile_repl"
325 log_must
eval "zfs receive $dest < $streamfile_repl"
326 # Set custom properties on the destination
327 log_must
eval "zfs set atime=off $dest"
328 log_must
eval "zfs set quota=123456789 $dest"
329 log_must
eval "zfs set '$userprop:orig'='$userval' $dest"
330 log_must
eval "zfs set '$userprop:origsub'='$userval' $destsub"
331 # Create a truncated incremental replication stream
332 mntpnt
=$
(get_prop mountpoint
$orig)
333 log_must
eval "dd if=/dev/urandom of=$mntpnt/file bs=1024k count=10"
334 log_must zfs snapshot
-r $orig@snap2
335 log_must
eval "zfs send -R -I $orig@snap1 $orig@snap2 > $streamfile_incr"
336 log_must
eval "dd if=$streamfile_incr of=$streamfile_trun bs=1024k count=9"
337 # Receive the truncated stream, verify original properties are kept
338 log_mustnot
eval "zfs recv -F -o copies=3 -o quota=987654321 "\
339 "-o '$userprop:new'='badval' $dest < $streamfile_trun"
340 log_must
eval "check_prop_source $dest copies 1 default"
341 log_must
eval "check_prop_source $destsub copies 1 default"
342 log_must
eval "check_prop_source $dest atime off local"
343 log_must
eval "check_prop_inherit $destsub atime $dest"
344 log_must
eval "check_prop_source $dest quota 123456789 local"
345 log_must
eval "check_prop_source $destsub quota 0 default"
346 log_must
eval "check_prop_source $dest '$userprop:orig' '$userval' local"
347 log_must
eval "check_prop_inherit $destsub '$userprop:orig' $dest"
348 log_must
eval "check_prop_source $destsub '$userprop:origsub' '$userval' local"
349 log_must
eval "check_prop_missing $dest '$userprop:new'"
351 log_must zfs destroy
-r -f $orig
352 log_must zfs destroy
-r -f $dest
355 # 3.7 Verify we can't receive a send stream overriding or excluding properties
356 # invalid for the dataset type unless the stream it's recursive, in which
357 # case only the appropriate properties are set on the destination.
359 log_must zfs create
-V 128K
-s $orig
360 log_must zfs snapshot
$orig@snap1
361 log_must
eval "zfs send $orig@snap1 > $streamfile_full"
362 log_mustnot
eval "zfs receive -x atime $dest < $streamfile_full"
363 log_mustnot
eval "zfs receive -o atime=off $dest < $streamfile_full"
364 log_must zfs destroy
-r -f $orig
365 log_must zfs create
$orig
366 log_must zfs create
-V 128K
-s $origsub
367 log_must zfs snapshot
-r $orig@snap1
368 log_must
eval "zfs send -R $orig@snap1 > $streamfile_repl"
369 log_must
eval "zfs receive -o atime=off $dest < $streamfile_repl"
370 log_must
eval "check_prop_source $dest type filesystem -"
371 log_must
eval "check_prop_source $dest atime off local"
372 log_must
eval "check_prop_source $destsub type volume -"
373 log_must
eval "check_prop_source $destsub atime - -"
375 log_must zfs destroy
-r -f $orig
376 log_must zfs destroy
-r -f $dest
379 # 3.8 Verify 'zfs recv -x|-o' works correctly when used in conjunction with -d
382 log_must zfs create
-p $orig/1/2/3/4
383 log_must
eval "zfs set copies=2 $orig"
384 log_must
eval "zfs set atime=on $orig"
385 log_must
eval "zfs set '$userprop:orig'='oldval' $orig"
386 log_must zfs snapshot
-r $orig@snap1
387 log_must
eval "zfs send -R $orig/1/2@snap1 > $streamfile_repl"
388 # Verify 'zfs recv -e'
389 log_must zfs create
$dest
390 log_must
eval "zfs receive -e -o copies=3 -x atime "\
391 "-o '$userprop:orig'='newval' $dest < $streamfile_repl"
392 log_must datasetexists
$dest/2/3/4
393 log_must
eval "check_prop_source $dest/2 copies 3 local"
394 log_must
eval "check_prop_inherit $dest/2/3/4 copies $dest/2"
395 log_must
eval "check_prop_source $dest/2/3/4 atime on default"
396 log_must
eval "check_prop_source $dest/2 '$userprop:orig' 'newval' local"
397 log_must
eval "check_prop_inherit $dest/2/3/4 '$userprop:orig' $dest/2"
398 log_must zfs destroy
-r -f $dest
399 # Verify 'zfs recv -d'
400 log_must zfs create
$dest
401 typeset fs
="$(echo $orig | awk -F'/' '{print $NF}')"
402 log_must
eval "zfs receive -d -o copies=3 -x atime "\
403 "-o '$userprop:orig'='newval' $dest < $streamfile_repl"
404 log_must datasetexists
$dest/$fs/1/2/3/4
405 log_must
eval "check_prop_source $dest/$fs/1/2 copies 3 local"
406 log_must
eval "check_prop_inherit $dest/$fs/1/2/3/4 copies $dest/$fs/1/2"
407 log_must
eval "check_prop_source $dest/$fs/1/2/3/4 atime on default"
408 log_must
eval "check_prop_source $dest/$fs/1/2 '$userprop:orig' 'newval' local"
409 log_must
eval "check_prop_inherit $dest/$fs/1/2/3/4 '$userprop:orig' $dest/$fs/1/2"
410 # We don't need to cleanup here
412 log_pass
"ZFS receive property override and exclude options passed."