# # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # # Copyright (c) 2013, 2015 by Delphix. All rights reserved. # . $STF_SUITE/include/libtest.shlib . $STF_SUITE/tests/functional/rsend/rsend.cfg # # Set up test model which includes various datasets # # @final # @snapB # @init # | # ______ pclone # | / # |@psnap # || @final # ||@final @final @snapC # ||@snapC @snapC @snapB # ||@snapA @snapB @snapA # ||@init @init @init # ||| | | # $pool -------- $FS ------- fs1 ------- fs2 # \ \\_____ \ | # vol vol \____ \ @fsnap # | | \ \ \ # @init @vsnap | ------------ fclone # @snapA @init \ | | # @final @snapB \ | @init # @snapC vclone @snapA # @final | @final # @init # @snapC # @final # # $1 pool name # function setup_test_model { typeset pool=$1 log_must $ZFS create -p $pool/$FS/fs1/fs2 log_must $ZFS snapshot $pool@psnap log_must $ZFS clone $pool@psnap $pool/pclone if is_global_zone ; then log_must $ZFS create -V 16M $pool/vol log_must $ZFS create -V 16M $pool/$FS/vol log_must $ZFS snapshot $pool/$FS/vol@vsnap log_must $ZFS clone $pool/$FS/vol@vsnap $pool/$FS/vclone fi log_must snapshot_tree $pool/$FS/fs1/fs2@fsnap log_must $ZFS clone $pool/$FS/fs1/fs2@fsnap $pool/$FS/fs1/fclone log_must $ZFS snapshot -r $pool@init log_must snapshot_tree $pool@snapA log_must snapshot_tree $pool@snapC log_must snapshot_tree $pool/pclone@snapB log_must snapshot_tree $pool/$FS@snapB log_must snapshot_tree $pool/$FS@snapC log_must snapshot_tree $pool/$FS/fs1@snapA log_must snapshot_tree $pool/$FS/fs1@snapB log_must snapshot_tree $pool/$FS/fs1@snapC log_must snapshot_tree $pool/$FS/fs1/fclone@snapA if is_global_zone ; then log_must $ZFS snapshot $pool/vol@snapA log_must $ZFS snapshot $pool/$FS/vol@snapB log_must $ZFS snapshot $pool/$FS/vol@snapC log_must $ZFS snapshot $pool/$FS/vclone@snapC fi log_must $ZFS snapshot -r $pool@final return 0 } # # Cleanup the BACKDIR and given pool content and all the sub datasets # # $1 pool name # function cleanup_pool { typeset pool=$1 log_must $RM -rf $BACKDIR/* if is_global_zone ; then log_must $ZFS destroy -Rf $pool else typeset list=$($ZFS list -H -r -t filesystem,snapshot,volume -o name $pool) for ds in $list ; do if [[ $ds != $pool ]] ; then if datasetexists $ds ; then log_must $ZFS destroy -Rf $ds fi fi done fi typeset mntpnt=$(get_prop mountpoint $pool) if ! ismounted $pool ; then # Make sure mountpoint directory is empty if [[ -d $mntpnt ]]; then log_must $RM -rf $mntpnt/* fi log_must $ZFS mount $pool fi if [[ -d $mntpnt ]]; then log_must $RM -rf $mntpnt/* fi return 0 } # # Detect if the given two filesystems have same sub-datasets # # $1 source filesystem # $2 destination filesystem # function cmp_ds_subs { typeset src_fs=$1 typeset dst_fs=$2 $ZFS list -r -H -t filesystem,snapshot,volume -o name $src_fs > $BACKDIR/src1 $ZFS list -r -H -t filesystem,snapshot,volume -o name $dst_fs > $BACKDIR/dst1 eval $SED -e 's:^$src_fs:PREFIX:g' < $BACKDIR/src1 > $BACKDIR/src eval $SED -e 's:^$dst_fs:PREFIX:g' < $BACKDIR/dst1 > $BACKDIR/dst $DIFF $BACKDIR/src $BACKDIR/dst typeset -i ret=$? $RM -f $BACKDIR/src $BACKDIR/dst $BACKDIR/src1 $BACKDIR/dst1 return $ret } # # Compare all the directores and files in two filesystems # # $1 source filesystem # $2 destination filesystem # function cmp_ds_cont { typeset src_fs=$1 typeset dst_fs=$2 typeset srcdir dstdir srcdir=$(get_prop mountpoint $src_fs) dstdir=$(get_prop mountpoint $dst_fs) $DIFF -r $srcdir $dstdir > /dev/null 2>&1 return $? } # # Compare the given two dataset properties # # $1 dataset 1 # $2 dataset 2 # function cmp_ds_prop { typeset dtst1=$1 typeset dtst2=$2 for item in "type" "origin" "volblocksize" "aclinherit" "aclmode" \ "atime" "canmount" "checksum" "compression" "copies" "devices" \ "exec" "quota" "readonly" "recordsize" "reservation" "setuid" \ "sharenfs" "snapdir" "version" "volsize" "xattr" "zoned" \ "mountpoint"; do $ZFS get -H -o property,value,source $item $dtst1 >> \ $BACKDIR/dtst1 $ZFS get -H -o property,value,source $item $dtst2 >> \ $BACKDIR/dtst2 done eval $SED -e 's:$dtst1:PREFIX:g' < $BACKDIR/dtst1 > $BACKDIR/dtst1 eval $SED -e 's:$dtst2:PREFIX:g' < $BACKDIR/dtst2 > $BACKDIR/dtst2 $DIFF $BACKDIR/dtst1 $BACKDIR/dtst2 typeset -i ret=$? $RM -f $BACKDIR/dtst1 $BACKDIR/dtst2 return $ret } # # Random create directories and files # # $1 directory # function random_tree { typeset dir=$1 if [[ -d $dir ]]; then $RM -rf $dir fi $MKDIR -p $dir typeset -i ret=$? typeset -i nl nd nf ((nl = RANDOM % 6 + 1)) ((nd = RANDOM % 3 )) ((nf = RANDOM % 5 )) $MKTREE -b $dir -l $nl -d $nd -f $nf ((ret |= $?)) return $ret } # # Put data in filesystem and take snapshot # # $1 snapshot name # function snapshot_tree { typeset snap=$1 typeset ds=${snap%%@*} typeset type=$(get_prop "type" $ds) typeset -i ret=0 if [[ $type == "filesystem" ]]; then typeset mntpnt=$(get_prop mountpoint $ds) ((ret |= $?)) if ((ret == 0)) ; then eval random_tree $mntpnt/${snap##$ds} ((ret |= $?)) fi fi if ((ret == 0)) ; then $ZFS snapshot $snap ((ret |= $?)) fi return $ret } # # Destroy the given snapshot and stuff # # $1 snapshot # function destroy_tree { typeset -i ret=0 typeset snap for snap in "$@" ; do $ZFS destroy $snap ret=$? typeset ds=${snap%%@*} typeset type=$(get_prop "type" $ds) if [[ $type == "filesystem" ]]; then typeset mntpnt=$(get_prop mountpoint $ds) ((ret |= $?)) if ((ret != 0)); then $RM -r $mntpnt/$snap ((ret |= $?)) fi fi if ((ret != 0)); then return $ret fi done return 0 } # # Get all the sub-datasets of give dataset with specific suffix # # $1 Given dataset # $2 Suffix # function getds_with_suffix { typeset ds=$1 typeset suffix=$2 typeset list=$($ZFS list -r -H -t filesystem,snapshot,volume -o name $ds \ | $GREP "$suffix$") $ECHO $list } # # Output inherited properties whitch is edited for file system # function fs_inherit_prop { typeset fs_prop if is_global_zone ; then fs_prop=$($ZFS inherit 2>&1 | \ $AWK '$2=="YES" && $3=="YES" {print $1}') if ! is_te_enabled ; then fs_prop=$(echo $fs_prop | $GREP -v "mlslabel") fi else fs_prop=$($ZFS inherit 2>&1 | \ $AWK '$2=="YES" && $3=="YES" {print $1}'| $EGREP -v "devices|mlslabel|sharenfs|sharesmb|zoned") fi $ECHO $fs_prop } # # Output inherited properties for volume # function vol_inherit_prop { $ECHO "checksum readonly" } # # Get the destination dataset to compare # function get_dst_ds { typeset srcfs=$1 typeset dstfs=$2 # # If the srcfs is not pool # if ! $ZPOOL list $srcfs > /dev/null 2>&1 ; then eval dstfs="$dstfs/${srcfs#*/}" fi $ECHO $dstfs } # # Make test files # # $1 Number of files to create # $2 Maximum file size # $3 File ID offset # $4 File system to create the files on # function mk_files { nfiles=$1 maxsize=$2 file_id_offset=$3 fs=$4 for ((i=0; i<$nfiles; i=i+1)); do $DD if=/dev/urandom \ of=/$fs/file-$maxsize-$((i+$file_id_offset)) \ bs=$(($RANDOM * $RANDOM % $maxsize)) \ count=1 >/dev/null 2>&1 || log_fail \ "Failed to create /$fs/file-$maxsize-$((i+$file_id_offset))" done $ECHO Created $nfiles files of random sizes up to $maxsize bytes } # # Remove test files # # $1 Number of files to remove # $2 Maximum file size # $3 File ID offset # $4 File system to remove the files from # function rm_files { nfiles=$1 maxsize=$2 file_id_offset=$3 fs=$4 for ((i=0; i<$nfiles; i=i+1)); do $RM -f /$fs/file-$maxsize-$((i+$file_id_offset)) done $ECHO Removed $nfiles files of random sizes up to $maxsize bytes } # # Mess up file contents # # $1 The file path # function mess_file { file=$1 filesize=$($STAT -c '%s' $file) offset=$(($RANDOM * $RANDOM % $filesize)) if (($RANDOM % 7 <= 1)); then # # We corrupt 2 bytes to minimize the chance that we # write the same value that's already there. # log_must eval "$DD if=/dev/random of=$file conv=notrunc " \ "bs=1 count=2 oseek=$offset >/dev/null 2>&1" else log_must $TRUNCATE -s $offset $file fi } # # Diff the send/receive filesystems # # $1 The sent filesystem # $2 The received filesystem # function file_check { sendfs=$1 recvfs=$2 if [[ -d /$recvfs/.zfs/snapshot/a && -d \ /$sendfs/.zfs/snapshot/a ]]; then $DIFF -r /$recvfs/.zfs/snapshot/a /$sendfs/.zfs/snapshot/a [[ $? -eq 0 ]] || log_fail "Differences found in snap a" fi if [[ -d /$recvfs/.zfs/snapshot/b && -d \ /$sendfs/.zfs/snapshot/b ]]; then $DIFF -r /$recvfs/.zfs/snapshot/b /$sendfs/.zfs/snapshot/b [[ $? -eq 0 ]] || log_fail "Differences found in snap b" fi } # # Resume test helper # # $1 The ZFS send command # $2 The filesystem where the streams are sent # $3 The receive filesystem # function resume_test { sendcmd=$1 streamfs=$2 recvfs=$3 stream_num=1 log_must eval "$sendcmd >/$streamfs/$stream_num" for ((i=0; i<2; i=i+1)); do mess_file /$streamfs/$stream_num log_mustnot $ZFS recv -sv $recvfs /$streamfs/$stream_num" [[ -f /$streamfs/$stream_num ]] || \ log_fail "NO FILE /$streamfs/$stream_num" done log_must $ZFS recv -sv $recvfs /$sendpool/initial.zsend" log_must eval "$ZFS send -v -i @a $sendfs@b " \ ">/$sendpool/incremental.zsend" fi if datasetexists $streamfs; then log_must $ZFS destroy -r $streamfs fi log_must $ZFS create -o compress=lz4 $sendpool/stream }