3 ############################################################################
5 # Script for running those SCST regression tests that can be run automatically.
7 # Copyright (C) 2008 Bart Van Assche <bart.vanassche@gmail.com>
9 # This program is free software; you can redistribute it and/or
10 # modify it under the terms of the GNU General Public License
11 # as published by the Free Software Foundation, version 2
14 # This program is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 ############################################################################
21 ############################################################################
22 # This script performs the following actions:
23 # - Creates a temporary directory for storing the output of the regression
24 # tests. No existing files are modified by this script.
25 # - Verifies whether the top-level *.patch files apply cleanly to the SCST
27 # - Duplicates the entire source tree to the temporary directory and
28 # compiles the SCST source code.
29 # - Duplicates the entire source tree to the temporary directory, applies
30 # the full-perf patches and again compiles the SCST source code.
31 # - Checks whether the specified kernel version is present
32 # in the directory specified through option -c.
33 # - If the source code of the specified kernel version is not present,
35 # - Convert the SCST source code into a kernel patch.
36 # - Extract the kernel sources.
37 # - Run checkpatch on the SCST kernel patch.
38 # - Apply the SCST kernel patch to the kernel tree.
39 # - Run 'make allmodconfig'.
40 # - Run the sparse source code checker on the SCST directory.
41 # - Run 'make headers_check'.
42 # - Compile the kernel tree.
43 # - Run 'make checkstack'.
44 # - Run 'make namespacecheck'.
45 # - Run 'make htmldocs'.
47 # Note: the results of the individual steps are not verified by this script
48 # -- the output generated by the individual steps has to be verified by
49 # reviewing the output files written into the temporary directory.
50 ############################################################################
53 ########################
54 # Function definitions #
55 ########################
58 echo "Usage: $0 [-c <dir>] [-d <dir>] [-f] [-h] [-j <jobs>] [-q] <kver1> <kver2> ..."
59 echo " -c - cache directory for Linux kernel tarballs."
60 echo " -d - directory for temporary regression test files."
61 echo " -f - full check -- do not only compile SCST but the whole" \
63 echo " -h - display this help information."
64 echo " -j - number of jobs that 'make' should run simultaneously."
65 echo " -k - remove temporary files before exiting."
66 echo " -q - download kernel sources silently."
67 echo " <kver1> <kver2> ... - kernel versions to test."
70 # First three components of the kernel version number.
71 function kernel_version {
72 echo "$1" | sed -n 's/^\([0-9]*\.[0-9]*\.[0-9]*\).*$/\1/p'
75 # Last component of the kernel version, or the empty string if $1 has only
78 echo "$1" | sed -n 's/^\([0-9]*\.[0-9]*\.[0-9]*\)[.-]\(.*\)$/\2/p'
81 # Create a linux-$1 tree in the current directory, where $1 is a kernel
82 # version number with either three or four components.
83 function extract_kernel_tree {
84 local kver="$(kernel_version $1)"
85 local plevel="$(patchlevel $1)"
86 local tmpdir=kernel-tree-tmp-$$
88 rm -rf "linux-$1" "${tmpdir}"
89 mkdir "${tmpdir}" || return $?
91 cd "${tmpdir}" || return $?
92 tar xjf "${kernel_sources}/linux-${kver}.tar.bz2" || return $?
93 cd "linux-${kver}" || return $?
94 if [ "${plevel}" != "" ]; then
95 bzip2 -cd "${kernel_sources}/patch-$1.bz2" \
96 | patch -p1 -f -s || return $?
99 mv "linux-${kver}" "../linux-$1" || return $?
100 if [ "$1" = "2.6.29" -o "$1" = "2.6.29.1" -o "$1" = "2.6.29.2" -o "$1" = "2.6.29.3" ]
102 cd "../linux-$1" || return $?
103 patch -f -s -p1 <<'EOF'
104 Make sure that branch profiling does not trigger sparse warnings.
105 See also http://bugzilla.kernel.org/show_bug.cgi?id=12925
107 See also http://lkml.org/lkml/2009/4/5/120
108 --- orig/linux-2.6.29/include/linux/compiler.h 2009-03-23 19:12:14.000000000 -0400
109 +++ linux-2.6.29/include/linux/compiler.h 2009-03-24 08:46:46.000000000 -0400
110 @@ -75,7 +75,8 @@ struct ftrace_branch_data {
111 * Note: DISABLE_BRANCH_PROFILING can be used by special lowlevel code
112 * to disable branch tracing on a per file basis.
114 -#if defined(CONFIG_TRACE_BRANCH_PROFILING) && !defined(DISABLE_BRANCH_PROFILING)
115 +#if defined(CONFIG_TRACE_BRANCH_PROFILING) \
116 + && !defined(DISABLE_BRANCH_PROFILING) && !defined(__CHECKER__)
117 void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
119 #define likely_notrace(x) __builtin_expect(!!(x), 1)
122 if [ "$1" = "2.6.31" -o "$1" = "2.6.31.1" -o "$1" = "2.6.31.2" -o "$1" = "2.6.31.3" ]
124 cd "../linux-$1" || return $?
125 patch -f -s -p1 <<'EOF'
126 Checking a 2.6.31.1 kernel configured with allyesconfig/allmodconfig
127 with sparse (make C=2) triggers a sparse warning on code that uses the
128 kmemcheck_annotate_bitfield() macro. An example of such a warning:
130 include/net/inet_sock.h:208:17: warning: do-while statement is not a compound statement
132 Signed-off-by: Bart Van Assche <bart.vanassche@gmail.com>
133 Cc: Vegard Nossum <vegardno@ifi.uio.no>
134 Cc: Andrew Morton <akpm@linux-foundation.org>
137 See also http://lkml.org/lkml/2009/9/26/51
139 --- linux-2.6.31.1/include/linux/kmemcheck-orig.h 2009-09-26 13:53:44.000000000 +0200
140 +++ linux-2.6.31.1/include/linux/kmemcheck.h 2009-09-26 13:53:56.000000000 +0200
141 @@ -137,13 +137,13 @@ static inline void kmemcheck_mark_initia
144 #define kmemcheck_annotate_bitfield(ptr, name) \
147 int _n = (long) &((ptr)->name##_end) \
148 - (long) &((ptr)->name##_begin); \
149 BUILD_BUG_ON(_n < 0); \
151 kmemcheck_mark_initialized(&((ptr)->name##_begin), _n); \
155 #define kmemcheck_annotate_variable(var) \
163 # Test whether the *.patch files in the SCST top-level directory apply cleanly
164 # to the SCST tree. Does not modify any files nor produce any output files.
165 function test_scst_tree_patches {
167 echo "Testing whether the SCST patches apply cleanly to the SCST tree ..."
168 for p in *.patch srpt/patches/scst_increase_max_tgt_cmds.patch
170 if ! patch -p0 -f --dry-run -s <$p &>/dev/null; then
171 echo "ERROR: patch $p does not apply cleanly."
175 if [ "${rc}" = 0 ]; then
180 # Copy the entire SCST source code tree from "$1" into the current directory.
181 # Only copy those files which are administered by Subversion.
182 function duplicate_scst_source_tree {
183 if [ -e "$1/AskingQuestions" ]; then
184 ( cd "$1" && svn status -v | cut -c41- \
185 | while read f; do [ ! -d "$f" ] && echo "$f"; done ) \
186 | tar -C "$1" --files-from=- -c -f - | tar -x -f -
192 # Compile the unpatched SCST source code.
193 function compile_scst_unpatched {
195 local outputfile="${outputdir}/compilation-output-unpatched.txt"
196 local workingdirectory="${outputdir}/scst-unpatched"
198 echo "Testing whether the SCST tree compiles fine ..."
200 if mkdir -p "${workingdirectory}" \
201 && cd "${workingdirectory}" \
202 && duplicate_scst_source_tree "${scst}" \
204 && make -s scst iscsi-scst \
205 && if "${scst_local}" = "true" ; then make -C scst_local clean; fi \
206 && if "${scst_local}" = "true" ; then make -C scst_local -s ; fi \
207 && if "${mpt_scst}" = "true" ; then make -C mpt clean; fi \
208 && if "${mpt_scst}" = "true" ; then make -C mpt -s ; fi \
209 && make -C srpt -s clean \
210 && make -C srpt -s ) \
220 # Test out-of-tree compilation agains the kernel header files in
221 # /lib/modules/$(uname -r)/build.
222 function compile_scst_patched {
224 local outputfile="${outputdir}/compilation-output-patched.txt"
225 local workingdirectory="${outputdir}/scst-patched"
227 echo "Testing whether the full-perf SCST tree compiles fine ..."
229 if mkdir -p "${workingdirectory}" \
230 && cd "${workingdirectory}" \
231 && duplicate_scst_source_tree "${scst}" \
232 && patch -p0 -f -s <"${scst}/iscsi-full_perf.patch" \
233 && patch -p0 -f -s <"${scst}/qla2x00t-full_perf.patch" \
234 && patch -p0 -f -s <"${scst}/scst-full_perf.patch" \
236 && make -s scst iscsi-scst \
237 && if "${scst_local}" = "true" ; then make -C scst_local clean; fi \
238 && if "${scst_local}" = "true" ; then make -C scst_local -s ; fi \
239 && if "${mpt_scst}" = "true" ; then make -C mpt clean; fi \
240 && if "${mpt_scst}" = "true" ; then make -C mpt -s ; fi \
241 && make -C srpt -s clean \
242 && make -C srpt -s ) \
252 # Download the file from URL $1 and save it in the current directory.
253 function download_file {
254 if [ ! -e "$(basename "$1")" ]; then
255 if [ "${quiet_download}" = "false" ]; then
256 echo "Downloading $1 ..."
258 if ! wget -q -nc "$1"; then
259 echo "Downloading $1 failed."
265 # Make sure the kernel tarball and patch file are present in directory
266 # ${kernel_sources}. Download any missing files from ${kernel_mirror}.
267 function download_kernel {
268 local kver="$(kernel_version $1)"
269 local plevel="$(patchlevel $1)"
271 mkdir -p "${kernel_sources}" || return $?
272 test -w "${kernel_sources}" || return $?
274 cd "${kernel_sources}" || return $?
275 download_file "${kernel_mirror}/linux-$(kernel_version $1).tar.bz2" \
277 if [ "${plevel}" != "" ]; then
278 download_file "${kernel_mirror}/patch-$1.bz2" || return $?
283 # Generate a kernel patch from the SCST source tree for kernel version $1.
284 function generate_kernel_patch {
285 local scst_dir="${PWD}"
286 local kver="$(kernel_version $1)"
287 local patchfile="${outputdir}/scst-$1-kernel.patch"
288 local patchfile_m="${outputdir}/scst-$1-kernel-matching-line-numbers.patch"
290 SIGNED_OFF_BY="..." \
291 scripts/generate-kernel-patch \
292 $([ "${scst_local}" = "true" ] && echo -- "-l") \
293 $([ "${mpt_scst}" = "true" ] && echo -- "-m") \
294 $([ "${qla2x00t}" = "true" ] && echo -- "-q") \
295 ${kver} > "${patchfile}"
297 SIGNED_OFF_BY="..." \
298 scripts/generate-kernel-patch \
300 $([ "${scst_local}" = "true" ] && echo -- "-l") \
301 $([ "${mpt_scst}" = "true" ] && echo -- "-m") \
302 $([ "${qla2x00t}" = "true" ] && echo -- "-q") \
303 ${kver} > "${patchfile_m}"
306 # Generate a kernel patch through scripts/generate-kernel-patch and test
307 # whether it applies cleanly to kernel version $1. Leaves a vanilla kernel
308 # in directory "${outputdir}/linux-$1" at exit.
309 function test_if_patch_applies_cleanly {
310 local kver="$(kernel_version $1)"
311 local plevel="$(patchlevel $1)"
312 local outputfile="${outputdir}/kernel-$1-patch-output.txt"
313 local patchfile="${outputdir}/scst-$1-kernel.patch"
316 echo "Testing whether the generated kernel patch applies cleanly ..."
317 ( cd "${outputdir}" && extract_kernel_tree "$1" )
318 ( cd "${outputdir}/linux-$1" \
319 && patch -p1 --dry-run -f < "${patchfile}" &> "${outputfile}" )
327 # Run checkpatch on the generated kernel patch. Assumes that there is a
328 # vanilla kernel tree present in directory "${outputdir}/linux-$1", and leaves
329 # this kernel tree clean.
330 function run_checkpatch {
331 local kver="$(kernel_version $1)"
332 local plevel="$(patchlevel $1)"
333 local outputfile="${outputdir}/checkpatch-$1-output.txt"
334 local patchfile="${outputdir}/scst-$1-kernel.patch"
336 if [ -e "${outputdir}/linux-$1/scripts/checkpatch.pl" ]
338 echo "Running checkpatch on the SCST kernel patch ..."
339 ( cd "${outputdir}/linux-$1" \
340 && scripts/checkpatch.pl - < "${patchfile}" &> "${outputfile}")
341 local errors=$(grep -c '^ERROR' "${outputfile}")
342 local warnings=$(grep -c '^WARNING' "${outputfile}")
343 echo "${errors} errors / ${warnings} warnings."
344 grep -E '^WARNING|^ERROR' "${outputfile}" | sort | uniq -c
346 echo "Skipping checkpatch step for kernel $1."
351 function patch_and_configure_kernel {
352 local patchfile="${outputdir}/scst-$1-kernel-matching-line-numbers.patch"
354 echo "Patching and configuring kernel ..."
356 cd "${outputdir}/linux-$1" \
357 && patch -p1 -f -s <"${patchfile}" \
358 >"${outputdir}/patch-command-output-$1.txt" \
359 && make -s allmodconfig &>/dev/null
363 # Patches and compiles a kernel tree. Assumes that there is a vanilla kernel
364 # tree present in directory "${outputdir}/linux-$1".
365 function compile_patched_kernel {
366 local kver="$(kernel_version $1)"
367 local plevel="$(patchlevel $1)"
368 local outputfile="${outputdir}/kernel-$1-compilation-output.txt"
370 echo "Compiling kernel $1 ..."
373 cd "${outputdir}/linux-$1" \
374 && LC_ALL=C make -s -k bzImage modules
377 echo "See also ${outputfile}."
381 # Compile subdirectory $2 of the patched kernel tree linux-$1.
382 function compile_kernel {
383 local kver="$(kernel_version $1)"
384 local plevel="$(patchlevel $1)"
385 local outputfile="${outputdir}/compilation-$1-output.txt"
388 echo "Compiling the patched kernel ..."
390 cd "${outputdir}/linux-$1" \
393 && LC_ALL=C make -k M="${subdir}"
395 local errors=$(grep -c ' error:' "${outputfile}")
396 local warnings=$(grep -c ' warning:' "${outputfile}")
397 echo "${errors} errors / ${warnings} warnings."
398 cat "${outputfile}" | grep -E 'warning:|error:' | sort | uniq -c
402 # Run the source code verification tool 'sparse' on the SCST code. Assumes that
403 # there is a patched kernel tree present in directory "${outputdir}/linux-$1".
404 # For more information about endianness annotations, see also
405 # http://lwn.net/Articles/205624/.
406 function run_sparse {
407 local kver="$(kernel_version $1)"
408 local plevel="$(patchlevel $1)"
409 local outputfile="${outputdir}/sparse-$1-output.txt"
412 echo "Running sparse on the patched kernel ..."
414 cd "${outputdir}/linux-$1" \
417 && LC_ALL=C make -k C=2 M="${subdir}" # CF=-D__CHECK_ENDIAN__
419 local errors=$(grep -c ' error:' "${outputfile}")
420 local warnings=$(grep -c ' warning:' "${outputfile}")
421 echo "${errors} errors / ${warnings} warnings."
422 cat "${outputfile}" \
423 | grep -E 'warning:|error:' \
424 | sed -e 's/^[^ ]*:[^ ]*:[^ ]*: //' \
425 -e "s/context imbalance in '[^']*':/context imbalance in <function>:/g" \
426 -e "s/context problem in '[^']*': '[^']*'/context problem in <function>: <function>/g" \
427 -e "s/function '[^']*'/function/g" \
428 -e "s/symbol '[^']*'/symbol/g" \
434 function run_checkstack {
435 local kver="$(kernel_version $1)"
436 local plevel="$(patchlevel $1)"
437 local outputfile="${outputdir}/checkstack-$1-output.txt"
439 echo "Running checkstack on the patched $1 kernel ..."
441 cd "${outputdir}/linux-$1" \
444 && LC_ALL=C make -k checkstack
446 echo "See also ${outputfile}."
450 function run_namespacecheck {
451 local kver="$(kernel_version $1)"
452 local plevel="$(patchlevel $1)"
453 local outputfile="${outputdir}/namespacecheck-$1-output.txt"
455 echo "Running namespacecheck on the patched $1 kernel ..."
457 cd "${outputdir}/linux-$1" \
460 && LC_ALL=C make -k namespacecheck
462 echo "See also ${outputfile}."
466 function run_headers_check {
467 local kver="$(kernel_version $1)"
468 local plevel="$(patchlevel $1)"
469 local outputfile="${outputdir}/headers_check-$1-output.txt"
471 echo "Running headers check on the patched $1 kernel ..."
473 cd "${outputdir}/linux-$1" \
476 && LC_ALL=C make -k headers_check
478 local errors=$(grep -c '^[^ ]' "${outputfile}")
479 echo "${errors} errors."
480 grep '^[^ ]' "${outputfile}" | sed 's/.*: //' | sort | uniq -c
484 function run_make_htmldocs {
485 local kver="$(kernel_version $1)"
486 local plevel="$(patchlevel $1)"
487 local outputfile="${outputdir}/htmldocs-$1-output.txt"
489 echo "Generating HTML documentation for the patched $1 kernel ..."
491 cd "${outputdir}/linux-$1" \
494 && LC_ALL=C make -k htmldocs
496 echo "See also ${outputfile}."
501 #########################
502 # Argument verification #
503 #########################
505 if [ ! -e scst -o ! -e iscsi-scst -o ! -e srpt ]; then
506 echo "Please run this script from inside the SCST subversion source tree."
511 # Where to store persistenly downloaded kernel tarballs and kernel patches.
512 kernel_sources="$HOME/software/downloads"
513 # URL for downloading kernel tarballs and kernel patches.
514 kernel_mirror="ftp://ftp.eu.kernel.org/pub/linux/kernel/v2.6"
516 # Directory in which the regression test output files will be stored. Must be
518 outputdir="${PWD}/regression-test-output-$(date +%Y-%m-%d_%Hh%Mm%Ss)"
519 # Driver configuration.
522 remove_temporary_files_at_end="false"
524 quiet_download="false"
526 set -- $(/usr/bin/getopt "c:d:fj:hkq" "$@")
527 while [ "$1" != "${1#-}" ]
530 '-c') kernel_sources="$2"; shift; shift;;
531 '-d') outputdir="$2"; shift; shift;;
532 '-f') full_check="true"; shift;;
533 '-h') usage; exit 1;;
534 '-j') export MAKEFLAGS="-j$2"; shift; shift;;
535 '-k') remove_temporary_files_at_end="true"; shift;;
536 '-q') quiet_download="true"; shift;;
544 # RHEL 4.x / CentOS 4.x has a kernel based on version 2.6.9.
545 # RHEL 5.x / CentOS 5.x has a kernel based on version 2.6.18.
546 # Ubuntu 8.04 (Hardy Heron) has a kernel based on version 2.6.24.
547 # Ubuntu 8.10 (Intrepid Ibex) has a kernel based on version 2.6.27.
548 # openSUSE 11.0 has a kernel based on version 2.6.25.
549 # openSUSE 11.1 has a kernel based on version 2.6.27.
550 #kernel_versions="2.6.23.17 2.6.24.7 2.6.25.20 2.6.26.8 2.6.27.21 2.6.28.9 2.6.29.1"
552 if [ "${kernel_versions}" = "" ]; then
562 if [ "$(type -p sparse)" = "" ]; then
563 echo "Error: sparse has not yet been installed."
564 echo "See also http://www.kernel.org/pub/software/devel/sparse/."
567 if ! mkdir -p "${outputdir}"; then
568 if [ -e "${outputdir}" ]; then
569 echo "Error: directory ${outputdir} already exists."
571 echo "Error: could not create directory ${outputdir}."
575 test_scst_tree_patches || exit $?
576 compile_scst_unpatched || exit $?
577 compile_scst_patched || exit $?
579 first_iteration="true"
580 for k in ${kernel_versions}
582 echo "===================="
583 printf "= kernel %-9s =\n" "${k}"
584 echo "===================="
586 download_kernel $k || continue
587 generate_kernel_patch $k || continue
588 test_if_patch_applies_cleanly $k || continue
589 if [ "${first_iteration}" = "true" ]; then
590 first_iteration="false"
592 patch_and_configure_kernel $k
593 run_sparse $k drivers/scst
595 patch_and_configure_kernel $k
596 compile_kernel $k drivers/scst
598 # run_headers_check $k
599 if [ "${full_check}" = "true" ]; then
600 compile_patched_kernel $k
602 run_namespacecheck $k
605 if [ "${remove_temporary_files_at_end}" = "true" ]; then
606 rm -rf "${outputdir}"
607 mkdir -p "${outputdir}"