1eda14cbcSMatt Macy#!/usr/bin/env bash 2eda14cbcSMatt Macy 3eda14cbcSMatt Macy# 4eda14cbcSMatt Macy# CDDL HEADER START 5eda14cbcSMatt Macy# 6eda14cbcSMatt Macy# This file and its contents are supplied under the terms of the 7eda14cbcSMatt Macy# Common Development and Distribution License ("CDDL"), version 1.0. 8eda14cbcSMatt Macy# You may only use this file in accordance with the terms of version 9eda14cbcSMatt Macy# 1.0 of the CDDL. 10eda14cbcSMatt Macy# 11eda14cbcSMatt Macy# A full copy of the text of the CDDL should have accompanied this 12eda14cbcSMatt Macy# source. A copy of the CDDL is also available via the Internet at 13eda14cbcSMatt Macy# http://www.illumos.org/license/CDDL. 14eda14cbcSMatt Macy# 15eda14cbcSMatt Macy# CDDL HEADER END 16eda14cbcSMatt Macy# 17eda14cbcSMatt Macy 18eda14cbcSMatt Macy# 19eda14cbcSMatt Macy# Copyright (c) 2015 by Delphix. All rights reserved. 20eda14cbcSMatt Macy# Copyright (C) 2016 Lawrence Livermore National Security, LLC. 217877fdebSMatt Macy# Copyright (c) 2017, Intel Corporation. 22eda14cbcSMatt Macy# 23eda14cbcSMatt Macy 24716fd348SMartin MatuskaBASE_DIR=${0%/*} 25eda14cbcSMatt MacySCRIPT_COMMON=common.sh 26bb2d13b6SMartin Matuskaif [[ -f "${BASE_DIR}/${SCRIPT_COMMON}" ]]; then 27eda14cbcSMatt Macy . "${BASE_DIR}/${SCRIPT_COMMON}" 28eda14cbcSMatt Macyelse 29eda14cbcSMatt Macy echo "Missing helper script ${SCRIPT_COMMON}" && exit 1 30eda14cbcSMatt Macyfi 31eda14cbcSMatt Macy 32eda14cbcSMatt Macy# shellcheck disable=SC2034 33eda14cbcSMatt MacyPROG=zloop.sh 34eda14cbcSMatt MacyGDB=${GDB:-gdb} 35eda14cbcSMatt Macy 36eda14cbcSMatt MacyDEFAULTWORKDIR=/var/tmp 37eda14cbcSMatt MacyDEFAULTCOREDIR=/var/tmp/zloop 38eda14cbcSMatt Macy 39eda14cbcSMatt Macyfunction usage 40eda14cbcSMatt Macy{ 413f9d360cSMartin Matuska cat >&2 <<EOF 423f9d360cSMartin Matuska 433f9d360cSMartin Matuska$0 [-hl] [-c <dump directory>] [-f <vdev directory>] 443f9d360cSMartin Matuska [-m <max core dumps>] [-s <vdev size>] [-t <timeout>] 453f9d360cSMartin Matuska [-I <max iterations>] [-- [extra ztest parameters]] 463f9d360cSMartin Matuska 473f9d360cSMartin Matuska This script runs ztest repeatedly with randomized arguments. 483f9d360cSMartin Matuska If a crash is encountered, the ztest logs, any associated 493f9d360cSMartin Matuska vdev files, and core file (if one exists) are moved to the 503f9d360cSMartin Matuska output directory ($DEFAULTCOREDIR by default). Any options 513f9d360cSMartin Matuska after the -- end-of-options marker will be passed to ztest. 523f9d360cSMartin Matuska 533f9d360cSMartin Matuska Options: 543f9d360cSMartin Matuska -c Specify a core dump directory to use. 553f9d360cSMartin Matuska -f Specify working directory for ztest vdev files. 563f9d360cSMartin Matuska -h Print this help message. 573f9d360cSMartin Matuska -l Create 'ztest.core.N' symlink to core directory. 583f9d360cSMartin Matuska -m Max number of core dumps to allow before exiting. 593f9d360cSMartin Matuska -s Size of vdev devices. 603f9d360cSMartin Matuska -t Total time to loop for, in seconds. If not provided, 613f9d360cSMartin Matuska zloop runs forever. 623f9d360cSMartin Matuska -I Max number of iterations to loop before exiting. 633f9d360cSMartin Matuska 643f9d360cSMartin MatuskaEOF 65eda14cbcSMatt Macy} 66eda14cbcSMatt Macy 67eda14cbcSMatt Macyfunction or_die 68eda14cbcSMatt Macy{ 69716fd348SMartin Matuska if ! "$@"; then 7016038816SMartin Matuska echo "Command failed: $*" 71eda14cbcSMatt Macy exit 1 72eda14cbcSMatt Macy fi 73eda14cbcSMatt Macy} 74eda14cbcSMatt Macy 75eda14cbcSMatt Macycase $(uname) in 76eda14cbcSMatt MacyFreeBSD) 77eda14cbcSMatt Macy coreglob="z*.core" 78eda14cbcSMatt Macy ;; 79eda14cbcSMatt MacyLinux) 80eda14cbcSMatt Macy # core file helpers 81716fd348SMartin Matuska read -r origcorepattern </proc/sys/kernel/core_pattern 82eda14cbcSMatt Macy coreglob="$(grep -E -o '^([^|%[:space:]]*)' /proc/sys/kernel/core_pattern)*" 83eda14cbcSMatt Macy 84eda14cbcSMatt Macy if [[ $coreglob = "*" ]]; then 85eda14cbcSMatt Macy echo "Setting core file pattern..." 86eda14cbcSMatt Macy echo "core" > /proc/sys/kernel/core_pattern 87eda14cbcSMatt Macy coreglob="$(grep -E -o '^([^|%[:space:]]*)' \ 88eda14cbcSMatt Macy /proc/sys/kernel/core_pattern)*" 89eda14cbcSMatt Macy fi 90eda14cbcSMatt Macy ;; 91eda14cbcSMatt Macy*) 92eda14cbcSMatt Macy exit 1 93eda14cbcSMatt Macy ;; 94eda14cbcSMatt Macyesac 95eda14cbcSMatt Macy 96eda14cbcSMatt Macyfunction core_file 97eda14cbcSMatt Macy{ 9816038816SMartin Matuska # shellcheck disable=SC2012,SC2086 9916038816SMartin Matuska ls -tr1 $coreglob 2>/dev/null | head -1 100eda14cbcSMatt Macy} 101eda14cbcSMatt Macy 102eda14cbcSMatt Macyfunction core_prog 103eda14cbcSMatt Macy{ 104e92ffd9bSMartin Matuska # shellcheck disable=SC2154 105eda14cbcSMatt Macy prog=$ZTEST 106eda14cbcSMatt Macy core_id=$($GDB --batch -c "$1" | grep "Core was generated by" | \ 107eda14cbcSMatt Macy tr \' ' ') 10816038816SMartin Matuska if [[ "$core_id" == *"zdb "* ]]; then 109e92ffd9bSMartin Matuska # shellcheck disable=SC2154 110eda14cbcSMatt Macy prog=$ZDB 111eda14cbcSMatt Macy fi 112eda14cbcSMatt Macy printf "%s" "$prog" 113eda14cbcSMatt Macy} 114eda14cbcSMatt Macy 115eda14cbcSMatt Macyfunction store_core 116eda14cbcSMatt Macy{ 117eda14cbcSMatt Macy core="$(core_file)" 118eda14cbcSMatt Macy if [[ $ztrc -ne 0 ]] || [[ -f "$core" ]]; then 119eda14cbcSMatt Macy df -h "$workdir" >>ztest.out 120eda14cbcSMatt Macy coreid=$(date "+zloop-%y%m%d-%H%M%S") 121eda14cbcSMatt Macy foundcrashes=$((foundcrashes + 1)) 122eda14cbcSMatt Macy 123eda14cbcSMatt Macy # zdb debugging 124eda14cbcSMatt Macy zdbcmd="$ZDB -U "$workdir/zpool.cache" -dddMmDDG ztest" 125eda14cbcSMatt Macy zdbdebug=$($zdbcmd 2>&1) 126eda14cbcSMatt Macy echo -e "$zdbcmd\n" >>ztest.zdb 127eda14cbcSMatt Macy echo "$zdbdebug" >>ztest.zdb 128eda14cbcSMatt Macy 129eda14cbcSMatt Macy dest=$coredir/$coreid 130eda14cbcSMatt Macy or_die mkdir -p "$dest/vdev" 131eda14cbcSMatt Macy 132eda14cbcSMatt Macy if [[ $symlink -ne 0 ]]; then 133e92ffd9bSMartin Matuska or_die ln -sf "$dest" "ztest.core.${foundcrashes}" 134eda14cbcSMatt Macy fi 135eda14cbcSMatt Macy 136eda14cbcSMatt Macy echo "*** ztest crash found - moving logs to $dest" 137eda14cbcSMatt Macy 138716fd348SMartin Matuska or_die mv ztest.history ztest.zdb ztest.out "$dest/" 139716fd348SMartin Matuska or_die mv "$workdir/"ztest* "$dest/vdev/" 140eda14cbcSMatt Macy 141eda14cbcSMatt Macy if [[ -e "$workdir/zpool.cache" ]]; then 142eda14cbcSMatt Macy or_die mv "$workdir/zpool.cache" "$dest/vdev/" 143eda14cbcSMatt Macy fi 144eda14cbcSMatt Macy 145eda14cbcSMatt Macy # check for core 146eda14cbcSMatt Macy if [[ -f "$core" ]]; then 147eda14cbcSMatt Macy coreprog=$(core_prog "$core") 148eda14cbcSMatt Macy coredebug=$($GDB --batch --quiet \ 149eda14cbcSMatt Macy -ex "set print thread-events off" \ 150eda14cbcSMatt Macy -ex "printf \"*\n* Backtrace \n*\n\"" \ 151eda14cbcSMatt Macy -ex "bt" \ 152eda14cbcSMatt Macy -ex "printf \"*\n* Libraries \n*\n\"" \ 153eda14cbcSMatt Macy -ex "info sharedlib" \ 154eda14cbcSMatt Macy -ex "printf \"*\n* Threads (full) \n*\n\"" \ 155eda14cbcSMatt Macy -ex "info threads" \ 156eda14cbcSMatt Macy -ex "printf \"*\n* Backtraces \n*\n\"" \ 157eda14cbcSMatt Macy -ex "thread apply all bt" \ 158eda14cbcSMatt Macy -ex "printf \"*\n* Backtraces (full) \n*\n\"" \ 159eda14cbcSMatt Macy -ex "thread apply all bt full" \ 160eda14cbcSMatt Macy -ex "quit" "$coreprog" "$core" 2>&1 | \ 161eda14cbcSMatt Macy grep -v "New LWP") 162eda14cbcSMatt Macy 163eda14cbcSMatt Macy # Dump core + logs to stored directory 164eda14cbcSMatt Macy echo "$coredebug" >>"$dest/ztest.gdb" 165eda14cbcSMatt Macy or_die mv "$core" "$dest/" 166eda14cbcSMatt Macy 167eda14cbcSMatt Macy # Record info in cores logfile 168eda14cbcSMatt Macy echo "*** core @ $coredir/$coreid/$core:" | \ 169eda14cbcSMatt Macy tee -a ztest.cores 170eda14cbcSMatt Macy fi 171eda14cbcSMatt Macy 172eda14cbcSMatt Macy if [[ $coremax -gt 0 ]] && 173eda14cbcSMatt Macy [[ $foundcrashes -ge $coremax ]]; then 174eda14cbcSMatt Macy echo "exiting... max $coremax allowed cores" 175eda14cbcSMatt Macy exit 1 176eda14cbcSMatt Macy else 177eda14cbcSMatt Macy echo "continuing..." 178eda14cbcSMatt Macy fi 179eda14cbcSMatt Macy fi 180eda14cbcSMatt Macy} 181eda14cbcSMatt Macy 182eda14cbcSMatt Macy# parse arguments 183eda14cbcSMatt Macy# expected format: zloop [-t timeout] [-c coredir] [-- extra ztest args] 184eda14cbcSMatt Macycoredir=$DEFAULTCOREDIR 185eda14cbcSMatt Macybasedir=$DEFAULTWORKDIR 186eda14cbcSMatt Macyrundir="zloop-run" 187eda14cbcSMatt Macytimeout=0 188eda14cbcSMatt Macysize="512m" 189eda14cbcSMatt Macycoremax=0 190eda14cbcSMatt Macysymlink=0 1913f9d360cSMartin Matuskaiterations=0 1923f9d360cSMartin Matuskawhile getopts ":ht:m:I:s:c:f:l" opt; do 193eda14cbcSMatt Macy case $opt in 194eda14cbcSMatt Macy t ) [[ $OPTARG -gt 0 ]] && timeout=$OPTARG ;; 195eda14cbcSMatt Macy m ) [[ $OPTARG -gt 0 ]] && coremax=$OPTARG ;; 196e92ffd9bSMartin Matuska I ) [[ -n $OPTARG ]] && iterations=$OPTARG ;; 197e92ffd9bSMartin Matuska s ) [[ -n $OPTARG ]] && size=$OPTARG ;; 198e92ffd9bSMartin Matuska c ) [[ -n $OPTARG ]] && coredir=$OPTARG ;; 199e92ffd9bSMartin Matuska f ) [[ -n $OPTARG ]] && basedir=$(readlink -f "$OPTARG") ;; 200eda14cbcSMatt Macy l ) symlink=1 ;; 201eda14cbcSMatt Macy h ) usage 202eda14cbcSMatt Macy exit 2 203eda14cbcSMatt Macy ;; 204eda14cbcSMatt Macy * ) echo "Invalid argument: -$OPTARG"; 205eda14cbcSMatt Macy usage 206eda14cbcSMatt Macy exit 1 207eda14cbcSMatt Macy esac 208eda14cbcSMatt Macydone 209eda14cbcSMatt Macy# pass remaining arguments on to ztest 210eda14cbcSMatt Macyshift $((OPTIND - 1)) 211eda14cbcSMatt Macy 212eda14cbcSMatt Macy# enable core dumps 213eda14cbcSMatt Macyulimit -c unlimited 214c03c5b1cSMartin Matuskaexport ASAN_OPTIONS=abort_on_error=true:halt_on_error=true:allocator_may_return_null=true:disable_coredump=false:detect_stack_use_after_return=true 215c03c5b1cSMartin Matuskaexport UBSAN_OPTIONS=abort_on_error=true:halt_on_error=true:print_stacktrace=true 216eda14cbcSMatt Macy 217eda14cbcSMatt Macyif [[ -f "$(core_file)" ]]; then 218eda14cbcSMatt Macy echo -n "There's a core dump here you might want to look at first... " 219eda14cbcSMatt Macy core_file 220eda14cbcSMatt Macy echo 221eda14cbcSMatt Macy exit 1 222eda14cbcSMatt Macyfi 223eda14cbcSMatt Macy 224eda14cbcSMatt Macyif [[ ! -d $coredir ]]; then 225eda14cbcSMatt Macy echo "core dump directory ($coredir) does not exist, creating it." 226eda14cbcSMatt Macy or_die mkdir -p "$coredir" 227eda14cbcSMatt Macyfi 228eda14cbcSMatt Macy 229eda14cbcSMatt Macyif [[ ! -w $coredir ]]; then 230eda14cbcSMatt Macy echo "core dump directory ($coredir) is not writable." 231eda14cbcSMatt Macy exit 1 232eda14cbcSMatt Macyfi 233eda14cbcSMatt Macy 234716fd348SMartin Matuskaor_die rm -f ztest.history ztest.zdb ztest.cores 235eda14cbcSMatt Macy 236eda14cbcSMatt Macyztrc=0 # ztest return value 237eda14cbcSMatt Macyfoundcrashes=0 # number of crashes found so far 238eda14cbcSMatt Macystarttime=$(date +%s) 239eda14cbcSMatt Macycurtime=$starttime 2403f9d360cSMartin Matuskaiteration=0 241eda14cbcSMatt Macy 242eda14cbcSMatt Macy# if no timeout was specified, loop forever. 2433f9d360cSMartin Matuskawhile (( timeout == 0 )) || (( curtime <= (starttime + timeout) )); do 2443f9d360cSMartin Matuska if (( iterations > 0 )) && (( iteration++ == iterations )); then 2453f9d360cSMartin Matuska break 2463f9d360cSMartin Matuska fi 2473f9d360cSMartin Matuska 248eda14cbcSMatt Macy zopt="-G -VVVVV" 249eda14cbcSMatt Macy 250eda14cbcSMatt Macy # start each run with an empty directory 251eda14cbcSMatt Macy workdir="$basedir/$rundir" 252eda14cbcSMatt Macy or_die rm -rf "$workdir" 253eda14cbcSMatt Macy or_die mkdir "$workdir" 254eda14cbcSMatt Macy 2557877fdebSMatt Macy # ashift range 9 - 15 256eda14cbcSMatt Macy align=$(((RANDOM % 2) * 3 + 9)) 2577877fdebSMatt Macy 258*e716630dSMartin Matuska # choose parity value 259*e716630dSMartin Matuska parity=$(((RANDOM % 3) + 1)) 260*e716630dSMartin Matuska 261*e716630dSMartin Matuska draid_data=0 262*e716630dSMartin Matuska draid_spares=0 263*e716630dSMartin Matuska 2647877fdebSMatt Macy # randomly use special classes 2657877fdebSMatt Macy class="special=random" 2667877fdebSMatt Macy 267*e716630dSMartin Matuska # choose between four types of configs 268*e716630dSMartin Matuska # (basic, raidz mix, raidz expansion, and draid mix) 269*e716630dSMartin Matuska case $((RANDOM % 4)) in 270*e716630dSMartin Matuska 271*e716630dSMartin Matuska # basic mirror configuration 272*e716630dSMartin Matuska 0) parity=1 2737877fdebSMatt Macy mirrors=2 2747877fdebSMatt Macy raid_children=0 2757877fdebSMatt Macy vdevs=2 2767877fdebSMatt Macy raid_type="raidz" 277*e716630dSMartin Matuska ;; 278*e716630dSMartin Matuska 2797877fdebSMatt Macy # fully randomized mirror/raidz (sans dRAID) 280*e716630dSMartin Matuska 1) mirrors=$(((RANDOM % 3) * 1)) 2817877fdebSMatt Macy raid_children=$((((RANDOM % 9) + parity + 1) * (RANDOM % 2))) 2827877fdebSMatt Macy vdevs=$(((RANDOM % 3) + 3)) 2837877fdebSMatt Macy raid_type="raidz" 284*e716630dSMartin Matuska ;; 285*e716630dSMartin Matuska 286*e716630dSMartin Matuska # randomized raidz expansion (one top-level raidz vdev) 287*e716630dSMartin Matuska 2) mirrors=0 288*e716630dSMartin Matuska vdevs=1 289*e716630dSMartin Matuska # derive initial raidz disk count based on parity choice 290*e716630dSMartin Matuska # P1: 3 - 7 disks 291*e716630dSMartin Matuska # P2: 5 - 9 disks 292*e716630dSMartin Matuska # P3: 7 - 11 disks 293*e716630dSMartin Matuska raid_children=$(((RANDOM % 5) + (parity * 2) + 1)) 294*e716630dSMartin Matuska 295*e716630dSMartin Matuska # 1/3 of the time use a dedicated '-X' raidz expansion test 296*e716630dSMartin Matuska if [[ $((RANDOM % 3)) -eq 0 ]]; then 297*e716630dSMartin Matuska zopt="$zopt -X -t 16" 298*e716630dSMartin Matuska raid_type="raidz" 2997877fdebSMatt Macy else 300*e716630dSMartin Matuska raid_type="eraidz" 301*e716630dSMartin Matuska fi 302*e716630dSMartin Matuska ;; 303*e716630dSMartin Matuska 3047877fdebSMatt Macy # fully randomized dRAID (sans mirror/raidz) 305*e716630dSMartin Matuska 3) mirrors=0 3067877fdebSMatt Macy draid_data=$(((RANDOM % 8) + 3)) 3077877fdebSMatt Macy draid_spares=$(((RANDOM % 2) + parity)) 3087877fdebSMatt Macy stripe=$((draid_data + parity)) 3097877fdebSMatt Macy extra=$((draid_spares + (RANDOM % 4))) 3107877fdebSMatt Macy raid_children=$(((((RANDOM % 4) + 1) * stripe) + extra)) 3117877fdebSMatt Macy vdevs=$((RANDOM % 3)) 3127877fdebSMatt Macy raid_type="draid" 313*e716630dSMartin Matuska ;; 314*e716630dSMartin Matuska *) 315*e716630dSMartin Matuska # avoid shellcheck SC2249 316*e716630dSMartin Matuska ;; 317*e716630dSMartin Matuska esac 3187877fdebSMatt Macy 3197877fdebSMatt Macy zopt="$zopt -K $raid_type" 320eda14cbcSMatt Macy zopt="$zopt -m $mirrors" 3217877fdebSMatt Macy zopt="$zopt -r $raid_children" 3227877fdebSMatt Macy zopt="$zopt -D $draid_data" 3237877fdebSMatt Macy zopt="$zopt -S $draid_spares" 324eda14cbcSMatt Macy zopt="$zopt -R $parity" 325eda14cbcSMatt Macy zopt="$zopt -v $vdevs" 326eda14cbcSMatt Macy zopt="$zopt -a $align" 3277877fdebSMatt Macy zopt="$zopt -C $class" 328eda14cbcSMatt Macy zopt="$zopt -s $size" 329eda14cbcSMatt Macy zopt="$zopt -f $workdir" 330eda14cbcSMatt Macy 33116038816SMartin Matuska cmd="$ZTEST $zopt $*" 332716fd348SMartin Matuska echo "$(date '+%m/%d %T') $cmd" | tee -a ztest.history ztest.out 333eda14cbcSMatt Macy $cmd >>ztest.out 2>&1 334eda14cbcSMatt Macy ztrc=$? 335eda14cbcSMatt Macy grep -E '===|WARNING' ztest.out >>ztest.history 336eda14cbcSMatt Macy 337eda14cbcSMatt Macy store_core 338eda14cbcSMatt Macy 339eda14cbcSMatt Macy curtime=$(date +%s) 340eda14cbcSMatt Macydone 341eda14cbcSMatt Macy 342eda14cbcSMatt Macyecho "zloop finished, $foundcrashes crashes found" 343eda14cbcSMatt Macy 344eda14cbcSMatt Macy# restore core pattern. 345eda14cbcSMatt Macycase $(uname) in 346eda14cbcSMatt MacyLinux) 347eda14cbcSMatt Macy echo "$origcorepattern" > /proc/sys/kernel/core_pattern 348eda14cbcSMatt Macy ;; 349eda14cbcSMatt Macy*) 350eda14cbcSMatt Macy ;; 351eda14cbcSMatt Macyesac 352eda14cbcSMatt Macy 353eda14cbcSMatt Macyuptime >>ztest.out 354eda14cbcSMatt Macy 355eda14cbcSMatt Macyif [[ $foundcrashes -gt 0 ]]; then 356eda14cbcSMatt Macy exit 1 357eda14cbcSMatt Macyfi 358