Add linux kernel device support
[zfs.git] / scripts / common.sh.in
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=@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
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
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() {
93         echo -e "${COLOR_GREEN}Pass${COLOR_RESET}"
94 }
95
96 fail() {
97         echo -e "${COLOR_RED}Fail${COLOR_RESET} ($1)"
98         exit $1
99 }
100
101 skip() {
102         echo -e "${COLOR_BROWN}Skip${COLOR_RESET}"
103 }
104
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 }
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 }