4 # The contents of this file are subject to the terms of the
5 # Common Development and Distribution License (the "License").
6 # You may not use this file except in compliance with the License.
8 # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 # or http://www.opensolaris.org/os/licensing.
10 # See the License for the specific language governing permissions
11 # and limitations under the License.
13 # When distributing Covered Code, include this CDDL HEADER in each
14 # file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 # If applicable, add the following below this CDDL HEADER, with the
16 # fields enclosed by brackets "[]" replaced with your own identifying
17 # information: Portions Copyright [yyyy] [name of copyright owner]
23 # Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 # Use is subject to license terms.
28 # Copyright (c) 2013, 2016 by Delphix. All rights reserved.
31 . $STF_SUITE/include/libtest.shlib
32 . $STF_SUITE/include/math.shlib
33 . $STF_SUITE/tests/functional/rsend/rsend.cfg
36 # Set up test model which includes various datasets
46 # ||@final @final @snapC
47 # ||@snapC @snapC @snapB
48 # ||@snapA @snapB @snapA
51 # $pool -------- $FS ------- fs1 ------- fs2
53 # vol vol \____ \ @fsnap
55 # @init @vsnap | ------------ fclone
57 # @final @snapB \ | @init
58 # @snapC vclone @snapA
66 function setup_test_model
70 log_must zfs create -p $pool/$FS/fs1/fs2
72 log_must zfs snapshot $pool@psnap
73 log_must zfs clone $pool@psnap $pool/pclone
75 if is_global_zone ; then
76 log_must zfs create -V 16M $pool/vol
77 log_must zfs create -V 16M $pool/$FS/vol
79 log_must zfs snapshot $pool/$FS/vol@vsnap
80 log_must zfs clone $pool/$FS/vol@vsnap $pool/$FS/vclone
83 log_must snapshot_tree $pool/$FS/fs1/fs2@fsnap
84 log_must zfs clone $pool/$FS/fs1/fs2@fsnap $pool/$FS/fs1/fclone
85 log_must zfs snapshot -r $pool@init
87 log_must snapshot_tree $pool@snapA
88 log_must snapshot_tree $pool@snapC
89 log_must snapshot_tree $pool/pclone@snapB
90 log_must snapshot_tree $pool/$FS@snapB
91 log_must snapshot_tree $pool/$FS@snapC
92 log_must snapshot_tree $pool/$FS/fs1@snapA
93 log_must snapshot_tree $pool/$FS/fs1@snapB
94 log_must snapshot_tree $pool/$FS/fs1@snapC
95 log_must snapshot_tree $pool/$FS/fs1/fclone@snapA
97 if is_global_zone ; then
98 log_must zfs snapshot $pool/vol@snapA
99 log_must zfs snapshot $pool/$FS/vol@snapB
100 log_must zfs snapshot $pool/$FS/vol@snapC
101 log_must zfs snapshot $pool/$FS/vclone@snapC
104 log_must zfs snapshot -r $pool@final
110 # Cleanup the BACKDIR and given pool content and all the sub datasets
114 function cleanup_pool
117 log_must rm -rf $BACKDIR/*
119 if is_global_zone ; then
120 log_must zfs destroy -Rf $pool
122 typeset list=$(zfs list -H -r -t all -o name $pool)
124 if [[ $ds != $pool ]] ; then
125 if datasetexists $ds ; then
126 log_must zfs destroy -Rf $ds
132 typeset mntpnt=$(get_prop mountpoint $pool)
133 if ! ismounted $pool ; then
134 # Make sure mountpoint directory is empty
135 if [[ -d $mntpnt ]]; then
136 log_must rm -rf $mntpnt/*
139 log_must zfs mount $pool
141 if [[ -d $mntpnt ]]; then
148 function cleanup_pools
155 # Detect if the given two filesystems have same sub-datasets
157 # $1 source filesystem
158 # $2 destination filesystem
165 zfs list -r -H -t all -o name $src_fs > $BACKDIR/src1
166 zfs list -r -H -t all -o name $dst_fs > $BACKDIR/dst1
168 eval sed -e 's:^$src_fs:PREFIX:g' < $BACKDIR/src1 > $BACKDIR/src
169 eval sed -e 's:^$dst_fs:PREFIX:g' < $BACKDIR/dst1 > $BACKDIR/dst
171 diff $BACKDIR/src $BACKDIR/dst
174 rm -f $BACKDIR/src $BACKDIR/dst $BACKDIR/src1 $BACKDIR/dst1
180 # Compare all the directores and files in two filesystems
182 # $1 source filesystem
183 # $2 destination filesystem
190 typeset srcdir dstdir
191 srcdir=$(get_prop mountpoint $src_fs)
192 dstdir=$(get_prop mountpoint $dst_fs)
194 diff -r $srcdir $dstdir > /dev/null 2>&1
199 # Compare the given two dataset properties
209 for item in "type" "origin" "volblocksize" "aclinherit" "aclmode" \
210 "atime" "canmount" "checksum" "compression" "copies" "devices" \
211 "exec" "quota" "readonly" "recordsize" "reservation" "setuid" \
212 "sharenfs" "snapdir" "version" "volsize" "xattr" "zoned" \
215 zfs get -H -o property,value,source $item $dtst1 >> \
217 zfs get -H -o property,value,source $item $dtst2 >> \
221 eval sed -e 's:$dtst1:PREFIX:g' < $BACKDIR/dtst1 > $BACKDIR/dtst1
222 eval sed -e 's:$dtst2:PREFIX:g' < $BACKDIR/dtst2 > $BACKDIR/dtst2
224 diff $BACKDIR/dtst1 $BACKDIR/dtst2
227 rm -f $BACKDIR/dtst1 $BACKDIR/dtst2
234 # Random create directories and files
242 if [[ -d $dir ]]; then
249 ((nl = RANDOM % 6 + 1))
252 mktree -b $dir -l $nl -d $nd -f $nf
259 # Put data in filesystem and take snapshot
263 function snapshot_tree
266 typeset ds=${snap%%@*}
267 typeset type=$(get_prop "type" $ds)
270 if [[ $type == "filesystem" ]]; then
271 typeset mntpnt=$(get_prop mountpoint $ds)
274 if ((ret == 0)) ; then
275 eval random_tree $mntpnt/${snap##$ds}
280 if ((ret == 0)) ; then
289 # Destroy the given snapshot and stuff
293 function destroy_tree
297 for snap in "$@" ; do
301 typeset ds=${snap%%@*}
302 typeset type=$(get_prop "type" $ds)
303 if [[ $type == "filesystem" ]]; then
304 typeset mntpnt=$(get_prop mountpoint $ds)
307 if ((ret != 0)); then
313 if ((ret != 0)); then
322 # Get all the sub-datasets of give dataset with specific suffix
327 function getds_with_suffix
332 typeset list=$(zfs list -r -H -t all -o name $ds | grep "$suffix$")
338 # Output inherited properties whitch is edited for file system
340 function fs_inherit_prop
343 if is_global_zone ; then
344 fs_prop=$(zfs inherit 2>&1 | \
345 awk '$2=="YES" && $3=="YES" {print $1}')
347 fs_prop=$(zfs inherit 2>&1 | \
348 awk '$2=="YES" && $3=="YES" {print $1}'|
349 egrep -v "devices|sharenfs|sharesmb|zoned")
356 # Output inherited properties for volume
358 function vol_inherit_prop
360 echo "checksum readonly"
364 # Get the destination dataset to compare
372 # If the srcfs is not pool
374 if ! zpool list $srcfs > /dev/null 2>&1 ; then
375 eval dstfs="$dstfs/${srcfs#*/}"
384 # $1 Number of files to create
385 # $2 Maximum file size
387 # $4 File system to create the files on
396 for ((i=0; i<$nfiles; i=i+1)); do
398 of=/$fs/file-$maxsize-$((i+$file_id_offset)) \
399 bs=$(($RANDOM * $RANDOM % $maxsize)) \
400 count=1 >/dev/null 2>&1 || log_fail \
401 "Failed to create /$fs/file-$maxsize-$((i+$file_id_offset))"
403 echo Created $nfiles files of random sizes up to $maxsize bytes
409 # $1 Number of files to remove
410 # $2 Maximum file size
412 # $4 File system to remove the files from
421 for ((i=0; i<$nfiles; i=i+1)); do
422 rm -f /$fs/file-$maxsize-$((i+$file_id_offset))
424 echo Removed $nfiles files of random sizes up to $maxsize bytes
428 # Mess up file contents
436 filesize=$(stat -c '%s' $file)
437 offset=$(($RANDOM * $RANDOM % $filesize))
438 if (($RANDOM % 7 <= 1)); then
440 # We corrupt 2 bytes to minimize the chance that we
441 # write the same value that's already there.
443 log_must eval "dd if=/dev/random of=$file conv=notrunc " \
444 "bs=1 count=2 oseek=$offset >/dev/null 2>&1"
446 log_must truncate -s $offset $file
451 # Diff the send/receive filesystems
453 # $1 The sent filesystem
454 # $2 The received filesystem
461 if [[ -d /$recvfs/.zfs/snapshot/a && -d \
462 /$sendfs/.zfs/snapshot/a ]]; then
463 diff -r /$recvfs/.zfs/snapshot/a /$sendfs/.zfs/snapshot/a
464 [[ $? -eq 0 ]] || log_fail "Differences found in snap a"
466 if [[ -d /$recvfs/.zfs/snapshot/b && -d \
467 /$sendfs/.zfs/snapshot/b ]]; then
468 diff -r /$recvfs/.zfs/snapshot/b /$sendfs/.zfs/snapshot/b
469 [[ $? -eq 0 ]] || log_fail "Differences found in snap b"
476 # $1 The ZFS send command
477 # $2 The filesystem where the streams are sent
478 # $3 The receive filesystem
487 log_must eval "$sendcmd >/$streamfs/$stream_num"
489 for ((i=0; i<2; i=i+1)); do
490 mess_file /$streamfs/$stream_num
491 log_mustnot zfs recv -suv $recvfs </$streamfs/$stream_num
492 stream_num=$((stream_num+1))
494 token=$(zfs get -Hp -o value receive_resume_token $recvfs)
495 log_must eval "zfs send -v -t $token >/$streamfs/$stream_num"
496 [[ -f /$streamfs/$stream_num ]] || \
497 log_fail "NO FILE /$streamfs/$stream_num"
499 log_must zfs recv -suv $recvfs </$streamfs/$stream_num
503 # Setup filesystems for the resumable send/receive tests
505 # $1 The "send" filesystem
506 # $2 The "recv" filesystem
508 function test_fs_setup
512 typeset sendpool=${sendfs%%/*}
513 typeset recvpool=${recvfs%%/*}
515 datasetexists $sendfs && log_must zfs destroy -r $sendpool
516 datasetexists $recvfs && log_must zfs destroy -r $recvpool
518 if $(datasetexists $sendfs || zfs create -o compress=lz4 $sendfs); then
519 mk_files 1000 256 0 $sendfs &
520 mk_files 1000 131072 0 $sendfs &
521 mk_files 100 1048576 0 $sendfs &
522 mk_files 10 10485760 0 $sendfs &
523 mk_files 1 104857600 0 $sendfs &
525 log_must zfs snapshot $sendfs@a
527 rm_files 200 256 0 $sendfs &
528 rm_files 200 131072 0 $sendfs &
529 rm_files 20 1048576 0 $sendfs &
530 rm_files 2 10485760 0 $sendfs &
533 mk_files 400 256 0 $sendfs &
534 mk_files 400 131072 0 $sendfs &
535 mk_files 40 1048576 0 $sendfs &
536 mk_files 4 10485760 0 $sendfs &
539 log_must zfs snapshot $sendfs@b
540 log_must eval "zfs send -v $sendfs@a >/$sendpool/initial.zsend"
541 log_must eval "zfs send -v -i @a $sendfs@b " \
542 ">/$sendpool/incremental.zsend"
545 if datasetexists $streamfs; then
546 log_must zfs destroy -r $streamfs
548 log_must zfs create -o compress=lz4 $sendpool/stream
552 # Check to see if the specified features are set in a send stream.
553 # The values for these features are found in kernel/fs/zfs/sys/zfs_ioctl.h
556 # $2-$n The flags expected in the stream
558 function stream_has_features
563 [[ -f $file ]] || log_fail "Couldn't find file: $file"
564 typeset flags=$(cat $file | zstreamdump | awk '/features =/ {print $3}')
567 feature[dedupprops]="2"
568 feature[sa_spill]="4"
569 feature[embed_data]="10000"
571 feature[mooch_byteswap]="40000"
572 feature[large_blocks]="80000"
573 feature[resuming]="100000"
574 feature[redacted]="200000"
575 feature[compressed]="400000"
577 typeset flag known derived=0
579 known=${feature[$flag]}
580 [[ -z $known ]] && log_fail "Unknown feature: $flag"
582 derived=$(echo "$flags & ${feature[$flag]} = X" | mdb | sed 's/ //g')
583 [[ $derived = $known ]] || return 1
590 # Parse zstreamdump -v output. The output varies for each kind of record:
591 # BEGIN records are simply output as "BEGIN"
592 # END records are output as "END"
593 # OBJECT records become "OBJECT <object num>"
594 # FREEOBJECTS records become "FREEOBJECTS <startobj> <numobjs>"
595 # FREE records become "<record type> <start> <length>"
596 # WRITE records become:
597 # "<record type> <compression type> <start> <logical size> <compressed size>
602 sed '/^WRITE/{N;s/\n/ /;}' | grep "^[A-Z]" | awk '{
603 if ($1 == "BEGIN" || $1 == "END") print $1
604 if ($1 == "OBJECT") print $1" "$4
605 if ($1 == "FREEOBJECTS") print $1" "$4" "$7
606 if ($1 == "FREE") print $1" "$7" "$10
607 if ($1 == "WRITE") print $1" "$15" "$18" "$21" "$24" "$27}'
611 # Given a send stream, verify that the size of the stream matches what's
612 # expected based on the source or target dataset. If the stream is an
613 # incremental stream, subtract the size of the source snapshot before
614 # comparing. This function does not currently handle incremental streams
617 # $1 The zstreamdump output file
618 # $2 The dataset to compare against
619 # This can be a source of a send or recv target (fs, not snapshot)
620 # $3 The percentage below which verification is deemed a failure
621 # $4 The source snapshot of an incremental send
624 function verify_stream_size
628 typeset percent=${3:-90}
631 [[ -f $stream ]] || log_fail "No such file: $stream"
632 datasetexists $ds || log_fail "No such dataset: $ds"
634 typeset stream_size=$(cat $stream | zstreamdump | sed -n \
635 's/ Total write size = \(.*\) (0x.*)/\1/p')
638 if [[ -n $inc_src ]]; then
639 inc_size=$(get_prop lrefer $inc_src)
640 if stream_has_features $stream compressed; then
641 inc_size=$(get_prop refer $inc_src)
645 if stream_has_features $stream compressed; then
646 ds_size=$(get_prop refer $ds)
648 ds_size=$(get_prop lrefer $ds)
650 ds_size=$((ds_size - inc_size))
652 within_percent $stream_size $ds_size $percent || log_fail \
653 "$stream_size $ds_size differed by too much"
656 # Cleanup function for tests involving resumable send
657 function resume_cleanup
662 datasetexists $sendfs && log_must zfs destroy -r $sendfs
663 datasetexists $streamfs && log_must zfs destroy -r $streamfs
665 rm -f /$POOL/initial.zsend /$POOL/incremental.zsend