]>
Commit | Line | Data |
---|---|---|
c9c0d073 BB |
1 | #!/bin/bash |
2 | # | |
3 | # Common support functions for testing scripts. If a .script-config | |
4 | # files is available it will be sourced so in-tree kernel modules and | |
5 | # utilities will be used. If no .script-config can be found then the | |
6 | # installed kernel modules and utilities will be used. | |
7 | ||
8 | basedir="$(dirname $0)" | |
9 | ||
10 | SCRIPT_CONFIG=.script-config | |
11 | if [ -f "${basedir}/../${SCRIPT_CONFIG}" ]; then | |
12 | . "${basedir}/../${SCRIPT_CONFIG}" | |
13 | else | |
14 | MODULES=(zlib_deflate spl splat zavl znvpair zunicode zcommon zfs) | |
15 | fi | |
16 | ||
17 | PROG="<define PROG>" | |
18 | CLEANUP= | |
19 | VERBOSE= | |
20 | VERBOSE_FLAG= | |
21 | FORCE= | |
22 | FORCE_FLAG= | |
23 | DUMP_LOG= | |
24 | ERROR= | |
25 | RAID0S=() | |
26 | RAID10S=() | |
27 | RAIDZS=() | |
28 | RAIDZ2S=() | |
325f0235 BB |
29 | TESTS_RUN=${TESTS_RUN:-'*'} |
30 | TESTS_SKIP=${TESTS_SKIP:-} | |
c9c0d073 BB |
31 | |
32 | prefix=@prefix@ | |
33 | exec_prefix=@exec_prefix@ | |
34 | libexecdir=@libexecdir@ | |
35 | pkglibexecdir=${libexecdir}/@PACKAGE@ | |
36 | bindir=@bindir@ | |
37 | sbindir=@sbindir@ | |
38 | ||
39 | ETCDIR=${ETCDIR:-/etc} | |
40 | DEVDIR=${DEVDIR:-/dev/disk/zpool} | |
41 | ZPOOLDIR=${ZPOOLDIR:-${pkglibexecdir}/zpool-config} | |
42 | ||
43 | ZDB=${ZDB:-${sbindir}/zdb} | |
44 | ZFS=${ZFS:-${sbindir}/zfs} | |
45 | ZINJECT=${ZINJECT:-${sbindir}/zinject} | |
46 | ZPOOL=${ZPOOL:-${sbindir}/zpool} | |
47 | ZPOOL_ID=${ZPOOL_ID:-${bindir}/zpool_id} | |
48 | ZTEST=${ZTEST:-${sbindir}/ztest} | |
49 | ||
50 | COMMON_SH=${COMMON_SH:-${pkglibexecdir}/common.sh} | |
51 | ZFS_SH=${ZFS_SH:-${pkglibexecdir}/zfs.sh} | |
52 | ZPOOL_CREATE_SH=${ZPOOL_CREATE_SH:-${pkglibexecdir}/zpool-create.sh} | |
53 | ||
54 | LDMOD=${LDMOD:-/sbin/modprobe} | |
55 | LSMOD=${LSMOD:-/sbin/lsmod} | |
56 | RMMOD=${RMMOD:-/sbin/rmmod} | |
57 | INFOMOD=${INFOMOD:-/sbin/modinfo} | |
58 | LOSETUP=${LOSETUP:-/sbin/losetup} | |
59 | SYSCTL=${SYSCTL:-/sbin/sysctl} | |
60 | UDEVADM=${UDEVADM:-/sbin/udevadm} | |
61 | AWK=${AWK:-/usr/bin/awk} | |
62 | ||
325f0235 BB |
63 | COLOR_BLACK="\033[0;30m" |
64 | COLOR_DK_GRAY="\033[1;30m" | |
65 | COLOR_BLUE="\033[0;34m" | |
66 | COLOR_LT_BLUE="\033[1;34m" | |
67 | COLOR_GREEN="\033[0;32m" | |
68 | COLOR_LT_GREEN="\033[1;32m" | |
69 | COLOR_CYAN="\033[0;36m" | |
70 | COLOR_LT_CYAN="\033[1;36m" | |
71 | COLOR_RED="\033[0;31m" | |
72 | COLOR_LT_RED="\033[1;31m" | |
73 | COLOR_PURPLE="\033[0;35m" | |
74 | COLOR_LT_PURPLE="\033[1;35m" | |
75 | COLOR_BROWN="\033[0;33m" | |
76 | COLOR_YELLOW="\033[1;33m" | |
77 | COLOR_LT_GRAY="\033[0;37m" | |
78 | COLOR_WHITE="\033[1;37m" | |
79 | COLOR_RESET="\033[0m" | |
80 | ||
c9c0d073 BB |
81 | die() { |
82 | echo -e "${PROG}: $1" >&2 | |
83 | exit 1 | |
84 | } | |
85 | ||
86 | msg() { | |
87 | if [ ${VERBOSE} ]; then | |
88 | echo "$@" | |
89 | fi | |
90 | } | |
91 | ||
92 | pass() { | |
325f0235 | 93 | echo -e "${COLOR_GREEN}Pass${COLOR_RESET}" |
c9c0d073 BB |
94 | } |
95 | ||
96 | fail() { | |
325f0235 | 97 | echo -e "${COLOR_RED}Fail${COLOR_RESET} ($1)" |
c9c0d073 BB |
98 | exit $1 |
99 | } | |
100 | ||
325f0235 BB |
101 | skip() { |
102 | echo -e "${COLOR_BROWN}Skip${COLOR_RESET}" | |
103 | } | |
104 | ||
c9c0d073 BB |
105 | spl_dump_log() { |
106 | ${SYSCTL} -w kernel.spl.debug.dump=1 &>/dev/null | |
107 | local NAME=`dmesg | tail -n 1 | cut -f5 -d' '` | |
108 | ${SPLBUILD}/cmd/spl ${NAME} >${NAME}.log | |
109 | echo | |
110 | echo "Dumped debug log: ${NAME}.log" | |
111 | tail -n1 ${NAME}.log | |
112 | echo | |
113 | return 0 | |
114 | } | |
115 | ||
116 | check_modules() { | |
117 | local LOADED_MODULES=() | |
118 | local MISSING_MODULES=() | |
119 | ||
120 | for MOD in ${MODULES[*]}; do | |
121 | local NAME=`basename $MOD .ko` | |
122 | ||
123 | if ${LSMOD} | egrep -q "^${NAME}"; then | |
124 | LOADED_MODULES=(${NAME} ${LOADED_MODULES[*]}) | |
125 | fi | |
126 | ||
127 | if [ ${INFOMOD} ${MOD} 2>/dev/null ]; then | |
128 | MISSING_MODULES=("\t${MOD}\n" ${MISSING_MODULES[*]}) | |
129 | fi | |
130 | done | |
131 | ||
132 | if [ ${#LOADED_MODULES[*]} -gt 0 ]; then | |
133 | ERROR="Unload these modules with '${PROG} -u':\n" | |
134 | ERROR="${ERROR}${LOADED_MODULES[*]}" | |
135 | return 1 | |
136 | fi | |
137 | ||
138 | if [ ${#MISSING_MODULES[*]} -gt 0 ]; then | |
139 | ERROR="The following modules can not be found," | |
140 | ERROR="${ERROR} ensure your source trees are built:\n" | |
141 | ERROR="${ERROR}${MISSING_MODULES[*]}" | |
142 | return 1 | |
143 | fi | |
144 | ||
145 | return 0 | |
146 | } | |
147 | ||
148 | load_module() { | |
149 | local NAME=`basename $1 .ko` | |
150 | ||
151 | if [ ${VERBOSE} ]; then | |
152 | echo "Loading ${NAME} ($@)" | |
153 | fi | |
154 | ||
155 | ${LDMOD} $* || ERROR="Failed to load $1" return 1 | |
156 | ||
157 | return 0 | |
158 | } | |
159 | ||
160 | load_modules() { | |
161 | mkdir -p /etc/zfs | |
162 | ||
163 | for MOD in ${MODULES[*]}; do | |
164 | local NAME=`basename ${MOD} .ko` | |
165 | local VALUE= | |
166 | ||
167 | for OPT in "$@"; do | |
168 | OPT_NAME=`echo ${OPT} | cut -f1 -d'='` | |
169 | ||
170 | if [ ${NAME} = "${OPT_NAME}" ]; then | |
171 | VALUE=`echo ${OPT} | cut -f2- -d'='` | |
172 | fi | |
173 | done | |
174 | ||
175 | load_module ${MOD} ${VALUE} || return 1 | |
176 | done | |
177 | ||
178 | if [ ${VERBOSE} ]; then | |
179 | echo "Successfully loaded ZFS module stack" | |
180 | fi | |
181 | ||
182 | return 0 | |
183 | } | |
184 | ||
185 | unload_module() { | |
186 | local NAME=`basename $1 .ko` | |
187 | ||
188 | if [ ${VERBOSE} ]; then | |
189 | echo "Unloading ${NAME} ($@)" | |
190 | fi | |
191 | ||
192 | ${RMMOD} ${NAME} || ERROR="Failed to unload ${NAME}" return 1 | |
193 | ||
194 | return 0 | |
195 | } | |
196 | ||
197 | unload_modules() { | |
198 | local MODULES_REVERSE=( $(echo ${MODULES[@]} | | |
199 | ${AWK} '{for (i=NF;i>=1;i--) printf $i" "} END{print ""}') ) | |
200 | ||
201 | for MOD in ${MODULES_REVERSE[*]}; do | |
202 | local NAME=`basename ${MOD} .ko` | |
203 | local USE_COUNT=`${LSMOD} | | |
204 | egrep "^${NAME} "| ${AWK} '{print $3}'` | |
205 | ||
206 | if [ "${USE_COUNT}" = 0 ] ; then | |
207 | ||
208 | if [ "${DUMP_LOG}" -a ${NAME} = "spl" ]; then | |
209 | spl_dump_log | |
210 | fi | |
211 | ||
212 | unload_module ${MOD} || return 1 | |
213 | fi | |
214 | done | |
215 | ||
216 | if [ ${VERBOSE} ]; then | |
217 | echo "Successfully unloaded ZFS module stack" | |
218 | fi | |
219 | ||
220 | return 0 | |
221 | } | |
222 | ||
223 | unused_loop_device() { | |
224 | for DEVICE in `ls -1 /dev/loop*`; do | |
225 | ${LOSETUP} ${DEVICE} &>/dev/null | |
226 | if [ $? -ne 0 ]; then | |
227 | echo ${DEVICE} | |
228 | return | |
229 | fi | |
230 | done | |
231 | ||
232 | die "Error: Unable to find unused loopback device" | |
233 | } | |
234 | ||
235 | # | |
236 | # This can be slightly dangerous because the loop devices we are | |
237 | # cleanup up may not be ours. However, if the devices are currently | |
238 | # in use we will not be able to remove them, and we only remove | |
239 | # devices which include 'zpool' in the name. So any damage we might | |
240 | # do should be limited to other zfs related testing. | |
241 | # | |
242 | cleanup_loop_devices() { | |
243 | local TMP_FILE=`mktemp` | |
244 | ||
245 | ${LOSETUP} -a | tr -d '()' >${TMP_FILE} | |
246 | ${AWK} -F":" -v losetup="$LOSETUP" \ | |
247 | '/zpool/ { system("losetup -d "$1) }' ${TMP_FILE} | |
248 | ${AWK} -F" " '/zpool/ { system("rm -f "$3) }' ${TMP_FILE} | |
249 | ||
250 | rm -f ${TMP_FILE} | |
251 | } | |
252 | ||
253 | # | |
254 | # The following udev helper functions assume that the provided | |
255 | # udev rules file will create a /dev/disk/zpool/<CHANNEL><RANK> | |
256 | # disk mapping. In this mapping each CHANNEL is represented by | |
257 | # the letters a-z, and the RANK is represented by the numbers | |
258 | # 1-n. A CHANNEL should identify a group of RANKS which are all | |
259 | # attached to a single controller, each RANK represents a disk. | |
260 | # This provides a simply mechanism to locate a specific drive | |
261 | # given a known hardware configuration. | |
262 | # | |
263 | udev_setup() { | |
264 | local SRC_PATH=$1 | |
265 | ||
266 | # When running in tree manually contruct symlinks in tree to | |
267 | # the proper devices. Symlinks are installed for all entires | |
268 | # in the config file regardless of if that device actually | |
269 | # exists. When installed as a package udev can be relied on for | |
270 | # this and it will only create links for devices which exist. | |
271 | if [ ${INTREE} ]; then | |
272 | PWD=`pwd` | |
273 | mkdir -p ${DEVDIR}/ | |
274 | cd ${DEVDIR}/ | |
275 | ${AWK} '!/^#/ && /./ { system( \ | |
276 | "ln -f -s /dev/disk/by-path/"$2" "$1";" \ | |
277 | "ln -f -s /dev/disk/by-path/"$2"-part1 "$1"p1;" \ | |
278 | "ln -f -s /dev/disk/by-path/"$2"-part9 "$1"p9;" \ | |
279 | ) }' $SRC_PATH | |
280 | cd ${PWD} | |
281 | else | |
282 | DST_FILE=`basename ${SRC_PATH} | cut -f1-2 -d'.'` | |
283 | DST_PATH=/etc/zfs/${DST_FILE} | |
284 | ||
285 | if [ -e ${DST_PATH} ]; then | |
286 | die "Error: Config ${DST_PATH} already exists" | |
287 | fi | |
288 | ||
289 | cp ${SRC_PATH} ${DST_PATH} | |
290 | ||
291 | if [ -f ${UDEVADM} ]; then | |
292 | ${UDEVADM} trigger | |
293 | ${UDEVADM} settle | |
294 | else | |
295 | /sbin/udevtrigger | |
296 | /sbin/udevsettle | |
297 | fi | |
298 | fi | |
299 | ||
300 | return 0 | |
301 | } | |
302 | ||
303 | udev_cleanup() { | |
304 | local SRC_PATH=$1 | |
305 | ||
306 | if [ ${INTREE} ]; then | |
307 | PWD=`pwd` | |
308 | cd ${DEVDIR}/ | |
309 | ${AWK} '!/^#/ && /./ { system( \ | |
310 | "rm -f "$1" "$1"p1 "$1"p9") }' $SRC_PATH | |
311 | cd ${PWD} | |
312 | fi | |
313 | ||
314 | return 0 | |
315 | } | |
316 | ||
317 | udev_cr2d() { | |
318 | local CHANNEL=`echo "obase=16; $1+96" | bc` | |
319 | local RANK=$2 | |
320 | ||
321 | printf "\x${CHANNEL}${RANK}" | |
322 | } | |
323 | ||
324 | udev_raid0_setup() { | |
325 | local RANKS=$1 | |
326 | local CHANNELS=$2 | |
327 | local IDX=0 | |
328 | ||
329 | RAID0S=() | |
330 | for RANK in `seq 1 ${RANKS}`; do | |
331 | for CHANNEL in `seq 1 ${CHANNELS}`; do | |
332 | DISK=`udev_cr2d ${CHANNEL} ${RANK}` | |
333 | RAID0S[${IDX}]="${DEVDIR}/${DISK}" | |
334 | let IDX=IDX+1 | |
335 | done | |
336 | done | |
337 | ||
338 | return 0 | |
339 | } | |
340 | ||
341 | udev_raid10_setup() { | |
342 | local RANKS=$1 | |
343 | local CHANNELS=$2 | |
344 | local IDX=0 | |
345 | ||
346 | RAID10S=() | |
347 | for RANK in `seq 1 ${RANKS}`; do | |
348 | for CHANNEL1 in `seq 1 2 ${CHANNELS}`; do | |
349 | let CHANNEL2=CHANNEL1+1 | |
350 | DISK1=`udev_cr2d ${CHANNEL1} ${RANK}` | |
351 | DISK2=`udev_cr2d ${CHANNEL2} ${RANK}` | |
352 | GROUP="${DEVDIR}/${DISK1} ${DEVDIR}/${DISK2}" | |
353 | RAID10S[${IDX}]="mirror ${GROUP}" | |
354 | let IDX=IDX+1 | |
355 | done | |
356 | done | |
357 | ||
358 | return 0 | |
359 | } | |
360 | ||
361 | udev_raidz_setup() { | |
362 | local RANKS=$1 | |
363 | local CHANNELS=$2 | |
364 | ||
365 | RAIDZS=() | |
366 | for RANK in `seq 1 ${RANKS}`; do | |
367 | RAIDZ=("raidz") | |
368 | ||
369 | for CHANNEL in `seq 1 ${CHANNELS}`; do | |
370 | DISK=`udev_cr2d ${CHANNEL} ${RANK}` | |
371 | RAIDZ[${CHANNEL}]="${DEVDIR}/${DISK}" | |
372 | done | |
373 | ||
374 | RAIDZS[${RANK}]="${RAIDZ[*]}" | |
375 | done | |
376 | ||
377 | return 0 | |
378 | } | |
379 | ||
380 | udev_raidz2_setup() { | |
381 | local RANKS=$1 | |
382 | local CHANNELS=$2 | |
383 | ||
384 | RAIDZ2S=() | |
385 | for RANK in `seq 1 ${RANKS}`; do | |
386 | RAIDZ2=("raidz2") | |
387 | ||
388 | for CHANNEL in `seq 1 ${CHANNELS}`; do | |
389 | DISK=`udev_cr2d ${CHANNEL} ${RANK}` | |
390 | RAIDZ2[${CHANNEL}]="${DEVDIR}/${DISK}" | |
391 | done | |
392 | ||
393 | RAIDZ2S[${RANK}]="${RAIDZ2[*]}" | |
394 | done | |
395 | ||
396 | return 0 | |
397 | } | |
325f0235 BB |
398 | |
399 | run_one_test() { | |
400 | local TEST_NUM=$1 | |
401 | local TEST_NAME=$2 | |
402 | ||
403 | printf "%-4d %-36s " ${TEST_NUM} "${TEST_NAME}" | |
404 | test_${TEST_NUM} | |
405 | } | |
406 | ||
407 | skip_one_test() { | |
408 | local TEST_NUM=$1 | |
409 | local TEST_NAME=$2 | |
410 | ||
411 | printf "%-4d %-36s " ${TEST_NUM} "${TEST_NAME}" | |
412 | skip | |
413 | } | |
414 | ||
415 | run_test() { | |
416 | local TEST_NUM=$1 | |
417 | local TEST_NAME=$2 | |
418 | ||
419 | for i in ${TESTS_SKIP[@]}; do | |
420 | if [[ $i == ${TEST_NUM} ]] ; then | |
421 | skip_one_test ${TEST_NUM} "${TEST_NAME}" | |
422 | return 0 | |
423 | fi | |
424 | done | |
425 | ||
426 | if [ "${TESTS_RUN[0]}" = "*" ]; then | |
427 | run_one_test ${TEST_NUM} "${TEST_NAME}" | |
428 | else | |
429 | for i in ${TESTS_RUN[@]}; do | |
430 | if [[ $i == ${TEST_NUM} ]] ; then | |
431 | run_one_test ${TEST_NUM} "${TEST_NAME}" | |
432 | return 0 | |
433 | fi | |
434 | done | |
435 | ||
436 | skip_one_test ${TEST_NUM} "${TEST_NAME}" | |
437 | fi | |
438 | } |