]>
Commit | Line | Data |
---|---|---|
6bb24f4d BB |
1 | # |
2 | # CDDL HEADER START | |
3 | # | |
4 | # The contents of this file are subject to the terms of the | |
5 | # Common Development and Distribution License (the "License"). | |
6 | # You may not use this file except in compliance with the License. | |
7 | # | |
8 | # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE | |
9 | # or http://www.opensolaris.org/os/licensing. | |
10 | # See the License for the specific language governing permissions | |
11 | # and limitations under the License. | |
12 | # | |
13 | # When distributing Covered Code, include this CDDL HEADER in each | |
14 | # file and include the License file at usr/src/OPENSOLARIS.LICENSE. | |
15 | # If applicable, add the following below this CDDL HEADER, with the | |
16 | # fields enclosed by brackets "[]" replaced with your own identifying | |
17 | # information: Portions Copyright [yyyy] [name of copyright owner] | |
18 | # | |
19 | # CDDL HEADER END | |
20 | # | |
21 | ||
22 | # | |
23 | # Copyright 2009 Sun Microsystems, Inc. All rights reserved. | |
24 | # Use is subject to license terms. | |
25 | # | |
26 | ||
27 | # | |
c1d9abf9 | 28 | # Copyright (c) 2013, 2016 by Delphix. All rights reserved. |
6bb24f4d BB |
29 | # |
30 | ||
31 | . $STF_SUITE/include/libtest.shlib | |
a7004725 | 32 | . $STF_SUITE/include/math.shlib |
caf9dd20 | 33 | . $STF_SUITE/tests/functional/cli_root/zfs_set/zfs_set_common.kshlib |
6bb24f4d BB |
34 | . $STF_SUITE/tests/functional/rsend/rsend.cfg |
35 | ||
36 | # | |
37 | # Set up test model which includes various datasets | |
38 | # | |
39 | # @final | |
40 | # @snapB | |
41 | # @init | |
42 | # | | |
43 | # ______ pclone | |
44 | # | / | |
45 | # |@psnap | |
46 | # || @final | |
47 | # ||@final @final @snapC | |
48 | # ||@snapC @snapC @snapB | |
49 | # ||@snapA @snapB @snapA | |
50 | # ||@init @init @init | |
51 | # ||| | | | |
52 | # $pool -------- $FS ------- fs1 ------- fs2 | |
53 | # \ \\_____ \ | | |
54 | # vol vol \____ \ @fsnap | |
55 | # | | \ \ \ | |
56 | # @init @vsnap | ------------ fclone | |
57 | # @snapA @init \ | | | |
58 | # @final @snapB \ | @init | |
59 | # @snapC vclone @snapA | |
60 | # @final | @final | |
61 | # @init | |
62 | # @snapC | |
63 | # @final | |
64 | # | |
65 | # $1 pool name | |
66 | # | |
67 | function setup_test_model | |
68 | { | |
69 | typeset pool=$1 | |
70 | ||
c1d9abf9 | 71 | log_must zfs create -p $pool/$FS/fs1/fs2 |
6bb24f4d | 72 | |
c1d9abf9 JWK |
73 | log_must zfs snapshot $pool@psnap |
74 | log_must zfs clone $pool@psnap $pool/pclone | |
6bb24f4d BB |
75 | |
76 | if is_global_zone ; then | |
c1d9abf9 JWK |
77 | log_must zfs create -V 16M $pool/vol |
78 | log_must zfs create -V 16M $pool/$FS/vol | |
47dfff3b | 79 | block_device_wait |
6bb24f4d | 80 | |
c1d9abf9 JWK |
81 | log_must zfs snapshot $pool/$FS/vol@vsnap |
82 | log_must zfs clone $pool/$FS/vol@vsnap $pool/$FS/vclone | |
47dfff3b | 83 | block_device_wait |
6bb24f4d BB |
84 | fi |
85 | ||
86 | log_must snapshot_tree $pool/$FS/fs1/fs2@fsnap | |
c1d9abf9 JWK |
87 | log_must zfs clone $pool/$FS/fs1/fs2@fsnap $pool/$FS/fs1/fclone |
88 | log_must zfs snapshot -r $pool@init | |
6bb24f4d BB |
89 | |
90 | log_must snapshot_tree $pool@snapA | |
91 | log_must snapshot_tree $pool@snapC | |
92 | log_must snapshot_tree $pool/pclone@snapB | |
93 | log_must snapshot_tree $pool/$FS@snapB | |
94 | log_must snapshot_tree $pool/$FS@snapC | |
95 | log_must snapshot_tree $pool/$FS/fs1@snapA | |
96 | log_must snapshot_tree $pool/$FS/fs1@snapB | |
97 | log_must snapshot_tree $pool/$FS/fs1@snapC | |
98 | log_must snapshot_tree $pool/$FS/fs1/fclone@snapA | |
99 | ||
100 | if is_global_zone ; then | |
c1d9abf9 JWK |
101 | log_must zfs snapshot $pool/vol@snapA |
102 | log_must zfs snapshot $pool/$FS/vol@snapB | |
103 | log_must zfs snapshot $pool/$FS/vol@snapC | |
104 | log_must zfs snapshot $pool/$FS/vclone@snapC | |
6bb24f4d BB |
105 | fi |
106 | ||
c1d9abf9 | 107 | log_must zfs snapshot -r $pool@final |
6bb24f4d BB |
108 | |
109 | return 0 | |
110 | } | |
111 | ||
112 | # | |
113 | # Cleanup the BACKDIR and given pool content and all the sub datasets | |
114 | # | |
115 | # $1 pool name | |
116 | # | |
117 | function cleanup_pool | |
118 | { | |
119 | typeset pool=$1 | |
c1d9abf9 | 120 | log_must rm -rf $BACKDIR/* |
6bb24f4d BB |
121 | |
122 | if is_global_zone ; then | |
e3bdcb8a | 123 | log_must_busy zfs destroy -Rf $pool |
6bb24f4d | 124 | else |
dd49132a | 125 | typeset list=$(zfs list -H -r -t all -o name $pool) |
6bb24f4d BB |
126 | for ds in $list ; do |
127 | if [[ $ds != $pool ]] ; then | |
128 | if datasetexists $ds ; then | |
e3bdcb8a | 129 | log_must_busy zfs destroy -Rf $ds |
6bb24f4d BB |
130 | fi |
131 | fi | |
132 | done | |
133 | fi | |
134 | ||
135 | typeset mntpnt=$(get_prop mountpoint $pool) | |
136 | if ! ismounted $pool ; then | |
137 | # Make sure mountpoint directory is empty | |
138 | if [[ -d $mntpnt ]]; then | |
c1d9abf9 | 139 | log_must rm -rf $mntpnt/* |
6bb24f4d BB |
140 | fi |
141 | ||
c1d9abf9 | 142 | log_must zfs mount $pool |
6bb24f4d BB |
143 | fi |
144 | if [[ -d $mntpnt ]]; then | |
dd49132a | 145 | rm -rf $mntpnt/* |
6bb24f4d BB |
146 | fi |
147 | ||
148 | return 0 | |
149 | } | |
150 | ||
dd49132a BB |
151 | function cleanup_pools |
152 | { | |
153 | cleanup_pool $POOL2 | |
154 | destroy_pool $POOL3 | |
155 | } | |
156 | ||
21d48b5e PD |
157 | function cmp_md5s { |
158 | typeset file1=$1 | |
159 | typeset file2=$2 | |
160 | ||
161 | eval md5sum $file1 | awk '{ print $1 }' > $BACKDIR/md5_file1 | |
162 | eval md5sum $file2 | awk '{ print $1 }' > $BACKDIR/md5_file2 | |
163 | diff $BACKDIR/md5_file1 $BACKDIR/md5_file2 | |
164 | typeset -i ret=$? | |
165 | ||
166 | rm -f $BACKDIR/md5_file1 $BACKDIR/md5_file2 | |
167 | ||
168 | return $ret | |
169 | } | |
170 | ||
6bb24f4d BB |
171 | # |
172 | # Detect if the given two filesystems have same sub-datasets | |
173 | # | |
174 | # $1 source filesystem | |
175 | # $2 destination filesystem | |
176 | # | |
177 | function cmp_ds_subs | |
178 | { | |
179 | typeset src_fs=$1 | |
180 | typeset dst_fs=$2 | |
181 | ||
dd49132a BB |
182 | zfs list -r -H -t all -o name $src_fs > $BACKDIR/src1 |
183 | zfs list -r -H -t all -o name $dst_fs > $BACKDIR/dst1 | |
6bb24f4d | 184 | |
c1d9abf9 JWK |
185 | eval sed -e 's:^$src_fs:PREFIX:g' < $BACKDIR/src1 > $BACKDIR/src |
186 | eval sed -e 's:^$dst_fs:PREFIX:g' < $BACKDIR/dst1 > $BACKDIR/dst | |
6bb24f4d | 187 | |
c1d9abf9 | 188 | diff $BACKDIR/src $BACKDIR/dst |
6bb24f4d BB |
189 | typeset -i ret=$? |
190 | ||
c1d9abf9 | 191 | rm -f $BACKDIR/src $BACKDIR/dst $BACKDIR/src1 $BACKDIR/dst1 |
6bb24f4d BB |
192 | |
193 | return $ret | |
194 | } | |
195 | ||
196 | # | |
4e33ba4c | 197 | # Compare all the directories and files in two filesystems |
6bb24f4d BB |
198 | # |
199 | # $1 source filesystem | |
200 | # $2 destination filesystem | |
201 | # | |
202 | function cmp_ds_cont | |
203 | { | |
204 | typeset src_fs=$1 | |
205 | typeset dst_fs=$2 | |
206 | ||
207 | typeset srcdir dstdir | |
208 | srcdir=$(get_prop mountpoint $src_fs) | |
209 | dstdir=$(get_prop mountpoint $dst_fs) | |
210 | ||
c1d9abf9 | 211 | diff -r $srcdir $dstdir > /dev/null 2>&1 |
510e66db | 212 | return $? |
6bb24f4d BB |
213 | } |
214 | ||
215 | # | |
216 | # Compare the given two dataset properties | |
217 | # | |
218 | # $1 dataset 1 | |
219 | # $2 dataset 2 | |
220 | # | |
221 | function cmp_ds_prop | |
222 | { | |
223 | typeset dtst1=$1 | |
224 | typeset dtst2=$2 | |
225 | ||
a7004725 | 226 | for item in "type" "origin" "volblocksize" "acltype" "dnodesize" \ |
6bb24f4d | 227 | "atime" "canmount" "checksum" "compression" "copies" "devices" \ |
a7004725 DK |
228 | "exec" "quota" "readonly" "recordsize" "reservation" "setuid" \ |
229 | "snapdir" "version" "volsize" "xattr" "zoned" "mountpoint"; | |
6bb24f4d | 230 | do |
c1d9abf9 | 231 | zfs get -H -o property,value,source $item $dtst1 >> \ |
6bb24f4d | 232 | $BACKDIR/dtst1 |
c1d9abf9 | 233 | zfs get -H -o property,value,source $item $dtst2 >> \ |
6bb24f4d BB |
234 | $BACKDIR/dtst2 |
235 | done | |
236 | ||
c1d9abf9 JWK |
237 | eval sed -e 's:$dtst1:PREFIX:g' < $BACKDIR/dtst1 > $BACKDIR/dtst1 |
238 | eval sed -e 's:$dtst2:PREFIX:g' < $BACKDIR/dtst2 > $BACKDIR/dtst2 | |
6bb24f4d | 239 | |
c1d9abf9 | 240 | diff $BACKDIR/dtst1 $BACKDIR/dtst2 |
6bb24f4d BB |
241 | typeset -i ret=$? |
242 | ||
c1d9abf9 | 243 | rm -f $BACKDIR/dtst1 $BACKDIR/dtst2 |
6bb24f4d BB |
244 | |
245 | return $ret | |
246 | ||
247 | } | |
248 | ||
249 | # | |
250 | # Random create directories and files | |
251 | # | |
252 | # $1 directory | |
253 | # | |
254 | function random_tree | |
255 | { | |
256 | typeset dir=$1 | |
257 | ||
258 | if [[ -d $dir ]]; then | |
c1d9abf9 | 259 | rm -rf $dir |
6bb24f4d | 260 | fi |
c1d9abf9 | 261 | mkdir -p $dir |
6bb24f4d BB |
262 | typeset -i ret=$? |
263 | ||
264 | typeset -i nl nd nf | |
265 | ((nl = RANDOM % 6 + 1)) | |
266 | ((nd = RANDOM % 3 )) | |
267 | ((nf = RANDOM % 5 )) | |
c1d9abf9 | 268 | mktree -b $dir -l $nl -d $nd -f $nf |
6bb24f4d BB |
269 | ((ret |= $?)) |
270 | ||
271 | return $ret | |
272 | } | |
273 | ||
274 | # | |
275 | # Put data in filesystem and take snapshot | |
276 | # | |
277 | # $1 snapshot name | |
278 | # | |
279 | function snapshot_tree | |
280 | { | |
281 | typeset snap=$1 | |
282 | typeset ds=${snap%%@*} | |
283 | typeset type=$(get_prop "type" $ds) | |
284 | ||
285 | typeset -i ret=0 | |
286 | if [[ $type == "filesystem" ]]; then | |
287 | typeset mntpnt=$(get_prop mountpoint $ds) | |
288 | ((ret |= $?)) | |
289 | ||
290 | if ((ret == 0)) ; then | |
291 | eval random_tree $mntpnt/${snap##$ds} | |
292 | ((ret |= $?)) | |
293 | fi | |
294 | fi | |
295 | ||
296 | if ((ret == 0)) ; then | |
c1d9abf9 | 297 | zfs snapshot $snap |
6bb24f4d BB |
298 | ((ret |= $?)) |
299 | fi | |
300 | ||
301 | return $ret | |
302 | } | |
303 | ||
304 | # | |
305 | # Destroy the given snapshot and stuff | |
306 | # | |
307 | # $1 snapshot | |
308 | # | |
309 | function destroy_tree | |
310 | { | |
311 | typeset -i ret=0 | |
312 | typeset snap | |
313 | for snap in "$@" ; do | |
e3bdcb8a | 314 | log_must_busy zfs destroy $snap |
6bb24f4d BB |
315 | |
316 | typeset ds=${snap%%@*} | |
317 | typeset type=$(get_prop "type" $ds) | |
318 | if [[ $type == "filesystem" ]]; then | |
319 | typeset mntpnt=$(get_prop mountpoint $ds) | |
e3bdcb8a GDN |
320 | if [[ -n $mntpnt ]]; then |
321 | rm -rf $mntpnt/$snap | |
6bb24f4d BB |
322 | fi |
323 | fi | |
6bb24f4d BB |
324 | done |
325 | ||
326 | return 0 | |
327 | } | |
328 | ||
329 | # | |
330 | # Get all the sub-datasets of give dataset with specific suffix | |
331 | # | |
332 | # $1 Given dataset | |
333 | # $2 Suffix | |
334 | # | |
335 | function getds_with_suffix | |
336 | { | |
337 | typeset ds=$1 | |
338 | typeset suffix=$2 | |
339 | ||
dd49132a | 340 | typeset list=$(zfs list -r -H -t all -o name $ds | grep "$suffix$") |
6bb24f4d | 341 | |
c1d9abf9 | 342 | echo $list |
6bb24f4d BB |
343 | } |
344 | ||
345 | # | |
346 | # Output inherited properties whitch is edited for file system | |
347 | # | |
348 | function fs_inherit_prop | |
349 | { | |
350 | typeset fs_prop | |
351 | if is_global_zone ; then | |
c1d9abf9 JWK |
352 | fs_prop=$(zfs inherit 2>&1 | \ |
353 | awk '$2=="YES" && $3=="YES" {print $1}') | |
6bb24f4d | 354 | if ! is_te_enabled ; then |
c1d9abf9 | 355 | fs_prop=$(echo $fs_prop | grep -v "mlslabel") |
6bb24f4d BB |
356 | fi |
357 | else | |
c1d9abf9 JWK |
358 | fs_prop=$(zfs inherit 2>&1 | \ |
359 | awk '$2=="YES" && $3=="YES" {print $1}'| | |
360 | egrep -v "devices|mlslabel|sharenfs|sharesmb|zoned") | |
6bb24f4d BB |
361 | fi |
362 | ||
c1d9abf9 | 363 | echo $fs_prop |
6bb24f4d BB |
364 | } |
365 | ||
366 | # | |
367 | # Output inherited properties for volume | |
368 | # | |
369 | function vol_inherit_prop | |
370 | { | |
c1d9abf9 | 371 | echo "checksum readonly" |
6bb24f4d BB |
372 | } |
373 | ||
374 | # | |
375 | # Get the destination dataset to compare | |
376 | # | |
377 | function get_dst_ds | |
378 | { | |
379 | typeset srcfs=$1 | |
380 | typeset dstfs=$2 | |
381 | ||
382 | # | |
383 | # If the srcfs is not pool | |
384 | # | |
c1d9abf9 | 385 | if ! zpool list $srcfs > /dev/null 2>&1 ; then |
6bb24f4d BB |
386 | eval dstfs="$dstfs/${srcfs#*/}" |
387 | fi | |
388 | ||
c1d9abf9 | 389 | echo $dstfs |
6bb24f4d BB |
390 | } |
391 | ||
392 | # | |
393 | # Make test files | |
394 | # | |
395 | # $1 Number of files to create | |
396 | # $2 Maximum file size | |
397 | # $3 File ID offset | |
398 | # $4 File system to create the files on | |
399 | # | |
400 | function mk_files | |
401 | { | |
402 | nfiles=$1 | |
403 | maxsize=$2 | |
404 | file_id_offset=$3 | |
405 | fs=$4 | |
21d48b5e | 406 | bs=512 |
6bb24f4d BB |
407 | |
408 | for ((i=0; i<$nfiles; i=i+1)); do | |
21d48b5e PD |
409 | file_name="/$fs/file-$maxsize-$((i+$file_id_offset))" |
410 | file_size=$((($RANDOM * $RANDOM % ($maxsize - 1)) + 1)) | |
411 | ||
412 | # | |
413 | # Create an interesting mix of files which contain both | |
414 | # data blocks and holes for more realistic test coverage. | |
415 | # Half the files are created as sparse then partially filled, | |
416 | # the other half is dense then a hole is punched in the file. | |
417 | # | |
418 | if [ $((RANDOM % 2)) -eq 0 ]; then | |
419 | truncate -s $file_size $file_name || \ | |
420 | log_fail "Failed to create $file_name" | |
421 | dd if=/dev/urandom of=$file_name \ | |
422 | bs=$bs count=$(($file_size / 2 / $bs)) \ | |
423 | seek=$(($RANDOM % (($file_size / 2 / $bs) + 1))) \ | |
424 | conv=notrunc >/dev/null 2>&1 || \ | |
425 | log_fail "Failed to create $file_name" | |
426 | else | |
427 | dd if=/dev/urandom of=$file_name \ | |
428 | bs=$file_size count=1 >/dev/null 2>&1 || \ | |
429 | log_fail "Failed to create $file_name" | |
430 | dd if=/dev/zero of=$file_name \ | |
431 | bs=$bs count=$(($file_size / 2 / $bs)) \ | |
432 | seek=$(($RANDOM % (($file_size / 2 / $bs) + 1))) \ | |
433 | conv=notrunc >/dev/null 2>&1 || \ | |
434 | log_fail "Failed to create $file_name" | |
435 | fi | |
6bb24f4d | 436 | done |
c1d9abf9 | 437 | echo Created $nfiles files of random sizes up to $maxsize bytes |
6bb24f4d BB |
438 | } |
439 | ||
440 | # | |
441 | # Remove test files | |
442 | # | |
443 | # $1 Number of files to remove | |
444 | # $2 Maximum file size | |
445 | # $3 File ID offset | |
446 | # $4 File system to remove the files from | |
447 | # | |
448 | function rm_files | |
449 | { | |
450 | nfiles=$1 | |
451 | maxsize=$2 | |
452 | file_id_offset=$3 | |
453 | fs=$4 | |
454 | ||
455 | for ((i=0; i<$nfiles; i=i+1)); do | |
c1d9abf9 | 456 | rm -f /$fs/file-$maxsize-$((i+$file_id_offset)) |
6bb24f4d | 457 | done |
c1d9abf9 | 458 | echo Removed $nfiles files of random sizes up to $maxsize bytes |
6bb24f4d BB |
459 | } |
460 | ||
b92f5d9f BB |
461 | # |
462 | # Simulate a random set of operations which could be reasonably expected | |
463 | # to occur on an average filesystem. | |
464 | # | |
465 | # $1 Number of files to modify | |
466 | # $2 Maximum file size | |
467 | # $3 File system to modify the file on | |
c2c6eadf | 468 | # $4 Enabled xattrs (optional) |
b92f5d9f BB |
469 | # |
470 | function churn_files | |
471 | { | |
472 | nfiles=$1 | |
473 | maxsize=$2 | |
474 | fs=$3 | |
c2c6eadf | 475 | xattrs=${4:-1} |
b92f5d9f BB |
476 | |
477 | # | |
478 | # Remove roughly half of the files in order to make it more | |
479 | # likely that a dnode will be reallocated. | |
480 | # | |
481 | for ((i=0; i<$nfiles; i=i+1)); do | |
482 | file_name="/$fs/file-$i" | |
483 | ||
484 | if [[ -e $file_name ]]; then | |
485 | if [ $((RANDOM % 2)) -eq 0 ]; then | |
486 | rm $file_name || \ | |
487 | log_fail "Failed to remove $file_name" | |
488 | fi | |
489 | fi | |
490 | done | |
491 | ||
492 | # | |
493 | # Remount the filesystem to simulate normal usage. This resets | |
494 | # the last allocated object id allowing for new objects to be | |
495 | # reallocated in the locations of previously freed objects. | |
496 | # | |
497 | log_must zfs unmount $fs | |
498 | log_must zfs mount $fs | |
499 | ||
500 | for i in {0..$nfiles}; do | |
501 | file_name="/$fs/file-$i" | |
502 | file_size=$((($RANDOM * $RANDOM % ($maxsize - 1)) + 1)) | |
503 | ||
504 | # | |
505 | # When the file exists modify it in one of five ways to | |
506 | # simulate normal usage: | |
507 | # - (20%) Remove and set and extended attribute on the file | |
508 | # - (20%) Overwrite the existing file | |
509 | # - (20%) Truncate the existing file to a random length | |
510 | # - (20%) Truncate the existing file to zero length | |
511 | # - (20%) Remove the file | |
512 | # | |
513 | # Otherwise create the missing file. 20% of the created | |
514 | # files will be small and use embedded block pointers, the | |
515 | # remainder with have random sizes up to the maximum size. | |
516 | # Three extended attributes are attached to all of the files. | |
517 | # | |
518 | if [[ -e $file_name ]]; then | |
519 | value=$((RANDOM % 5)) | |
c2c6eadf | 520 | if [ $value -eq 0 -a $xattrs -ne 0 ]; then |
b92f5d9f | 521 | attrname="testattr$((RANDOM % 3))" |
caf9dd20 BB |
522 | attrlen="$(((RANDOM % 1000) + 1))" |
523 | attrvalue="$(random_string VALID_NAME_CHAR \ | |
524 | $attrlen)" | |
b92f5d9f BB |
525 | attr -qr $attrname $file_name || \ |
526 | log_fail "Failed to remove $attrname" | |
caf9dd20 BB |
527 | attr -qs $attrname \ |
528 | -V "$attrvalue" $file_name || \ | |
b92f5d9f BB |
529 | log_fail "Failed to set $attrname" |
530 | elif [ $value -eq 1 ]; then | |
531 | dd if=/dev/urandom of=$file_name \ | |
532 | bs=$file_size count=1 >/dev/null 2>&1 || \ | |
533 | log_fail "Failed to overwrite $file_name" | |
534 | elif [ $value -eq 2 ]; then | |
535 | truncate -s $file_size $file_name || \ | |
536 | log_fail "Failed to truncate $file_name" | |
537 | elif [ $value -eq 3 ]; then | |
538 | truncate -s 0 $file_name || \ | |
539 | log_fail "Failed to truncate $file_name" | |
540 | else | |
541 | rm $file_name || \ | |
542 | log_fail "Failed to remove $file_name" | |
543 | fi | |
544 | else | |
545 | if [ $((RANDOM % 5)) -eq 0 ]; then | |
546 | file_size=$((($RANDOM % 64) + 1)) | |
547 | fi | |
548 | ||
549 | dd if=/dev/urandom of=$file_name \ | |
550 | bs=$file_size count=1 >/dev/null 2>&1 || \ | |
551 | log_fail "Failed to create $file_name" | |
552 | ||
c2c6eadf TC |
553 | if [ $xattrs -ne 0 ]; then |
554 | for j in {0..2}; do | |
555 | attrname="testattr$j" | |
caf9dd20 BB |
556 | attrlen="$(((RANDOM % 1000) + 1))" |
557 | attrvalue="$(random_string \ | |
558 | VALID_NAME_CHAR $attrlen)" | |
559 | attr -qs $attrname \ | |
560 | -V "$attrvalue" $file_name || \ | |
561 | log_fail "Failed to set $attrname" | |
c2c6eadf TC |
562 | done |
563 | fi | |
b92f5d9f BB |
564 | fi |
565 | done | |
566 | ||
567 | return 0 | |
568 | } | |
569 | ||
6bb24f4d BB |
570 | # |
571 | # Mess up file contents | |
572 | # | |
573 | # $1 The file path | |
574 | # | |
575 | function mess_file | |
576 | { | |
577 | file=$1 | |
578 | ||
c1d9abf9 | 579 | filesize=$(stat -c '%s' $file) |
6bb24f4d BB |
580 | offset=$(($RANDOM * $RANDOM % $filesize)) |
581 | if (($RANDOM % 7 <= 1)); then | |
582 | # | |
583 | # We corrupt 2 bytes to minimize the chance that we | |
584 | # write the same value that's already there. | |
585 | # | |
c1d9abf9 | 586 | log_must eval "dd if=/dev/urandom of=$file conv=notrunc " \ |
47dfff3b | 587 | "bs=1 count=2 seek=$offset >/dev/null 2>&1" |
6bb24f4d | 588 | else |
c1d9abf9 | 589 | log_must truncate -s $offset $file |
6bb24f4d BB |
590 | fi |
591 | } | |
592 | ||
593 | # | |
594 | # Diff the send/receive filesystems | |
595 | # | |
596 | # $1 The sent filesystem | |
597 | # $2 The received filesystem | |
598 | # | |
599 | function file_check | |
600 | { | |
601 | sendfs=$1 | |
602 | recvfs=$2 | |
603 | ||
604 | if [[ -d /$recvfs/.zfs/snapshot/a && -d \ | |
605 | /$sendfs/.zfs/snapshot/a ]]; then | |
c1d9abf9 | 606 | diff -r /$recvfs/.zfs/snapshot/a /$sendfs/.zfs/snapshot/a |
6bb24f4d BB |
607 | [[ $? -eq 0 ]] || log_fail "Differences found in snap a" |
608 | fi | |
609 | if [[ -d /$recvfs/.zfs/snapshot/b && -d \ | |
610 | /$sendfs/.zfs/snapshot/b ]]; then | |
c1d9abf9 | 611 | diff -r /$recvfs/.zfs/snapshot/b /$sendfs/.zfs/snapshot/b |
6bb24f4d BB |
612 | [[ $? -eq 0 ]] || log_fail "Differences found in snap b" |
613 | fi | |
614 | } | |
615 | ||
616 | # | |
617 | # Resume test helper | |
618 | # | |
619 | # $1 The ZFS send command | |
620 | # $2 The filesystem where the streams are sent | |
621 | # $3 The receive filesystem | |
622 | # | |
623 | function resume_test | |
624 | { | |
625 | sendcmd=$1 | |
626 | streamfs=$2 | |
627 | recvfs=$3 | |
628 | ||
629 | stream_num=1 | |
630 | log_must eval "$sendcmd >/$streamfs/$stream_num" | |
631 | ||
632 | for ((i=0; i<2; i=i+1)); do | |
633 | mess_file /$streamfs/$stream_num | |
dd49132a | 634 | log_mustnot zfs recv -suv $recvfs </$streamfs/$stream_num |
6bb24f4d BB |
635 | stream_num=$((stream_num+1)) |
636 | ||
c1d9abf9 JWK |
637 | token=$(zfs get -Hp -o value receive_resume_token $recvfs) |
638 | log_must eval "zfs send -v -t $token >/$streamfs/$stream_num" | |
6bb24f4d BB |
639 | [[ -f /$streamfs/$stream_num ]] || \ |
640 | log_fail "NO FILE /$streamfs/$stream_num" | |
641 | done | |
dd49132a | 642 | log_must zfs recv -suv $recvfs </$streamfs/$stream_num |
6bb24f4d BB |
643 | } |
644 | ||
645 | # | |
646 | # Setup filesystems for the resumable send/receive tests | |
647 | # | |
dd49132a BB |
648 | # $1 The "send" filesystem |
649 | # $2 The "recv" filesystem | |
6bb24f4d BB |
650 | # |
651 | function test_fs_setup | |
652 | { | |
dd49132a BB |
653 | typeset sendfs=$1 |
654 | typeset recvfs=$2 | |
aee1dd4d | 655 | typeset streamfs=$3 |
dd49132a BB |
656 | typeset sendpool=${sendfs%%/*} |
657 | typeset recvpool=${recvfs%%/*} | |
6bb24f4d | 658 | |
e3bdcb8a GDN |
659 | datasetexists $sendfs && log_must_busy zfs destroy -r $sendpool |
660 | datasetexists $recvfs && log_must_busy zfs destroy -r $recvpool | |
aee1dd4d | 661 | datasetexists $streamfs && log_must_busy zfs destroy -r $streamfs |
6bb24f4d | 662 | |
dd49132a | 663 | if $(datasetexists $sendfs || zfs create -o compress=lz4 $sendfs); then |
6bb24f4d BB |
664 | mk_files 1000 256 0 $sendfs & |
665 | mk_files 1000 131072 0 $sendfs & | |
666 | mk_files 100 1048576 0 $sendfs & | |
667 | mk_files 10 10485760 0 $sendfs & | |
668 | mk_files 1 104857600 0 $sendfs & | |
a7004725 | 669 | log_must wait |
c1d9abf9 | 670 | log_must zfs snapshot $sendfs@a |
6bb24f4d BB |
671 | |
672 | rm_files 200 256 0 $sendfs & | |
673 | rm_files 200 131072 0 $sendfs & | |
674 | rm_files 20 1048576 0 $sendfs & | |
675 | rm_files 2 10485760 0 $sendfs & | |
a7004725 | 676 | log_must wait |
6bb24f4d BB |
677 | |
678 | mk_files 400 256 0 $sendfs & | |
679 | mk_files 400 131072 0 $sendfs & | |
680 | mk_files 40 1048576 0 $sendfs & | |
681 | mk_files 4 10485760 0 $sendfs & | |
a7004725 | 682 | log_must wait |
6bb24f4d | 683 | |
c1d9abf9 JWK |
684 | log_must zfs snapshot $sendfs@b |
685 | log_must eval "zfs send -v $sendfs@a >/$sendpool/initial.zsend" | |
686 | log_must eval "zfs send -v -i @a $sendfs@b " \ | |
6bb24f4d BB |
687 | ">/$sendpool/incremental.zsend" |
688 | fi | |
689 | ||
aee1dd4d | 690 | log_must zfs create -o compress=lz4 $streamfs |
6bb24f4d | 691 | } |
a7004725 DK |
692 | |
693 | # | |
694 | # Check to see if the specified features are set in a send stream. | |
695 | # The values for these features are found in include/sys/zfs_ioctl.h | |
696 | # | |
697 | # $1 The stream file | |
698 | # $2-$n The flags expected in the stream | |
699 | # | |
700 | function stream_has_features | |
701 | { | |
702 | typeset file=$1 | |
703 | shift | |
704 | ||
705 | [[ -f $file ]] || log_fail "Couldn't find file: $file" | |
706 | typeset flags=$(cat $file | zstreamdump | \ | |
707 | awk '/features =/ {features = $3} END {print features}') | |
708 | typeset -A feature | |
709 | feature[dedup]="1" | |
710 | feature[dedupprops]="2" | |
711 | feature[sa_spill]="4" | |
712 | feature[embed_data]="10000" | |
713 | feature[lz4]="20000" | |
714 | feature[mooch_byteswap]="40000" | |
715 | feature[large_blocks]="80000" | |
716 | feature[resuming]="100000" | |
717 | feature[redacted]="200000" | |
718 | feature[compressed]="400000" | |
719 | ||
720 | typeset flag known derived=0 | |
721 | for flag in "$@"; do | |
722 | known=${feature[$flag]} | |
723 | [[ -z $known ]] && log_fail "Unknown feature: $flag" | |
724 | ||
725 | derived=$(printf "%x" $((0x${flags} & 0x${feature[$flag]}))) | |
726 | [[ $derived = $known ]] || return 1 | |
727 | done | |
728 | ||
729 | return 0 | |
730 | } | |
731 | ||
a7004725 DK |
732 | # |
733 | # Given a send stream, verify that the size of the stream matches what's | |
734 | # expected based on the source or target dataset. If the stream is an | |
735 | # incremental stream, subtract the size of the source snapshot before | |
736 | # comparing. This function does not currently handle incremental streams | |
737 | # that remove data. | |
738 | # | |
739 | # $1 The zstreamdump output file | |
740 | # $2 The dataset to compare against | |
741 | # This can be a source of a send or recv target (fs, not snapshot) | |
742 | # $3 The percentage below which verification is deemed a failure | |
743 | # $4 The source snapshot of an incremental send | |
744 | # | |
745 | ||
746 | function verify_stream_size | |
747 | { | |
748 | typeset stream=$1 | |
749 | typeset ds=$2 | |
750 | typeset percent=${3:-90} | |
751 | typeset inc_src=$4 | |
752 | ||
753 | [[ -f $stream ]] || log_fail "No such file: $stream" | |
754 | datasetexists $ds || log_fail "No such dataset: $ds" | |
755 | ||
756 | typeset stream_size=$(cat $stream | zstreamdump | sed -n \ | |
757 | 's/ Total write size = \(.*\) (0x.*)/\1/p') | |
758 | ||
759 | typeset inc_size=0 | |
760 | if [[ -n $inc_src ]]; then | |
761 | inc_size=$(get_prop lrefer $inc_src) | |
762 | if stream_has_features $stream compressed; then | |
763 | inc_size=$(get_prop refer $inc_src) | |
764 | fi | |
765 | fi | |
766 | ||
767 | if stream_has_features $stream compressed; then | |
768 | ds_size=$(get_prop refer $ds) | |
769 | else | |
770 | ds_size=$(get_prop lrefer $ds) | |
771 | fi | |
772 | ds_size=$((ds_size - inc_size)) | |
773 | ||
774 | within_percent $stream_size $ds_size $percent || log_fail \ | |
775 | "$stream_size $ds_size differed by too much" | |
776 | } | |
777 | ||
778 | # Cleanup function for tests involving resumable send | |
779 | function resume_cleanup | |
780 | { | |
781 | typeset sendfs=$1 | |
782 | typeset streamfs=$2 | |
aee1dd4d | 783 | typeset sendpool=${sendfs%%/*} |
a7004725 | 784 | |
e3bdcb8a GDN |
785 | datasetexists $sendfs && log_must_busy zfs destroy -r $sendfs |
786 | datasetexists $streamfs && log_must_busy zfs destroy -r $streamfs | |
a7004725 | 787 | cleanup_pool $POOL2 |
aee1dd4d | 788 | rm -f /$sendpool/initial.zsend /$sendpool/incremental.zsend |
a7004725 | 789 | } |
b92f5d9f BB |
790 | |
791 | # Randomly set the property to one of the enumerated values. | |
792 | function rand_set_prop | |
793 | { | |
794 | typeset dtst=$1 | |
795 | typeset prop=$2 | |
796 | shift 2 | |
797 | typeset value=$(random_get $@) | |
798 | ||
799 | log_must eval "zfs set $prop='$value' $dtst" | |
800 | } | |
801 | ||
caf9dd20 BB |
802 | # Generate a recursive checksum of a filesystem which includes the file |
803 | # contents and any associated xattrs. | |
b92f5d9f BB |
804 | function recursive_cksum |
805 | { | |
caf9dd20 BB |
806 | find $1 -type f -exec sh -c 'sha256sum {}; getfattr \ |
807 | --absolute-names --only-values -d {} | sha256sum' \; | \ | |
b92f5d9f BB |
808 | sort -k 2 | awk '{ print $1 }' | sha256sum |
809 | } |