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 https://opensource.org/licenses/CDDL-1.0. 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 typeset objnum=$1 51 typeset mntpnt=$2 52 typeset 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/zero of=${mntpnt}/fh$objnum bs=512 count=5 seek=4 conv=notrunc 57 elif [[ $type == "hole2" ]]; then 58 dd if=/dev/zero of=${mntpnt}/fh$objnum bs=512 count=4 seek=5 conv=notrunc 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 typeset objnum=$1 69 typeset mntpnt1=$2 70 typeset mntpnt2=$3 71 typeset type1=$4 72 typeset 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 $TESTDIR/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 $mntpnt2/h* 138 139# Add empty objects to $fs to exercise dmu_traverse code 140for i in {1..100}; do 141 log_must touch $mntpnt/uf$i 142done 143 144log_must zfs snapshot $fs@s1 145log_must zfs snapshot $fs2@s1 146 147log_must eval "zfs send $fs@s1 > $TESTDIR/zr010p" 148log_must eval "zfs send $fs2@s1 > $TESTDIR/zr010p2" 149 150 151# 152# Test that, when we receive a full send as a clone of itself, 153# nop-write saves us all the space used by data blocks. 154# 155log_must eval "zfs receive -o origin=$fs@s1 $rfs < $TESTDIR/zr010p" 156size=$(get_prop used $rfs) 157size2=$(get_prop used $fs) 158if [[ $size -ge $(($size2 / 10)) ]] then 159 log_fail "nop-write failure; expected usage less than "\ 160 "$(($size2 / 10)), but is using $size" 161fi 162log_must zfs destroy -fr $rfs 163 164# Correctness testing: receive each full send as a clone of the other fiesystem. 165log_must eval "zfs receive -o origin=$fs2@s1 $rfs < $TESTDIR/zr010p" 166mntpnt_old=$(get_prop mountpoint $fs) 167mntpnt_new=$(get_prop mountpoint $rfs) 168log_must directory_diff $mntpnt_old $mntpnt_new 169log_must zfs destroy -r $rfs 170 171log_must eval "zfs receive -o origin=$fs@s1 $rfs < $TESTDIR/zr010p2" 172mntpnt_old=$(get_prop mountpoint $fs2) 173mntpnt_new=$(get_prop mountpoint $rfs) 174log_must directory_diff $mntpnt_old $mntpnt_new 175 176log_pass "zfs receive of full send as clone works" 177