xref: /freebsd/sys/contrib/openzfs/tests/zfs-tests/tests/functional/cli_root/zfs_receive/zfs_receive_010_pos.ksh (revision 61145dc2b94f12f6a47344fb9aac702321880e43)
1#!/bin/ksh -p
2# SPDX-License-Identifier: CDDL-1.0
3#
4# CDDL HEADER START
5#
6# The contents of this file are subject to the terms of the
7# Common Development and Distribution License (the "License").
8# You may not use this file except in compliance with the License.
9#
10# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
11# or https://opensource.org/licenses/CDDL-1.0.
12# See the License for the specific language governing permissions
13# and limitations under the License.
14#
15# When distributing Covered Code, include this CDDL HEADER in each
16# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
17# If applicable, add the following below this CDDL HEADER, with the
18# fields enclosed by brackets "[]" replaced with your own identifying
19# information: Portions Copyright [yyyy] [name of copyright owner]
20#
21# CDDL HEADER END
22#
23
24#
25# Copyright (c) 2015, 2016 by Delphix. All rights reserved.
26#
27
28. $STF_SUITE/include/libtest.shlib
29
30#
31# DESCRIPTION:
32# Test that receiving a full send as a clone works correctly.
33#
34# STRATEGY:
35# 1. Create pool and filesystems.
36# 2. Send filesystem, receive as clone of itself.
37# 3. Verify that nop-write saves space.
38# 4. Send filesystem, receive as clone of other filesystem.
39# 5. Verify that contents are correct.
40# 6. Repeat steps 4 and 5 with filesystems swapped.
41#
42
43verify_runnable "both"
44
45fs=$TESTPOOL/$TESTFS/base/fs
46fs2=$TESTPOOL/$TESTFS/base/fs2
47rfs=$TESTPOOL/$TESTFS/base/rfs
48
49function make_object
50{
51	typeset objnum=$1
52	typeset mntpnt=$2
53	typeset type=$3
54	if [[ $type == "file" ]]; then
55		dd if=/dev/urandom of=${mntpnt}/f$objnum bs=512 count=16
56	elif [[ $type == "hole1" ]]; then
57		dd if=/dev/zero of=${mntpnt}/fh$objnum bs=512 count=5 seek=4 conv=notrunc
58	elif [[ $type == "hole2" ]]; then
59		dd if=/dev/zero of=${mntpnt}/fh$objnum bs=512 count=4 seek=5 conv=notrunc
60	elif [[ $type == "directory" ]]; then
61		mkdir ${mntpnt}/d$objnum
62	elif [[ $type == "missing" ]]; then
63		touch ${mntpnt}/h$objnum
64	fi
65}
66
67function create_pair
68{
69	typeset objnum=$1
70	typeset mntpnt1=$2
71	typeset mntpnt2=$3
72	typeset type1=$4
73	typeset type2=$5
74	make_object $objnum $mntpnt1 $type1
75	make_object $objnum $mntpnt2 $type2
76}
77
78function cleanup
79{
80	zfs destroy -Rf $TESTPOOL/$TESTFS/base
81	rm $TESTDIR/zr010p*
82}
83
84log_assert "zfs receive of full send as clone should work"
85log_onexit cleanup
86log_must zfs create -o checksum=sha256 -o compression=gzip -o recordsize=512 \
87	$TESTPOOL/$TESTFS/base
88
89log_must zfs create $fs
90log_must zfs create $fs2
91mntpnt=$(get_prop mountpoint $fs)
92mntpnt2=$(get_prop mountpoint $fs2)
93
94#
95# Now, we create the two filesystems.  By creating objects with
96# different types and the same object number in each filesystem, we
97# create a situation where, when you receive the full send of each as
98# a clone of the other, we will test to ensure that the code correctly
99# handles receiving all object types onto all other object types.
100#
101
102# Receive a file onto a file (and vice versa).
103create_pair 8 $mntpnt $mntpnt2 "file" "file"
104
105# Receive a file onto a file with holes (and vice versa).
106create_pair 9 $mntpnt $mntpnt2 "file" "hole1"
107
108# Receive a file onto a directory (and vice versa).
109create_pair 10 $mntpnt $mntpnt2 "file" "directory"
110
111# Receive a file onto a missing object (and vice versa).
112create_pair 11 $mntpnt $mntpnt2 "file" "missing"
113
114# Receive a file with holes onto a file with holes (and vice versa).
115create_pair 12 $mntpnt $mntpnt2 "hole1" "hole2"
116
117# Receive a file with holes onto a directory (and vice versa).
118create_pair 13 $mntpnt $mntpnt2 "hole1" "directory"
119
120# Receive a file with holes onto a missing object (and vice versa).
121create_pair 14 $mntpnt $mntpnt2 "hole1" "missing"
122
123# Receive a directory onto a directory (and vice versa).
124create_pair 15 $mntpnt $mntpnt2 "directory" "directory"
125
126# Receive a directory onto a missing object (and vice versa).
127create_pair 16 $mntpnt $mntpnt2 "directory" "missing"
128
129# Receive a missing object onto a missing object (and vice versa).
130create_pair 17 $mntpnt $mntpnt2 "missing" "missing"
131
132# Receive a file with a different record size onto a file (and vice versa).
133log_must zfs set recordsize=128k $fs
134dd if=/dev/urandom of=$mntpnt/f18 bs=128k count=64
135touch $mntpnt2/f18
136
137# Remove objects that are intended to be missing.
138rm $mntpnt/h17 $mntpnt2/h*
139
140# Add empty objects to $fs to exercise dmu_traverse code
141for i in {1..100}; do
142	log_must touch $mntpnt/uf$i
143done
144
145log_must zfs snapshot $fs@s1
146log_must zfs snapshot $fs2@s1
147
148log_must eval "zfs send $fs@s1 > $TESTDIR/zr010p"
149log_must eval "zfs send $fs2@s1 > $TESTDIR/zr010p2"
150
151
152#
153# Test that, when we receive a full send as a clone of itself,
154# nop-write saves us all the space used by data blocks.
155#
156log_must eval "zfs receive -o origin=$fs@s1 $rfs < $TESTDIR/zr010p"
157size=$(get_prop used $rfs)
158size2=$(get_prop used $fs)
159if [[ $size -ge $(($size2 / 10)) ]] then
160        log_fail "nop-write failure; expected usage less than "\
161		"$(($size2 / 10)), but is using $size"
162fi
163log_must zfs destroy -fr $rfs
164
165# Correctness testing: receive each full send as a clone of the other fiesystem.
166log_must eval "zfs receive -o origin=$fs2@s1 $rfs < $TESTDIR/zr010p"
167mntpnt_old=$(get_prop mountpoint $fs)
168mntpnt_new=$(get_prop mountpoint $rfs)
169log_must directory_diff $mntpnt_old $mntpnt_new
170log_must zfs destroy -r $rfs
171
172log_must eval "zfs receive -o origin=$fs@s1 $rfs < $TESTDIR/zr010p2"
173mntpnt_old=$(get_prop mountpoint $fs2)
174mntpnt_new=$(get_prop mountpoint $rfs)
175log_must directory_diff $mntpnt_old $mntpnt_new
176
177log_pass "zfs receive of full send as clone works"
178