1# 2# CDDL HEADER START 3# 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. 7# 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. 12# 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] 18# 19# CDDL HEADER END 20# 21 22# 23# Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24# Use is subject to license terms. 25# 26 27# 28# Copyright (c) 2013, 2018 by Delphix. All rights reserved. 29# Copyright (c) 2020 by Datto Inc. All rights reserved. 30# 31 32. $STF_SUITE/include/libtest.shlib 33. $STF_SUITE/include/math.shlib 34. $STF_SUITE/tests/functional/cli_root/zfs_set/zfs_set_common.kshlib 35. $STF_SUITE/tests/functional/rsend/rsend.cfg 36 37# 38# Set up test model which includes various datasets 39# 40# @final 41# @snapB 42# @init 43# | 44# ______ pclone 45# | / 46# |@psnap 47# || @final 48# ||@final @final @snapC 49# ||@snapC @snapC @snapB 50# ||@snapA @snapB @snapA 51# ||@init @init @init 52# ||| | | 53# $pool -------- $FS ------- fs1 ------- fs2 54# \ \\_____ \ | 55# vol vol \____ \ @fsnap 56# | | \ \ \ 57# @init @vsnap | ------------ fclone 58# @snapA @init \ | | 59# @final @snapB \ | @init 60# @snapC vclone @snapA 61# @final | @final 62# @init 63# @snapC 64# @final 65# 66# $1 pool name 67# 68function setup_test_model 69{ 70 typeset pool=$1 71 72 log_must zfs create -p $pool/$FS/fs1/fs2 73 74 log_must zfs snapshot $pool@psnap 75 log_must zfs clone $pool@psnap $pool/pclone 76 77 if is_global_zone ; then 78 log_must zfs create -V 16M $pool/vol 79 log_must zfs create -V 16M $pool/$FS/vol 80 block_device_wait 81 82 log_must zfs snapshot $pool/$FS/vol@vsnap 83 log_must zfs clone $pool/$FS/vol@vsnap $pool/$FS/vclone 84 block_device_wait 85 fi 86 87 log_must snapshot_tree $pool/$FS/fs1/fs2@fsnap 88 log_must zfs clone $pool/$FS/fs1/fs2@fsnap $pool/$FS/fs1/fclone 89 log_must zfs snapshot -r $pool@init 90 91 log_must snapshot_tree $pool@snapA 92 log_must snapshot_tree $pool@snapC 93 log_must snapshot_tree $pool/pclone@snapB 94 log_must snapshot_tree $pool/$FS@snapB 95 log_must snapshot_tree $pool/$FS@snapC 96 log_must snapshot_tree $pool/$FS/fs1@snapA 97 log_must snapshot_tree $pool/$FS/fs1@snapB 98 log_must snapshot_tree $pool/$FS/fs1@snapC 99 log_must snapshot_tree $pool/$FS/fs1/fclone@snapA 100 101 if is_global_zone ; then 102 log_must zfs snapshot $pool/vol@snapA 103 log_must zfs snapshot $pool/$FS/vol@snapB 104 log_must zfs snapshot $pool/$FS/vol@snapC 105 log_must zfs snapshot $pool/$FS/vclone@snapC 106 fi 107 108 log_must zfs snapshot -r $pool@final 109 110 return 0 111} 112 113# 114# Cleanup the BACKDIR and given pool content and all the sub datasets 115# 116# $1 pool name 117# 118function cleanup_pool 119{ 120 typeset pool=$1 121 log_must rm -rf $BACKDIR/* 122 123 if is_global_zone ; then 124 log_must_busy zfs destroy -Rf $pool 125 else 126 typeset list=$(zfs list -H -r -t all -o name $pool) 127 for ds in $list ; do 128 if [[ $ds != $pool ]] ; then 129 if datasetexists $ds ; then 130 log_must_busy zfs destroy -Rf $ds 131 fi 132 fi 133 done 134 fi 135 136 typeset mntpnt=$(get_prop mountpoint $pool) 137 if ! ismounted $pool ; then 138 # Make sure mountpoint directory is empty 139 if [[ -d $mntpnt ]]; then 140 log_must rm -rf $mntpnt/* 141 fi 142 143 log_must zfs mount $pool 144 fi 145 if [[ -d $mntpnt ]]; then 146 rm -rf $mntpnt/* 147 fi 148 149 return 0 150} 151 152function cleanup_pools 153{ 154 cleanup_pool $POOL2 155 destroy_pool $POOL3 156} 157 158function cmp_md5s { 159 typeset file1=$1 160 typeset file2=$2 161 162 typeset sum1=$(md5digest $file1) 163 typeset sum2=$(md5digest $file2) 164 test "$sum1" = "$sum2" 165} 166 167# 168# Detect if the given two filesystems have same sub-datasets 169# 170# $1 source filesystem 171# $2 destination filesystem 172# 173function cmp_ds_subs 174{ 175 typeset src_fs=$1 176 typeset dst_fs=$2 177 178 zfs list -r -H -t all -o name $src_fs > $BACKDIR/src1 179 zfs list -r -H -t all -o name $dst_fs > $BACKDIR/dst1 180 181 eval sed -e 's:^$src_fs:PREFIX:g' < $BACKDIR/src1 > $BACKDIR/src 182 eval sed -e 's:^$dst_fs:PREFIX:g' < $BACKDIR/dst1 > $BACKDIR/dst 183 184 diff $BACKDIR/src $BACKDIR/dst 185 typeset -i ret=$? 186 187 rm -f $BACKDIR/src $BACKDIR/dst $BACKDIR/src1 $BACKDIR/dst1 188 189 return $ret 190} 191 192# 193# Compare all the directories and files in two filesystems 194# 195# $1 source filesystem 196# $2 destination filesystem 197# 198function cmp_ds_cont 199{ 200 typeset src_fs=$1 201 typeset dst_fs=$2 202 203 typeset srcdir dstdir 204 srcdir=$(get_prop mountpoint $src_fs) 205 dstdir=$(get_prop mountpoint $dst_fs) 206 207 diff -r $srcdir $dstdir > /dev/null 2>&1 208 return $? 209} 210 211# 212# Compare the given two dataset properties 213# 214# $1 dataset 1 215# $2 dataset 2 216# 217function cmp_ds_prop 218{ 219 typeset dtst1=$1 220 typeset dtst2=$2 221 typeset -a props=("type" "origin" "volblocksize" "acltype" "dnodesize" \ 222 "atime" "canmount" "checksum" "compression" "copies" "devices" \ 223 "exec" "quota" "readonly" "recordsize" "reservation" "setuid" \ 224 "snapdir" "version" "volsize" "xattr" "mountpoint"); 225 if is_freebsd; then 226 props+=("jailed") 227 else 228 props+=("zoned") 229 fi 230 231 for prop in $props; 232 do 233 zfs get -H -o property,value,source $prop $dtst1 >> \ 234 $BACKDIR/dtst1 235 zfs get -H -o property,value,source $prop $dtst2 >> \ 236 $BACKDIR/dtst2 237 done 238 239 eval sed -e 's:$dtst1:PREFIX:g' < $BACKDIR/dtst1 > $BACKDIR/dtst1 240 eval sed -e 's:$dtst2:PREFIX:g' < $BACKDIR/dtst2 > $BACKDIR/dtst2 241 242 diff $BACKDIR/dtst1 $BACKDIR/dtst2 243 typeset -i ret=$? 244 245 rm -f $BACKDIR/dtst1 $BACKDIR/dtst2 246 247 return $ret 248 249} 250 251# 252# Random create directories and files 253# 254# $1 directory 255# 256function random_tree 257{ 258 typeset dir=$1 259 260 if [[ -d $dir ]]; then 261 rm -rf $dir 262 fi 263 mkdir -p $dir 264 typeset -i ret=$? 265 266 typeset -i nl nd nf 267 ((nl = RANDOM % 6 + 1)) 268 ((nd = RANDOM % 3 )) 269 ((nf = RANDOM % 5 )) 270 mktree -b $dir -l $nl -d $nd -f $nf 271 ((ret |= $?)) 272 273 return $ret 274} 275 276# 277# Put data in filesystem and take snapshot 278# 279# $1 snapshot name 280# 281function snapshot_tree 282{ 283 typeset snap=$1 284 typeset ds=${snap%%@*} 285 typeset type=$(get_prop "type" $ds) 286 287 typeset -i ret=0 288 if [[ $type == "filesystem" ]]; then 289 typeset mntpnt=$(get_prop mountpoint $ds) 290 ((ret |= $?)) 291 292 if ((ret == 0)) ; then 293 eval random_tree $mntpnt/${snap##$ds} 294 ((ret |= $?)) 295 fi 296 fi 297 298 if ((ret == 0)) ; then 299 zfs snapshot $snap 300 ((ret |= $?)) 301 fi 302 303 return $ret 304} 305 306# 307# Destroy the given snapshot and stuff 308# 309# $1 snapshot 310# 311function destroy_tree 312{ 313 typeset -i ret=0 314 typeset snap 315 for snap in "$@" ; do 316 log_must_busy zfs destroy $snap 317 318 typeset ds=${snap%%@*} 319 typeset type=$(get_prop "type" $ds) 320 if [[ $type == "filesystem" ]]; then 321 typeset mntpnt=$(get_prop mountpoint $ds) 322 if [[ -n $mntpnt ]]; then 323 rm -rf $mntpnt/$snap 324 fi 325 fi 326 done 327 328 return 0 329} 330 331# 332# Get all the sub-datasets of give dataset with specific suffix 333# 334# $1 Given dataset 335# $2 Suffix 336# 337function getds_with_suffix 338{ 339 typeset ds=$1 340 typeset suffix=$2 341 342 typeset list=$(zfs list -r -H -t all -o name $ds | grep "$suffix$") 343 344 echo $list 345} 346 347# 348# Output inherited properties which is edited for file system 349# 350function fs_inherit_prop 351{ 352 typeset fs_prop 353 if is_global_zone ; then 354 fs_prop=$(zfs inherit 2>&1 | \ 355 awk '$2=="YES" && $3=="YES" {print $1}') 356 if ! is_te_enabled ; then 357 fs_prop=$(echo $fs_prop | grep -v "mlslabel") 358 fi 359 else 360 fs_prop=$(zfs inherit 2>&1 | \ 361 awk '$2=="YES" && $3=="YES" {print $1}'| 362 egrep -v "devices|mlslabel|sharenfs|sharesmb|zoned") 363 fi 364 365 echo $fs_prop 366} 367 368# 369# Output inherited properties for volume 370# 371function vol_inherit_prop 372{ 373 echo "checksum readonly" 374} 375 376# 377# Get the destination dataset to compare 378# 379function get_dst_ds 380{ 381 typeset srcfs=$1 382 typeset dstfs=$2 383 384 # 385 # If the srcfs is not pool 386 # 387 if ! zpool list $srcfs > /dev/null 2>&1 ; then 388 eval dstfs="$dstfs/${srcfs#*/}" 389 fi 390 391 echo $dstfs 392} 393 394# 395# Make test files 396# 397# $1 Number of files to create 398# $2 Maximum file size 399# $3 File ID offset 400# $4 File system to create the files on 401# 402function mk_files 403{ 404 nfiles=$1 405 maxsize=$2 406 file_id_offset=$3 407 fs=$4 408 bs=512 409 410 for ((i=0; i<$nfiles; i=i+1)); do 411 file_name="/$fs/file-$maxsize-$((i+$file_id_offset))" 412 file_size=$((($RANDOM * $RANDOM % ($maxsize - 1)) + 1)) 413 414 # 415 # Create an interesting mix of files which contain both 416 # data blocks and holes for more realistic test coverage. 417 # Half the files are created as sparse then partially filled, 418 # the other half is dense then a hole is punched in the file. 419 # 420 if [ $((RANDOM % 2)) -eq 0 ]; then 421 truncate -s $file_size $file_name || \ 422 log_fail "Failed to create $file_name" 423 dd if=/dev/urandom of=$file_name \ 424 bs=$bs count=$(($file_size / 2 / $bs)) \ 425 seek=$(($RANDOM % (($file_size / 2 / $bs) + 1))) \ 426 conv=notrunc >/dev/null 2>&1 || \ 427 log_fail "Failed to create $file_name" 428 else 429 dd if=/dev/urandom of=$file_name \ 430 bs=$file_size count=1 >/dev/null 2>&1 || \ 431 log_fail "Failed to create $file_name" 432 dd if=/dev/zero of=$file_name \ 433 bs=$bs count=$(($file_size / 2 / $bs)) \ 434 seek=$(($RANDOM % (($file_size / 2 / $bs) + 1))) \ 435 conv=notrunc >/dev/null 2>&1 || \ 436 log_fail "Failed to create $file_name" 437 fi 438 done 439 echo Created $nfiles files of random sizes up to $maxsize bytes 440} 441 442# 443# Remove test files 444# 445# $1 Number of files to remove 446# $2 Maximum file size 447# $3 File ID offset 448# $4 File system to remove the files from 449# 450function rm_files 451{ 452 nfiles=$1 453 maxsize=$2 454 file_id_offset=$3 455 fs=$4 456 457 for ((i=0; i<$nfiles; i=i+1)); do 458 rm -f /$fs/file-$maxsize-$((i+$file_id_offset)) 459 done 460 echo Removed $nfiles files of random sizes up to $maxsize bytes 461} 462 463# 464# Simulate a random set of operations which could be reasonably expected 465# to occur on an average filesystem. 466# 467# $1 Number of files to modify 468# $2 Maximum file size 469# $3 File system to modify the file on 470# $4 Enabled xattrs (optional) 471# 472function churn_files 473{ 474 nfiles=$1 475 maxsize=$2 476 fs=$3 477 xattrs=${4:-1} 478 479 # 480 # Remove roughly half of the files in order to make it more 481 # likely that a dnode will be reallocated. 482 # 483 for ((i=0; i<$nfiles; i=i+1)); do 484 file_name="/$fs/file-$i" 485 486 if [[ -e $file_name ]]; then 487 if [ $((RANDOM % 2)) -eq 0 ]; then 488 rm $file_name || \ 489 log_fail "Failed to remove $file_name" 490 fi 491 fi 492 done 493 494 # 495 # Remount the filesystem to simulate normal usage. This resets 496 # the last allocated object id allowing for new objects to be 497 # reallocated in the locations of previously freed objects. 498 # 499 log_must zfs unmount $fs 500 log_must zfs mount $fs 501 502 for i in {0..$nfiles}; do 503 file_name="/$fs/file-$i" 504 file_size=$((($RANDOM * $RANDOM % ($maxsize - 1)) + 1)) 505 506 # 507 # When the file exists modify it in one of five ways to 508 # simulate normal usage: 509 # - (20%) Remove and set and extended attribute on the file 510 # - (20%) Overwrite the existing file 511 # - (20%) Truncate the existing file to a random length 512 # - (20%) Truncate the existing file to zero length 513 # - (20%) Remove the file 514 # 515 # Otherwise create the missing file. 20% of the created 516 # files will be small and use embedded block pointers, the 517 # remainder with have random sizes up to the maximum size. 518 # Three extended attributes are attached to all of the files. 519 # 520 if [[ -e $file_name ]]; then 521 value=$((RANDOM % 5)) 522 if [ $value -eq 0 -a $xattrs -ne 0 ]; then 523 attrname="testattr$((RANDOM % 3))" 524 attrlen="$(((RANDOM % 1000) + 1))" 525 attrvalue="$(random_string VALID_NAME_CHAR \ 526 $attrlen)" 527 rm_xattr $attrname $file_name || \ 528 log_fail "Failed to remove $attrname" 529 set_xattr $attrname "$attrvalue" $file_name || \ 530 log_fail "Failed to set $attrname" 531 elif [ $value -eq 1 ]; then 532 dd if=/dev/urandom of=$file_name \ 533 bs=$file_size count=1 >/dev/null 2>&1 || \ 534 log_fail "Failed to overwrite $file_name" 535 elif [ $value -eq 2 ]; then 536 truncate -s $file_size $file_name || \ 537 log_fail "Failed to truncate $file_name" 538 elif [ $value -eq 3 ]; then 539 truncate -s 0 $file_name || \ 540 log_fail "Failed to truncate $file_name" 541 else 542 rm $file_name || \ 543 log_fail "Failed to remove $file_name" 544 fi 545 else 546 if [ $((RANDOM % 5)) -eq 0 ]; then 547 file_size=$((($RANDOM % 64) + 1)) 548 fi 549 550 dd if=/dev/urandom of=$file_name \ 551 bs=$file_size count=1 >/dev/null 2>&1 || \ 552 log_fail "Failed to create $file_name" 553 554 if [ $xattrs -ne 0 ]; then 555 for j in {0..2}; do 556 attrname="testattr$j" 557 attrlen="$(((RANDOM % 1000) + 1))" 558 attrvalue="$(random_string \ 559 VALID_NAME_CHAR $attrlen)" 560 set_xattr $attrname \ 561 "$attrvalue" $file_name || \ 562 log_fail "Failed to set $attrname" 563 done 564 fi 565 fi 566 done 567 568 return 0 569} 570 571# 572# Mess up a send file's contents 573# 574# $1 The send file path 575# 576function mess_send_file 577{ 578 file=$1 579 580 filesize=$(stat_size $file) 581 582 offset=$(($RANDOM * $RANDOM % $filesize)) 583 584 # The random offset might truncate the send stream to be 585 # smaller than the DRR_BEGIN record. If this happens, then 586 # the receiving system won't have enough info to create the 587 # partial dataset at all. We use zstreamdump to check for 588 # this and retry in this case. 589 nr_begins=$(head -c $offset $file | zstreamdump | \ 590 grep DRR_BEGIN | awk '{ print $5 }') 591 while [ "$nr_begins" -eq 0 ]; do 592 offset=$(($RANDOM * $RANDOM % $filesize)) 593 nr_begins=$(head -c $offset $file | zstreamdump | \ 594 grep DRR_BEGIN | awk '{ print $5 }') 595 done 596 597 if (($RANDOM % 7 <= 1)); then 598 # 599 # We corrupt 2 bytes to minimize the chance that we 600 # write the same value that's already there. 601 # 602 log_must eval "dd if=/dev/urandom of=$file conv=notrunc " \ 603 "bs=1 count=2 seek=$offset >/dev/null 2>&1" 604 else 605 log_must truncate -s $offset $file 606 fi 607} 608 609# 610# Diff the send/receive filesystems 611# 612# $1 The sent filesystem 613# $2 The received filesystem 614# 615function file_check 616{ 617 sendfs=$1 618 recvfs=$2 619 620 if [[ -d /$recvfs/.zfs/snapshot/a && -d \ 621 /$sendfs/.zfs/snapshot/a ]]; then 622 diff -r /$recvfs/.zfs/snapshot/a /$sendfs/.zfs/snapshot/a 623 [[ $? -eq 0 ]] || log_fail "Differences found in snap a" 624 fi 625 if [[ -d /$recvfs/.zfs/snapshot/b && -d \ 626 /$sendfs/.zfs/snapshot/b ]]; then 627 diff -r /$recvfs/.zfs/snapshot/b /$sendfs/.zfs/snapshot/b 628 [[ $? -eq 0 ]] || log_fail "Differences found in snap b" 629 fi 630} 631 632# 633# Resume test helper 634# 635# $1 The ZFS send command 636# $2 The filesystem where the streams are sent 637# $3 The receive filesystem 638# 639function resume_test 640{ 641 sendcmd=$1 642 streamfs=$2 643 recvfs=$3 644 645 stream_num=1 646 log_must eval "$sendcmd >/$streamfs/$stream_num" 647 648 for ((i=0; i<2; i=i+1)); do 649 mess_send_file /$streamfs/$stream_num 650 log_mustnot zfs recv -suv $recvfs </$streamfs/$stream_num 651 stream_num=$((stream_num+1)) 652 653 token=$(zfs get -Hp -o value receive_resume_token $recvfs) 654 log_must eval "zfs send -t $token >/$streamfs/$stream_num" 655 [[ -f /$streamfs/$stream_num ]] || \ 656 log_fail "NO FILE /$streamfs/$stream_num" 657 done 658 log_must zfs recv -suv $recvfs </$streamfs/$stream_num 659} 660 661function get_resume_token 662{ 663 sendcmd=$1 664 streamfs=$2 665 recvfs=$3 666 667 log_must eval "$sendcmd > /$streamfs/1" 668 mess_send_file /$streamfs/1 669 log_mustnot zfs recv -suv $recvfs < /$streamfs/1 2>&1 670 token=$(zfs get -Hp -o value receive_resume_token $recvfs) 671 echo "$token" > /$streamfs/resume_token 672 673 return 0 674} 675 676# 677# Setup filesystems for the resumable send/receive tests 678# 679# $1 The "send" filesystem 680# $2 The "recv" filesystem 681# 682function test_fs_setup 683{ 684 typeset sendfs=$1 685 typeset recvfs=$2 686 typeset streamfs=$3 687 typeset sendpool=${sendfs%%/*} 688 typeset recvpool=${recvfs%%/*} 689 690 datasetexists $sendfs && log_must_busy zfs destroy -r $sendpool 691 datasetexists $recvfs && log_must_busy zfs destroy -r $recvpool 692 datasetexists $streamfs && log_must_busy zfs destroy -r $streamfs 693 694 if datasetexists $sendfs || zfs create -o compress=lz4 $sendfs; then 695 mk_files 1000 256 0 $sendfs & 696 mk_files 1000 131072 0 $sendfs & 697 mk_files 100 1048576 0 $sendfs & 698 mk_files 10 10485760 0 $sendfs & 699 mk_files 1 104857600 0 $sendfs & 700 log_must wait 701 log_must zfs snapshot $sendfs@a 702 703 rm_files 200 256 0 $sendfs & 704 rm_files 200 131072 0 $sendfs & 705 rm_files 20 1048576 0 $sendfs & 706 rm_files 2 10485760 0 $sendfs & 707 log_must wait 708 709 mk_files 400 256 0 $sendfs & 710 mk_files 400 131072 0 $sendfs & 711 mk_files 40 1048576 0 $sendfs & 712 mk_files 4 10485760 0 $sendfs & 713 log_must wait 714 715 log_must zfs snapshot $sendfs@b 716 log_must eval "zfs send -v $sendfs@a >/$sendpool/initial.zsend" 717 log_must eval "zfs send -v -i @a $sendfs@b " \ 718 ">/$sendpool/incremental.zsend" 719 fi 720 721 log_must zfs create -o compress=lz4 $streamfs 722} 723 724# 725# Check to see if the specified features are set in a send stream. 726# The values for these features are found in include/sys/zfs_ioctl.h 727# 728# $1 The stream file 729# $2-$n The flags expected in the stream 730# 731function stream_has_features 732{ 733 typeset file=$1 734 shift 735 736 [[ -f $file ]] || log_fail "Couldn't find file: $file" 737 typeset flags=$(cat $file | zstreamdump | \ 738 awk '/features =/ {features = $3} END {print features}') 739 typeset -A feature 740 feature[dedup]="1" 741 feature[dedupprops]="2" 742 feature[sa_spill]="4" 743 feature[embed_data]="10000" 744 feature[lz4]="20000" 745 feature[mooch_byteswap]="40000" 746 feature[large_blocks]="80000" 747 feature[resuming]="100000" 748 feature[redacted]="200000" 749 feature[compressed]="400000" 750 751 typeset flag known derived=0 752 for flag in "$@"; do 753 known=${feature[$flag]} 754 [[ -z $known ]] && log_fail "Unknown feature: $flag" 755 756 derived=$(printf "%x" $((0x${flags} & 0x${feature[$flag]}))) 757 [[ $derived = $known ]] || return 1 758 done 759 760 return 0 761} 762 763# 764# Given a send stream, verify that the size of the stream matches what's 765# expected based on the source or target dataset. If the stream is an 766# incremental stream, subtract the size of the source snapshot before 767# comparing. This function does not currently handle incremental streams 768# that remove data. 769# 770# $1 The zstreamdump output file 771# $2 The dataset to compare against 772# This can be a source of a send or recv target (fs, not snapshot) 773# $3 The percentage below which verification is deemed a failure 774# $4 The source snapshot of an incremental send 775# 776 777function verify_stream_size 778{ 779 typeset stream=$1 780 typeset ds=$2 781 typeset percent=${3:-90} 782 typeset inc_src=$4 783 784 [[ -f $stream ]] || log_fail "No such file: $stream" 785 datasetexists $ds || log_fail "No such dataset: $ds" 786 787 typeset stream_size=$(cat $stream | zstreamdump | sed -n \ 788 's/ Total payload size = \(.*\) (0x.*)/\1/p') 789 790 typeset inc_size=0 791 if [[ -n $inc_src ]]; then 792 inc_size=$(get_prop lrefer $inc_src) 793 if stream_has_features $stream compressed; then 794 inc_size=$(get_prop refer $inc_src) 795 fi 796 fi 797 798 if stream_has_features $stream compressed; then 799 ds_size=$(get_prop refer $ds) 800 else 801 ds_size=$(get_prop lrefer $ds) 802 fi 803 ds_size=$((ds_size - inc_size)) 804 805 within_percent $stream_size $ds_size $percent || log_fail \ 806 "$stream_size $ds_size differed by too much" 807} 808 809# Cleanup function for tests involving resumable send 810function resume_cleanup 811{ 812 typeset sendfs=$1 813 typeset streamfs=$2 814 typeset sendpool=${sendfs%%/*} 815 816 datasetexists $sendfs && log_must_busy zfs destroy -r $sendfs 817 datasetexists $streamfs && log_must_busy zfs destroy -r $streamfs 818 cleanup_pool $POOL2 819 rm -f /$sendpool/initial.zsend /$sendpool/incremental.zsend 820} 821 822# Randomly set the property to one of the enumerated values. 823function rand_set_prop 824{ 825 typeset dtst=$1 826 typeset prop=$2 827 shift 2 828 typeset value=$(random_get $@) 829 830 log_must eval "zfs set $prop='$value' $dtst" 831} 832 833# Generate a recursive checksum of a filesystem which includes the file 834# contents and any associated extended attributes. 835function recursive_cksum 836{ 837 case "$(uname)" in 838 FreeBSD) 839 find $1 -type f -exec sh -c 'sha256 -q {}; lsextattr -q \ 840 system {} | sha256 -q; lsextattr -q user {} | sha256 -q' \ 841 \; | sort | sha256 -q 842 ;; 843 *) 844 find $1 -type f -exec sh -c 'sha256sum {}; getfattr \ 845 --absolute-names --only-values -d {} | sha256sum' \; | \ 846 sort -k 2 | awk '{ print $1 }' | sha256sum | \ 847 awk '{ print $1 }' 848 ;; 849 esac 850} 851