1# !/bin/ksh
2#
3# This file and its contents are supplied under the terms of the
4# Common Development and Distribution License ("CDDL"), version 1.0.
5# You may only use this file in accordance with the terms of version
6# 1.0 of the CDDL.
7#
8# A full copy of the text of the CDDL should have accompanied this
9# source.  A copy of the CDDL is also available via the Internet at
10# http://www.illumos.org/license/CDDL.
11#
12
13#
14# Copyright (c) 2012 by Delphix. All rights reserved.
15#
16
17#
18# DESCRIPTION
19# Verify that "zfs list" gives correct values for written and written@
20# proerties for the dataset when different operations are on done on it
21#
22#
23# STRATEGY
24# 1) Create recursive datasets
25# 2) Take snapshots, write data and verify  written/ written@ properties for
26#    following cases
27#    a) Delete data
28#    b) Write Data
29#    c) Clone
30#    d) Delete snapshot
31#    e) Recursive datasets
32
33. $STF_SUITE/include/libtest.shlib
34. $STF_SUITE/include/math.shlib
35
36function cleanup
37{
38	for ds in $datasets; do
39		datasetexists $ds && log_must $ZFS destroy -R $TESTPOOL/$TESTFS1
40	done
41}
42function get_prop_mb
43{
44	typeset prop=$1
45	typeset dataset=$2
46	typeset -l value=$(get_prop $prop $dataset)
47	((value = value / mb_block))
48	$ECHO $value
49}
50
51datasets="$TESTPOOL/$TESTFS1 $TESTPOOL/$TESTFS1/$TESTFS2 \
52    $TESTPOOL/$TESTFS1/$TESTFS2/$TESTFS3"
53
54log_assert "verify zfs written and written@ property"
55log_onexit cleanup
56
57typeset -l i=1
58typeset -l blocks=50
59typeset -l expected_written=0
60typeset -l expected_writtenat=0
61typeset -l written=0
62typeset -l total=0
63typeset -l snap1_size=0
64typeset -l snap2_size=0
65typeset -l snap3_size=0
66typeset -l metadata=0
67typeset -l mb_block=0
68((mb_block = 1024 * 1024))
69# approximate metadata on dataset when empty is 32KB
70((metadata = 32 * 1024))
71
72log_note "verify written property statistics for dataset"
73log_must $ZFS create -p $TESTPOOL/$TESTFS1/$TESTFS2/$TESTFS3
74for i in 1 2 3; do
75	log_must $ZFS snapshot $TESTPOOL/$TESTFS1@snap$i
76	log_must $DD if=/dev/urandom of=/$TESTPOOL/$TESTFS1/testfile.$i bs=1M \
77	    count=$blocks
78	log_must $SYNC
79	written=$(get_prop written $TESTPOOL/$TESTFS1)
80	((expected_written=blocks * mb_block))
81	within_percent $written $expected_written 99.5 || \
82	    log_fail "Unexpected written value $written $expected_written"
83	((total = total + blocks))
84	((blocks = blocks + 50))
85done
86
87log_note "verify written property statistics for snapshots"
88blocks=0
89for i in 1 2 3; do
90	written=$(get_prop written $TESTPOOL/$TESTFS1@snap$i)
91	if [[ $blocks -eq 0 ]]; then
92		expected_written=$metadata
93	else
94		((expected_written = blocks * mb_block))
95	fi
96	within_percent $written $expected_written 99.5 || \
97	    log_fail "Unexpected written value $written $expected_written $i"
98	((blocks = blocks + 50))
99done
100
101snap1_size=$total
102((snap2_size = total-50))
103((snap3_size = total-100))
104
105log_note "verify written@ for the same dataset"
106blocks=50
107for i in 1 2 3; do
108	writtenat=$(get_prop written@snap$i $TESTPOOL/$TESTFS1)
109	((expected_writtenat = total * mb_block))
110	within_percent $writtenat $expected_writtenat 99.5 || \
111	    log_fail "Unexpected written@ value"
112	((total = total - blocks))
113	((blocks = blocks + 50))
114done
115log_note "delete data"
116before_written=$(get_prop written $TESTPOOL/$TESTFS1)
117log_must $RM /$TESTPOOL/$TESTFS1/testfile.3
118snap3_size=0
119log_must $SYNC
120written=$(get_prop written $TESTPOOL/$TESTFS1)
121writtenat3=$(get_prop written@snap3 $TESTPOOL/$TESTFS1)
122[[ $written -eq $writtenat3 ]] || \
123    log_fail "Written and written@ dont match $written $writtenat3"
124within_percent $written $before_written 0.1 && \
125    log_fail "Unexpected written value after delete $written $before_written"
126writtenat=$(get_prop written@snap1 $TESTPOOL/$TESTFS1)
127((snap1_size = snap1_size - 150))
128((expected_writtenat = snap1_size * mb_block))
129within_percent $writtenat $expected_writtenat 99.5 || \
130    log_fail "Unexpected written value after delete $writtenat $expected_writtenat"
131writtenat=$(get_prop written@snap2 $TESTPOOL/$TESTFS1)
132((snap2_size = snap2_size - 150))
133((expected_writtenat = snap2_size * mb_block))
134within_percent $writtenat $expected_writtenat 99.5 || \
135    log_fail "Unexpected written value after delete"
136
137log_note "write data"
138blocks=20
139log_must $DD if=/dev/urandom of=/$TESTPOOL/$TESTFS1/testfile.3 bs=1M \
140    count=$blocks
141log_must $SYNC
142written=$(get_prop written $TESTPOOL/$TESTFS1)
143writtenat1=$(get_prop written@snap1 $TESTPOOL/$TESTFS1)
144writtenat2=$(get_prop written@snap2 $TESTPOOL/$TESTFS1)
145writtenat3=$(get_prop written@snap3 $TESTPOOL/$TESTFS1)
146((snap3_size = snap3_size + blocks))
147((expected_writtenat = snap3_size * mb_block))
148[[ $written -eq $writtenat3 ]] || \
149    log_fail "Unexpected_written value"
150within_percent $writtenat3 $expected_writtenat 99.5 || \
151    log_fail "Unexpected_written@ value for snap3"
152((snap2_size = snap2_size + blocks))
153((expected_writtenat = snap2_size * mb_block))
154within_percent $writtenat2 $expected_writtenat 99.5 || \
155    log_fail "Unexpected_written@ value for snap2"
156((snap1_size = snap1_size + blocks))
157((expected_writtenat = snap1_size * mb_block))
158within_percent $writtenat1 $expected_writtenat 99.5 || \
159    log_fail "Unexpected_written@ value for snap1"
160
161log_note "write data to a clone"
162before_clone=$(get_prop written $TESTPOOL/$TESTFS1)
163log_must $ZFS clone $TESTPOOL/$TESTFS1@snap1 $TESTPOOL/$TESTFS1/snap1.clone
164log_must $DD if=/dev/urandom of=/$TESTPOOL/$TESTFS1/snap1.clone/testfile bs=1M \
165    count=40
166after_clone=$(get_prop written $TESTPOOL/$TESTFS1)
167[[ $before_clone -eq $after_clone ]] || \
168    log_fail "unexpected written for clone $before_clone $after_clone"
169
170log_note "deleted snapshot"
171typeset -l before_written1=$(get_prop_mb written@snap1 $TESTPOOL/$TESTFS1)
172typeset -l before_written3=$(get_prop_mb written@snap3 $TESTPOOL/$TESTFS1)
173typeset -l snap_before_written2=$(get_prop_mb written $TESTPOOL/$TESTFS1@snap2)
174typeset -l snap_before_written3=$(get_prop_mb written $TESTPOOL/$TESTFS1@snap3)
175log_must $ZFS destroy $TESTPOOL/$TESTFS1@snap2
176log_mustnot snapexists $TESTPOOL/$TESTFS1@snap2
177log_must $SYNC
178written1=$(get_prop_mb written@snap1 $TESTPOOL/$TESTFS1)
179written3=$(get_prop_mb written@snap3 $TESTPOOL/$TESTFS1)
180[[ $before_written1 -eq $written1 && $before_written3 -eq $written3 ]] || \
181    log_fail "unexpected written values $before_written1 $written1"
182typeset -l expected_written3
183((expected_written3 = snap_before_written2 + snap_before_written3))
184prev_written=$(get_prop_mb written $TESTPOOL/$TESTFS1@snap3)
185within_percent $prev_written $expected_written3 99.5 || \
186    log_fail "unexpected written value $prev_written $expected_written3"
187
188log_must $ZFS destroy $TESTPOOL/$TESTFS1@snap3
189log_mustnot snapexists $TESTPOOL/$TESTFS1@snap3
190written=$(get_prop written $TESTPOOL/$TESTFS1)
191writtenat1=$(get_prop written@snap1 $TESTPOOL/$TESTFS1)
192[[ $written -ne $writtenat1 ]] && \
193    log_fail "Unexpected last snapshot written value"
194
195log_note "verify written@ property for recursive datasets"
196blocks=10
197log_must $ZFS snapshot -r $TESTPOOL/$TESTFS1@now
198for ds in $datasets; do
199	writtenat=$(get_prop written@now $ds)
200	[[ $writtenat -ne 0 ]] && \
201	    log_fail "Unexpected written@ value"
202	log_must $DD if=/dev/urandom of=/$ds/testfile bs=1M count=$blocks
203	log_must $SYNC
204	writtenat=$(get_prop written@now $ds)
205	((expected_writtenat = blocks * mb_block))
206	within_percent $writtenat $expected_writtenat 0.1 || \
207	    log_fail "Unexpected written value"
208	((blocks = blocks + 10))
209done
210
211log_note "verify written@ output for recursive datasets"
212blocks=20
213for ds in $datasets; do
214	log_must $ZFS snapshot $ds@current
215	log_must $DD if=/dev/urandom of=/$ds/testfile bs=1M \
216	    count=$blocks
217	log_must $SYNC
218done
219recursive_output=$($ZFS get -r written@current $TESTPOOL | \
220    $GREP -v $TESTFS1@ | $GREP -v $TESTFS2@ | $GREP -v $TESTFS3@ | \
221    $GREP -v "VALUE" | $GREP -v "-")
222expected="20.0M"
223for ds in $datasets; do
224	writtenat=$($ECHO "$recursive_output" | $GREP -v $ds/)
225	writtenat=$($ECHO "$writtenat" | $GREP $ds | $AWK '{print $3}')
226	[[ $writtenat == $expected ]] || \
227	    log_fail "recursive written property output mismatch"
228done
229
230log_pass "zfs written and written@ property fields print correct values"
231