1 #
2 # This file and its contents are supplied under the terms of the
3 # Common Development and Distribution License ("CDDL"), version 1.0.
4 # You may only use this file in accordance with the terms of version
5 # 1.0 of the CDDL.
6 #
7 # A full copy of the text of the CDDL should have accompanied this
8 # source. A copy of the CDDL is also available via the Internet at
9 # http://www.illumos.org/license/CDDL.
10 #
11
12 #
13 # Copyright 2016 Nexenta Systems, Inc. All rights reserved.
14 #
15
16 . $STF_SUITE/include/libtest.shlib
17
18 function cleanup
19 {
20 if poolexists $TESTPOOL ; then
21 destroy_pool $TESTPOOL
22 fi
23
24 if poolexists $TESTPOOL2 ; then
25 destroy_pool $TESTPOOL2
26 fi
27 }
28
29 function disk_vendor
30 {
31 typeset disk=$1
32
33 if $(is_physical_device $disk) ; then
34 echo inquiry | format $disk | nawk '/Vendor:/{print $NF}'
35 else
36 echo UNKNOWN
37 fi
38 }
39
40 function disk_model
41 {
42 typeset disk=$1
43
44 if $(is_physical_device $disk) ; then
45 echo inquiry | format $disk | nawk '/Product:/{print $NF}'
46 else
47 echo UNKNOWN
48 fi
49 }
50
51 function disk_info
52 {
53 typeset disk=$1
54 typeset vendor=$(disk_vendor $disk)
55 typeset model=$(disk_model $disk)
56
57 echo "$vendor-$model"
58 }
59
60 function disk_is_ssd
61 {
62 typeset disk=$1
63
64 if $(is_physical_device $disk) ; then
65 if disk_info $disk | egrep -i "$SSD_MODELS" >/dev/null 2>&1 ; then
66 return 0
67 fi
68 fi
69
70 return 1
71 }
72
73 function set_disks
74 {
75 MIN_DSK_COUNT=$(( $MIN_SSD_COUNT + $MIN_HDD_COUNT ))
76 SSD_COUNT=0
77 HDD_COUNT=0
78
79 typeset disk
80 for disk in $DISKS ; do
81 if $(disk_is_ssd $disk) ; then
82 (( SSD_COUNT = SSD_COUNT + 1 ))
83 eval "SSD_DISK$SSD_COUNT=$disk"
84 else
85 (( HDD_COUNT = HDD_COUNT + 1 ))
86 eval "HDD_DISK$HDD_COUNT=$disk"
87 fi
88 done
89
90 # HDD only setup
91 if [[ $SSD_COUNT -lt $MIN_SSD_COUNT && $HDD_COUNT -ge $MIN_DSK_COUNT ]] ; then
92 for SSD_COUNT in {1..$MIN_SSD_COUNT} ; do
93 eval "SSD_DISK$SSD_COUNT=\$HDD_DISK$HDD_COUNT"
94 unset HDD_DISK$HDD_COUNT
95 (( HDD_COUNT = HDD_COUNT - 1 ))
96 done
97 fi
98
99 # SSD only setup
100 if [[ $HDD_COUNT -lt $MIN_HDD_COUNT && $SSD_COUNT -ge $MIN_DSK_COUNT ]] ; then
101 for HDD_COUNT in {1..$MIN_HDD_COUNT} ; do
102 eval "HDD_DISK$HDD_COUNT=\$SSD_DISK$SSD_COUNT"
103 unset SSD_DISK$SSD_COUNT
104 (( SSD_COUNT = SSD_COUNT - 1 ))
105 done
106 fi
107
108 # diskless setup
109 if [[ $HDD_COUNT -lt $MIN_HDD_COUNT || $SSD_COUNT -lt $MIN_SSD_COUNT ]] ; then
110 mkdir -p $VDEV_DIR
111
112 for HDD_COUNT in {1..$MIN_HDD_COUNT} ; do
113 eval "HDD_DISK$HDD_COUNT=\"$VDEV_DIR/hdd$HDD_COUNT\""
114 done
115
116 for SSD_COUNT in {1..$MIN_SSD_COUNT} ; do
117 eval "SSD_DISK$SSD_COUNT=\"$VDEV_DIR/ssd$SSD_COUNT\""
118 done
119 fi
120
121 typeset -i item=0
122
123 for item in {1..$HDD_COUNT} ; do
124 eval "HDD_DISKS=\"$HDD_DISKS \$HDD_DISK$item\""
125 export HDD_DISK$item
126 done
127
128 export HDD_COUNT HDD_DISKS
129
130 for item in {1..$SSD_COUNT} ; do
131 eval "SSD_DISKS=\"$SSD_DISKS \$SSD_DISK$item\""
132 export SSD_DISK$item
133 done
134
135 export SSD_COUNT SSD_DISKS
136 }
137
138 function test_disks
139 {
140 echo "SSD_COUNT=$SSD_COUNT"
141 echo "HDD_COUNT=$HDD_COUNT"
142
143 echo "SSD_DISKS = $SSD_DISKS"
144 echo "HDD_DISKS = $HDD_DISKS"
145 }
146
147 function create_disks
148 {
149 typeset -i ret=0
150 test -d "$VDEV_DIR" || return $ret
151
152 typeset -i item
153 typeset disk
154
155 for item in {1..$HDD_COUNT} ; do
156 eval "disk=\$HDD_DISK$item"
157 echo mkfile $VDEV_SIZE $disk
158 mkfile $VDEV_SIZE $disk
159 ((ret |= $?))
160 done
161
162 for item in {1..$SSD_COUNT} ; do
163 eval "disk=\$SSD_DISK$item"
164 echo mkfile $VDEV_SIZE $disk
165 mkfile $VDEV_SIZE $disk
166 ((ret |= $?))
167 done
168
169 return $ret
170 }
171
172 #
173 # Enable krrp debug
174 #
175 function enable_krrp_debug
176 {
177 echo krrp_debug/W 1 | mdb -kw
178 }
179
180 #
181 # Disable krrp debug
182 #
183 function disable_krrp_debug
184 {
185 echo krrp_debug/W 0 | mdb -kw
186 }
187
188 #
189 # Try zpool status/iostat for given pool
190 #
191 # $1 pool
192 #
193 function display_status
194 {
195 typeset pool=$1
196 typeset -i ret=0
197
198 zpool status -xv $pool >/dev/null 2>&1
199 ret=$?
200
201 zpool iostat >/dev/null 2>&1
202 ((ret |= $?))
203
204 typeset mntpnt=$(get_prop mountpoint $pool)
205 dd if=/dev/urandom of=$mntpnt/testfile.$$ &
206 typeset pid=$!
207
208 zpool iostat -v 1 60 > /dev/null
209 ((ret |= $?))
210
211 kill -9 $pid
212
213 return $ret
214 }
215
216 function create_dataset # <dataset> [size]
217 {
218 typeset dataset_name=$1
219 typeset size=${2:+-V $2}
220
221 if [[ -z $dataset_name ]] ; then
222 log_note "Missing dataset name."
223 return 1
224 fi
225
226 if [[ -d /$dataset_name ]] ; then
227 rm -rf /$dataset_name
228 fi
229
230 zfs create -p $dataset_name $size
231
232 return $?
233 }
234
235 # Return 0 if create successfully or the pool exists; $? otherwise
236 # Note: In local zones, this function should return 0 silently.
237 #
238 # $1 - pool name: required
239 # $2 - pool_type: optional
240 # $3 - recordsize: optional
241 # $4 - compression: optional
242
243 function create_pool #pool_name
244 {
245 typeset pool_name=${1%%/*}
246 typeset pool_type=$2
247 typeset recordsize=$3
248 typeset compression=$4
249
250 if [[ -z $pool_name ]]; then
251 log_note "Missing pool name."
252 return 1
253 fi
254
255 is_global_zone || return 0
256
257 if poolexists $pool_name ; then
258 destroy_pool $pool_name
259 fi
260
261 if [[ -d /$pool_name ]] ; then
262 rm -rf /$pool_name
263 fi
264
265 if [[ -z $pool_type ]] ; then
266 pool_type=$(get_random_pool_type)
267 fi
268
269 if [[ -z $recordsize ]] ; then
270 recordsize=$(get_random_recordsize)
271 fi
272
273 if [[ -z $compression ]] ; then
274 compression=$(get_random_compression)
275 fi
276
277 if [[ $pool_type == "stripe" ]] ; then
278 pool_type=""
279 fi
280
281 zpool create -f \
282 -O compression=$compression \
283 -O recordsize=$recordsize \
284 -o cachefile=none \
285 $pool_name \
286 $pool_type $HDD_DISKS
287
288 return $?
289 }
290
291 # Return 0 if create successfully or the pool exists; $? otherwise
292 # Note: In local zones, this function should return 0 silently.
293 #
294 # $1 - pool name: required
295 # $2 - wbc_mode: optional
296 # $3 - pool_type: optional
297 # $4 - special_type: optional
298 # $5 - recordsize: optional
299 # $6 - compression: optional
300
301 function create_pool_special #pool_name
302 {
303 typeset pool_name=${1%%/*}
304 typeset wbc_mode=$2
305 typeset pool_type=$3
306 typeset special_type=$4
307 typeset recordsize=$5
308 typeset compression=$6
309
310 if [[ -z $pool_name ]]; then
311 log_note "Missing pool name."
312 return 1
313 fi
314
315 is_global_zone || return 0
316
317 if poolexists $pool_name ; then
318 destroy_pool $pool_name
319 fi
320
321 if [[ -d /$pool_name ]] ; then
322 rm -rf /$pool_name
323 fi
324
325 if [[ -z $pool_type ]] ; then
326 pool_type=$(get_random_pool_type)
327 fi
328
329 if [[ -z $special_type ]] ; then
330 special_type=$(get_random_special_type)
331 fi
332
333 if [[ -z $recordsize ]] ; then
334 recordsize=$(get_random_recordsize)
335 fi
336
337 if [[ -z $compression ]] ; then
338 compression=$(get_random_compression)
339 fi
340
341 if [[ $wbc_mode == "none" ]] ; then
342 wbc_mode=""
343 fi
344
345 if [[ -n $wbc_mode ]] ; then
346 wbc_mode="-O wbc_mode=$wbc_mode"
347 fi
348
349 if [[ $pool_type == "stripe" ]] ; then
350 pool_type=""
351 fi
352
353 if [[ $special_type == "stripe" ]] ; then
354 special_type=""
355 fi
356
357 zpool create -f \
358 -O compression=$compression \
359 -O recordsize=$recordsize \
360 -o cachefile=none \
361 $wbc_mode \
362 $pool_name \
363 $pool_type $HDD_DISKS \
364 special $special_type $SSD_DISKS
365
366 return $?
367 }
368
369 function get_random_recordsize
370 {
371 random_get "4k" "8k" "16k" "32k" "64k" "128k"
372 }
373
374 function get_random_compression
375 {
376 random_get "off" "on" "lzjb" "gzip" "zle" "lz4"
377 }
378
379 function get_random_pool_type
380 {
381 random_get "stripe" "mirror" "raidz" "raidz2" "raidz3"
382 }
383
384 function get_random_special_type
385 {
386 random_get "stripe" "mirror"
387 }
388
389 function get_wbc_mode # <dataset>
390 {
391 typeset dataset=$1
392
393 if [[ -z $dataset ]] ; then
394 log_note "Missing dataset name."
395 return 1
396 fi
397
398 zfs get -H -o value wbc_mode $dataset
399
400 return $?
401 }
402
403 function set_wbc_mode # <dataset> <mode>
404 {
405 typeset dataset=$1
406 typeset mode=$2
407
408 if [[ -z $dataset ]] ; then
409 log_note "Missing dataset name."
410 return 1
411 fi
412
413 if [[ -z $mode ]] ; then
414 log_note "Missing wbc mode."
415 return 1
416 fi
417
418 zfs set wbc_mode=$mode $dataset
419 value=$(get_wbc_mode $dataset)
420
421 if [[ "$mode" != "$value" ]] ; then
422 return 1
423 fi
424
425 return 0
426 }
427
428 function enable_wbc # <dataset>
429 {
430 typeset dataset=$1
431
432 if [[ -z $dataset ]] ; then
433 log_note "Missing dataset name."
434 return 1
435 fi
436
437 set_wbc_mode $dataset on
438
439 return $?
440 }
441
442 function disable_wbc # <dataset>
443 {
444 typeset dataset=$1
445
446 if [[ -z $dataset ]] ; then
447 log_note "Missing dataset name."
448 return 1
449 fi
450
451 set_wbc_mode $dataset off
452
453 return $?
454 }
455
456 function check_pool_errors # <pool> [<vdev>]
457 {
458 typeset pool=$1
459 shift
460
461 if [[ $# -gt 0 ]] ; then
462 typeset checkvdev=$1
463 else
464 typeset checkvdev=""
465 fi
466
467 typeset -i errnum=0
468 typeset c_read=0
469 typeset c_write=0
470 typeset c_cksum=0
471 typeset tmpfile=/var/tmp/file.$$
472 typeset healthstr="pool '$pool' is healthy"
473 typeset output=$(zpool status -x $pool)
474
475 if [[ "$output" == "$healthstr" ]] ; then
476 return $errnum
477 fi
478
479 zpool status -x $pool | egrep -v "^$" | \
480 egrep -v "special|pool:|state:|config:|errors:" >$tmpfile
481
482 typeset line
483 typeset -i fetchbegin=1
484
485 while read line; do
486 if [[ $fetchbegin -ne 0 ]] ; then
487 echo $line | grep "NAME" >/dev/null 2>&1
488 if [[ $? -eq 0 ]] ; then
489 fetchbegin=0
490 continue
491 fi
492 fi
493
494 if [[ -n $checkvdev ]] ; then
495 echo $line | grep $checkvdev >/dev/null 2>&1
496 if [[ $? -ne 0 ]] ; then
497 continue
498 fi
499
500 c_read=`echo $line | awk '{print $3}'`
501 c_write=`echo $line | awk '{print $4}'`
502 c_cksum=`echo $line | awk '{print $5}'`
503
504 if [[ $c_read != 0 || $c_write != 0 || $c_cksum != 0 ]] ; then
505 (( errnum = errnum + 1 ))
506 fi
507
508 break
509 fi
510
511 c_read=`echo $line | awk '{print $3}'`
512 c_write=`echo $line | awk '{print $4}'`
513 c_cksum=`echo $line | awk '{print $5}'`
514
515 if [[ $c_read != 0 || $c_write != 0 || $c_cksum != 0 ]] ; then
516 (( errnum = errnum + 1 ))
517 fi
518
519 done <$tmpfile
520
521 rm -f $tmpfile
522
523 return $errnum
524 }
525
526 function get_pool_prop # <property> <pool>
527 {
528 typeset property=$1
529 typeset pool=$2
530 typeset value
531
532 if [[ -z $property ]]; then
533 log_fail "The property name is not defined."
534 fi
535
536 if [[ -z $pool ]]; then
537 log_fail "The pool name is not defined."
538 fi
539
540 if ! poolexists $pool; then
541 log_fail "Pool '$pool' does not exist."
542 fi
543
544 value=$(zpool get -H -o value $property $pool)
545
546 if [[ $? != 0 ]]; then
547 log_fail "Unable to get property '$property' for pool '$pool'."
548 fi
549
550 echo $value
551
552 return 0
553 }
554
555 function set_pool_prop # <property> <value> <pool>
556 {
557 typeset property=$1
558 typeset value=$2
559 typeset pool=$3
560 typeset check
561
562 if [[ -z $property ]]; then
563 log_fail "The property name is not defined."
564 fi
565
566 if [[ -z $value ]]; then
567 log_fail "The '$property' property value is not defined."
568 fi
569
570 if [[ -z $pool ]]; then
571 log_fail "The pool name is not defined."
572 fi
573
574 zpool set $property=$value $pool
575
576 if [[ $? != 0 ]]; then
577 log_note "Unable to set '$property' property to" \
578 "'$value' for pool '$pool'."
579 return 1
580 fi
581
582 check=$(get_pool_prop $property $pool)
583
584 if [[ "$check" != "$value" ]]; then
585 log_note "Unexpected '$property' property value:" \
586 "'$check' (expected '$value')."
587 return 1
588 fi
589
590 return 0
591 }