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 }