1#!/bin/ksh -p
2#
3# CDDL HEADER START
4#
5# This file and its contents are supplied under the terms of the
6# Common Development and Distribution License ("CDDL"), version 1.0.
7# You may only use this file in accordance with the terms of version
8# 1.0 of the CDDL.
9#
10# A full copy of the text of the CDDL should have accompanied this
11# source.  A copy of the CDDL is also available via the Internet at
12# http://www.illumos.org/license/CDDL.
13#
14# CDDL HEADER END
15#
16
17#
18# Copyright (c) 2012, 2016 by Delphix. All rights reserved.
19# Copyright (c) 2018 Datto, Inc. All rights reserved.
20#
21
22. $STF_SUITE/tests/functional/rsend/rsend.kshlib
23. $STF_SUITE/tests/functional/cli_root/cli_common.kshlib
24
25#
26# DESCRIPTION:
27#	Verify 'zfs send' can send dataset holds.
28#	Verify 'zfs receive' can receive dataset holds.
29#
30# STRATEGY:
31#	1. Create a snapshot.
32#	2. Create a full send stream with the fs, including holds.
33#	3. Receive the send stream and verify the data integrity.
34#	4. Fill in fs with some new data.
35#	5. Create an incremental send stream with the fs, including holds.
36#	6. Receive the incremental send stream and verify the data integrity.
37#	7. Verify the holds have been received as expected.
38#	8. Create an incremental snap with no holds, and send that with -h.
39#	9. Confirm the snapshot was received as expected.
40#	10. Create an incremental snapshot and place a hold on it.
41#	11. Receive the incremental stream with -h and verify holds skipped.
42#
43
44verify_runnable "both"
45
46function cleanup
47{
48	eval "zfs holds $init_snap |grep -q hold1-1" &&
49	    log_must zfs release hold1-1 $init_snap
50	eval "zfs holds $init_snap |grep -q hold1-2" &&
51	    log_must zfs release hold1-2 $init_snap
52	eval "zfs holds $recv_snap |grep -q hold1-1" &&
53	    log_must zfs release hold1-1 $recv_snap
54	eval "zfs holds $recv_snap |grep -q hold1-2" &&
55	    log_must zfs release hold1-2 $recv_snap
56	eval "zfs holds $inc_snap |grep -q hold2-1" &&
57	    log_must zfs release hold2-1 $inc_snap
58	eval "zfs holds $recv_inc_snap |grep -q hold2-1" &&
59	    log_must zfs release hold2-1 $recv_inc_snap
60	eval "zfs holds $inc_snap3 |grep -q hold3-1" &&
61	    log_must zfs release hold3-1 $inc_snap3
62
63	# destroy datasets
64	datasetexists $recv_root/$TESTFS1 &&
65	    log_must destroy_dataset "$recv_root/$TESTFS1" "-Rf"
66	datasetexists $recv_root && log_must destroy_dataset "$recv_root" "-Rf"
67	datasetexists $TESTPOOL/$TESTFS1 && log_must destroy_dataset "$TESTPOOL/$TESTFS1" "-Rf"
68
69	[[ -e $full_bkup ]] && log_must rm -f $full_bkup
70	[[ -e $inc_bkup ]] && log_must rm -f $inc_bkup
71	[[ -e $inc_data2 ]] && log_must rm -f $inc_data2
72	[[ -d $TESTDIR1 ]] && log_must rm -rf $TESTDIR1
73
74}
75
76#
77# Check if hold exists on the specified dataset.
78#
79function check_hold #<snapshot> <hold>
80{
81	typeset dataset=$1
82	typeset hold=$2
83
84	log_note "checking $dataset for $hold"
85	eval "zfs holds $dataset |grep -q $hold"
86}
87
88log_assert "Verify 'zfs send/recv' can send and receive dataset holds."
89log_onexit cleanup
90
91init_snap=$TESTPOOL/$TESTFS1@init_snap
92inc_snap=$TESTPOOL/$TESTFS1@inc_snap
93inc_snap2=$TESTPOOL/$TESTFS1@inc_snap2
94inc_snap3=$TESTPOOL/$TESTFS1@inc_snap3
95full_bkup=$TEST_BASE_DIR/fullbkup.$$
96inc_bkup=$TEST_BASE_DIR/incbkup.$$
97init_data=$TESTDIR/$TESTFILE1
98inc_data=$TESTDIR/$TESTFILE2
99inc_data2=$TESTDIR/testfile3
100recv_root=$TESTPOOL/rst_ctr
101recv_snap=$recv_root/$TESTFS1@init_snap
102recv_inc_snap=$recv_root/$TESTFS1@inc_snap
103recv_inc_snap2=$recv_root/$TESTFS1@inc_snap2
104recv_inc_snap3=$recv_root/$TESTFS1@inc_snap3
105recv_data=$TESTDIR1/$TESTFS1/$TESTFILE1
106recv_inc_data=$TESTDIR1/$TESTFS1/$TESTFILE2
107recv_inc_data2=$TESTDIR1/$TESTFS1/testfile3
108
109log_note "Verify 'zfs send' can create full send stream."
110
111# Preparation
112if ! datasetexists $TESTPOOL/$TESTFS1; then
113	log_must zfs create $TESTPOOL/$TESTFS1
114fi
115[[ -e $init_data ]] && log_must rm -f $init_data
116log_must zfs create $recv_root
117[[ ! -d $TESTDIR1 ]] && log_must mkdir -p $TESTDIR1
118[[ ! -d $TESTDIR ]] && log_must mkdir -p $TESTDIR
119log_must zfs set mountpoint=$TESTDIR $TESTPOOL/$TESTFS1
120log_must zfs set mountpoint=$TESTDIR1 $recv_root
121
122file_write -o create -f $init_data -b $BLOCK_SIZE -c $WRITE_COUNT
123
124log_must zfs snapshot $init_snap
125log_must zfs hold hold1-1 $init_snap
126log_must zfs hold hold1-2 $init_snap
127log_must eval "zfs send -h $init_snap > $full_bkup"
128
129log_note "Verify the send stream is valid to receive."
130
131log_must zfs recv -F $recv_snap <$full_bkup
132log_must datasetexists $recv_snap
133receive_check $recv_snap ${recv_snap%%@*}
134
135log_note "Verify the holds were received."
136log_must check_hold $recv_snap hold1-1
137log_must check_hold $recv_snap hold1-2
138compare_cksum $init_data $recv_data
139
140log_note "Verify 'zfs send -i' can create incremental send stream."
141
142file_write -o create -f $inc_data -b $BLOCK_SIZE -c $WRITE_COUNT -d 0
143
144log_must zfs snapshot $inc_snap
145log_must zfs hold hold2-1 $inc_snap
146log_must eval "zfs send -h -i $init_snap $inc_snap > $inc_bkup"
147
148log_note "Verify the incremental send stream is valid to receive."
149
150log_must zfs recv -F $recv_inc_snap <$inc_bkup
151log_must datasetexists $recv_inc_snap
152log_note "Verify the hold was received from the incremental send."
153
154log_must check_hold $recv_inc_snap hold2-1
155
156compare_cksum $inc_data $recv_inc_data
157
158log_note "Verify send -h works when there are no holds."
159file_write -o create -f $inc_data2 -b $BLOCK_SIZE -c $WRITE_COUNT -d 0
160log_must zfs snapshot $inc_snap2
161log_must eval "zfs send -h -i $inc_snap $inc_snap2 > $inc_bkup"
162log_must zfs recv -F $recv_inc_snap2 <$inc_bkup
163log_must datasetexists $recv_inc_snap2
164compare_cksum $inc_data2 $recv_inc_data2
165
166log_note "Verify send -h fails properly when receive dataset already exists"
167log_must zfs recv -F $recv_inc_snap2 <$inc_bkup
168
169log_note "Verify recv -h skips the receive of holds"
170log_must zfs snapshot $inc_snap3
171log_must zfs hold hold3-1 $inc_snap3
172log_must eval "zfs send -h -i $inc_snap2 $inc_snap3 > $inc_bkup"
173log_must zfs recv -F -h $recv_inc_snap3 <$inc_bkup
174log_must datasetexists $recv_inc_snap3
175log_mustnot check_hold $recv_inc_snap3 hold3-1
176
177log_pass "'zfs send/recv' can send and receive dataset holds."
178