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