1#!/bin/ksh
2
3#
4# This file and its contents are supplied under the terms of the
5# Common Development and Distribution License ("CDDL"), version 1.0.
6# You may only use this file in accordance with the terms of version
7# 1.0 of the CDDL.
8#
9# A full copy of the text of the CDDL should have accompanied this
10# source.  A copy of the CDDL is also available via the Internet at
11# http://www.illumos.org/license/CDDL.
12#
13
14#
15# Copyright (c) 2018 by Delphix. All rights reserved.
16#
17
18. $STF_SUITE/tests/functional/redacted_send/redacted.kshlib
19
20#
21# Description:
22# Verify redacted send streams reliably handle holes.
23#
24# Strategy:
25# 1. Holes written at the beginning and end of a non-sparse file in the
26#    redacted list are correctly redacted.
27# 2. Holes written throughout a non-sparse file in the redacted list are
28#    correctly redacted.
29# 3. Data written into a hole in a sparse file in the redacted list are
30#    correctly redacted.
31# 4. Holes in metadata blocks.
32#
33
34typeset ds_name="holes"
35typeset sendfs="$POOL/$ds_name"
36typeset recvfs="$POOL2/$ds_name"
37typeset clone="$POOL/${ds_name}_clone"
38typeset tmpdir="$(get_prop mountpoint $POOL)/tmp"
39typeset stream=$(mktemp $tmpdir/stream.XXXX)
40setup_dataset $ds_name '' setup_holes
41typeset clone_mnt="$(get_prop mountpoint $clone)"
42typeset send_mnt="$(get_prop mountpoint $sendfs)"
43typeset recv_mnt="/$POOL2/$ds_name"
44typeset M=$((1024 * 1024))
45
46log_onexit redacted_cleanup $sendfs $recvfs
47
48# Write holes at the start and end of a non-sparse file.
49if is_illumos; then
50	log_must mkholes -h 0:$M -h $((7 * M)):$M $clone_mnt/f1
51else
52	log_must dd if=/dev/zero of=$clone_mnt/f1 bs=1M count=1 conv=notrunc
53	log_must dd if=/dev/zero of=$clone_mnt/f1 bs=1M count=1 conv=notrunc seek=7
54fi
55log_must zfs snapshot $clone@snap1
56log_must zfs redact $sendfs@snap book1 $clone@snap1
57log_must eval "zfs send --redact book1 $sendfs@snap >$stream"
58log_must eval "zfs recv $recvfs <$stream"
59compare_files $sendfs $recvfs "f1" "$RANGE5"
60log_must zfs rollback -R $clone@snap
61log_must zfs destroy -R $recvfs
62
63# Write two overlapping sets of holes into the same non-sparse file.
64log_must stride_dd -i /dev/zero -o $clone_mnt/f1 -b $((128 * 1024)) -c 8 -s 2 -k 3
65log_must stride_dd -i /dev/zero -o $clone_mnt/f1 -b $((256 * 1024)) -c 8 -s 2 -k 6
66log_must zfs snapshot $clone@snap1
67log_must zfs redact $sendfs@snap book2 $clone@snap1
68log_must eval "zfs send --redact book2 $sendfs@snap >$stream"
69log_must eval "zfs recv $recvfs <$stream"
70compare_files $sendfs $recvfs "f1" "$RANGE6"
71log_must zfs rollback -R $clone@snap
72log_must zfs destroy -R $recvfs
73
74# Write data into the middle of a hole.
75if is_illumos; then
76	log_must mkholes -d $((3 * M)):$((2 * M)) $clone_mnt/f2
77else
78	log_must dd if=/dev/urandom of=$clone_mnt/f2 bs=1M count=2 seek=3 \
79	    conv=notrunc
80fi
81log_must zfs snapshot $clone@snap1
82log_must zfs redact $sendfs@snap book3 $clone@snap1
83log_must eval "zfs send --redact book3 $sendfs@snap >$stream"
84log_must eval "zfs recv $recvfs <$stream"
85compare_files $sendfs $recvfs "f2" "$RANGE14"
86log_must zfs rollback -R $clone@snap
87log_must zfs destroy -R $recvfs
88
89# Remove a file with holes.
90log_must rm $clone_mnt/f3
91log_must zfs snapshot $clone@snap1
92log_must zfs redact $sendfs@snap book4 $clone@snap1
93log_must eval "zfs send --redact book4 $sendfs@snap >$stream"
94log_must eval "zfs recv $recvfs <$stream"
95compare_files $sendfs $recvfs "f3" "$RANGE7"
96log_must zfs rollback -R $clone@snap
97log_must zfs destroy -R $recvfs
98
99# Create a hole in a L0 metadata block by removing files.
100log_must rm $send_mnt/manyrm_clone/f{32..96}
101log_must zfs snapshot $sendfs/manyrm_clone@snap1
102
103log_must zfs redact $sendfs/manyrm@snap book6 $sendfs/manyrm_clone@snap1
104log_must eval "zfs send --redact book6 $sendfs/manyrm@snap >$stream"
105log_must eval "zfs recv $recvfs <$stream"
106log_must mount_redacted -f $recvfs
107for i in {1..31} {97..256}; do
108	diff $send_mnt/manyrm/f$i $recv_mnt/f$i || log_fail \
109	    "File f$i did not match in the send and recv datasets."
110done
111for i in {32..96}; do
112	file_size=$(stat_size $send_mnt/manyrm/f$i)
113	redacted_size=$(stat_size $recv_mnt/f$i)
114	[[ $file_size -eq $redacted_size ]] || log_fail \
115	    "File f$i has size $file_size and redacted size $redacted_size"
116done
117log_must zfs rollback -R $clone@snap
118log_must zfs destroy -R $recvfs
119
120log_pass "Redacted send streams reliably handle holes."
121