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