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