1#!/bin/ksh -p
2
3#
4# This file and its contents are supplied under the terms of the
5# Common Development and Distribution License ("CDDL"), version 1.0.
6# You may only use this file in accordance with the terms of version
7# 1.0 of the CDDL.
8#
9# A full copy of the text of the CDDL should have accompanied this
10# source.  A copy of the CDDL is also available via the Internet at
11# http://www.illumos.org/license/CDDL.
12#
13
14#
15# Copyright (c) 2015 by Delphix. All rights reserved.
16#
17
18. $STF_SUITE/tests/functional/rsend/rsend.kshlib
19
20#
21# Description:
22# Verify compressed send works correctly with datasets of varying recsize.
23#
24# Strategy:
25# 1. Check the recv behavior (into pools with features enabled and disabled)
26#    of all combinations of -c -p and -L. Verify the stream is compressed,
27#    and that the recsize property and that of a received file is correct
28#    according to this matrix:
29#
30# +---------+--------+------------+------------+-----------+-----------+
31# | send    | send   | received   | received   | received  | received  |
32# | stream  | stream | file bs    | prop       | file bs   | props     |
33# | recsize | flags  | (disabled) | (disabled) | (enabled) | (enabled) |
34# +---------+--------+------------+------------+-----------+-----------+
35# |    128k |        |       128k |       128k |      128k |      128k |
36# |    128k |     -c |      Fails |      Fails |      128k |      128k |
37# |    128k |     -p |       128k |       128k |      128k |      128k |
38# |    128k |     -L |       128k |       128k |      128k |      128k |
39# |    128k |    -cp |      Fails |      Fails |      128k |      128k |
40# |    128k |    -cL |      Fails |      Fails |      128k |      128k |
41# |    128k |    -pL |       128k |       128k |      128k |      128k |
42# |    128k |   -cpL |      Fails |      Fails |      128k |      128k |
43# |      1m |        |      Fails |      Fails |      128k |      128k |
44# |      1m |     -c |      Fails |      Fails |      128k |      128k |
45# |      1m |     -p |       128k |       128k |      128k |        1m |
46# |      1m |     -L |      Fails |      Fails |        1m |      128k |
47# |      1m |    -cp |      Fails |      Fails |      128k |        1m |
48# |      1m |    -cL |      Fails |      Fails |        1m |      128k |
49# |      1m |    -pL |      Fails |      Fails |        1m |        1m |
50# |      1m |   -cpL |      Fails |      Fails |        1m |        1m |
51# +---------+--------+------------+------------+-----------+-----------+
52#
53
54verify_runnable "both"
55
56function cleanup
57{
58	datasetexists $TESTPOOL/128k && destroy_dataset $TESTPOOL/128k
59	datasetexists $TESTPOOL/1m && destroy_dataset $TESTPOOL/1m
60	cleanup_pool $POOL2
61	destroy_pool $POOL3
62}
63
64# For a received stream, verify the recsize (prop and file) match expectations.
65function check_recsize
66{
67	typeset recv_ds=$1
68	typeset expected_file_bs=$2
69	typeset expected_recsize=$3
70	typeset file="$(get_prop mountpoint $recv_ds)/testfile"
71
72	[[ -f $file ]] || log_fail "file '$file' doesn't exist"
73
74	typeset read_recsize=$(get_prop recsize $recv_ds)
75	if is_freebsd; then
76		typeset read_file_bs=$(stat -f "%k" $file)
77	else
78		typeset read_file_bs=$(stat $file | sed -n \
79		    's/.*IO Block: \([0-9]*\).*/\1/p')
80	fi
81
82	[[ $read_recsize = $expected_recsize ]] || log_fail \
83	    "read_recsize: $read_recsize expected_recsize: $expected_recsize"
84	[[ $read_file_bs = $expected_file_bs ]] || log_fail \
85	    "read_file_bs: $read_file_bs expected_file_bs: $expected_file_bs"
86}
87
88#
89# This function does a zfs send and receive according to the parameters
90# below, and verifies the data shown in the strategy section.
91#
92# -[cpL] flags to pass through to 'zfs send'
93# -d Receive into a pool with all features disabled
94#
95# $1 The recordsize of the send dataset
96# $2 Whether or not the recv should work.
97# $3 The blocksize expected in a received file (default 128k)
98# $4 The recordsize property expected in a received dataset (default 128k)
99#
100function check
101{
102	typeset recv_pool=$POOL2
103	typeset flags='-'
104
105	while getopts "cdpL" opt; do
106		case $opt in
107		c)
108			flags+='c'
109			;;
110		d)
111			recv_pool=$POOL3
112			;;
113		p)
114			flags+='p'
115			;;
116		L)
117			flags+='L'
118			;;
119		esac
120	done
121	shift $(($OPTIND - 1))
122	[[ ${#flags} -eq 1 ]] && flags=''
123
124	typeset recsize=$1
125	typeset verify=$2
126	typeset expected_file_bs=${3-131072}
127	typeset expected_recsize=${4-131072}
128	typeset send_ds=$TESTPOOL/$recsize
129	typeset send_snap=$send_ds@snap
130	typeset recv_ds=$recv_pool/$recsize
131	typeset stream=$BACKDIR/stream.out
132
133	datasetexists $send_ds || log_fail "send ds: $send_ds doesn't exist"
134	[[ -f $stream ]] && log_must rm $stream
135	log_must eval "zfs send $flags $send_snap >$stream"
136	$verify eval "zfs recv $recv_ds <$stream"
137	typeset stream_size=$(zstream dump $stream | sed -n \
138	    's/	Total write size = \(.*\) (0x.*)/\1/p')
139
140	#
141	# Special case: For a send dataset with large blocks, don't try to
142	# verify the stream size is correct if the compress flag is present
143	# but the large blocks flag isn't. In these cases, the user data
144	# isn't compressed in the stream (though metadata is) so the
145	# verification would fail.
146	#
147	typeset do_size_test=true
148	[[ $recsize = $large && $flags =~ 'c' && ! $flags =~ 'L' ]] && \
149	    do_size_test=false
150
151	$do_size_test && verify_stream_size $stream $send_ds
152
153	if [[ $verify = "log_mustnot" ]]; then
154		datasetnonexists $recv_ds || log_fail "$recv_ds shouldn't exist"
155		return
156	fi
157
158	check_recsize $recv_ds $expected_file_bs $expected_recsize
159	$do_size_test && verify_stream_size $stream $recv_ds
160	log_must_busy zfs destroy -r $recv_ds
161}
162
163log_assert "Verify compressed send works with datasets of varying recsize."
164log_onexit cleanup
165typeset recsize opts dir
166typeset small=$((128 * 1024))
167typeset large=$((1024 * 1024))
168
169# Create POOL3 with features disabled and datasets to create test send streams
170datasetexists $POOL3 && log_must zpool destroy $POOL3
171log_must zpool create -d $POOL3 $DISK3
172write_compressible $BACKDIR 32m
173for recsize in $small $large; do
174	log_must zfs create -o compress=gzip -o recsize=$recsize \
175	    $TESTPOOL/$recsize
176	dir=$(get_prop mountpoint $TESTPOOL/$recsize)
177	log_must cp $BACKDIR/file.0 $dir/testfile
178	log_must zfs snapshot $TESTPOOL/$recsize@snap
179done
180
181# Run tests for send streams without large blocks
182for opts in '' -d -c -p -dp -L -dL -cp -cL -pL -dpL -cpL; do
183	check $opts $small log_must
184done
185for opts in -dc -dcp -dcL -dcpL; do
186	check $opts $small log_mustnot
187done
188
189# Run tests for send streams with large blocks
190for opts in '' -d -dp -c; do
191	check $opts $large log_must
192done
193for opts in -dc -dL -dcp -dcL -dpL -dcpL; do
194	check $opts $large log_mustnot
195done
196check -p $large log_must $small $large
197check -L $large log_must $large $small
198check -cp $large log_must $small $large
199check -cL $large log_must $large $small
200check -pL $large log_must $large $large
201check -cpL $large log_must $large $large
202
203log_pass "Compressed send works with datasets of varying recsize."
204