From 7cfa8f9f0e4d4be101d742f989354793b261ab44 Mon Sep 17 00:00:00 2001 From: Gleb Chesnokov Date: Thu, 28 May 2026 17:29:36 +0300 Subject: [PATCH 1/2] scripts/run-regression-tests: Add option to skip module builds Allow per-kernel -nb suffix to run patch generation, kernel configuration and static analysis without compiling the patched SCST modules. --- scripts/run-regression-tests | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/scripts/run-regression-tests b/scripts/run-regression-tests index f16ab18ba..f03d23470 100755 --- a/scripts/run-regression-tests +++ b/scripts/run-regression-tests @@ -39,7 +39,7 @@ # - Run 'make allmodconfig'. # - Run the sparse source code checker on the SCST directory. # - Run 'make headers_check'. -# - Compile the kernel tree. +# - Optionally compile the patched SCST kernel modules. # - Run 'make checkstack'. # - Run 'make namespacecheck'. # - Run 'make htmldocs'. @@ -58,14 +58,26 @@ source "$(dirname "$0")/kernel-functions" function usage { - echo "Usage: $0 [-c ] [-d ] [-f] [-h] [-j ] [-p ] [-q] ..." + echo "Usage: $0 [-c ] [-d ] [-h] [-j ] [-k] [-l] [-p] [-q] ..." echo " -c - cache directory for Linux kernel tarballs." echo " -d - directory for temporary regression test files." echo " -h - display this help information." echo " -j - number of jobs that 'make' should run simultaneously." echo " -k - remove temporary files before exiting." + echo " -l - skip local SCST compilation and package build tests." + echo " -p - generate multiple patches instead of one big patch." echo " -q - download kernel sources silently." echo " ... - kernel versions to test." + echo " Per-kernel suffixes:" + echo " -4 - disable IPv6." + echo " -f - run full kernel checks." + echo " -i - also run sparse on IBM VIO related SCSI code." + echo " -nb - skip patched SCST kernel module compilation." + echo " -nc - skip checkpatch." + echo " -nm - skip smatch." + echo " -ns - skip sparse." + echo " -p - generate multiple patches for this kernel." + echo " -u - enable GENERATING_UPSTREAM_PATCH." } # Test whether the *.patch files in the SCST top-level directory apply cleanly @@ -652,6 +664,7 @@ do run_checkpatch="true" run_sparse="true" run_smatch="true" + run_module_compilation="true" ipv6="true" global_multiple_patches="${multiple_patches}" while true; do @@ -664,6 +677,7 @@ do '-4') ipv6="false";; '-f') full_check="true";; '-i') ibmvio="true";; + '-nb') run_module_compilation="false";; '-nc') run_checkpatch="false";; '-ns') run_sparse="false";; '-nm') run_smatch="false";; @@ -718,7 +732,11 @@ do if [ "${run_smatch}" = "true" ]; then run_smatch "$k" "${subdirs[@]}" fi - compile_kernel "$k" "${subdirs[@]}" + if [ "${run_module_compilation}" = "true" ]; then + compile_kernel "$k" "${subdirs[@]}" + else + echo "Skipping patched SCST kernel module compilation." + fi if [ "${full_check}" = "true" ]; then run_headers_check "$k" compile_patched_kernel "$k" From 736651c6300d5b3b39afd9aeaf341e06e159f6ef Mon Sep 17 00:00:00 2001 From: Gleb Chesnokov Date: Thu, 28 May 2026 17:48:30 +0300 Subject: [PATCH 2/2] github: Add sparse and smatch workflow Run run-regression-tests in analyzer-only mode for push and pull request events. Report findings as warnings and upload logs for review. --- .github/workflows/static_analysis.yml | 306 ++++++++++++++++++++++++++ 1 file changed, 306 insertions(+) create mode 100644 .github/workflows/static_analysis.yml diff --git a/.github/workflows/static_analysis.yml b/.github/workflows/static_analysis.yml new file mode 100644 index 000000000..b582071ed --- /dev/null +++ b/.github/workflows/static_analysis.yml @@ -0,0 +1,306 @@ +name: Static analysis + +on: + push: + branches: + - master + pull_request: + branches: + - master + workflow_dispatch: + inputs: + kernel_version: + description: Kernel version to pass to scripts/run-regression-tests. + required: false + default: '7.0' + type: string + +permissions: + contents: read + +defaults: + run: + shell: bash + +concurrency: + group: ${{github.workflow}}-${{github.event.pull_request.number || github.ref}} + cancel-in-progress: true + +jobs: + sparse_smatch: + name: sparse and smatch + runs-on: ubuntu-latest + timeout-minutes: 120 + env: + KERNEL_VERSION: ${{github.event.inputs.kernel_version || '7.0'}} + steps: + - name: Checkout code + uses: actions/checkout@v5 + + - name: Select kernel version + id: kernel + run: | + artifact_kernel="$(printf '%s' "${KERNEL_VERSION}" | + tr -c 'A-Za-z0-9._-' '-')" + + echo "artifact-name=static-analysis-${artifact_kernel}" \ + >> "${GITHUB_OUTPUT}" + echo "Kernel version: ${KERNEL_VERSION}" >> "${GITHUB_STEP_SUMMARY}" + + - name: Cache kernel sources + uses: actions/cache@v5 + with: + path: ~/.cache/scst-kernels + key: scst-kernels-${{runner.os}}-${{env.KERNEL_VERSION}} + restore-keys: | + scst-kernels-${{runner.os}}- + + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y \ + bc \ + bison \ + build-essential \ + flex \ + libelf-dev \ + libsqlite3-dev \ + libssl-dev \ + sparse \ + wget \ + xz-utils + + - name: Install smatch + run: | + git clone --depth=1 https://github.com/error27/smatch.git + make -j"$(nproc)" -C smatch + sudo BINDIR=/bin SHAREDIR=/home/runner/share make -C smatch install + + - name: Run sparse and smatch + run: | + set -u + + workdir="${RUNNER_TEMP}/scst-static-analysis" + artifactdir="${RUNNER_TEMP}/scst-static-analysis-artifacts" + raw_log="${workdir}/run-regression-tests.log" + log="${artifactdir}/run-regression-tests.log" + path_list="${artifactdir}/scst-analysis-paths.txt" + + append_summary() { + printf '%s\n' "$@" >> "${GITHUB_STEP_SUMMARY}" + } + + print_progress_log() { + awk ' + /^[[:space:]]*[0-9]+ errors? \/ [0-9]+ warnings?\.$/ { + next + } + + / info:| warning:| warn:| error:/ { + next + } + + /^make\[[0-9]+\]: (Entering|Leaving) directory/ { + next + } + + /^[[:space:]]*(CC|CHECK|LD|MODPOST)[[:space:]\[]/ { + next + } + + /^[[:space:]]*WARNING:/ { + next + } + + { + print + } + ' + } + + build_scst_path_list() { + { + printf '%s\n' \ + 'drivers/scst/' \ + 'include/scst/' \ + 'dev_handlers/' \ + 'fcst/' \ + 'iscsi-scst/' \ + 'srpt/' \ + 'scst_local/' + + while IFS= read -r -d '' patch; do + # shellcheck disable=SC2016 + awk ' + function emit_path(path, alias) { + if (path == "" || path == "/dev/null") + return + + print path + if (path !~ /[.][ch]$/) + return + + alias = path + sub(/^drivers\/scst\//, "", alias) + if (alias != path) + print alias + + alias = path + sub(/^include\/scst\//, "", alias) + if (alias != path) + print alias + + alias = path + sub(/^drivers\/scsi\/qla2xxx\//, "", alias) + if (alias != path) + print alias + + alias = path + sub(/^.*\//, "", alias) + if (alias != path) + print alias + } + + /^\+\+\+ / { + path = $2 + sub(/^b\//, "", path) + sub(/^linux-[^/]+\//, "", path) + emit_path(path) + } + ' "${patch}" + done < <( + find "${workdir}" -path "${workdir}/patchdir-*/*" \ + -type f -print0 + ) + } | sed '/^$/d' | sort -u > "${path_list}" + } + + filter_scst_findings() { + awk ' + FILENAME == ARGV[1] { + paths[++n] = $0 + next + } + + function normalize(line) { + gsub(/ error:/, " warning:", line) + gsub(/ warn:/, " warning:", line) + return line + } + + function is_scst_line(line, i) { + for (i = 1; i <= n; i++) + if (index(line, paths[i]) > 0) + return 1 + return 0 + } + + /^[[:space:]]*[0-9]+ errors? \/ [0-9]+ warnings?\.$/ { + next + } + + / warning:| warn:| error:/ { + if (is_scst_line($0)) + print normalize($0) + next + } + ' "${path_list}" - + } + + count_findings() { + grep -E -c ' warning:| warn:| error:' "$1" || true + } + + rm -rf "${workdir}" "${artifactdir}" + mkdir -p "${workdir}" "${artifactdir}" "${HOME}/.cache/scst-kernels" + + set +e + ./scripts/run-regression-tests \ + -l \ + -q \ + -c "${HOME}/.cache/scst-kernels" \ + -d "${workdir}" \ + "${KERNEL_VERSION}-nc-nb" 2>&1 \ + | tee "${raw_log}" \ + | print_progress_log \ + | tee "${log}" + status="${PIPESTATUS[0]}" + set -e + + build_scst_path_list + + append_summary "" "### sparse and smatch" "" + + if [ "${status}" -ne 0 ]; then + printf '::warning title=Static analysis::%s\n' \ + "run-regression-tests exited with status ${status}" + append_summary \ + "run-regression-tests exited with status ${status}." \ + "" + fi + + found_outputs=false + for output in "${workdir}"/sparse-*-output.txt "${workdir}"/smatch-*-output.txt; do + [ -e "${output}" ] || continue + + found_outputs=true + title="$(basename "${output}")" + analyzer="${title%%-*}" + filtered_all="${workdir}/${title%.txt}-scst-all.txt" + filtered="${artifactdir}/${title%.txt}-scst-only.txt" + filter_scst_findings < "${output}" > "${filtered_all}" + awk '!seen[$0]++' "${filtered_all}" > "${filtered}" + findings="$(awk 'END { print NR }' "${filtered}")" + scst_findings="$(awk 'END { print NR }' "${filtered_all}")" + total_findings="$(count_findings "${output}")" + duplicate_findings=$((scst_findings - findings)) + suppressed_findings=$((total_findings - scst_findings)) + + printf '%s: %s SCST warnings (%s external, %s duplicates hidden)\n' \ + "${analyzer}" \ + "${findings}" \ + "${suppressed_findings}" \ + "${duplicate_findings}" + append_summary "- ${analyzer}: ${findings} warnings (${title})" + hidden_summary=" ${suppressed_findings} external and" + hidden_summary+=" ${duplicate_findings} duplicate warnings hidden." + append_summary "${hidden_summary}" + if [ "${findings}" -gt 0 ]; then + printf '===== %s SCST warnings =====\n' "${analyzer}" + head -100 "${filtered}" + printf '::warning title=%s::%s SCST warnings from %s; see logs.\n' \ + "${analyzer}" "${findings}" "${analyzer}" + fi + done + + if [ "${found_outputs}" = false ]; then + echo "::warning title=Static analysis::No sparse or smatch output files were produced." + append_summary "No sparse or smatch output files were produced." + fi + + append_summary \ + "" \ + "
First findings" \ + "" \ + '```text' + for output in "${artifactdir}"/sparse-*-scst-only.txt \ + "${artifactdir}"/smatch-*-scst-only.txt; do + [ -e "${output}" ] || continue + + { + printf '===== %s =====\n' "$(basename "${output}")" + head -100 "${output}" + } >> "${GITHUB_STEP_SUMMARY}" + done + append_summary '```' "
" + + exit 0 + + - name: Upload analysis logs + if: always() + uses: actions/upload-artifact@v6 + with: + name: ${{steps.kernel.outputs.artifact-name}} + path: ${{runner.temp}}/scst-static-analysis-artifacts + if-no-files-found: warn + retention-days: 14