]>
Commit | Line | Data |
---|---|---|
cae5b340 AX |
1 | #!/bin/bash |
2 | # | |
3 | # CDDL HEADER START | |
4 | # | |
5 | # The contents of this file are subject to the terms of the | |
6 | # Common Development and Distribution License, Version 1.0 only | |
7 | # (the "License"). You may not use this file except in compliance | |
8 | # with the License. | |
9 | # | |
10 | # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE | |
11 | # or http://www.opensolaris.org/os/licensing. | |
12 | # See the License for the specific language governing permissions | |
13 | # and limitations under the License. | |
14 | # | |
15 | # When distributing Covered Code, include this CDDL HEADER in each | |
16 | # file and include the License file at usr/src/OPENSOLARIS.LICENSE. | |
17 | # If applicable, add the following below this CDDL HEADER, with the | |
18 | # fields enclosed by brackets "[]" replaced with your own identifying | |
19 | # information: Portions Copyright [yyyy] [name of copyright owner] | |
20 | # | |
21 | # CDDL HEADER END | |
22 | # | |
23 | basedir=$(dirname "$0") | |
24 | ||
25 | SCRIPT_COMMON=common.sh | |
26 | if [ -f "${basedir}/${SCRIPT_COMMON}" ]; then | |
27 | . "${basedir}/${SCRIPT_COMMON}" | |
28 | else | |
29 | echo "Missing helper script ${SCRIPT_COMMON}" && exit 1 | |
30 | fi | |
31 | ||
32 | PROG=zfs-tests.sh | |
33 | VERBOSE= | |
34 | QUIET= | |
35 | CLEANUP=1 | |
36 | CLEANUPALL=0 | |
37 | LOOPBACK=1 | |
38 | FILESIZE="4G" | |
39 | RUNFILE=${RUNFILE:-"linux.run"} | |
40 | FILEDIR=${FILEDIR:-/var/tmp} | |
41 | DISKS=${DISKS:-""} | |
42 | SINGLETEST=() | |
43 | SINGLETESTUSER="root" | |
41d74433 AX |
44 | TAGS="functional" |
45 | ITERATIONS=1 | |
cae5b340 AX |
46 | ZFS_DBGMSG="$STF_SUITE/callbacks/zfs_dbgmsg.ksh" |
47 | ZFS_DMESG="$STF_SUITE/callbacks/zfs_dmesg.ksh" | |
48 | ZFS_MMP="$STF_SUITE/callbacks/zfs_mmp.ksh" | |
49 | TESTFAIL_CALLBACKS=${TESTFAIL_CALLBACKS:-"$ZFS_DBGMSG:$ZFS_DMESG:$ZFS_MMP"} | |
50 | ||
51 | # | |
52 | # Attempt to remove loopback devices and files which where created earlier | |
53 | # by this script to run the test framework. The '-k' option may be passed | |
54 | # to the script to suppress cleanup for debugging purposes. | |
55 | # | |
56 | cleanup() { | |
57 | if [ $CLEANUP -eq 0 ]; then | |
58 | return 0 | |
59 | fi | |
60 | ||
61 | if [ $LOOPBACK -eq 1 ]; then | |
62 | for TEST_LOOPBACK in ${LOOPBACKS}; do | |
63 | LOOP_DEV=$(basename "$TEST_LOOPBACK") | |
64 | DM_DEV=$(sudo "${DMSETUP}" ls 2>/dev/null | \ | |
65 | grep "${LOOP_DEV}" | cut -f1) | |
66 | ||
67 | if [ -n "$DM_DEV" ]; then | |
68 | sudo "${DMSETUP}" remove "${DM_DEV}" || | |
69 | echo "Failed to remove: ${DM_DEV}" | |
70 | fi | |
71 | ||
72 | if [ -n "${TEST_LOOPBACK}" ]; then | |
73 | sudo "${LOSETUP}" -d "${TEST_LOOPBACK}" || | |
74 | echo "Failed to remove: ${TEST_LOOPBACK}" | |
75 | fi | |
76 | done | |
77 | fi | |
78 | ||
79 | for TEST_FILE in ${FILES}; do | |
80 | rm -f "${TEST_FILE}" &>/dev/null | |
81 | done | |
82 | ||
83 | # Preserve in-tree symlinks to aid debugging. | |
84 | if [ -z "${INTREE}" ] && [ -d "$STF_PATH" ]; then | |
85 | rm -Rf "$STF_PATH" | |
86 | fi | |
87 | } | |
88 | trap cleanup EXIT | |
89 | ||
90 | # | |
91 | # Attempt to remove all testpools (testpool.XXX), unopened dm devices, | |
92 | # loopback devices, and files. This is a useful way to cleanup a previous | |
93 | # test run failure which has left the system in an unknown state. This can | |
94 | # be dangerous and should only be used in a dedicated test environment. | |
95 | # | |
96 | cleanup_all() { | |
97 | local TEST_POOLS | |
98 | TEST_POOLS=$(sudo "$ZPOOL" list -H -o name | grep testpool) | |
99 | local TEST_LOOPBACKS | |
100 | TEST_LOOPBACKS=$(sudo "${LOSETUP}" -a|grep file-vdev|cut -f1 -d:) | |
101 | local TEST_FILES | |
102 | TEST_FILES=$(ls /var/tmp/file-vdev* 2>/dev/null) | |
103 | ||
104 | msg | |
105 | msg "--- Cleanup ---" | |
106 | msg "Removing pool(s): $(echo "${TEST_POOLS}" | tr '\n' ' ')" | |
107 | for TEST_POOL in $TEST_POOLS; do | |
108 | sudo "$ZPOOL" destroy "${TEST_POOL}" | |
109 | done | |
110 | ||
111 | msg "Removing dm(s): $(sudo "${DMSETUP}" ls | | |
112 | grep loop | tr '\n' ' ')" | |
113 | sudo "${DMSETUP}" remove_all | |
114 | ||
115 | msg "Removing loopback(s): $(echo "${TEST_LOOPBACKS}" | tr '\n' ' ')" | |
116 | for TEST_LOOPBACK in $TEST_LOOPBACKS; do | |
117 | sudo "${LOSETUP}" -d "${TEST_LOOPBACK}" | |
118 | done | |
119 | ||
120 | msg "Removing files(s): $(echo "${TEST_FILES}" | tr '\n' ' ')" | |
121 | for TEST_FILE in $TEST_FILES; do | |
122 | sudo rm -f "${TEST_FILE}" | |
123 | done | |
124 | } | |
125 | ||
126 | # | |
127 | # Log a failure message, cleanup, and return an error. | |
128 | # | |
129 | fail() { | |
130 | echo -e "${PROG}: $1" >&2 | |
131 | cleanup | |
132 | exit 1 | |
133 | } | |
134 | ||
135 | # | |
136 | # Takes a name as the only arguments and looks for the following variations | |
137 | # on that name. If one is found it is returned. | |
138 | # | |
139 | # $RUNFILEDIR/<name> | |
140 | # $RUNFILEDIR/<name>.run | |
141 | # <name> | |
142 | # <name>.run | |
143 | # | |
144 | find_runfile() { | |
145 | local NAME=$1 | |
146 | local RESULT="" | |
147 | ||
148 | if [ -f "$RUNFILEDIR/$NAME" ]; then | |
149 | RESULT="$RUNFILEDIR/$NAME" | |
150 | elif [ -f "$RUNFILEDIR/$NAME.run" ]; then | |
151 | RESULT="$RUNFILEDIR/$NAME.run" | |
152 | elif [ -f "$NAME" ]; then | |
153 | RESULT="$NAME" | |
154 | elif [ -f "$NAME.run" ]; then | |
155 | RESULT="$NAME.run" | |
156 | fi | |
157 | ||
158 | echo "$RESULT" | |
159 | } | |
160 | ||
161 | # | |
162 | # Symlink file if it appears under any of the given paths. | |
163 | # | |
164 | create_links() { | |
165 | local dir_list="$1" | |
166 | local file_list="$2" | |
167 | ||
168 | [ -n "$STF_PATH" ] || fail "STF_PATH wasn't correctly set" | |
169 | ||
170 | for i in $file_list; do | |
171 | for j in $dir_list; do | |
172 | [ ! -e "$STF_PATH/$i" ] || continue | |
173 | ||
174 | if [ ! -d "$j/$i" ] && [ -e "$j/$i" ]; then | |
175 | ln -s "$j/$i" "$STF_PATH/$i" || \ | |
176 | fail "Couldn't link $i" | |
177 | break | |
178 | fi | |
179 | done | |
180 | ||
181 | [ ! -e "$STF_PATH/$i" ] && STF_MISSING_BIN="$STF_MISSING_BIN$i " | |
182 | done | |
183 | } | |
184 | ||
185 | # | |
186 | # Constrain the path to limit the available binaries to a known set. | |
187 | # When running in-tree a top level ./bin/ directory is created for | |
188 | # convenience, otherwise a temporary directory is used. | |
189 | # | |
190 | constrain_path() { | |
191 | . "$STF_SUITE/include/commands.cfg" | |
192 | ||
193 | if [ -n "${INTREE}" ]; then | |
194 | STF_PATH="$BUILDDIR/bin" | |
195 | if [ ! -d "$STF_PATH" ]; then | |
196 | mkdir "$STF_PATH" | |
197 | fi | |
198 | else | |
199 | SYSTEMDIR=${SYSTEMDIR:-/var/tmp/constrained_path.XXXX} | |
200 | STF_PATH=$(/bin/mktemp -d "$SYSTEMDIR") | |
201 | fi | |
202 | ||
203 | STF_MISSING_BIN="" | |
204 | chmod 755 "$STF_PATH" || fail "Couldn't chmod $STF_PATH" | |
205 | ||
206 | # Standard system utilities | |
207 | create_links "/bin /usr/bin /sbin /usr/sbin" "$SYSTEM_FILES" | |
208 | ||
209 | if [ -z "${INTREE}" ]; then | |
210 | # Special case links for standard zfs utilities | |
211 | create_links "/bin /usr/bin /sbin /usr/sbin" "$ZFS_FILES" | |
212 | ||
213 | # Special case links for zfs test suite utilties | |
214 | create_links "$TESTSDIR/bin" "$ZFSTEST_FILES" | |
215 | else | |
216 | # Special case links for standard zfs utilities | |
217 | DIRS="$(find "$CMDDIR" -type d \( ! -name .deps -a \ | |
218 | ! -name .libs \) -print | tr '\n' ' ')" | |
219 | create_links "$DIRS" "$ZFS_FILES" | |
220 | ||
221 | # Special case links for zfs test suite utilties | |
222 | DIRS="$(find "$TESTSDIR" -type d \( ! -name .deps -a \ | |
223 | ! -name .libs \) -print | tr '\n' ' ')" | |
224 | create_links "$DIRS" "$ZFSTEST_FILES" | |
225 | fi | |
226 | ||
227 | # Exceptions | |
228 | ln -fs "$STF_PATH/awk" "$STF_PATH/nawk" | |
229 | ln -fs /sbin/fsck.ext4 "$STF_PATH/fsck" | |
230 | ln -fs /sbin/mkfs.ext4 "$STF_PATH/newfs" | |
231 | ln -fs "$STF_PATH/gzip" "$STF_PATH/compress" | |
232 | ln -fs "$STF_PATH/gunzip" "$STF_PATH/uncompress" | |
233 | ln -fs "$STF_PATH/exportfs" "$STF_PATH/share" | |
234 | ln -fs "$STF_PATH/exportfs" "$STF_PATH/unshare" | |
235 | } | |
236 | ||
237 | # | |
238 | # Output a useful usage message. | |
239 | # | |
240 | usage() { | |
241 | cat << EOF | |
242 | USAGE: | |
243 | $0 [hvqxkf] [-s SIZE] [-r RUNFILE] [-t PATH] [-u USER] | |
244 | ||
245 | DESCRIPTION: | |
246 | ZFS Test Suite launch script | |
247 | ||
248 | OPTIONS: | |
249 | -h Show this message | |
250 | -v Verbose zfs-tests.sh output | |
251 | -q Quiet test-runner output | |
252 | -x Remove all testpools, dm, lo, and files (unsafe) | |
253 | -k Disable cleanup after test failure | |
254 | -f Use files only, disables block device tests | |
41d74433 AX |
255 | -c Only create and populate constrained path |
256 | -I NUM Number of iterations | |
cae5b340 AX |
257 | -d DIR Use DIR for files and loopback devices |
258 | -s SIZE Use vdevs of SIZE (default: 4G) | |
259 | -r RUNFILE Run tests in RUNFILE (default: linux.run) | |
260 | -t PATH Run single test at PATH relative to test suite | |
41d74433 | 261 | -T TAGS Comma separated list of tags |
cae5b340 AX |
262 | -u USER Run single test as USER (default: root) |
263 | ||
264 | EXAMPLES: | |
265 | # Run the default (linux) suite of tests and output the configuration used. | |
266 | $0 -v | |
267 | ||
268 | # Run a smaller suite of tests designed to run more quickly. | |
269 | $0 -r linux-fast | |
270 | ||
271 | # Cleanup a previous run of the test suite prior to testing, run the | |
272 | # default (linux) suite of tests and perform no cleanup on exit. | |
273 | $0 -x | |
274 | ||
275 | EOF | |
276 | } | |
277 | ||
41d74433 | 278 | while getopts 'hvqxkfcd:s:r:?t:T:u:I:' OPTION; do |
cae5b340 AX |
279 | case $OPTION in |
280 | h) | |
281 | usage | |
282 | exit 1 | |
283 | ;; | |
284 | v) | |
285 | # shellcheck disable=SC2034 | |
286 | VERBOSE=1 | |
287 | ;; | |
288 | q) | |
289 | QUIET="-q" | |
290 | ;; | |
291 | x) | |
292 | CLEANUPALL=1 | |
293 | ;; | |
294 | k) | |
295 | CLEANUP=0 | |
296 | ;; | |
297 | f) | |
298 | LOOPBACK=0 | |
299 | ;; | |
300 | d) | |
301 | FILEDIR="$OPTARG" | |
302 | ;; | |
41d74433 AX |
303 | I) |
304 | ITERATIONS="$OPTARG" | |
305 | if [ "$ITERATIONS" -le 0 ]; then | |
306 | fail "Iterations must be greater than 0." | |
307 | fi | |
308 | ;; | |
cae5b340 AX |
309 | s) |
310 | FILESIZE="$OPTARG" | |
311 | ;; | |
312 | r) | |
313 | RUNFILE="$OPTARG" | |
314 | ;; | |
315 | t) | |
316 | if [ ${#SINGLETEST[@]} -ne 0 ]; then | |
317 | fail "-t can only be provided once." | |
318 | fi | |
319 | SINGLETEST+=("$OPTARG") | |
320 | ;; | |
41d74433 AX |
321 | T) |
322 | TAGS="$OPTARG" | |
323 | ;; | |
cae5b340 AX |
324 | u) |
325 | SINGLETESTUSER="$OPTARG" | |
326 | ;; | |
327 | ?) | |
328 | usage | |
329 | exit | |
330 | ;; | |
331 | esac | |
332 | done | |
333 | ||
334 | shift $((OPTIND-1)) | |
335 | ||
336 | FILES=${FILES:-"$FILEDIR/file-vdev0 $FILEDIR/file-vdev1 $FILEDIR/file-vdev2"} | |
337 | LOOPBACKS=${LOOPBACKS:-""} | |
338 | ||
339 | if [ ${#SINGLETEST[@]} -ne 0 ]; then | |
340 | RUNFILEDIR="/var/tmp" | |
341 | RUNFILE="zfs-tests.$$.run" | |
342 | SINGLEQUIET="False" | |
343 | ||
344 | if [ -n "$QUIET" ]; then | |
345 | SINGLEQUIET="True" | |
346 | fi | |
347 | ||
348 | cat >$RUNFILEDIR/$RUNFILE << EOF | |
349 | [DEFAULT] | |
350 | pre = | |
351 | quiet = $SINGLEQUIET | |
352 | pre_user = root | |
353 | user = $SINGLETESTUSER | |
354 | timeout = 600 | |
355 | post_user = root | |
356 | post = | |
357 | outputdir = /var/tmp/test_results | |
358 | EOF | |
359 | for t in "${SINGLETEST[@]}" | |
360 | do | |
361 | SINGLETESTDIR=$(dirname "$t") | |
362 | SINGLETESTFILE=$(basename "$t") | |
363 | SETUPSCRIPT= | |
364 | CLEANUPSCRIPT= | |
365 | ||
366 | if [ -f "$STF_SUITE/$SINGLETESTDIR/setup.ksh" ]; then | |
367 | SETUPSCRIPT="setup" | |
368 | fi | |
369 | ||
370 | if [ -f "$STF_SUITE/$SINGLETESTDIR/cleanup.ksh" ]; then | |
371 | CLEANUPSCRIPT="cleanup" | |
372 | fi | |
373 | ||
374 | cat >>$RUNFILEDIR/$RUNFILE << EOF | |
375 | ||
376 | [$SINGLETESTDIR] | |
377 | tests = ['$SINGLETESTFILE'] | |
378 | pre = $SETUPSCRIPT | |
379 | post = $CLEANUPSCRIPT | |
380 | EOF | |
381 | done | |
382 | fi | |
383 | ||
384 | # | |
385 | # Attempt to locate the runfile describing the test workload. | |
386 | # | |
387 | if [ -n "$RUNFILE" ]; then | |
388 | SAVED_RUNFILE="$RUNFILE" | |
389 | RUNFILE=$(find_runfile "$RUNFILE") | |
390 | [ -z "$RUNFILE" ] && fail "Cannot find runfile: $SAVED_RUNFILE" | |
391 | fi | |
392 | ||
393 | if [ ! -r "$RUNFILE" ]; then | |
394 | fail "Cannot read runfile: $RUNFILE" | |
395 | fi | |
396 | ||
397 | # | |
398 | # This script should not be run as root. Instead the test user, which may | |
399 | # be a normal user account, needs to be configured such that it can | |
400 | # run commands via sudo passwordlessly. | |
401 | # | |
402 | if [ "$(id -u)" = "0" ]; then | |
403 | fail "This script must not be run as root." | |
404 | fi | |
405 | ||
406 | if [ "$(sudo whoami)" != "root" ]; then | |
407 | fail "Passwordless sudo access required." | |
408 | fi | |
409 | ||
410 | # | |
411 | # Constain the available binaries to a known set. | |
412 | # | |
413 | constrain_path | |
414 | ||
415 | # | |
416 | # Check if ksh exists | |
417 | # | |
418 | [ -e "$STF_PATH/ksh" ] || fail "This test suite requires ksh." | |
419 | [ -e "$STF_SUITE/include/default.cfg" ] || fail \ | |
420 | "Missing $STF_SUITE/include/default.cfg file." | |
421 | ||
422 | # | |
423 | # Verify the ZFS module stack if loaded. | |
424 | # | |
425 | sudo "${ZFS_SH}" &>/dev/null | |
426 | ||
427 | # | |
428 | # Attempt to cleanup all previous state for a new test run. | |
429 | # | |
430 | if [ $CLEANUPALL -ne 0 ]; then | |
431 | cleanup_all | |
432 | fi | |
433 | ||
434 | # | |
435 | # By default preserve any existing pools | |
436 | # | |
437 | if [ -z "${KEEP}" ]; then | |
438 | KEEP=$(sudo "$ZPOOL" list -H -o name) | |
439 | if [ -z "${KEEP}" ]; then | |
440 | KEEP="rpool" | |
441 | fi | |
442 | fi | |
443 | ||
444 | __ZFS_POOL_EXCLUDE="$(echo $KEEP | sed ':a;N;s/\n/ /g;ba')" | |
445 | ||
446 | . "$STF_SUITE/include/default.cfg" | |
447 | ||
448 | msg | |
449 | msg "--- Configuration ---" | |
450 | msg "Runfile: $RUNFILE" | |
451 | msg "STF_TOOLS: $STF_TOOLS" | |
452 | msg "STF_SUITE: $STF_SUITE" | |
453 | msg "STF_PATH: $STF_PATH" | |
454 | ||
455 | # | |
456 | # No DISKS have been provided so a basic file or loopback based devices | |
457 | # must be created for the test suite to use. | |
458 | # | |
459 | if [ -z "${DISKS}" ]; then | |
460 | # | |
461 | # Create sparse files for the test suite. These may be used | |
462 | # directory or have loopback devices layered on them. | |
463 | # | |
464 | for TEST_FILE in ${FILES}; do | |
465 | [ -f "$TEST_FILE" ] && fail "Failed file exists: ${TEST_FILE}" | |
466 | truncate -s "${FILESIZE}" "${TEST_FILE}" || | |
467 | fail "Failed creating: ${TEST_FILE} ($?)" | |
468 | DISKS="$DISKS$TEST_FILE " | |
469 | done | |
470 | ||
471 | # | |
472 | # If requested setup loopback devices backed by the sparse files. | |
473 | # | |
474 | if [ $LOOPBACK -eq 1 ]; then | |
475 | DISKS="" | |
476 | check_loop_utils | |
477 | ||
478 | for TEST_FILE in ${FILES}; do | |
479 | TEST_LOOPBACK=$(sudo "${LOSETUP}" -f) | |
480 | sudo "${LOSETUP}" "${TEST_LOOPBACK}" "${TEST_FILE}" || | |
481 | fail "Failed: ${TEST_FILE} -> ${TEST_LOOPBACK}" | |
482 | LOOPBACKS="${LOOPBACKS}${TEST_LOOPBACK} " | |
483 | BASELOOPBACKS=$(basename "$TEST_LOOPBACK") | |
484 | DISKS="$DISKS$BASELOOPBACKS " | |
485 | done | |
486 | fi | |
487 | fi | |
488 | ||
489 | NUM_DISKS=$(echo "${DISKS}" | $AWK '{print NF}') | |
490 | [ "$NUM_DISKS" -lt 3 ] && fail "Not enough disks ($NUM_DISKS/3 minimum)" | |
491 | ||
492 | # | |
493 | # Disable SELinux until the ZFS Test Suite has been updated accordingly. | |
494 | # | |
495 | if [ -x "$STF_PATH/setenforce" ]; then | |
496 | sudo setenforce permissive &>/dev/null | |
497 | fi | |
498 | ||
499 | # | |
500 | # Enable internal ZFS debug log and clear it. | |
501 | # | |
502 | if [ -e /sys/module/zfs/parameters/zfs_dbgmsg_enable ]; then | |
503 | sudo /bin/sh -c "echo 1 >/sys/module/zfs/parameters/zfs_dbgmsg_enable" | |
504 | sudo /bin/sh -c "echo 0 >/proc/spl/kstat/zfs/dbgmsg" | |
505 | fi | |
506 | ||
507 | msg "FILEDIR: $FILEDIR" | |
508 | msg "FILES: $FILES" | |
509 | msg "LOOPBACKS: $LOOPBACKS" | |
510 | msg "DISKS: $DISKS" | |
511 | msg "NUM_DISKS: $NUM_DISKS" | |
512 | msg "FILESIZE: $FILESIZE" | |
41d74433 AX |
513 | msg "ITERATIONS: $ITERATIONS" |
514 | msg "TAGS: $TAGS" | |
cae5b340 AX |
515 | msg "Keep pool(s): $KEEP" |
516 | msg "Missing util(s): $STF_MISSING_BIN" | |
517 | msg "" | |
518 | ||
519 | export STF_TOOLS | |
520 | export STF_SUITE | |
521 | export STF_PATH | |
522 | export DISKS | |
523 | export KEEP | |
524 | export __ZFS_POOL_EXCLUDE | |
525 | export TESTFAIL_CALLBACKS | |
526 | export PATH=$STF_PATH | |
527 | ||
41d74433 AX |
528 | msg "${TEST_RUNNER} ${QUIET} -c ${RUNFILE} -T ${TAGS} -i ${STF_SUITE}" \ |
529 | "-I ${ITERATIONS}" | |
530 | ${TEST_RUNNER} ${QUIET} -c "${RUNFILE}" -T "${TAGS}" -i "${STF_SUITE}" \ | |
531 | -I "${ITERATIONS}" | |
cae5b340 AX |
532 | RESULT=$? |
533 | echo | |
534 | ||
535 | if [ ${#SINGLETEST[@]} -ne 0 ]; then | |
536 | rm -f "$RUNFILE" &>/dev/null | |
537 | fi | |
538 | ||
539 | exit ${RESULT} |