2605 want to resume interrupted zfs send
[illumos-gate.git] / usr / src / test / zfs-tests / tests / functional / rsend / rsend.kshlib
blob24bec0de6b56ee8e1a171038307db2c5bc8a4254
2 # CDDL HEADER START
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]
19 # CDDL HEADER END
23 # Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24 # Use is subject to license terms.
28 # Copyright (c) 2013, 2015 by Delphix. All rights reserved.
31 . $STF_SUITE/include/libtest.shlib
32 . $STF_SUITE/tests/functional/rsend/rsend.cfg
35 # Set up test model which includes various datasets
37 #               @final
38 #               @snapB
39 #               @init
40 #               |
41 #   ______ pclone
42 #  |      /
43 #  |@psnap
44 #  ||                         @final
45 #  ||@final       @final      @snapC
46 #  ||@snapC       @snapC      @snapB
47 #  ||@snapA       @snapB      @snapA
48 #  ||@init        @init       @init
49 #  |||            |           |
50 # $pool -------- $FS ------- fs1 ------- fs2
51 #    \             \\_____     \          |
52 #     vol           vol   \____ \         @fsnap
53 #      |              |        \ \              \
54 #      @init          @vsnap   |  ------------ fclone
55 #      @snapA         @init \  |                    |
56 #      @final         @snapB \ |                    @init
57 #                     @snapC  vclone                @snapA
58 #                     @final       |                @final
59 #                                 @init
60 #                                 @snapC
61 #                                 @final
63 # $1 pool name
65 function setup_test_model
67         typeset pool=$1
69         log_must $ZFS create -p $pool/$FS/fs1/fs2
71         log_must $ZFS snapshot $pool@psnap
72         log_must $ZFS clone $pool@psnap $pool/pclone
74         if is_global_zone ; then
75                 log_must $ZFS create -V 16M $pool/vol
76                 log_must $ZFS create -V 16M $pool/$FS/vol
78                 log_must $ZFS snapshot $pool/$FS/vol@vsnap
79                 log_must $ZFS clone $pool/$FS/vol@vsnap $pool/$FS/vclone
80         fi
82         log_must snapshot_tree $pool/$FS/fs1/fs2@fsnap
83         log_must $ZFS clone $pool/$FS/fs1/fs2@fsnap $pool/$FS/fs1/fclone
84         log_must $ZFS snapshot -r $pool@init
86         log_must snapshot_tree $pool@snapA
87         log_must snapshot_tree $pool@snapC
88         log_must snapshot_tree $pool/pclone@snapB
89         log_must snapshot_tree $pool/$FS@snapB
90         log_must snapshot_tree $pool/$FS@snapC
91         log_must snapshot_tree $pool/$FS/fs1@snapA
92         log_must snapshot_tree $pool/$FS/fs1@snapB
93         log_must snapshot_tree $pool/$FS/fs1@snapC
94         log_must snapshot_tree $pool/$FS/fs1/fclone@snapA
96         if is_global_zone ; then
97                 log_must $ZFS snapshot $pool/vol@snapA
98                 log_must $ZFS snapshot $pool/$FS/vol@snapB
99                 log_must $ZFS snapshot $pool/$FS/vol@snapC
100                 log_must $ZFS snapshot $pool/$FS/vclone@snapC
101         fi
103         log_must $ZFS snapshot -r $pool@final
105         return 0
109 # Cleanup the BACKDIR and given pool content and all the sub datasets
111 # $1 pool name
113 function cleanup_pool
115         typeset pool=$1
116         log_must $RM -rf $BACKDIR/*
118         if is_global_zone ; then
119                 log_must $ZFS destroy -Rf $pool
120         else
121                 typeset list=$($ZFS list -H -r -t filesystem,snapshot,volume -o name $pool)
122                 for ds in $list ; do
123                         if [[ $ds != $pool ]] ; then
124                                 if datasetexists $ds ; then
125                                         log_must $ZFS destroy -Rf $ds
126                                 fi
127                         fi
128                 done
129         fi
131         typeset mntpnt=$(get_prop mountpoint $pool)
132         if ! ismounted $pool ; then
133                 # Make sure mountpoint directory is empty
134                 if [[ -d $mntpnt ]]; then
135                         log_must $RM -rf $mntpnt/*
136                 fi
138                 log_must $ZFS mount $pool
139         fi
140         if [[ -d $mntpnt ]]; then
141                 log_must $RM -rf $mntpnt/*
142         fi
144         return 0
148 # Detect if the given two filesystems have same sub-datasets
150 # $1 source filesystem
151 # $2 destination filesystem
153 function cmp_ds_subs
155         typeset src_fs=$1
156         typeset dst_fs=$2
158         $ZFS list -r -H -t filesystem,snapshot,volume -o name $src_fs > $BACKDIR/src1
159         $ZFS list -r -H -t filesystem,snapshot,volume -o name $dst_fs > $BACKDIR/dst1
161         eval $SED -e 's:^$src_fs:PREFIX:g' < $BACKDIR/src1 > $BACKDIR/src
162         eval $SED -e 's:^$dst_fs:PREFIX:g' < $BACKDIR/dst1 > $BACKDIR/dst
164         $DIFF $BACKDIR/src $BACKDIR/dst
165         typeset -i ret=$?
167         $RM -f $BACKDIR/src $BACKDIR/dst $BACKDIR/src1 $BACKDIR/dst1
169         return $ret
173 # Compare all the directores and files in two filesystems
175 # $1 source filesystem
176 # $2 destination filesystem
178 function cmp_ds_cont
180         typeset src_fs=$1
181         typeset dst_fs=$2
183         typeset srcdir dstdir
184         srcdir=$(get_prop mountpoint $src_fs)
185         dstdir=$(get_prop mountpoint $dst_fs)
187         $DIFF -r $srcdir $dstdir > /dev/null 2>&1
188         echo $?
192 # Compare the given two dataset properties
194 # $1 dataset 1
195 # $2 dataset 2
197 function cmp_ds_prop
199         typeset dtst1=$1
200         typeset dtst2=$2
202         for item in "type" "origin" "volblocksize" "aclinherit" "aclmode" \
203             "atime" "canmount" "checksum" "compression" "copies" "devices" \
204             "exec" "quota" "readonly" "recordsize" "reservation" "setuid" \
205             "sharenfs" "snapdir" "version" "volsize" "xattr" "zoned" \
206             "mountpoint";
207         do
208                 $ZFS get -H -o property,value,source $item $dtst1 >> \
209                     $BACKDIR/dtst1
210                 $ZFS get -H -o property,value,source $item $dtst2 >> \
211                     $BACKDIR/dtst2
212         done
214         eval $SED -e 's:$dtst1:PREFIX:g' < $BACKDIR/dtst1 > $BACKDIR/dtst1
215         eval $SED -e 's:$dtst2:PREFIX:g' < $BACKDIR/dtst2 > $BACKDIR/dtst2
217         $DIFF $BACKDIR/dtst1 $BACKDIR/dtst2
218         typeset -i ret=$?
220         $RM -f $BACKDIR/dtst1 $BACKDIR/dtst2
222         return $ret
227 # Random create directories and files
229 # $1 directory
231 function random_tree
233         typeset dir=$1
235         if [[ -d $dir ]]; then
236                 $RM -rf $dir
237         fi
238         $MKDIR -p $dir
239         typeset -i ret=$?
241         typeset -i nl nd nf
242         ((nl = RANDOM % 6 + 1))
243         ((nd = RANDOM % 3 ))
244         ((nf = RANDOM % 5 ))
245         $MKTREE -b $dir -l $nl -d $nd -f $nf
246         ((ret |= $?))
248         return $ret
252 # Put data in filesystem and take snapshot
254 # $1 snapshot name
256 function snapshot_tree
258         typeset snap=$1
259         typeset ds=${snap%%@*}
260         typeset type=$(get_prop "type" $ds)
262         typeset -i ret=0
263         if [[ $type == "filesystem" ]]; then
264                 typeset mntpnt=$(get_prop mountpoint $ds)
265                 ((ret |= $?))
267                 if ((ret == 0)) ; then
268                         eval random_tree $mntpnt/${snap##$ds}
269                         ((ret |= $?))
270                 fi
271         fi
273         if ((ret == 0)) ; then
274                 $ZFS snapshot $snap
275                 ((ret |= $?))
276         fi
278         return $ret
282 # Destroy the given snapshot and stuff
284 # $1 snapshot
286 function destroy_tree
288         typeset -i ret=0
289         typeset snap
290         for snap in "$@" ; do
291                 $ZFS destroy $snap
292                 ret=$?
294                 typeset ds=${snap%%@*}
295                 typeset type=$(get_prop "type" $ds)
296                 if [[ $type == "filesystem" ]]; then
297                         typeset mntpnt=$(get_prop mountpoint $ds)
298                         ((ret |= $?))
300                         if ((ret != 0)); then
301                                 $RM -r $mntpnt/$snap
302                                 ((ret |= $?))
303                         fi
304                 fi
306                 if ((ret != 0)); then
307                         return $ret
308                 fi
309         done
311         return 0
315 # Get all the sub-datasets of give dataset with specific suffix
317 # $1 Given dataset
318 # $2 Suffix
320 function getds_with_suffix
322         typeset ds=$1
323         typeset suffix=$2
325         typeset list=$($ZFS list -r -H -t filesystem,snapshot,volume -o name $ds \
326             | $GREP "$suffix$")
328         $ECHO $list
332 # Output inherited properties whitch is edited for file system
334 function fs_inherit_prop
336         typeset fs_prop
337         if is_global_zone ; then
338                 fs_prop=$($ZFS inherit 2>&1 | \
339                     $AWK '$2=="YES" && $3=="YES" {print $1}')
340                 if ! is_te_enabled ; then
341                         fs_prop=$(echo $fs_prop | $GREP -v "mlslabel")
342                 fi
343         else
344                 fs_prop=$($ZFS inherit 2>&1 | \
345                     $AWK '$2=="YES" && $3=="YES" {print $1}'|
346                     $EGREP -v "devices|mlslabel|sharenfs|sharesmb|zoned")
347         fi
349         $ECHO $fs_prop
353 # Output inherited properties for volume
355 function vol_inherit_prop
357         $ECHO "checksum readonly"
361 # Get the destination dataset to compare
363 function get_dst_ds
365         typeset srcfs=$1
366         typeset dstfs=$2
368         #
369         # If the srcfs is not pool
370         #
371         if ! $ZPOOL list $srcfs > /dev/null 2>&1 ; then
372                 eval dstfs="$dstfs/${srcfs#*/}"
373         fi
375         $ECHO $dstfs
379 # Make test files
381 # $1 Number of files to create
382 # $2 Maximum file size
383 # $3 File ID offset
384 # $4 File system to create the files on
386 function mk_files
388         nfiles=$1
389         maxsize=$2
390         file_id_offset=$3
391         fs=$4
393         for ((i=0; i<$nfiles; i=i+1)); do
394                 $DD if=/dev/urandom \
395                     of=/$fs/file-$maxsize-$((i+$file_id_offset)) \
396                     bs=$(($RANDOM * $RANDOM % $maxsize)) \
397                     count=1 >/dev/null 2>&1 || log_fail \
398                     "Failed to create /$fs/file-$maxsize-$((i+$file_id_offset))"
399         done
400         $ECHO Created $nfiles files of random sizes up to $maxsize bytes
404 # Remove test files
406 # $1 Number of files to remove
407 # $2 Maximum file size
408 # $3 File ID offset
409 # $4 File system to remove the files from
411 function rm_files
413         nfiles=$1
414         maxsize=$2
415         file_id_offset=$3
416         fs=$4
418         for ((i=0; i<$nfiles; i=i+1)); do
419                 $RM -f /$fs/file-$maxsize-$((i+$file_id_offset))
420         done
421         $ECHO Removed $nfiles files of random sizes up to $maxsize bytes
425 # Mess up file contents
427 # $1 The file path
429 function mess_file
431         file=$1
433         filesize=$($STAT -c '%s' $file)
434         offset=$(($RANDOM * $RANDOM % $filesize))
435         if (($RANDOM % 7 <= 1)); then
436                 #
437                 # We corrupt 2 bytes to minimize the chance that we
438                 # write the same value that's already there.
439                 #
440                 log_must eval "$DD if=/dev/random of=$file conv=notrunc " \
441                     "bs=1 count=2 oseek=$offset >/dev/null 2>&1"
442         else
443                 log_must $TRUNCATE -s $offset $file
444         fi
448 # Diff the send/receive filesystems
450 # $1 The sent filesystem
451 # $2 The received filesystem
453 function file_check
455         sendfs=$1
456         recvfs=$2
458         if [[ -d /$recvfs/.zfs/snapshot/a && -d \
459             /$sendfs/.zfs/snapshot/a ]]; then
460                 $DIFF -r /$recvfs/.zfs/snapshot/a /$sendfs/.zfs/snapshot/a
461                 [[ $? -eq 0 ]] || log_fail "Differences found in snap a"
462         fi
463         if [[ -d /$recvfs/.zfs/snapshot/b && -d \
464             /$sendfs/.zfs/snapshot/b ]]; then
465                 $DIFF -r /$recvfs/.zfs/snapshot/b /$sendfs/.zfs/snapshot/b
466                 [[ $? -eq 0 ]] || log_fail "Differences found in snap b"
467         fi
471 # Resume test helper
473 # $1 The ZFS send command
474 # $2 The filesystem where the streams are sent
475 # $3 The receive filesystem
477 function resume_test
479         sendcmd=$1
480         streamfs=$2
481         recvfs=$3
483         stream_num=1
484         log_must eval "$sendcmd >/$streamfs/$stream_num"
486         for ((i=0; i<2; i=i+1)); do
487                 mess_file /$streamfs/$stream_num
488                 log_mustnot $ZFS recv -sv $recvfs </$streamfs/$stream_num
489                 stream_num=$((stream_num+1))
491                 token=$($ZFS get -Hp -o value receive_resume_token $recvfs)
492                 log_must eval "$ZFS send -v -t $token >/$streamfs/$stream_num"
493                 [[ -f /$streamfs/$stream_num ]] || \
494                     log_fail "NO FILE /$streamfs/$stream_num"
495         done
496         log_must $ZFS recv -sv $recvfs </$streamfs/$stream_num
500 # Setup filesystems for the resumable send/receive tests
502 # $1 The pool to set up with the "send" filesystems
503 # $2 The pool for receive
505 function test_fs_setup
507         sendpool=$1
508         recvpool=$2
510         sendfs=$sendpool/sendfs
511         recvfs=$recvpool/recvfs
512         streamfs=$sendpool/stream
514         if datasetexists $recvfs; then
515                 log_must $ZFS destroy -r $recvfs
516         fi
517         if datasetexists $sendfs; then
518                 log_must $ZFS destroy -r $sendfs
519         fi
520         if $($ZFS create -o compress=lz4 $sendfs); then
521                 mk_files 1000 256 0 $sendfs &
522                 mk_files 1000 131072 0 $sendfs &
523                 mk_files 100 1048576 0 $sendfs &
524                 mk_files 10 10485760 0 $sendfs &
525                 mk_files 1 104857600 0 $sendfs &
526                 log_must $WAIT
527                 log_must $ZFS snapshot $sendfs@a
529                 rm_files 200 256 0 $sendfs &
530                 rm_files 200 131072 0 $sendfs &
531                 rm_files 20 1048576 0 $sendfs &
532                 rm_files 2 10485760 0 $sendfs &
533                 log_must $WAIT
535                 mk_files 400 256 0 $sendfs &
536                 mk_files 400 131072 0 $sendfs &
537                 mk_files 40 1048576 0 $sendfs &
538                 mk_files 4 10485760 0 $sendfs &
539                 log_must $WAIT
541                 log_must $ZFS snapshot $sendfs@b
542                 log_must eval "$ZFS send -v $sendfs@a >/$sendpool/initial.zsend"
543                 log_must eval "$ZFS send -v -i @a $sendfs@b " \
544                     ">/$sendpool/incremental.zsend"
545         fi
547         if datasetexists $streamfs; then
548                 log_must $ZFS destroy -r $streamfs
549         fi
550         log_must $ZFS create -o compress=lz4 $sendpool/stream