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 #
  28 # Copyright (c) 2013 by Delphix. All rights reserved.
  29 #
  30 
  31 . $STF_SUITE/include/libtest.shlib
  32 . $STF_SUITE/tests/functional/redundancy/redundancy.cfg
  33 
  34 function cleanup
  35 {
  36         if poolexists $TESTPOOL; then
  37                 destroy_pool $TESTPOOL
  38         fi
  39         typeset dir
  40         for dir in $TESTDIR $BASEDIR; do
  41                 if [[ -d $dir ]]; then
  42                         log_must $RM -rf $dir
  43                 fi
  44         done
  45 }
  46 
  47 #
  48 # Get random number between min and max number.
  49 #
  50 # $1 Minimal value
  51 # $2 Maximal value
  52 #
  53 function random
  54 {
  55         typeset -i min=$1
  56         typeset -i max=$2
  57         typeset -i value
  58 
  59         while true; do
  60                 ((value = RANDOM % (max + 1)))
  61                 if ((value >= min)); then
  62                         break
  63                 fi
  64         done
  65 
  66         $ECHO $value
  67 }
  68 
  69 #
  70 # Record the directories construction and checksum all the files which reside
  71 # within the specified pool
  72 #
  73 # $1 The specified pool
  74 # $2 The file which save the record.
  75 #
  76 function record_data
  77 {
  78         typeset pool=$1
  79         typeset recordfile=$2
  80 
  81         [[ -z $pool ]] && log_fail "No specified pool."
  82         [[ -f $recordfile ]] && log_must $RM -f $recordfile
  83 
  84         typeset mntpnt
  85         mntpnt=$(get_prop mountpoint $pool)
  86         log_must eval "$DU -a $mntpnt > $recordfile 2>&1"
  87         #
  88         # When the data was damaged, checksum is failing and return 1
  89         # So, will not use log_must
  90         #
  91         $FIND $mntpnt -type f -exec $CKSUM {} + >> $recordfile 2>&1
  92 }
  93 
  94 #
  95 # Create test pool and fill with files and directories.
  96 #
  97 # $1 pool name
  98 # $2 pool type
  99 # $3 virtual devices number
 100 #
 101 function setup_test_env
 102 {
 103         typeset pool=$1
 104         typeset keyword=$2
 105         typeset -i vdev_cnt=$3
 106         typeset vdevs
 107 
 108         typeset -i i=0
 109         while (( i < vdev_cnt )); do
 110                 vdevs="$vdevs $BASEDIR/vdev$i"
 111                 ((i += 1))
 112         done
 113 
 114         if [[ ! -d $BASEDIR ]]; then
 115                 log_must $MKDIR $BASEDIR
 116         fi
 117 
 118         if poolexists $pool ; then
 119                 destroy_pool $pool
 120         fi
 121 
 122         log_must $MKFILE $DEV_SIZE $vdevs
 123 
 124         log_must $ZPOOL create -m $TESTDIR $pool $keyword $vdevs
 125 
 126         log_note "Filling up the filesystem ..."
 127         typeset -i ret=0
 128         typeset -i i=0
 129         typeset file=$TESTDIR/file
 130         while $TRUE ; do
 131                 $FILE_WRITE -o create -f $file.$i \
 132                         -b $BLOCKSZ -c $NUM_WRITES
 133                 ret=$?
 134                 (( $ret != 0 )) && break
 135                 (( i = i + 1 ))
 136         done
 137         (($ret != 28 )) && log_note "$FILE_WRITE return value($ret) is unexpected."
 138 
 139         record_data $TESTPOOL $PRE_RECORD_FILE
 140 }
 141 
 142 #
 143 # Check pool status is healthy
 144 #
 145 # $1 pool
 146 #
 147 function is_healthy
 148 {
 149         typeset pool=$1
 150 
 151         typeset healthy_output="pool '$pool' is healthy"
 152         typeset real_output=$($ZPOOL status -x $pool)
 153 
 154         if [[ "$real_output" == "$healthy_output" ]]; then
 155                 return 0
 156         else
 157                 typeset -i ret
 158                 $ZPOOL status -x $pool | $GREP "state:" | \
 159                         $GREP "FAULTED" >/dev/null 2>&1
 160                 ret=$?
 161                 (( $ret == 0 )) && return 1
 162                 typeset l_scan
 163                 typeset errnum
 164                 l_scan=$($ZPOOL status -x $pool | $GREP "scan:")
 165                 l_scan=${l_scan##*"with"}
 166                 errnum=$($ECHO $l_scan | $AWK '{print $1}')
 167 
 168                 return $errnum
 169         fi
 170 }
 171 
 172 #
 173 # Check pool data is valid
 174 #
 175 # $1 pool
 176 #
 177 function is_data_valid
 178 {
 179         typeset pool=$1
 180 
 181         record_data $pool $PST_RECORD_FILE
 182         if ! $DIFF $PRE_RECORD_FILE $PST_RECORD_FILE > /dev/null 2>&1; then
 183                 return 1
 184         fi
 185 
 186         return 0
 187 }
 188 
 189 #
 190 # Get the specified count devices name
 191 #
 192 # $1 pool name
 193 # $2 devices count
 194 #
 195 function get_vdevs #pool cnt
 196 {
 197         typeset pool=$1
 198         typeset -i cnt=$2
 199 
 200         typeset all_devs=$($ZPOOL iostat -v $pool | $AWK '{print $1}'| \
 201                 $EGREP -v "^pool$|^capacity$|^mirror$|^raidz1$|^raidz2$|---" | \
 202                 $EGREP -v "/old$|^$pool$")
 203         typeset -i i=0
 204         typeset vdevs
 205         while ((i < cnt)); do
 206                 typeset dev=$($ECHO $all_devs | $AWK '{print $1}')
 207                 eval all_devs=\${all_devs##*$dev}
 208 
 209                 vdevs="$dev $vdevs"
 210                 ((i += 1))
 211         done
 212 
 213         $ECHO "$vdevs"
 214 }
 215 
 216 #
 217 # Synchronize all the data in pool
 218 #
 219 # $1 pool name
 220 #
 221 function sync_pool #pool
 222 {
 223         typeset pool=$1
 224 
 225         log_must $SYNC
 226         log_must $SLEEP 2
 227         # Flush all the pool data.
 228         typeset -i ret
 229         $ZPOOL scrub $pool >/dev/null 2>&1
 230         ret=$?
 231         (( $ret != 0 )) && \
 232                 log_fail "$ZPOOL scrub $pool failed."
 233 
 234         while ! is_pool_scrubbed $pool; do
 235                 if is_pool_resilvered $pool ; then
 236                         log_fail "$pool should not be resilver completed."
 237                 fi
 238                 log_must $SLEEP 2
 239         done
 240 }
 241 
 242 #
 243 # Create and replace the same name virtual device files
 244 #
 245 # $1 pool name
 246 # $2-n virtual device files
 247 #
 248 function replace_missing_devs
 249 {
 250         typeset pool=$1
 251         shift
 252 
 253         typeset vdev
 254         for vdev in $@; do
 255                 log_must $MKFILE $DEV_SIZE $vdev
 256                 log_must $ZPOOL replace -f $pool $vdev $vdev
 257                 while true; do
 258                         if ! is_pool_resilvered $pool ; then
 259                                 log_must $SLEEP 2
 260                         else
 261                                 break
 262                         fi
 263                 done
 264         done
 265 }
 266 
 267 #
 268 # Damage the pool's virtual device files.
 269 #
 270 # $1 pool name
 271 # $2 Failing devices count
 272 # $3 damage vdevs method, if not null, we keep
 273 #    the label for the vdevs
 274 #
 275 function damage_devs
 276 {
 277         typeset pool=$1
 278         typeset -i cnt=$2
 279         typeset label="$3"
 280         typeset vdevs
 281         typeset -i bs_count
 282 
 283         vdevs=$(get_vdevs $pool $cnt)
 284         if [[ -n $label ]]; then
 285                 typeset dev
 286                 for dev in $vdevs; do
 287                         bs_count=$($LS -l $dev | $AWK '{print $5}')
 288                         (( bs_count = bs_count/1024 - 512 ))
 289                         $DD if=/dev/zero of=$dev seek=512 bs=1024 \
 290                                 count=$bs_count conv=notrunc >/dev/null 2>&1
 291                 done
 292         else
 293                 log_must $MKFILE $DEV_SIZE $vdevs
 294         fi
 295 
 296         sync_pool $pool
 297 }
 298 
 299 #
 300 # Clear errors in the pool caused by data corruptions
 301 #
 302 # $1 pool name
 303 #
 304 function clear_errors
 305 {
 306         typeset pool=$1
 307 
 308         log_must $ZPOOL clear $pool
 309 
 310         if ! is_healthy $pool ; then
 311                 log_note "$pool should be healthy."
 312                 return 1
 313         fi
 314         if ! is_data_valid $pool ; then
 315                 log_note "Data should be valid in $pool."
 316                 return 1
 317         fi
 318 
 319         return 0
 320 }
 321 
 322 #
 323 # Remove the specified pool's virtual device files
 324 #
 325 # $1 Pool name
 326 # $2 Missing devices count
 327 #
 328 function remove_devs
 329 {
 330         typeset pool=$1
 331         typeset -i cnt=$2
 332         typeset vdevs
 333 
 334         vdevs=$(get_vdevs $pool $cnt)
 335         log_must $RM -f $vdevs
 336 
 337         sync_pool $pool
 338 }
 339 
 340 #
 341 # Recover the bad or missing device files in the pool
 342 #
 343 # $1 Pool name
 344 # $2 Missing devices count
 345 #
 346 function recover_bad_missing_devs
 347 {
 348         typeset pool=$1
 349         typeset -i cnt=$2
 350         typeset vdevs
 351 
 352         vdevs=$(get_vdevs $pool $cnt)
 353         replace_missing_devs $pool $vdevs
 354 
 355         if ! is_healthy $pool ; then
 356                 log_note "$pool should be healthy."
 357                 return 1
 358         fi
 359         if ! is_data_valid $pool ; then
 360                 log_note "Data should be valid in $pool."
 361                 return 1
 362         fi
 363 
 364         return 0
 365 }