From ed179f217482882534db5f446d76ad3465ef3fea Mon Sep 17 00:00:00 2001 From: Kernel Patches Daemon Date: Wed, 29 Jan 2025 18:50:06 -0800 Subject: [PATCH] adding ci files --- .../veristat_baseline_compare/action.yml | 49 + .github/scripts/compare-veristat-results.sh | 18 + .github/scripts/matrix.py | 202 ++ .../scripts/tests/test_veristat_compare.py | 75 + .github/scripts/veristat_compare.py | 263 ++ .github/workflows/kernel-build-test.yml | 129 + .github/workflows/kernel-build.yml | 176 ++ .github/workflows/kernel-test.yml | 88 + .github/workflows/lint.yml | 65 + .github/workflows/test.yml | 62 + .github/workflows/veristat-kernel.yml | 65 + .github/workflows/veristat-meta.yml | 87 + README | 18 - ci/diffs/.keep | 0 ...-unnecessary-audit-log-for-CPU-secur.patch | 33 + ...e-SPECULATION_MITIGATIONS-to-arch-Kc.patch | 69 + ...lftest-failures-due-to-llvm18-change.patch | 94 + ...er-bug-due-to-incorrect-branch-offse.patch | 67 + ...-bpf-Fix-a-btf_dump-selftest-failure.patch | 40 + ...sockopt_lock_sock-in-ip_sock_set_tos.patch | 99 + ...lter-out-_GNU_SOURCE-when-compiling-.patch | 51 + ...x-bpf_cookie-and-find_vma-in-nested-.patch | 50 + ...x-pyperf180-compilation-failure-with.patch | 78 + ...sable-detection-of-llvm-when-buildin.patch | 41 + ...x-inet_csk_accept-prototype-in-test_.patch | 32 + ...f-work-around-latest-Clang-smartness.patch | 31 + ...kxceiver-ksft_print_msg-fix-format-t.patch | 89 + ...s-compilation-to-non-host-endianness.patch | 142 + ...Fix-symbol-counting-logic-by-looking.patch | 65 + ...s-compilation-to-non-host-endianness.patch | 117 + ci/diffs/0099-s390x_nolockdep.diff | 48 + ci/diffs/0099-selftest-cross-compile.diff | 13 + ...ancing-slot-in-iter_folioq_get_pages.patch | 46 + ...lftests-bpf-Fix-uprobe-consumer-test.patch | 58 + ...ext-fix-build-after-renames-in-sched.patch | 231 ++ ...-samples-bpf-fix-samples-compilation.patch | 61 + ...to-remove-ftrace_test_recursion_tryl.patch | 46 + ...g-Define-ftrace_get_symaddr-for-s390.patch | 28 + ...dd-fno-strict-aliasing-to-BPF_CFLAGS.patch | 75 + ...d-std-gnu11-to-BPF_CFLAGS-and-CFLAGS.patch | 63 + ...nge-the-read-result-collector-to-onl.patch | 2542 +++++++++++++++++ ...nvalid-irq-restore-in-scx_ops_bypass.patch | 56 + ...99-scx-Fix-maximal-BPF-selftest-prog.patch | 56 + ci/vmtest/configs/DENYLIST | 15 + ci/vmtest/configs/DENYLIST.aarch64 | 4 + ci/vmtest/configs/DENYLIST.rc | 3 + ci/vmtest/configs/DENYLIST.s390x | 11 + ci/vmtest/configs/DENYLIST.test_progs-bpf_gcc | 904 ++++++ ci/vmtest/configs/DENYLIST.x86_64 | 1 + ci/vmtest/configs/run-vmtest.env | 42 + ci/vmtest/configs/run_veristat.kernel.cfg | 4 + ci/vmtest/configs/run_veristat.meta.cfg | 4 + ci/vmtest/configs/veristat_meta.cfg | 10 + 53 files changed, 6698 insertions(+), 18 deletions(-) create mode 100644 .github/actions/veristat_baseline_compare/action.yml create mode 100755 .github/scripts/compare-veristat-results.sh create mode 100644 .github/scripts/matrix.py create mode 100644 .github/scripts/tests/test_veristat_compare.py create mode 100644 .github/scripts/veristat_compare.py create mode 100644 .github/workflows/kernel-build-test.yml create mode 100644 .github/workflows/kernel-build.yml create mode 100644 .github/workflows/kernel-test.yml create mode 100644 .github/workflows/lint.yml create mode 100644 .github/workflows/test.yml create mode 100644 .github/workflows/veristat-kernel.yml create mode 100644 .github/workflows/veristat-meta.yml create mode 100644 ci/diffs/.keep create mode 100644 ci/diffs/0001-Revert-bpf-Avoid-unnecessary-audit-log-for-CPU-secur.patch create mode 100644 ci/diffs/0001-arch-Kconfig-Move-SPECULATION_MITIGATIONS-to-arch-Kc.patch create mode 100644 ci/diffs/0001-bpf-Fix-a-few-selftest-failures-due-to-llvm18-change.patch create mode 100644 ci/diffs/0001-bpf-Fix-a-verifier-bug-due-to-incorrect-branch-offse.patch create mode 100644 ci/diffs/0001-bpf-next-selftests-bpf-Fix-a-btf_dump-selftest-failure.patch create mode 100644 ci/diffs/0001-net-bpf-Use-sockopt_lock_sock-in-ip_sock_set_tos.patch create mode 100644 ci/diffs/0001-selftests-bpf-Filter-out-_GNU_SOURCE-when-compiling-.patch create mode 100644 ci/diffs/0001-selftests-bpf-Fix-bpf_cookie-and-find_vma-in-nested-.patch create mode 100644 ci/diffs/0001-selftests-bpf-Fix-pyperf180-compilation-failure-with.patch create mode 100644 ci/diffs/0001-selftests-bpf-disable-detection-of-llvm-when-buildin.patch create mode 100644 ci/diffs/0001-selftests-bpf-fix-inet_csk_accept-prototype-in-test_.patch create mode 100644 ci/diffs/0001-selftests-bpf-work-around-latest-Clang-smartness.patch create mode 100644 ci/diffs/0001-selftests-bpf-xskxceiver-ksft_print_msg-fix-format-t.patch create mode 100644 ci/diffs/0001-tools-resolve_btfids-fix-cross-compilation-to-non-host-endianness.patch create mode 100644 ci/diffs/0001-tracing-kprobes-Fix-symbol-counting-logic-by-looking.patch create mode 100644 ci/diffs/0002-tools-resolve_btfids-fix-cross-compilation-to-non-host-endianness.patch create mode 100644 ci/diffs/0099-s390x_nolockdep.diff create mode 100644 ci/diffs/0099-selftest-cross-compile.diff create mode 100644 ci/diffs/0199-iov_iter-fix-advancing-slot-in-iter_folioq_get_pages.patch create mode 100644 ci/diffs/0299-selftests-bpf-Fix-uprobe-consumer-test.patch create mode 100644 ci/diffs/0399-selftests-sched_ext-fix-build-after-renames-in-sched.patch create mode 100644 ci/diffs/0499-samples-bpf-fix-samples-compilation.patch create mode 100644 ci/diffs/2000-s390-fgraph-Fix-to-remove-ftrace_test_recursion_tryl.patch create mode 100644 ci/diffs/2001-s390-tracing-Define-ftrace_get_symaddr-for-s390.patch create mode 100644 ci/diffs/2001-selftests-bpf-add-fno-strict-aliasing-to-BPF_CFLAGS.patch create mode 100644 ci/diffs/2002-selftests-bpf-add-std-gnu11-to-BPF_CFLAGS-and-CFLAGS.patch create mode 100644 ci/diffs/8888-Revert-netfs-Change-the-read-result-collector-to-onl.patch create mode 100644 ci/diffs/9998-sched_ext-Fix-invalid-irq-restore-in-scx_ops_bypass.patch create mode 100644 ci/diffs/9999-scx-Fix-maximal-BPF-selftest-prog.patch create mode 100644 ci/vmtest/configs/DENYLIST create mode 100644 ci/vmtest/configs/DENYLIST.aarch64 create mode 100644 ci/vmtest/configs/DENYLIST.rc create mode 100644 ci/vmtest/configs/DENYLIST.s390x create mode 100644 ci/vmtest/configs/DENYLIST.test_progs-bpf_gcc create mode 100644 ci/vmtest/configs/DENYLIST.x86_64 create mode 100644 ci/vmtest/configs/run-vmtest.env create mode 100644 ci/vmtest/configs/run_veristat.kernel.cfg create mode 100644 ci/vmtest/configs/run_veristat.meta.cfg create mode 100644 ci/vmtest/configs/veristat_meta.cfg diff --git a/.github/actions/veristat_baseline_compare/action.yml b/.github/actions/veristat_baseline_compare/action.yml new file mode 100644 index 0000000000000..9e25a2b0bf1ca --- /dev/null +++ b/.github/actions/veristat_baseline_compare/action.yml @@ -0,0 +1,49 @@ +name: 'run-veristat' +description: 'Run veristat benchmark' +inputs: + veristat_output: + description: 'Veristat output filepath' + required: true + baseline_name: + description: 'Veristat baseline cache name' + required: true +runs: + using: "composite" + steps: + - uses: actions/upload-artifact@v4 + with: + name: ${{ inputs.baseline_name }} + if-no-files-found: error + path: ${{ github.workspace }}/${{ inputs.veristat_output }} + + # For pull request: + # - get baseline log from cache + # - compare it to current run + - if: ${{ github.event_name == 'pull_request' }} + uses: actions/cache/restore@v4 + with: + key: ${{ inputs.baseline_name }} + restore-keys: | + ${{ inputs.baseline_name }}- + path: '${{ github.workspace }}/${{ inputs.baseline_name }}' + + - if: ${{ github.event_name == 'pull_request' }} + name: Show veristat comparison + shell: bash + run: ./.github/scripts/compare-veristat-results.sh + env: + BASELINE_PATH: ${{ github.workspace }}/${{ inputs.baseline_name }} + VERISTAT_OUTPUT: ${{ inputs.veristat_output }} + + # For push: just put baseline log to cache + - if: ${{ github.event_name == 'push' }} + shell: bash + run: | + mv "${{ github.workspace }}/${{ inputs.veristat_output }}" \ + "${{ github.workspace }}/${{ inputs.baseline_name }}" + + - if: ${{ github.event_name == 'push' }} + uses: actions/cache/save@v4 + with: + key: ${{ inputs.baseline_name }}-${{ github.run_id }} + path: '${{ github.workspace }}/${{ inputs.baseline_name }}' diff --git a/.github/scripts/compare-veristat-results.sh b/.github/scripts/compare-veristat-results.sh new file mode 100755 index 0000000000000..f95c3c192d80d --- /dev/null +++ b/.github/scripts/compare-veristat-results.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +if [[ ! -f "${BASELINE_PATH}" ]]; then + echo "# No ${BASELINE_PATH} available" >> "${GITHUB_STEP_SUMMARY}" + + echo "No ${BASELINE_PATH} available" + echo "Printing veristat results" + cat "${VERISTAT_OUTPUT}" + + exit +fi + +selftests/bpf/veristat \ + --output-format csv \ + --emit file,prog,verdict,states \ + --compare "${BASELINE_PATH}" "${VERISTAT_OUTPUT}" > compare.csv + +python3 ./.github/scripts/veristat_compare.py compare.csv diff --git a/.github/scripts/matrix.py b/.github/scripts/matrix.py new file mode 100644 index 0000000000000..785c23379d5e7 --- /dev/null +++ b/.github/scripts/matrix.py @@ -0,0 +1,202 @@ +#!/usr/bin/env python3 + +import os +import dataclasses +import json + +from enum import Enum +from typing import Any, Dict, List, Final, Set, Union + +MANAGED_OWNER: Final[str] = "kernel-patches" +MANAGED_REPOS: Final[Set[str]] = { + f"{MANAGED_OWNER}/bpf", + f"{MANAGED_OWNER}/vmtest", +} + +DEFAULT_RUNNER: Final[str] = "ubuntu-24.04" +DEFAULT_LLVM_VERSION: Final[int] = 17 +DEFAULT_SELF_HOSTED_RUNNER_TAGS: Final[List[str]] = ["self-hosted", "docker-noble-main"] + + +class Arch(str, Enum): + """ + CPU architecture supported by CI. + """ + + AARCH64 = "aarch64" + S390X = "s390x" + X86_64 = "x86_64" + + +class Compiler(str, Enum): + GCC = "gcc" + LLVM = "llvm" + + +@dataclasses.dataclass +class Toolchain: + compiler: Compiler + # This is relevant ONLY for LLVM and should not be required for GCC + version: int + + @property + def short_name(self) -> str: + return str(self.compiler.value) + + @property + def full_name(self) -> str: + if self.compiler == Compiler.GCC: + return self.short_name + + return f"{self.short_name}-{self.version}" + + def to_dict(self) -> Dict[str, Union[str, int]]: + return { + "name": self.short_name, + "fullname": self.full_name, + "version": self.version, + } + + +@dataclasses.dataclass +class BuildConfig: + arch: Arch + toolchain: Toolchain + kernel: str = "LATEST" + run_veristat: bool = False + parallel_tests: bool = False + build_release: bool = False + + @property + def runs_on(self) -> List[str]: + if is_managed_repo(): + return DEFAULT_SELF_HOSTED_RUNNER_TAGS + [self.arch.value] + return [DEFAULT_RUNNER] + + @property + def build_runs_on(self) -> List[str]: + if is_managed_repo(): + # Build s390x on x86_64 + return DEFAULT_SELF_HOSTED_RUNNER_TAGS + [ + self.arch.value == "s390x" and Arch.X86_64.value or self.arch.value, + ] + return [DEFAULT_RUNNER] + + @property + def tests(self) -> Dict[str, Any]: + tests_list = [ + "test_progs", + "test_progs_parallel", + "test_progs_no_alu32", + "test_progs_no_alu32_parallel", + "test_verifier", + ] + + if self.arch.value != "s390x": + tests_list.append("test_maps") + + if self.toolchain.version >= 18: + tests_list.append("test_progs_cpuv4") + + # if self.arch in [Arch.X86_64, Arch.AARCH64]: + # tests_list.append("sched_ext") + + # Don't run GCC BPF runner, because too many tests are failing + # See: https://lore.kernel.org/bpf/87bjw6qpje.fsf@oracle.com/ + # if self.arch == Arch.X86_64: + # tests_list.append("test_progs-bpf_gcc") + + if not self.parallel_tests: + tests_list = [test for test in tests_list if not test.endswith("parallel")] + + return {"include": [generate_test_config(test) for test in tests_list]} + + def to_dict(self) -> Dict[str, Any]: + return { + "arch": self.arch.value, + "toolchain": self.toolchain.to_dict(), + "kernel": self.kernel, + "run_veristat": self.run_veristat, + "parallel_tests": self.parallel_tests, + "build_release": self.build_release, + "runs_on": self.runs_on, + "tests": self.tests, + "build_runs_on": self.build_runs_on, + } + + +def is_managed_repo() -> bool: + return ( + os.environ["GITHUB_REPOSITORY_OWNER"] == MANAGED_OWNER + and os.environ["GITHUB_REPOSITORY"] in MANAGED_REPOS + ) + + +def set_output(name, value): + """Write an output variable to the GitHub output file.""" + with open(os.getenv("GITHUB_OUTPUT"), "a", encoding="utf-8") as file: + file.write(f"{name}={value}\n") + + +def generate_test_config(test: str) -> Dict[str, Union[str, int]]: + """Create the configuration for the provided test.""" + is_parallel = test.endswith("_parallel") + config = { + "test": test, + "continue_on_error": is_parallel, + # While in experimental mode, parallel jobs may get stuck + # anywhere, including in user space where the kernel won't detect + # a problem and panic. We add a second layer of (smaller) timeouts + # here such that if we get stuck in a parallel run, we hit this + # timeout and fail without affecting the overall job success (as + # would be the case if we hit the job-wide timeout). For + # non-experimental jobs, 360 is the default which will be + # superseded by the overall workflow timeout (but we need to + # specify something). + "timeout_minutes": 30 if is_parallel else 360, + } + return config + + +if __name__ == "__main__": + matrix = [ + BuildConfig( + arch=Arch.X86_64, + toolchain=Toolchain(compiler=Compiler.GCC, version=DEFAULT_LLVM_VERSION), + run_veristat=True, + parallel_tests=True, + ), + BuildConfig( + arch=Arch.X86_64, + toolchain=Toolchain(compiler=Compiler.LLVM, version=DEFAULT_LLVM_VERSION), + build_release=True, + ), + BuildConfig( + arch=Arch.X86_64, + toolchain=Toolchain(compiler=Compiler.LLVM, version=18), + build_release=True, + ), + BuildConfig( + arch=Arch.AARCH64, + toolchain=Toolchain(compiler=Compiler.GCC, version=DEFAULT_LLVM_VERSION), + ), + # BuildConfig( + # arch=Arch.AARCH64, + # toolchain=Toolchain( + # compiler=Compiler.LLVM, + # version=DEFAULT_LLVM_VERSION + # ), + # ), + BuildConfig( + arch=Arch.S390X, + toolchain=Toolchain(compiler=Compiler.GCC, version=DEFAULT_LLVM_VERSION), + ), + ] + + # Outside of those repositories we only run on x86_64 + if not is_managed_repo(): + matrix = [config for config in matrix if config.arch == Arch.X86_64] + + json_matrix = json.dumps({"include": [config.to_dict() for config in matrix]}) + print(json_matrix) + set_output("build_matrix", json_matrix) diff --git a/.github/scripts/tests/test_veristat_compare.py b/.github/scripts/tests/test_veristat_compare.py new file mode 100644 index 0000000000000..b65b69295235d --- /dev/null +++ b/.github/scripts/tests/test_veristat_compare.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 + +import unittest +from typing import Iterable, List + +from ..veristat_compare import parse_table, VeristatFields + + +def gen_csv_table(records: Iterable[str]) -> List[str]: + return [ + ",".join(VeristatFields.headers()), + *records, + ] + + +class TestVeristatCompare(unittest.TestCase): + def test_parse_table_ignore_new_prog(self): + table = gen_csv_table( + [ + "prog_file.bpf.o,prog_name,N/A,success,N/A,N/A,1,N/A", + ] + ) + veristat_info = parse_table(table) + self.assertEqual(veristat_info.table, []) + self.assertFalse(veristat_info.changes) + self.assertFalse(veristat_info.new_failures) + + def test_parse_table_ignore_removed_prog(self): + table = gen_csv_table( + [ + "prog_file.bpf.o,prog_name,success,N/A,N/A,1,N/A,N/A", + ] + ) + veristat_info = parse_table(table) + self.assertEqual(veristat_info.table, []) + self.assertFalse(veristat_info.changes) + self.assertFalse(veristat_info.new_failures) + + def test_parse_table_new_failure(self): + table = gen_csv_table( + [ + "prog_file.bpf.o,prog_name,success,failure,MISMATCH,1,1,+0 (+0.00%)", + ] + ) + veristat_info = parse_table(table) + self.assertEqual( + veristat_info.table, + [["prog_file.bpf.o", "prog_name", "success -> failure (!!)", "+0.00 %"]], + ) + self.assertTrue(veristat_info.changes) + self.assertTrue(veristat_info.new_failures) + + def test_parse_table_new_changes(self): + table = gen_csv_table( + [ + "prog_file.bpf.o,prog_name,failure,success,MISMATCH,0,0,+0 (+0.00%)", + "prog_file.bpf.o,prog_name_increase,failure,failure,MATCH,1,2,+1 (+100.00%)", + "prog_file.bpf.o,prog_name_decrease,success,success,MATCH,1,1,-1 (-100.00%)", + ] + ) + veristat_info = parse_table(table) + self.assertEqual( + veristat_info.table, + [ + ["prog_file.bpf.o", "prog_name", "failure -> success", "+0.00 %"], + ["prog_file.bpf.o", "prog_name_increase", "failure", "+100.00 %"], + ["prog_file.bpf.o", "prog_name_decrease", "success", "-100.00 %"], + ], + ) + self.assertTrue(veristat_info.changes) + self.assertFalse(veristat_info.new_failures) + + +if __name__ == "__main__": + unittest.main() diff --git a/.github/scripts/veristat_compare.py b/.github/scripts/veristat_compare.py new file mode 100644 index 0000000000000..07271b8cbd3aa --- /dev/null +++ b/.github/scripts/veristat_compare.py @@ -0,0 +1,263 @@ +#!/usr/bin/env python3 + +# This script reads a CSV file produced by the following invocation: +# +# veristat --emit file,prog,verdict,states \ +# --output-format csv \ +# --compare ... +# +# And produces a markdown summary for the file. +# The summary is printed to standard output and appended to a file +# pointed to by GITHUB_STEP_SUMMARY variable. +# +# Script exits with return code 1 if there are new failures in the +# veristat results. +# +# For testing purposes invoke as follows: +# +# GITHUB_STEP_SUMMARY=/dev/null python3 veristat-compare.py test.csv +# +# File format (columns): +# 0. file_name +# 1. prog_name +# 2. verdict_base +# 3. verdict_comp +# 4. verdict_diff +# 5. total_states_base +# 6. total_states_comp +# 7. total_states_diff +# +# Records sample: +# file-a,a,success,failure,MISMATCH,12,12,+0 (+0.00%) +# file-b,b,success,success,MATCH,67,67,+0 (+0.00%) +# +# For better readability suffixes '_OLD' and '_NEW' +# are used instead of '_base' and '_comp' for variable +# names etc. + +import io +import os +import sys +import re +import csv +import logging +import argparse +import enum +from dataclasses import dataclass +from typing import Dict, Iterable, List, Final + + +TRESHOLD_PCT: Final[int] = 0 + +SUMMARY_HEADERS = ["File", "Program", "Verdict", "States Diff (%)"] + +# expected format: +0 (+0.00%) / -0 (-0.00%) +TOTAL_STATES_DIFF_REGEX = ( + r"(?P[+-]\d+) \((?P[+-]\d+\.\d+)\%\)" +) + + +TEXT_SUMMARY_TEMPLATE: Final[str] = ( + """ +# {title} + +{table} +""".strip() +) + +HTML_SUMMARY_TEMPLATE: Final[str] = ( + """ +# {title} + +
+Click to expand + +{table} +
+""".strip() +) + +GITHUB_MARKUP_REPLACEMENTS: Final[Dict[str, str]] = { + "->": "→", + "(!!)": ":bangbang:", +} + +NEW_FAILURE_SUFFIX: Final[str] = "(!!)" + + +class VeristatFields(str, enum.Enum): + FILE_NAME = "file_name" + PROG_NAME = "prog_name" + VERDICT_OLD = "verdict_base" + VERDICT_NEW = "verdict_comp" + VERDICT_DIFF = "verdict_diff" + TOTAL_STATES_OLD = "total_states_base" + TOTAL_STATES_NEW = "total_states_comp" + TOTAL_STATES_DIFF = "total_states_diff" + + @classmethod + def headers(cls) -> List[str]: + return [ + cls.FILE_NAME, + cls.PROG_NAME, + cls.VERDICT_OLD, + cls.VERDICT_NEW, + cls.VERDICT_DIFF, + cls.TOTAL_STATES_OLD, + cls.TOTAL_STATES_NEW, + cls.TOTAL_STATES_DIFF, + ] + + +@dataclass +class VeristatInfo: + table: list + changes: bool + new_failures: bool + + def get_results_title(self) -> str: + if self.new_failures: + return "There are new veristat failures" + + if self.changes: + return "There are changes in verification performance" + + return "No changes in verification performance" + + def get_results_summary(self, markup: bool = False) -> str: + title = self.get_results_title() + if not self.table: + return f"# {title}\n" + + template = TEXT_SUMMARY_TEMPLATE + table = format_table(headers=SUMMARY_HEADERS, rows=self.table) + + if markup: + template = HTML_SUMMARY_TEMPLATE + table = github_markup_decorate(table) + + return template.format(title=title, table=table) + + +def get_state_diff(value: str) -> float: + if value == "N/A": + return 0.0 + + matches = re.match(TOTAL_STATES_DIFF_REGEX, value) + if not matches: + raise ValueError(f"Failed to parse total states diff field value '{value}'") + + if percentage_diff := matches.group("percentage_diff"): + return float(percentage_diff) + + raise ValueError(f"Invalid {VeristatFields.TOTAL_STATES_DIFF} field value: {value}") + + +def parse_table(csv_file: Iterable[str]) -> VeristatInfo: + reader = csv.DictReader(csv_file) + assert reader.fieldnames == VeristatFields.headers() + + new_failures = False + changes = False + table = [] + + for record in reader: + add = False + + verdict_old, verdict_new = ( + record[VeristatFields.VERDICT_OLD], + record[VeristatFields.VERDICT_NEW], + ) + + # Ignore results from completely new and removed programs + if "N/A" in [verdict_new, verdict_old]: + continue + + if record[VeristatFields.VERDICT_DIFF] == "MISMATCH": + changes = True + add = True + verdict = f"{verdict_old} -> {verdict_new}" + if verdict_new == "failure": + new_failures = True + verdict += f" {NEW_FAILURE_SUFFIX}" + else: + verdict = record[VeristatFields.VERDICT_NEW] + + diff = get_state_diff(record[VeristatFields.TOTAL_STATES_DIFF]) + if abs(diff) > TRESHOLD_PCT: + changes = True + add = True + + if not add: + continue + + table.append( + [ + record[VeristatFields.FILE_NAME], + record[VeristatFields.PROG_NAME], + verdict, + f"{diff:+.2f} %", + ] + ) + + return VeristatInfo(table=table, changes=changes, new_failures=new_failures) + + +def github_markup_decorate(input_str: str) -> str: + for text, markup in GITHUB_MARKUP_REPLACEMENTS.items(): + input_str = input_str.replace(text, markup) + return input_str + + +def format_table(headers: List[str], rows: List[List[str]]) -> str: + column_width = [ + max(len(row[column_idx]) for row in [headers] + rows) + for column_idx in range(len(headers)) + ] + + # Row template string in the following format: + # "{0:8}|{1:10}|{2:15}|{3:7}|{4:10}" + row_template = "|".join( + f"{{{idx}:{width}}}" for idx, width in enumerate(column_width) + ) + row_template_nl = f"|{row_template}|\n" + + with io.StringIO() as out: + out.write(row_template_nl.format(*headers)) + + separator_row = ["-" * width for width in column_width] + out.write(row_template_nl.format(*separator_row)) + + for row in rows: + row_str = row_template_nl.format(*row) + out.write(row_str) + + return out.getvalue() + + +def main(compare_csv_filename: os.PathLike, output_filename: os.PathLike) -> None: + with open(compare_csv_filename, newline="", encoding="utf-8") as csv_file: + veristat_results = parse_table(csv_file) + + sys.stdout.write(veristat_results.get_results_summary()) + + with open(output_filename, encoding="utf-8", mode="a") as file: + file.write(veristat_results.get_results_summary(markup=True)) + + if veristat_results.new_failures: + return 1 + + return 0 + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description="Print veristat comparison output as markdown step summary" + ) + parser.add_argument("filename") + args = parser.parse_args() + summary_filename = os.getenv("GITHUB_STEP_SUMMARY") + if not summary_filename: + logging.error("GITHUB_STEP_SUMMARY environment variable is not set") + sys.exit(1) + sys.exit(main(args.filename, summary_filename)) diff --git a/.github/workflows/kernel-build-test.yml b/.github/workflows/kernel-build-test.yml new file mode 100644 index 0000000000000..cfe4e46223dd7 --- /dev/null +++ b/.github/workflows/kernel-build-test.yml @@ -0,0 +1,129 @@ +name: Reusable Build/Test/Veristat workflow + +on: + workflow_call: + inputs: + arch: + required: true + type: string + description: The architecture to build against, e.g x86_64, aarch64, s390x... + toolchain_full: + required: true + type: string + description: The toolchain and for llvm, its version, e.g gcc, llvm-15 + toolchain: + required: true + type: string + description: The toolchain, e.g gcc, llvm + runs_on: + required: true + type: string + description: The runners to run the test on. This is a json string representing an array of labels. + build_runs_on: + required: true + type: string + description: The runners to run the builds on. This is a json string representing an array of labels. + llvm-version: + required: true + type: string + description: The version of LLVM used to build selftest.... for llvm toolchain, this should match the one from toolchain_full, for gcc it is an arbritrary version we decide to build selftests against. + kernel: + required: true + type: string + description: The kernel to run the test against. For KPD this is always LATEST, which runs against a newly built kernel. + tests: + required: true + type: string + description: A serialized json array with the tests to be running, it must follow the json-matrix format, https://www.jitsejan.com/use-github-actions-with-json-file-as-matrix + run_veristat: + required: true + type: boolean + description: Whether or not to run the veristat job. + run_tests: + required: true + type: boolean + description: Whether or not to run the test job. + download_sources: + required: true + type: boolean + description: Whether to download the linux sources into the working directory. + default: false + build_release: + required: true + type: boolean + description: Build selftests with -O2 optimization in addition to non-optimized build. + default: false + secrets: + AWS_ROLE_ARN: + required: true + +jobs: + # Build kernel and selftest + build: + uses: ./.github/workflows/kernel-build.yml + with: + arch: ${{ inputs.arch }} + toolchain_full: ${{ inputs.toolchain_full }} + toolchain: ${{ inputs.toolchain }} + runs_on: ${{ inputs.build_runs_on }} + llvm-version: ${{ inputs.llvm-version }} + kernel: ${{ inputs.kernel }} + download_sources: ${{ inputs.download_sources }} + build-release: + if: ${{ inputs.build_release }} + uses: ./.github/workflows/kernel-build.yml + with: + arch: ${{ inputs.arch }} + toolchain_full: ${{ inputs.toolchain_full }} + toolchain: ${{ inputs.toolchain }} + runs_on: ${{ inputs.runs_on }} + llvm-version: ${{ inputs.llvm-version }} + kernel: ${{ inputs.kernel }} + download_sources: ${{ inputs.download_sources }} + release: true + test: + if: ${{ inputs.run_tests }} + uses: ./.github/workflows/kernel-test.yml + # Setting name to test here to avoid lengthy autogenerated names due to matrix + # e.g build-and-test x86_64-gcc / test (test_progs_parallel, true, 30) / test_progs_parallel on x86_64 with gcc + name: "test" + needs: [build] + strategy: + fail-fast: false + matrix: ${{ fromJSON(inputs.tests) }} + with: + arch: ${{ inputs.arch }} + toolchain_full: ${{ inputs.toolchain_full }} + runs_on: ${{ inputs.runs_on }} + kernel: ${{ inputs.kernel }} + test: ${{ matrix.test }} + continue_on_error: ${{ toJSON(matrix.continue_on_error) }} + timeout_minutes: ${{ matrix.timeout_minutes }} + + veristat-kernel: + if: ${{ inputs.run_veristat }} + uses: ./.github/workflows/veristat-kernel.yml + needs: [build] + permissions: + id-token: write + contents: read + with: + arch: ${{ inputs.arch }} + toolchain: ${{ inputs.toolchain }} + runs_on: ${{ inputs.runs_on }} + + veristat-meta: + # Check for vars.AWS_REGION is necessary to skip this job in case of a PR from a fork. + if: ${{ inputs.run_veristat && github.repository_owner == 'kernel-patches' && vars.AWS_REGION }} + uses: ./.github/workflows/veristat-meta.yml + needs: [build] + permissions: + id-token: write + contents: read + with: + arch: ${{ inputs.arch }} + toolchain: ${{ inputs.toolchain }} + aws_region: ${{ vars.AWS_REGION }} + runs_on: ${{ inputs.runs_on }} + secrets: + AWS_ROLE_ARN: ${{ secrets.AWS_ROLE_ARN }} diff --git a/.github/workflows/kernel-build.yml b/.github/workflows/kernel-build.yml new file mode 100644 index 0000000000000..9769daed4bccf --- /dev/null +++ b/.github/workflows/kernel-build.yml @@ -0,0 +1,176 @@ + +name: Reusable build workflow + +on: + workflow_call: + inputs: + arch: + required: true + type: string + description: The architecture to build against, e.g x86_64, aarch64, s390x... + toolchain_full: + required: true + type: string + description: The toolchain and for llvm, its version, e.g gcc, llvm-15 + toolchain: + required: true + type: string + description: The toolchain, e.g gcc, llvm + runs_on: + required: true + type: string + description: The runners to run the test on. This is a json string representing an array of labels. + llvm-version: + required: true + type: string + description: The version of LLVM used to build selftest.... for llvm toolchain, this should match the one from toolchain_full, for gcc it is an arbritrary version we decide to build selftests against. + kernel: + required: true + type: string + description: The kernel to run the test against. For KPD this is always LATEST, which runs against a newly built kernel. + download_sources: + required: true + type: boolean + description: Whether to download the linux sources into the working directory. + default: false + release: + required: false + type: boolean + description: Build selftest with -O2 optimization + default: false + +jobs: + build: + name: build for ${{ inputs.arch }} with ${{ inputs.toolchain_full }}${{ inputs.release && '-O2' || '' }} + runs-on: ${{ fromJSON(inputs.runs_on) }} + timeout-minutes: 100 + env: + ARTIFACTS_ARCHIVE: "vmlinux-${{ inputs.arch }}-${{ inputs.toolchain_full }}.tar.zst" + + BUILD_BPF_GCC: ${{ inputs.arch == 'x86_64' && 'true' || '' }} + BPF_GCC_INSTALL_DIR: ${{ github.workspace }}/bpf-gcc + + BPF_NEXT_BASE_BRANCH: 'master' + BPF_NEXT_FETCH_DEPTH: 64 # A bit of history is needed to facilitate incremental builds + # BUILD_SCHED_EXT_SELFTESTS: ${{ inputs.arch == 'x86_64' || inputs.arch == 'aarch64' && 'true' || '' }} + KBUILD_OUTPUT: ${{ github.workspace }}/kbuild-output + KERNEL: ${{ inputs.kernel }} + KERNEL_ROOT: ${{ github.workspace }} + REPO_PATH: "" + REPO_ROOT: ${{ github.workspace }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: ${{ inputs.download_sources && 1 || env.BPF_NEXT_FETCH_DEPTH }} + - if: ${{ inputs.download_sources }} + name: Download bpf-next tree + env: + FETCH_DEPTH: ${{ env.BPF_NEXT_FETCH_DEPTH }} + uses: libbpf/ci/get-linux-source@v3 + with: + dest: '.kernel' + rev: ${{ env.BPF_NEXT_BASE_BRANCH }} + - uses: libbpf/ci/prepare-incremental-build@v3 + with: + repo-root: ${{ inputs.download_sources && '.kernel' || env.REPO_ROOT }} + base-branch: >- + ${{ inputs.download_sources && env.BPF_NEXT_BASE_BRANCH + || github.event_name == 'pull_request' && github.base_ref + || github.ref_name + }} + arch: ${{ inputs.arch }} + toolchain_full: ${{ inputs.toolchain_full }} + kbuild-output: ${{ env.KBUILD_OUTPUT }} + - if: ${{ inputs.download_sources }} + name: Move linux source in place + shell: bash + run: | + cd .kernel + rm -rf .git + mv -t .. $(ls -A) + cd .. + rmdir .kernel + - uses: libbpf/ci/patch-kernel@v3 + with: + patches-root: '${{ github.workspace }}/ci/diffs' + repo-root: ${{ env.REPO_ROOT }} + + - name: Setup build environment + uses: libbpf/ci/setup-build-env@v3 + with: + arch: ${{ inputs.arch }} + llvm-version: ${{ inputs.llvm-version }} + pahole: master + + - name: Build kernel image + uses: libbpf/ci/build-linux@v3 + with: + arch: ${{ inputs.arch }} + toolchain: ${{ inputs.toolchain }} + kbuild-output: ${{ env.KBUILD_OUTPUT }} + max-make-jobs: 32 + llvm-version: ${{ inputs.llvm-version }} + + - if: ${{ env.BUILD_BPF_GCC }} + name: Build GCC for BPF selftests + uses: libbpf/ci/build-bpf-gcc@v3 + with: + install-dir: ${{ env.BPF_GCC_INSTALL_DIR }} + + - name: Build selftests/bpf + uses: libbpf/ci/build-selftests@v3 + env: + MAX_MAKE_JOBS: 32 + RELEASE: ${{ inputs.release && '1' || '' }} + BPF_GCC: ${{ env.BUILD_BPF_GCC && env.BPF_GCC_INSTALL_DIR || '' }} + with: + arch: ${{ inputs.arch }} + kernel-root: ${{ env.KERNEL_ROOT }} + llvm-version: ${{ inputs.llvm-version }} + toolchain: ${{ inputs.toolchain }} + + - if: ${{ env.BUILD_SCHED_EXT_SELFTESTS }} + name: Build selftests/sched_ext + uses: libbpf/ci/build-scx-selftests@v3 + with: + kbuild-output: ${{ env.KBUILD_OUTPUT }} + repo-root: ${{ env.REPO_ROOT }} + arch: ${{ inputs.arch }} + toolchain: ${{ inputs.toolchain }} + llvm-version: ${{ inputs.llvm-version }} + max-make-jobs: 32 + + - if: ${{ github.event_name != 'push' }} + name: Build samples + uses: libbpf/ci/build-samples@v3 + with: + arch: ${{ inputs.arch }} + toolchain: ${{ inputs.toolchain }} + kbuild-output: ${{ env.KBUILD_OUTPUT }} + max-make-jobs: 32 + llvm-version: ${{ inputs.llvm-version }} + - name: Tar artifacts + id: tar-artifacts + uses: libbpf/ci/tar-artifacts@v3 + env: + ARCHIVE_BPF_SELFTESTS: 'true' + ARCHIVE_MAKE_HELPERS: 'true' + ARCHIVE_SCHED_EXT_SELFTESTS: ${{ env.BUILD_SCHED_EXT_SELFTESTS }} + with: + arch: ${{ inputs.arch }} + archive: ${{ env.ARTIFACTS_ARCHIVE }} + kbuild-output: ${{ env.KBUILD_OUTPUT }} + repo-root: ${{ env.REPO_ROOT }} + - if: ${{ github.event_name != 'push' }} + name: Remove KBUILD_OUTPUT content + shell: bash + run: | + # Remove $KBUILD_OUTPUT to prevent cache creation for pull requests. + # Only on pushed changes are build artifacts actually cached, because + # of github.com/actions/cache's cache isolation logic. + rm -rf "${KBUILD_OUTPUT}" + - uses: actions/upload-artifact@v4 + with: + name: vmlinux-${{ inputs.arch }}-${{ inputs.toolchain_full }}${{ inputs.release && '-release' || '' }} + if-no-files-found: error + path: ${{ env.ARTIFACTS_ARCHIVE }} diff --git a/.github/workflows/kernel-test.yml b/.github/workflows/kernel-test.yml new file mode 100644 index 0000000000000..70ece7eb5cfb0 --- /dev/null +++ b/.github/workflows/kernel-test.yml @@ -0,0 +1,88 @@ +name: Reusable test workflow + +on: + workflow_call: + inputs: + arch: + required: true + type: string + description: The architecture to build against, e.g x86_64, aarch64, s390x... + toolchain_full: + required: true + type: string + description: The toolchain and for llvm, its version, e.g gcc, llvm-15 + runs_on: + required: true + type: string + description: The runners to run the test on. This is a json string representing an array of labels. + kernel: + required: true + type: string + description: The kernel to run the test against. For KPD this is always LATEST, which runs against a newly built kernel. + test: + required: true + type: string + description: The test to run in the vm, e.g test_progs, test_maps, test_progs_no_alu32... + continue_on_error: + required: true + type: string + description: Whether to continue on error. This is typically set to true for parallel tests which are currently known to fail, but we don't want to fail the whole CI because of that. + timeout_minutes: + required: true + type: number + description: In case a test runs for too long, after how many seconds shall we timeout and error. + +jobs: + test: + name: ${{ inputs.test }} on ${{ inputs.arch }} with ${{ inputs.toolchain_full }} + runs-on: ${{ fromJSON(inputs.runs_on) }} + timeout-minutes: 100 + env: + ARCH: ${{ inputs.arch }} + KERNEL: ${{ inputs.kernel }} + REPO_ROOT: ${{ github.workspace }} + REPO_PATH: "" + # https://github.com/actions/runner/issues/1483#issuecomment-1031671517 + # booleans are weird in GH. + CONTINUE_ON_ERROR: ${{ inputs.continue_on_error }} + DEPLOYMENT: ${{ github.repository == 'kernel-patches/bpf' && 'prod' || 'rc' }} + ALLOWLIST_FILE: /tmp/allowlist + DENYLIST_FILE: /tmp/denylist + steps: + - uses: actions/checkout@v4 + with: + sparse-checkout: | + .github + ci + + - uses: actions/download-artifact@v4 + with: + name: vmlinux-${{ inputs.arch }}-${{ inputs.toolchain_full }} + path: . + + - name: Untar artifacts + # zstd is installed by default in the runner images. + run: zstd -d -T0 vmlinux-${{ inputs.arch }}-${{ inputs.toolchain_full }}.tar.zst --stdout | tar -xf - + + - name: Run selftests + uses: libbpf/ci/run-vmtest@v3 + # https://github.com/actions/runner/issues/1483#issuecomment-1031671517 + # booleans are weird in GH. + continue-on-error: ${{ fromJSON(env.CONTINUE_ON_ERROR) }} + timeout-minutes: ${{ inputs.timeout_minutes }} + env: + ARCH: ${{ inputs.arch }} + DEPLOYMENT: ${{ env.DEPLOYMENT }} + KERNEL_TEST: ${{ inputs.test }} + SELFTESTS_BPF: ${{ github.workspace }}/selftests/bpf + VMTEST_CONFIGS: ${{ github.workspace }}/ci/vmtest/configs + TEST_PROGS_WATCHDOG_TIMEOUT: 300 + with: + arch: ${{ inputs.arch }} + vmlinuz: '${{ github.workspace }}/vmlinuz' + kernel-root: ${{ env.REPO_ROOT }} + max-cpu: 8 + kernel-test: ${{ inputs.test }} + # Here we must use kbuild-output local to the repo, because + # it was extracted from the artifacts. + kbuild-output: ${{ env.REPO_ROOT }}/kbuild-output diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000000000..1c910fd297309 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,65 @@ +name: "lint" + +on: + pull_request: + push: + branches: + - master + +jobs: + shellcheck: + # This workflow gets injected into other Linux repositories, but we don't + # want it to run there. + if: ${{ github.repository == 'kernel-patches/vmtest' }} + name: ShellCheck + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Run ShellCheck + uses: ludeeus/action-shellcheck@master + env: + SHELLCHECK_OPTS: --severity=warning --exclude=SC1091 + + # Ensure some consistency in the formatting. + lint: + if: ${{ github.repository == 'kernel-patches/vmtest' }} + name: Lint + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Run black + uses: psf/black@stable + with: + src: ./.github/scripts + + validate_matrix: + if: ${{ github.repository == 'kernel-patches/vmtest' }} + name: Validate matrix.py + runs-on: ubuntu-latest + env: + GITHUB_REPOSITORY_OWNER: ${{ matrix.owner }} + GITHUB_REPOSITORY: ${{ matrix.repository }} + GITHUB_OUTPUT: /dev/stdout + strategy: + matrix: + owner: ['kernel-patches', 'foo'] + repository: ['bpf', 'vmtest', 'bar'] + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: run script + run: | + python3 .github/scripts/matrix.py + + unittests: + if: ${{ github.repository == 'kernel-patches/vmtest' }} + name: Unittests + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Run unittests + run: python3 -m unittest scripts/tests/*.py + working-directory: .github diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000000000..fdf9d9f58253f --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,62 @@ +name: bpf-ci + +on: + pull_request: + push: + branches: + - bpf_base + - bpf-next_base + +concurrency: + group: ci-test-${{ github.ref_name }} + cancel-in-progress: true + +jobs: + set-matrix: + # FIXME: set-matrix is lightweight, run it on any self-hosted machines for kernel-patches org + # so we do not wait for GH hosted runners when there potentially all are busy because of bpf-rc + # repo for instance. + # This could be somehow fixed long term by making this action/workflow re-usable and letting the called + # specify what to run on. + runs-on: ${{ github.repository_owner == 'kernel-patches' && 'x86_64' || 'ubuntu-latest' }} + outputs: + build-matrix: ${{ steps.set-matrix-impl.outputs.build_matrix }} + steps: + - uses: actions/checkout@v4 + with: + sparse-checkout: | + .github + ci + - id: set-matrix-impl + run: | + python3 .github/scripts/matrix.py + + build-and-test: + # Setting name to arch-compiler here to avoid lengthy autogenerated names due to matrix + # e.g build-and-test x86_64-gcc / test (test_progs_parallel, true, 30) / test_progs_parallel on x86_64 with gcc + name: "${{ matrix.arch }}-${{ matrix.toolchain.fullname }}" + uses: ./.github/workflows/kernel-build-test.yml + needs: [set-matrix] + permissions: + id-token: write + contents: read + strategy: + fail-fast: false + matrix: ${{ fromJSON(needs.set-matrix.outputs.build-matrix) }} + with: + arch: ${{ matrix.arch }} + toolchain_full: ${{ matrix.toolchain.fullname }} + toolchain: ${{ matrix.toolchain.name }} + runs_on: ${{ toJSON(matrix.runs_on) }} + build_runs_on: ${{ toJSON(matrix.build_runs_on) }} + llvm-version: ${{ matrix.toolchain.version }} + kernel: ${{ matrix.kernel }} + tests: ${{ toJSON(matrix.tests) }} + run_veristat: ${{ matrix.run_veristat }} + # We only run tests on pull requests. + run_tests: ${{ github.event_name != 'push' }} + # Download sources + download_sources: ${{ github.repository == 'kernel-patches/vmtest' }} + build_release: ${{ matrix.build_release }} + secrets: + AWS_ROLE_ARN: ${{ secrets.AWS_ROLE_ARN }} diff --git a/.github/workflows/veristat-kernel.yml b/.github/workflows/veristat-kernel.yml new file mode 100644 index 0000000000000..0557daebf5bab --- /dev/null +++ b/.github/workflows/veristat-kernel.yml @@ -0,0 +1,65 @@ +name: veristat_kernel + +on: + workflow_call: + inputs: + arch: + required: true + type: string + description: The architecture to build against, e.g x86_64, aarch64, s390x... + toolchain: + required: true + type: string + description: The toolchain, e.g gcc, llvm + runs_on: + required: true + type: string + description: The runners to run the test on. This is a json string representing an array of labels. + +jobs: + veristat: + name: ${{ inputs.arch }}-${{ inputs.toolchain }} veristat_kernel + runs-on: ${{ fromJSON(inputs.runs_on) }} + timeout-minutes: 100 + permissions: + id-token: write + contents: read + env: + KERNEL: LATEST + REPO_ROOT: ${{ github.workspace }} + REPO_PATH: "" + KBUILD_OUTPUT: kbuild-output/ + ARCH_AND_TOOL: ${{ inputs.arch }}-${{ inputs.toolchain }} + + steps: + + - uses: actions/checkout@v4 + with: + sparse-checkout: | + .github + ci + + - uses: actions/download-artifact@v4 + with: + name: vmlinux-${{ env.ARCH_AND_TOOL }} + path: . + + - name: Untar artifacts + run: zstd -d -T0 vmlinux-${{ env.ARCH_AND_TOOL }}.tar.zst --stdout | tar -xf - + + - name: Run veristat + uses: libbpf/ci/run-vmtest@v3 + with: + arch: x86_64 + vmlinuz: '${{ github.workspace }}/vmlinuz' + kernel-root: '.' + max-cpu: 8 + kernel-test: 'run_veristat_kernel' + output-dir: '${{ github.workspace }}' + + - name: Compare and save veristat.kernel.csv + uses: ./.github/actions/veristat_baseline_compare + with: + veristat_output: veristat-kernel + baseline_name: ${{ env.ARCH_AND_TOOL}}-baseline-veristat-kernel + diff --git a/.github/workflows/veristat-meta.yml b/.github/workflows/veristat-meta.yml new file mode 100644 index 0000000000000..00700a8205e62 --- /dev/null +++ b/.github/workflows/veristat-meta.yml @@ -0,0 +1,87 @@ +name: veristat_meta + +on: + workflow_call: + inputs: + arch: + required: true + type: string + description: The architecture to build against, e.g x86_64, aarch64, s390x... + toolchain: + required: true + type: string + description: The toolchain, e.g gcc, llvm + runs_on: + required: true + type: string + description: The runners to run the test on. This is a json string representing an array of labels. + aws_region: + required: true + type: string + description: The AWS region where we pull bpf objects to run against veristat. + secrets: + AWS_ROLE_ARN: + required: true + description: The AWS role used by GH to pull BPF objects from AWS. + +jobs: + veristat: + name: ${{ inputs.arch }}-${{ inputs.toolchain }} veristat_meta + runs-on: ${{ fromJSON(inputs.runs_on) }} + timeout-minutes: 100 + permissions: + id-token: write + contents: read + env: + KERNEL: LATEST + REPO_ROOT: ${{ github.workspace }} + REPO_PATH: "" + KBUILD_OUTPUT: kbuild-output/ + ARCH_AND_TOOL: ${{ inputs.arch }}-${{ inputs.toolchain }} + + steps: + + - uses: actions/checkout@v4 + with: + sparse-checkout: | + .github + ci + + - uses: actions/download-artifact@v4 + with: + name: vmlinux-${{ env.ARCH_AND_TOOL }} + path: . + + - name: Untar artifacts + run: zstd -d -T0 vmlinux-${{ env.ARCH_AND_TOOL }}.tar.zst --stdout | tar -xf - + + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v3 + with: + aws-region: ${{ inputs.aws_region }} + role-to-assume: ${{ secrets.AWS_ROLE_ARN }} + role-session-name: github-action-bpf-ci + + - name: Download BPF objects + run: | + mkdir ./bpf_objects + aws s3 sync s3://veristat-bpf-binaries ./bpf_objects + env: + AWS_ROLE_ARN: ${{ secrets.AWS_ROLE_ARN }} + + - name: Run veristat + uses: libbpf/ci/run-vmtest@v3 + with: + arch: x86_64 + vmlinuz: '${{ github.workspace }}/vmlinuz' + kernel-root: '.' + max-cpu: 8 + kernel-test: 'run_veristat_meta' + output-dir: '${{ github.workspace }}' + + - name: Compare and save veristat.meta.csv + uses: ./.github/actions/veristat_baseline_compare + with: + veristat_output: veristat-meta + baseline_name: ${{ env.ARCH_AND_TOOL}}-baseline-veristat-meta + diff --git a/README b/README index fd903645e6de0..e69de29bb2d1d 100644 --- a/README +++ b/README @@ -1,18 +0,0 @@ -Linux kernel -============ - -There are several guides for kernel developers and users. These guides can -be rendered in a number of formats, like HTML and PDF. Please read -Documentation/admin-guide/README.rst first. - -In order to build the documentation, use ``make htmldocs`` or -``make pdfdocs``. The formatted documentation can also be read online at: - - https://www.kernel.org/doc/html/latest/ - -There are various text files in the Documentation/ subdirectory, -several of them using the reStructuredText markup notation. - -Please read the Documentation/process/changes.rst file, as it contains the -requirements for building and running the kernel, and information about -the problems which may result by upgrading your kernel. diff --git a/ci/diffs/.keep b/ci/diffs/.keep new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/ci/diffs/0001-Revert-bpf-Avoid-unnecessary-audit-log-for-CPU-secur.patch b/ci/diffs/0001-Revert-bpf-Avoid-unnecessary-audit-log-for-CPU-secur.patch new file mode 100644 index 0000000000000..3b6139225e7bf --- /dev/null +++ b/ci/diffs/0001-Revert-bpf-Avoid-unnecessary-audit-log-for-CPU-secur.patch @@ -0,0 +1,33 @@ +From 5440a12ac8fb2a8e051c597fcf5d85b427fe612a Mon Sep 17 00:00:00 2001 +From: Andrii Nakryiko +Date: Fri, 13 Oct 2023 12:44:34 -0700 +Subject: [PATCH] Revert "bpf: Avoid unnecessary audit log for CPU security + mitigations" + +This reverts commit 236334aeec0f93217cf9235f2004e61a0a1a5985. +--- + include/linux/bpf.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/include/linux/bpf.h b/include/linux/bpf.h +index f0891ba24cb1..61bde4520f5c 100644 +--- a/include/linux/bpf.h ++++ b/include/linux/bpf.h +@@ -2164,12 +2164,12 @@ static inline bool bpf_allow_uninit_stack(void) + + static inline bool bpf_bypass_spec_v1(void) + { +- return cpu_mitigations_off() || perfmon_capable(); ++ return perfmon_capable() || cpu_mitigations_off(); + } + + static inline bool bpf_bypass_spec_v4(void) + { +- return cpu_mitigations_off() || perfmon_capable(); ++ return perfmon_capable() || cpu_mitigations_off(); + } + + int bpf_map_new_fd(struct bpf_map *map, int flags); +-- +2.34.1 + diff --git a/ci/diffs/0001-arch-Kconfig-Move-SPECULATION_MITIGATIONS-to-arch-Kc.patch b/ci/diffs/0001-arch-Kconfig-Move-SPECULATION_MITIGATIONS-to-arch-Kc.patch new file mode 100644 index 0000000000000..63bdd28adedd2 --- /dev/null +++ b/ci/diffs/0001-arch-Kconfig-Move-SPECULATION_MITIGATIONS-to-arch-Kc.patch @@ -0,0 +1,69 @@ +From c71766e8ff7a7f950522d25896fba758585500df Mon Sep 17 00:00:00 2001 +From: Song Liu +Date: Mon, 22 Apr 2024 21:14:40 -0700 +Subject: [PATCH] arch/Kconfig: Move SPECULATION_MITIGATIONS to arch/Kconfig + +SPECULATION_MITIGATIONS is currently defined only for x86. As a result, +IS_ENABLED(CONFIG_SPECULATION_MITIGATIONS) is always false for other +archs. f337a6a21e2f effectively set "mitigations=off" by default on +non-x86 archs, which is not desired behavior. Jakub observed this +change when running bpf selftests on s390 and arm64. + +Fix this by moving SPECULATION_MITIGATIONS to arch/Kconfig so that it is +available in all archs and thus can be used safely in kernel/cpu.c + +Fixes: f337a6a21e2f ("x86/cpu: Actually turn off mitigations by default for SPECULATION_MITIGATIONS=n") +Cc: stable@vger.kernel.org +Cc: Sean Christopherson +Cc: Ingo Molnar +Cc: Daniel Sneddon +Cc: Jakub Kicinski +Signed-off-by: Song Liu +--- + arch/Kconfig | 10 ++++++++++ + arch/x86/Kconfig | 10 ---------- + 2 files changed, 10 insertions(+), 10 deletions(-) + +diff --git a/arch/Kconfig b/arch/Kconfig +index 9f066785bb71..8f4af75005f8 100644 +--- a/arch/Kconfig ++++ b/arch/Kconfig +@@ -1609,4 +1609,14 @@ config CC_HAS_SANE_FUNCTION_ALIGNMENT + # strict alignment always, even with -falign-functions. + def_bool CC_HAS_MIN_FUNCTION_ALIGNMENT || CC_IS_CLANG + ++menuconfig SPECULATION_MITIGATIONS ++ bool "Mitigations for speculative execution vulnerabilities" ++ default y ++ help ++ Say Y here to enable options which enable mitigations for ++ speculative execution hardware vulnerabilities. ++ ++ If you say N, all mitigations will be disabled. You really ++ should know what you are doing to say so. ++ + endmenu +diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig +index 39886bab943a..50c890fce5e0 100644 +--- a/arch/x86/Kconfig ++++ b/arch/x86/Kconfig +@@ -2486,16 +2486,6 @@ config PREFIX_SYMBOLS + def_bool y + depends on CALL_PADDING && !CFI_CLANG + +-menuconfig SPECULATION_MITIGATIONS +- bool "Mitigations for speculative execution vulnerabilities" +- default y +- help +- Say Y here to enable options which enable mitigations for +- speculative execution hardware vulnerabilities. +- +- If you say N, all mitigations will be disabled. You really +- should know what you are doing to say so. +- + if SPECULATION_MITIGATIONS + + config MITIGATION_PAGE_TABLE_ISOLATION +-- +2.43.0 + diff --git a/ci/diffs/0001-bpf-Fix-a-few-selftest-failures-due-to-llvm18-change.patch b/ci/diffs/0001-bpf-Fix-a-few-selftest-failures-due-to-llvm18-change.patch new file mode 100644 index 0000000000000..a13d767197413 --- /dev/null +++ b/ci/diffs/0001-bpf-Fix-a-few-selftest-failures-due-to-llvm18-change.patch @@ -0,0 +1,94 @@ +From fb9a697860acd8f54f2ba6647923794378eb33da Mon Sep 17 00:00:00 2001 +From: Yonghong Song +Date: Sun, 26 Nov 2023 21:03:42 -0800 +Subject: [PATCH] bpf: Fix a few selftest failures due to llvm18 change + +With latest upstream llvm18, the following test cases failed: + + $ ./test_progs -j + #13/2 bpf_cookie/multi_kprobe_link_api:FAIL + #13/3 bpf_cookie/multi_kprobe_attach_api:FAIL + #13 bpf_cookie:FAIL + #77 fentry_fexit:FAIL + #78/1 fentry_test/fentry:FAIL + #78 fentry_test:FAIL + #82/1 fexit_test/fexit:FAIL + #82 fexit_test:FAIL + #112/1 kprobe_multi_test/skel_api:FAIL + #112/2 kprobe_multi_test/link_api_addrs:FAIL + [...] + #112 kprobe_multi_test:FAIL + #356/17 test_global_funcs/global_func17:FAIL + #356 test_global_funcs:FAIL + +Further analysis shows llvm upstream patch [1] is responsible for the above +failures. For example, for function bpf_fentry_test7() in net/bpf/test_run.c, +without [1], the asm code is: + + 0000000000000400 : + 400: f3 0f 1e fa endbr64 + 404: e8 00 00 00 00 callq 0x409 + 409: 48 89 f8 movq %rdi, %rax + 40c: c3 retq + 40d: 0f 1f 00 nopl (%rax) + +... and with [1], the asm code is: + + 0000000000005d20 : + 5d20: e8 00 00 00 00 callq 0x5d25 + 5d25: c3 retq + +... and is called instead of +and this caused test failures for #13/#77 etc. except #356. + +For test case #356/17, with [1] (progs/test_global_func17.c)), the main prog +looks like: + + 0000000000000000 : + 0: b4 00 00 00 2a 00 00 00 w0 = 0x2a + 1: 95 00 00 00 00 00 00 00 exit + +... which passed verification while the test itself expects a verification +failure. + +Let us add 'barrier_var' style asm code in both places to prevent function +specialization which caused selftests failure. + + [1] https://github.com/llvm/llvm-project/pull/72903 + +Signed-off-by: Yonghong Song +Signed-off-by: Daniel Borkmann +Link: https://lore.kernel.org/bpf/20231127050342.1945270-1-yonghong.song@linux.dev +--- + net/bpf/test_run.c | 2 +- + tools/testing/selftests/bpf/progs/test_global_func17.c | 1 + + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c +index c9fdcc5cdce1..711cf5d59816 100644 +--- a/net/bpf/test_run.c ++++ b/net/bpf/test_run.c +@@ -542,7 +542,7 @@ struct bpf_fentry_test_t { + + int noinline bpf_fentry_test7(struct bpf_fentry_test_t *arg) + { +- asm volatile (""); ++ asm volatile ("": "+r"(arg)); + return (long)arg; + } + +diff --git a/tools/testing/selftests/bpf/progs/test_global_func17.c b/tools/testing/selftests/bpf/progs/test_global_func17.c +index a32e11c7d933..5de44b09e8ec 100644 +--- a/tools/testing/selftests/bpf/progs/test_global_func17.c ++++ b/tools/testing/selftests/bpf/progs/test_global_func17.c +@@ -5,6 +5,7 @@ + + __noinline int foo(int *p) + { ++ barrier_var(p); + return p ? (*p = 42) : 0; + } + +-- +2.34.1 + diff --git a/ci/diffs/0001-bpf-Fix-a-verifier-bug-due-to-incorrect-branch-offse.patch b/ci/diffs/0001-bpf-Fix-a-verifier-bug-due-to-incorrect-branch-offse.patch new file mode 100644 index 0000000000000..5832a42664706 --- /dev/null +++ b/ci/diffs/0001-bpf-Fix-a-verifier-bug-due-to-incorrect-branch-offse.patch @@ -0,0 +1,67 @@ +From dfce9cb3140592b886838e06f3e0c25fea2a9cae Mon Sep 17 00:00:00 2001 +From: Yonghong Song +Date: Thu, 30 Nov 2023 18:46:40 -0800 +Subject: [PATCH 1/1] bpf: Fix a verifier bug due to incorrect branch offset + comparison with cpu=v4 + +Bpf cpu=v4 support is introduced in [1] and Commit 4cd58e9af8b9 +("bpf: Support new 32bit offset jmp instruction") added support for new +32bit offset jmp instruction. Unfortunately, in function +bpf_adj_delta_to_off(), for new branch insn with 32bit offset, the offset +(plus/minor a small delta) compares to 16-bit offset bound +[S16_MIN, S16_MAX], which caused the following verification failure: + $ ./test_progs-cpuv4 -t verif_scale_pyperf180 + ... + insn 10 cannot be patched due to 16-bit range + ... + libbpf: failed to load object 'pyperf180.bpf.o' + scale_test:FAIL:expect_success unexpected error: -12 (errno 12) + #405 verif_scale_pyperf180:FAIL + +Note that due to recent llvm18 development, the patch [2] (already applied +in bpf-next) needs to be applied to bpf tree for testing purpose. + +The fix is rather simple. For 32bit offset branch insn, the adjusted +offset compares to [S32_MIN, S32_MAX] and then verification succeeded. + + [1] https://lore.kernel.org/all/20230728011143.3710005-1-yonghong.song@linux.dev + [2] https://lore.kernel.org/bpf/20231110193644.3130906-1-yonghong.song@linux.dev + +Fixes: 4cd58e9af8b9 ("bpf: Support new 32bit offset jmp instruction") +Signed-off-by: Yonghong Song +Signed-off-by: Andrii Nakryiko +Link: https://lore.kernel.org/bpf/20231201024640.3417057-1-yonghong.song@linux.dev +--- + kernel/bpf/core.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c +index cd3afe57ece3..fe254ae035fe 100644 +--- a/kernel/bpf/core.c ++++ b/kernel/bpf/core.c +@@ -371,14 +371,18 @@ static int bpf_adj_delta_to_imm(struct bpf_insn *insn, u32 pos, s32 end_old, + static int bpf_adj_delta_to_off(struct bpf_insn *insn, u32 pos, s32 end_old, + s32 end_new, s32 curr, const bool probe_pass) + { +- const s32 off_min = S16_MIN, off_max = S16_MAX; ++ s64 off_min, off_max, off; + s32 delta = end_new - end_old; +- s32 off; + +- if (insn->code == (BPF_JMP32 | BPF_JA)) ++ if (insn->code == (BPF_JMP32 | BPF_JA)) { + off = insn->imm; +- else ++ off_min = S32_MIN; ++ off_max = S32_MAX; ++ } else { + off = insn->off; ++ off_min = S16_MIN; ++ off_max = S16_MAX; ++ } + + if (curr < pos && curr + off + 1 >= end_old) + off += delta; +-- +2.34.1 + diff --git a/ci/diffs/0001-bpf-next-selftests-bpf-Fix-a-btf_dump-selftest-failure.patch b/ci/diffs/0001-bpf-next-selftests-bpf-Fix-a-btf_dump-selftest-failure.patch new file mode 100644 index 0000000000000..ea6b2386d0345 --- /dev/null +++ b/ci/diffs/0001-bpf-next-selftests-bpf-Fix-a-btf_dump-selftest-failure.patch @@ -0,0 +1,40 @@ +From patchwork Fri Aug 2 18:54:34 2024 +From: Yonghong Song +Subject: [PATCH bpf-next] selftests/bpf: Fix a btf_dump selftest failure + +Jakub reported bpf selftest "btf_dump" failure after forwarding to +v6.11-rc1 with netdev. + Error: #33 btf_dump + Error: #33/15 btf_dump/btf_dump: var_data + btf_dump_data:FAIL:find type id unexpected find type id: actual -2 < expected 0 + +The reason for the failure is due to + commit 94ede2a3e913 ("profiling: remove stale percpu flip buffer variables") +where percpu static variable "cpu_profile_flip" is removed. + +Let us replace "cpu_profile_flip" with a variable in bpf subsystem +so whenever that variable gets deleted or renamed, we can detect the +failure immediately. In this case, I picked a static percpu variable +"bpf_cgrp_storage_busy" which is defined in kernel/bpf/bpf_cgrp_storage.c. + +Reported-by: Jakub Kicinski +Signed-off-by: Yonghong Song +--- + tools/testing/selftests/bpf/prog_tests/btf_dump.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/tools/testing/selftests/bpf/prog_tests/btf_dump.c b/tools/testing/selftests/bpf/prog_tests/btf_dump.c +index 09a8e6f9b379..b293b8501fd6 100644 +--- a/tools/testing/selftests/bpf/prog_tests/btf_dump.c ++++ b/tools/testing/selftests/bpf/prog_tests/btf_dump.c +@@ -805,8 +805,8 @@ static void test_btf_dump_var_data(struct btf *btf, struct btf_dump *d, + TEST_BTF_DUMP_VAR(btf, d, NULL, str, "cpu_number", int, BTF_F_COMPACT, + "int cpu_number = (int)100", 100); + #endif +- TEST_BTF_DUMP_VAR(btf, d, NULL, str, "cpu_profile_flip", int, BTF_F_COMPACT, +- "static int cpu_profile_flip = (int)2", 2); ++ TEST_BTF_DUMP_VAR(btf, d, NULL, str, "bpf_cgrp_storage_busy", int, BTF_F_COMPACT, ++ "static int bpf_cgrp_storage_busy = (int)2", 2); + } + + static void test_btf_datasec(struct btf *btf, struct btf_dump *d, char *str, diff --git a/ci/diffs/0001-net-bpf-Use-sockopt_lock_sock-in-ip_sock_set_tos.patch b/ci/diffs/0001-net-bpf-Use-sockopt_lock_sock-in-ip_sock_set_tos.patch new file mode 100644 index 0000000000000..bd12bd9b3fba5 --- /dev/null +++ b/ci/diffs/0001-net-bpf-Use-sockopt_lock_sock-in-ip_sock_set_tos.patch @@ -0,0 +1,99 @@ +From c8268f8e9fa33c32e1f2f86fc7b703408a396c70 Mon Sep 17 00:00:00 2001 +From: Yonghong Song +Date: Fri, 27 Oct 2023 11:24:24 -0700 +Subject: [PATCH] net: bpf: Use sockopt_lock_sock() in ip_sock_set_tos() + +With latest sync from net-next tree, bpf-next has a bpf selftest failure: + [root@arch-fb-vm1 bpf]# ./test_progs -t setget_sockopt + ... + [ 76.194349] ============================================ + [ 76.194682] WARNING: possible recursive locking detected + [ 76.195039] 6.6.0-rc7-g37884503df08-dirty #67 Tainted: G W OE + [ 76.195518] -------------------------------------------- + [ 76.195852] new_name/154 is trying to acquire lock: + [ 76.196159] ffff8c3e06ad8d30 (sk_lock-AF_INET){+.+.}-{0:0}, at: ip_sock_set_tos+0x19/0x30 + [ 76.196669] + [ 76.196669] but task is already holding lock: + [ 76.197028] ffff8c3e06ad8d30 (sk_lock-AF_INET){+.+.}-{0:0}, at: inet_listen+0x21/0x70 + [ 76.197517] + [ 76.197517] other info that might help us debug this: + [ 76.197919] Possible unsafe locking scenario: + [ 76.197919] + [ 76.198287] CPU0 + [ 76.198444] ---- + [ 76.198600] lock(sk_lock-AF_INET); + [ 76.198831] lock(sk_lock-AF_INET); + [ 76.199062] + [ 76.199062] *** DEADLOCK *** + [ 76.199062] + [ 76.199420] May be due to missing lock nesting notation + [ 76.199420] + [ 76.199879] 2 locks held by new_name/154: + [ 76.200131] #0: ffff8c3e06ad8d30 (sk_lock-AF_INET){+.+.}-{0:0}, at: inet_listen+0x21/0x70 + [ 76.200644] #1: ffffffff90f96a40 (rcu_read_lock){....}-{1:2}, at: __cgroup_bpf_run_filter_sock_ops+0x55/0x290 + [ 76.201268] + [ 76.201268] stack backtrace: + [ 76.201538] CPU: 4 PID: 154 Comm: new_name Tainted: G W OE 6.6.0-rc7-g37884503df08-dirty #67 + [ 76.202134] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.13.0-1ubuntu1.1 04/01/2014 + [ 76.202699] Call Trace: + [ 76.202858] + [ 76.203002] dump_stack_lvl+0x4b/0x80 + [ 76.203239] __lock_acquire+0x740/0x1ec0 + [ 76.203503] lock_acquire+0xc1/0x2a0 + [ 76.203766] ? ip_sock_set_tos+0x19/0x30 + [ 76.204050] ? sk_stream_write_space+0x12a/0x230 + [ 76.204389] ? lock_release+0xbe/0x260 + [ 76.204661] lock_sock_nested+0x32/0x80 + [ 76.204942] ? ip_sock_set_tos+0x19/0x30 + [ 76.205208] ip_sock_set_tos+0x19/0x30 + [ 76.205452] do_ip_setsockopt+0x4b3/0x1580 + [ 76.205719] __bpf_setsockopt+0x62/0xa0 + [ 76.205963] bpf_sock_ops_setsockopt+0x11/0x20 + [ 76.206247] bpf_prog_630217292049c96e_bpf_test_sockopt_int+0xbc/0x123 + [ 76.206660] bpf_prog_493685a3bae00bbd_bpf_test_ip_sockopt+0x49/0x4b + [ 76.207055] bpf_prog_b0bcd27f269aeea0_skops_sockopt+0x44c/0xec7 + [ 76.207437] __cgroup_bpf_run_filter_sock_ops+0xda/0x290 + [ 76.207829] __inet_listen_sk+0x108/0x1b0 + [ 76.208122] inet_listen+0x48/0x70 + [ 76.208373] __sys_listen+0x74/0xb0 + [ 76.208630] __x64_sys_listen+0x16/0x20 + [ 76.208911] do_syscall_64+0x3f/0x90 + [ 76.209174] entry_SYSCALL_64_after_hwframe+0x6e/0xd8 + ... + +Both ip_sock_set_tos() and inet_listen() calls lock_sock(sk) which +caused a dead lock. + +To fix the issue, use sockopt_lock_sock() in ip_sock_set_tos() +instead. sockopt_lock_sock() will avoid lock_sock() if it is in bpf +context. + +Fixes: 878d951c6712 ("inet: lock the socket in ip_sock_set_tos()") +Suggested-by: Martin KaFai Lau +Signed-off-by: Yonghong Song +Signed-off-by: Andrii Nakryiko +Reviewed-by: Eric Dumazet +Link: https://lore.kernel.org/bpf/20231027182424.1444845-1-yonghong.song@linux.dev +--- + net/ipv4/ip_sockglue.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c +index 9c68b6b74d9f..2efc53526a38 100644 +--- a/net/ipv4/ip_sockglue.c ++++ b/net/ipv4/ip_sockglue.c +@@ -602,9 +602,9 @@ void __ip_sock_set_tos(struct sock *sk, int val) + + void ip_sock_set_tos(struct sock *sk, int val) + { +- lock_sock(sk); ++ sockopt_lock_sock(sk); + __ip_sock_set_tos(sk, val); +- release_sock(sk); ++ sockopt_release_sock(sk); + } + EXPORT_SYMBOL(ip_sock_set_tos); + +-- +2.34.1 + diff --git a/ci/diffs/0001-selftests-bpf-Filter-out-_GNU_SOURCE-when-compiling-.patch b/ci/diffs/0001-selftests-bpf-Filter-out-_GNU_SOURCE-when-compiling-.patch new file mode 100644 index 0000000000000..da5bcdc455967 --- /dev/null +++ b/ci/diffs/0001-selftests-bpf-Filter-out-_GNU_SOURCE-when-compiling-.patch @@ -0,0 +1,51 @@ +From 41c24102af7b6236277a214428b203d51a3462df Mon Sep 17 00:00:00 2001 +From: Stanislav Fomichev +Date: Thu, 25 Jul 2024 14:40:29 -0700 +Subject: [PATCH 1/1] selftests/bpf: Filter out _GNU_SOURCE when compiling + test_cpp + +Jakub reports build failures when merging linux/master with net tree: + +CXX test_cpp +In file included from :454: +:2:9: error: '_GNU_SOURCE' macro redefined [-Werror,-Wmacro-redefined] + 2 | #define _GNU_SOURCE + | ^ +:445:9: note: previous definition is here + 445 | #define _GNU_SOURCE 1 + +The culprit is commit cc937dad85ae ("selftests: centralize -D_GNU_SOURCE= to +CFLAGS in lib.mk") which unconditionally added -D_GNU_SOUCE to CLFAGS. +Apparently clang++ also unconditionally adds it for the C++ targets [0] +which causes a conflict. Add small change in the selftests makefile +to filter it out for test_cpp. + +Not sure which tree it should go via, targeting bpf for now, but net +might be better? + +0: https://stackoverflow.com/questions/11670581/why-is-gnu-source-defined-by-default-and-how-to-turn-it-off + +Signed-off-by: Stanislav Fomichev +Signed-off-by: Andrii Nakryiko +Acked-by: Jiri Olsa +Link: https://lore.kernel.org/bpf/20240725214029.1760809-1-sdf@fomichev.me +--- + tools/testing/selftests/bpf/Makefile | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile +index dd49c1d23a60..81d4757ecd4c 100644 +--- a/tools/testing/selftests/bpf/Makefile ++++ b/tools/testing/selftests/bpf/Makefile +@@ -713,7 +713,7 @@ $(OUTPUT)/xdp_features: xdp_features.c $(OUTPUT)/network_helpers.o $(OUTPUT)/xdp + # Make sure we are able to include and link libbpf against c++. + $(OUTPUT)/test_cpp: test_cpp.cpp $(OUTPUT)/test_core_extern.skel.h $(BPFOBJ) + $(call msg,CXX,,$@) +- $(Q)$(CXX) $(CFLAGS) $(filter %.a %.o %.cpp,$^) $(LDLIBS) -o $@ ++ $(Q)$(CXX) $(subst -D_GNU_SOURCE=,,$(CFLAGS)) $(filter %.a %.o %.cpp,$^) $(LDLIBS) -o $@ + + # Benchmark runner + $(OUTPUT)/bench_%.o: benchs/bench_%.c bench.h $(BPFOBJ) +-- +2.43.0 + diff --git a/ci/diffs/0001-selftests-bpf-Fix-bpf_cookie-and-find_vma-in-nested-.patch b/ci/diffs/0001-selftests-bpf-Fix-bpf_cookie-and-find_vma-in-nested-.patch new file mode 100644 index 0000000000000..4ebfe20b24707 --- /dev/null +++ b/ci/diffs/0001-selftests-bpf-Fix-bpf_cookie-and-find_vma-in-nested-.patch @@ -0,0 +1,50 @@ +From f3d2080e8cf23125f79e345061149ae40f66816f Mon Sep 17 00:00:00 2001 +From: Song Liu +Date: Mon, 3 Jun 2024 23:43:17 -0700 +Subject: [PATCH bpf-next] selftests/bpf: Fix bpf_cookie and find_vma in nested + VM + +bpf_cookie and find_vma are flaky in nested VMs, which is used by some CI +systems. It turns out these failures are caused by unreliable perf event +in nested VM. Fix these by: + + 1. Use PERF_COUNT_SW_CPU_CLOCK in find_vma; + 2. Increase sample_freq in bpf_cookie. + +Signed-off-by: Song Liu +--- + tools/testing/selftests/bpf/prog_tests/bpf_cookie.c | 2 +- + tools/testing/selftests/bpf/prog_tests/find_vma.c | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/tools/testing/selftests/bpf/prog_tests/bpf_cookie.c b/tools/testing/selftests/bpf/prog_tests/bpf_cookie.c +index 4407ea428e77..070c52c312e5 100644 +--- a/tools/testing/selftests/bpf/prog_tests/bpf_cookie.c ++++ b/tools/testing/selftests/bpf/prog_tests/bpf_cookie.c +@@ -451,7 +451,7 @@ static void pe_subtest(struct test_bpf_cookie *skel) + attr.type = PERF_TYPE_SOFTWARE; + attr.config = PERF_COUNT_SW_CPU_CLOCK; + attr.freq = 1; +- attr.sample_freq = 1000; ++ attr.sample_freq = 10000; + pfd = syscall(__NR_perf_event_open, &attr, -1, 0, -1, PERF_FLAG_FD_CLOEXEC); + if (!ASSERT_GE(pfd, 0, "perf_fd")) + goto cleanup; +diff --git a/tools/testing/selftests/bpf/prog_tests/find_vma.c b/tools/testing/selftests/bpf/prog_tests/find_vma.c +index 5165b38f0e59..f7619e0ade10 100644 +--- a/tools/testing/selftests/bpf/prog_tests/find_vma.c ++++ b/tools/testing/selftests/bpf/prog_tests/find_vma.c +@@ -29,8 +29,8 @@ static int open_pe(void) + + /* create perf event */ + attr.size = sizeof(attr); +- attr.type = PERF_TYPE_HARDWARE; +- attr.config = PERF_COUNT_HW_CPU_CYCLES; ++ attr.type = PERF_TYPE_SOFTWARE; ++ attr.config = PERF_COUNT_SW_CPU_CLOCK; + attr.freq = 1; + attr.sample_freq = 1000; + pfd = syscall(__NR_perf_event_open, &attr, 0, -1, -1, PERF_FLAG_FD_CLOEXEC); +-- +2.43.0 + diff --git a/ci/diffs/0001-selftests-bpf-Fix-pyperf180-compilation-failure-with.patch b/ci/diffs/0001-selftests-bpf-Fix-pyperf180-compilation-failure-with.patch new file mode 100644 index 0000000000000..d55d2e7af8651 --- /dev/null +++ b/ci/diffs/0001-selftests-bpf-Fix-pyperf180-compilation-failure-with.patch @@ -0,0 +1,78 @@ +From 100888fb6d8a185866b1520031ee7e3182b173de Mon Sep 17 00:00:00 2001 +From: Yonghong Song +Date: Fri, 10 Nov 2023 11:36:44 -0800 +Subject: [PATCH] selftests/bpf: Fix pyperf180 compilation failure with clang18 + +With latest clang18 (main branch of llvm-project repo), when building bpf selftests, + [~/work/bpf-next (master)]$ make -C tools/testing/selftests/bpf LLVM=1 -j + +The following compilation error happens: + fatal error: error in backend: Branch target out of insn range + ... + Stack dump: + 0. Program arguments: clang -g -Wall -Werror -D__TARGET_ARCH_x86 -mlittle-endian + -I/home/yhs/work/bpf-next/tools/testing/selftests/bpf/tools/include + -I/home/yhs/work/bpf-next/tools/testing/selftests/bpf -I/home/yhs/work/bpf-next/tools/include/uapi + -I/home/yhs/work/bpf-next/tools/testing/selftests/usr/include -idirafter + /home/yhs/work/llvm-project/llvm/build.18/install/lib/clang/18/include -idirafter /usr/local/include + -idirafter /usr/include -Wno-compare-distinct-pointer-types -DENABLE_ATOMICS_TESTS -O2 --target=bpf + -c progs/pyperf180.c -mcpu=v3 -o /home/yhs/work/bpf-next/tools/testing/selftests/bpf/pyperf180.bpf.o + 1. parser at end of file + 2. Code generation + ... + +The compilation failure only happens to cpu=v2 and cpu=v3. cpu=v4 is okay +since cpu=v4 supports 32-bit branch target offset. + +The above failure is due to upstream llvm patch [1] where some inlining behavior +are changed in clang18. + +To workaround the issue, previously all 180 loop iterations are fully unrolled. +The bpf macro __BPF_CPU_VERSION__ (implemented in clang18 recently) is used to avoid +unrolling changes if cpu=v4. If __BPF_CPU_VERSION__ is not available and the +compiler is clang18, the unrollng amount is unconditionally reduced. + + [1] https://github.com/llvm/llvm-project/commit/1a2e77cf9e11dbf56b5720c607313a566eebb16e + +Signed-off-by: Yonghong Song +Signed-off-by: Andrii Nakryiko +Tested-by: Alan Maguire +Link: https://lore.kernel.org/bpf/20231110193644.3130906-1-yonghong.song@linux.dev +--- + tools/testing/selftests/bpf/progs/pyperf180.c | 22 +++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/tools/testing/selftests/bpf/progs/pyperf180.c b/tools/testing/selftests/bpf/progs/pyperf180.c +index c39f559d3100..42c4a8b62e36 100644 +--- a/tools/testing/selftests/bpf/progs/pyperf180.c ++++ b/tools/testing/selftests/bpf/progs/pyperf180.c +@@ -1,4 +1,26 @@ + // SPDX-License-Identifier: GPL-2.0 + // Copyright (c) 2019 Facebook + #define STACK_MAX_LEN 180 ++ ++/* llvm upstream commit at clang18 ++ * https://github.com/llvm/llvm-project/commit/1a2e77cf9e11dbf56b5720c607313a566eebb16e ++ * changed inlining behavior and caused compilation failure as some branch ++ * target distance exceeded 16bit representation which is the maximum for ++ * cpu v1/v2/v3. Macro __BPF_CPU_VERSION__ is later implemented in clang18 ++ * to specify which cpu version is used for compilation. So a smaller ++ * unroll_count can be set if __BPF_CPU_VERSION__ is less than 4, which ++ * reduced some branch target distances and resolved the compilation failure. ++ * ++ * To capture the case where a developer/ci uses clang18 but the corresponding ++ * repo checkpoint does not have __BPF_CPU_VERSION__, a smaller unroll_count ++ * will be set as well to prevent potential compilation failures. ++ */ ++#ifdef __BPF_CPU_VERSION__ ++#if __BPF_CPU_VERSION__ < 4 ++#define UNROLL_COUNT 90 ++#endif ++#elif __clang_major__ == 18 ++#define UNROLL_COUNT 90 ++#endif ++ + #include "pyperf.h" +-- +2.34.1 + diff --git a/ci/diffs/0001-selftests-bpf-disable-detection-of-llvm-when-buildin.patch b/ci/diffs/0001-selftests-bpf-disable-detection-of-llvm-when-buildin.patch new file mode 100644 index 0000000000000..6497a6cc38c90 --- /dev/null +++ b/ci/diffs/0001-selftests-bpf-disable-detection-of-llvm-when-buildin.patch @@ -0,0 +1,41 @@ +From 42839864a62ee244ec280b09149b1cb439f681db Mon Sep 17 00:00:00 2001 +From: Manu Bretelle +Date: Fri, 27 Oct 2023 18:25:39 -0700 +Subject: [PATCH bpf-next] selftests/bpf: disable detection of llvm when + building bpftool + +The VMs in which we run the selftests do not have llvm installed. +We build selftests/bpftool in a host that have llvm. +bpftool currently will use llvm first and fallback to libbfd but there +is no way to disable detection from the command line. + +Removing it from the feature detection should force us to use libbfd. + +Signed-off-by: Manu Bretelle +--- + tools/bpf/bpftool/Makefile | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/tools/bpf/bpftool/Makefile b/tools/bpf/bpftool/Makefile +index e9154ace80ff..01314458e25e 100644 +--- a/tools/bpf/bpftool/Makefile ++++ b/tools/bpf/bpftool/Makefile +@@ -95,7 +95,6 @@ RM ?= rm -f + FEATURE_USER = .bpftool + + FEATURE_TESTS := clang-bpf-co-re +-FEATURE_TESTS += llvm + FEATURE_TESTS += libcap + FEATURE_TESTS += libbfd + FEATURE_TESTS += libbfd-liberty +@@ -104,7 +103,6 @@ FEATURE_TESTS += disassembler-four-args + FEATURE_TESTS += disassembler-init-styled + + FEATURE_DISPLAY := clang-bpf-co-re +-FEATURE_DISPLAY += llvm + FEATURE_DISPLAY += libcap + FEATURE_DISPLAY += libbfd + FEATURE_DISPLAY += libbfd-liberty +-- +2.39.3 + diff --git a/ci/diffs/0001-selftests-bpf-fix-inet_csk_accept-prototype-in-test_.patch b/ci/diffs/0001-selftests-bpf-fix-inet_csk_accept-prototype-in-test_.patch new file mode 100644 index 0000000000000..3fa007c51db68 --- /dev/null +++ b/ci/diffs/0001-selftests-bpf-fix-inet_csk_accept-prototype-in-test_.patch @@ -0,0 +1,32 @@ +From 0daad0a615e687e1247230f3d0c31ae60ba32314 Mon Sep 17 00:00:00 2001 +From: Andrii Nakryiko +Date: Tue, 28 May 2024 15:29:38 -0700 +Subject: [PATCH bpf-next] selftests/bpf: fix inet_csk_accept prototype in + test_sk_storage_tracing.c + +Recent kernel change ([0]) changed inet_csk_accept() prototype. Adapt +progs/test_sk_storage_tracing.c to take that into account. + + [0] 92ef0fd55ac8 ("net: change proto and proto_ops accept type") + +Signed-off-by: Andrii Nakryiko +--- + tools/testing/selftests/bpf/progs/test_sk_storage_tracing.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/bpf/progs/test_sk_storage_tracing.c b/tools/testing/selftests/bpf/progs/test_sk_storage_tracing.c +index 02e718f06e0f..40531e56776e 100644 +--- a/tools/testing/selftests/bpf/progs/test_sk_storage_tracing.c ++++ b/tools/testing/selftests/bpf/progs/test_sk_storage_tracing.c +@@ -84,7 +84,7 @@ int BPF_PROG(trace_tcp_connect, struct sock *sk) + } + + SEC("fexit/inet_csk_accept") +-int BPF_PROG(inet_csk_accept, struct sock *sk, int flags, int *err, bool kern, ++int BPF_PROG(inet_csk_accept, struct sock *sk, struct proto_accept_arg *arg, + struct sock *accepted_sk) + { + set_task_info(accepted_sk); +-- +2.43.0 + diff --git a/ci/diffs/0001-selftests-bpf-work-around-latest-Clang-smartness.patch b/ci/diffs/0001-selftests-bpf-work-around-latest-Clang-smartness.patch new file mode 100644 index 0000000000000..ec1e29a8ab974 --- /dev/null +++ b/ci/diffs/0001-selftests-bpf-work-around-latest-Clang-smartness.patch @@ -0,0 +1,31 @@ +From d31a7125891994681503770cff46a119692fb2b9 Mon Sep 17 00:00:00 2001 +From: Andrii Nakryiko +Date: Mon, 11 Dec 2023 17:09:38 -0800 +Subject: [PATCH 1/1] selftests/bpf: work around latest Clang smartness + +Work around the issue while we deal with it in the Clang itself. +See [0]. + + [0] https://github.com/llvm/llvm-project/pull/73662#issuecomment-1849281758 + +Signed-off-by: Andrii Nakryiko +--- + tools/testing/selftests/bpf/progs/iters.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/testing/selftests/bpf/progs/iters.c b/tools/testing/selftests/bpf/progs/iters.c +index 3aca3dc145b5..929ba6fa2105 100644 +--- a/tools/testing/selftests/bpf/progs/iters.c ++++ b/tools/testing/selftests/bpf/progs/iters.c +@@ -1420,7 +1420,7 @@ SEC("raw_tp") + __success + int iter_arr_with_actual_elem_count(const void *ctx) + { +- int i, n = loop_data.n, sum = 0; ++ unsigned i, n = loop_data.n, sum = 0; + + if (n > ARRAY_SIZE(loop_data.data)) + return 0; +-- +2.34.1 + diff --git a/ci/diffs/0001-selftests-bpf-xskxceiver-ksft_print_msg-fix-format-t.patch b/ci/diffs/0001-selftests-bpf-xskxceiver-ksft_print_msg-fix-format-t.patch new file mode 100644 index 0000000000000..e631fac0cc698 --- /dev/null +++ b/ci/diffs/0001-selftests-bpf-xskxceiver-ksft_print_msg-fix-format-t.patch @@ -0,0 +1,89 @@ +From fe69a1b1b6ed9ffc2c578c63f526026a8ab74f0c Mon Sep 17 00:00:00 2001 +From: Anders Roxell +Date: Thu, 9 Nov 2023 18:43:28 +0100 +Subject: [PATCH] selftests: bpf: xskxceiver: ksft_print_msg: fix format type + error + +Crossbuilding selftests/bpf for architecture arm64, format specifies +type error show up like. + +xskxceiver.c:912:34: error: format specifies type 'int' but the argument +has type '__u64' (aka 'unsigned long long') [-Werror,-Wformat] + ksft_print_msg("[%s] expected meta_count [%d], got meta_count [%d]\n", + ~~ + %llu + __func__, pkt->pkt_nb, meta->count); + ^~~~~~~~~~~ +xskxceiver.c:929:55: error: format specifies type 'unsigned long long' but + the argument has type 'u64' (aka 'unsigned long') [-Werror,-Wformat] + ksft_print_msg("Frag invalid addr: %llx len: %u\n", addr, len); + ~~~~ ^~~~ + +Fixing the issues by casting to (unsigned long long) and changing the +specifiers to be %llu from %d and %u, since with u64s it might be %llx +or %lx, depending on architecture. + +Signed-off-by: Anders Roxell +Link: https://lore.kernel.org/r/20231109174328.1774571-1-anders.roxell@linaro.org +Signed-off-by: Alexei Starovoitov +--- + tools/testing/selftests/bpf/xskxceiver.c | 19 ++++++++++++------- + 1 file changed, 12 insertions(+), 7 deletions(-) + +diff --git a/tools/testing/selftests/bpf/xskxceiver.c b/tools/testing/selftests/bpf/xskxceiver.c +index 591ca9637b23..b604c570309a 100644 +--- a/tools/testing/selftests/bpf/xskxceiver.c ++++ b/tools/testing/selftests/bpf/xskxceiver.c +@@ -908,8 +908,9 @@ static bool is_metadata_correct(struct pkt *pkt, void *buffer, u64 addr) + struct xdp_info *meta = data - sizeof(struct xdp_info); + + if (meta->count != pkt->pkt_nb) { +- ksft_print_msg("[%s] expected meta_count [%d], got meta_count [%d]\n", +- __func__, pkt->pkt_nb, meta->count); ++ ksft_print_msg("[%s] expected meta_count [%d], got meta_count [%llu]\n", ++ __func__, pkt->pkt_nb, ++ (unsigned long long)meta->count); + return false; + } + +@@ -926,11 +927,13 @@ static bool is_frag_valid(struct xsk_umem_info *umem, u64 addr, u32 len, u32 exp + + if (addr >= umem->num_frames * umem->frame_size || + addr + len > umem->num_frames * umem->frame_size) { +- ksft_print_msg("Frag invalid addr: %llx len: %u\n", addr, len); ++ ksft_print_msg("Frag invalid addr: %llx len: %u\n", ++ (unsigned long long)addr, len); + return false; + } + if (!umem->unaligned_mode && addr % umem->frame_size + len > umem->frame_size) { +- ksft_print_msg("Frag crosses frame boundary addr: %llx len: %u\n", addr, len); ++ ksft_print_msg("Frag crosses frame boundary addr: %llx len: %u\n", ++ (unsigned long long)addr, len); + return false; + } + +@@ -1029,7 +1032,8 @@ static int complete_pkts(struct xsk_socket_info *xsk, int batch_size) + u64 addr = *xsk_ring_cons__comp_addr(&xsk->umem->cq, idx + rcvd - 1); + + ksft_print_msg("[%s] Too many packets completed\n", __func__); +- ksft_print_msg("Last completion address: %llx\n", addr); ++ ksft_print_msg("Last completion address: %llx\n", ++ (unsigned long long)addr); + return TEST_FAILURE; + } + +@@ -1513,8 +1517,9 @@ static int validate_tx_invalid_descs(struct ifobject *ifobject) + } + + if (stats.tx_invalid_descs != ifobject->xsk->pkt_stream->nb_pkts / 2) { +- ksft_print_msg("[%s] tx_invalid_descs incorrect. Got [%u] expected [%u]\n", +- __func__, stats.tx_invalid_descs, ++ ksft_print_msg("[%s] tx_invalid_descs incorrect. Got [%llu] expected [%u]\n", ++ __func__, ++ (unsigned long long)stats.tx_invalid_descs, + ifobject->xsk->pkt_stream->nb_pkts); + return TEST_FAILURE; + } +-- +2.34.1 + diff --git a/ci/diffs/0001-tools-resolve_btfids-fix-cross-compilation-to-non-host-endianness.patch b/ci/diffs/0001-tools-resolve_btfids-fix-cross-compilation-to-non-host-endianness.patch new file mode 100644 index 0000000000000..19d269de7e8ca --- /dev/null +++ b/ci/diffs/0001-tools-resolve_btfids-fix-cross-compilation-to-non-host-endianness.patch @@ -0,0 +1,142 @@ +From 3772e6cdb51f21a11df2acf6aa431cc8b9137bfb Mon Sep 17 00:00:00 2001 +From: Viktor Malik +Date: Tue, 6 Feb 2024 13:46:09 +0100 +Subject: [PATCH 1/2] tools/resolve_btfids: Refactor set sorting with types + from btf_ids.h + +Instead of using magic offsets to access BTF ID set data, leverage types +from btf_ids.h (btf_id_set and btf_id_set8) which define the actual +layout of the data. Thanks to this change, set sorting should also +continue working if the layout changes. + +This requires to sync the definition of 'struct btf_id_set8' from +include/linux/btf_ids.h to tools/include/linux/btf_ids.h. We don't sync +the rest of the file at the moment, b/c that would require to also sync +multiple dependent headers and we don't need any other defs from +btf_ids.h. + +Signed-off-by: Viktor Malik +Signed-off-by: Andrii Nakryiko +Acked-by: Daniel Xu +Link: https://lore.kernel.org/bpf/ff7f062ddf6a00815fda3087957c4ce667f50532.1707223196.git.vmalik@redhat.com +--- + tools/bpf/resolve_btfids/main.c | 35 ++++++++++++++++++++------------- + tools/include/linux/btf_ids.h | 9 +++++++++ + 2 files changed, 30 insertions(+), 14 deletions(-) + +diff --git a/tools/bpf/resolve_btfids/main.c b/tools/bpf/resolve_btfids/main.c +index 27a23196d58e..32634f00abba 100644 +--- a/tools/bpf/resolve_btfids/main.c ++++ b/tools/bpf/resolve_btfids/main.c +@@ -70,6 +70,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -78,7 +79,7 @@ + #include + + #define BTF_IDS_SECTION ".BTF_ids" +-#define BTF_ID "__BTF_ID__" ++#define BTF_ID_PREFIX "__BTF_ID__" + + #define BTF_STRUCT "struct" + #define BTF_UNION "union" +@@ -161,7 +162,7 @@ static int eprintf(int level, int var, const char *fmt, ...) + + static bool is_btf_id(const char *name) + { +- return name && !strncmp(name, BTF_ID, sizeof(BTF_ID) - 1); ++ return name && !strncmp(name, BTF_ID_PREFIX, sizeof(BTF_ID_PREFIX) - 1); + } + + static struct btf_id *btf_id__find(struct rb_root *root, const char *name) +@@ -441,7 +442,7 @@ static int symbols_collect(struct object *obj) + * __BTF_ID__TYPE__vfs_truncate__0 + * prefix = ^ + */ +- prefix = name + sizeof(BTF_ID) - 1; ++ prefix = name + sizeof(BTF_ID_PREFIX) - 1; + + /* struct */ + if (!strncmp(prefix, BTF_STRUCT, sizeof(BTF_STRUCT) - 1)) { +@@ -649,19 +650,18 @@ static int cmp_id(const void *pa, const void *pb) + static int sets_patch(struct object *obj) + { + Elf_Data *data = obj->efile.idlist; +- int *ptr = data->d_buf; + struct rb_node *next; + + next = rb_first(&obj->sets); + while (next) { +- unsigned long addr, idx; ++ struct btf_id_set8 *set8; ++ struct btf_id_set *set; ++ unsigned long addr, off; + struct btf_id *id; +- int *base; +- int cnt; + + id = rb_entry(next, struct btf_id, rb_node); + addr = id->addr[0]; +- idx = addr - obj->efile.idlist_addr; ++ off = addr - obj->efile.idlist_addr; + + /* sets are unique */ + if (id->addr_cnt != 1) { +@@ -670,14 +670,21 @@ static int sets_patch(struct object *obj) + return -1; + } + +- idx = idx / sizeof(int); +- base = &ptr[idx] + (id->is_set8 ? 2 : 1); +- cnt = ptr[idx]; ++ if (id->is_set) { ++ set = data->d_buf + off; ++ qsort(set->ids, set->cnt, sizeof(set->ids[0]), cmp_id); ++ } else { ++ set8 = data->d_buf + off; ++ /* ++ * Make sure id is at the beginning of the pairs ++ * struct, otherwise the below qsort would not work. ++ */ ++ BUILD_BUG_ON(set8->pairs != &set8->pairs[0].id); ++ qsort(set8->pairs, set8->cnt, sizeof(set8->pairs[0]), cmp_id); ++ } + + pr_debug("sorting addr %5lu: cnt %6d [%s]\n", +- (idx + 1) * sizeof(int), cnt, id->name); +- +- qsort(base, cnt, id->is_set8 ? sizeof(uint64_t) : sizeof(int), cmp_id); ++ off, id->is_set ? set->cnt : set8->cnt, id->name); + + next = rb_next(next); + } +diff --git a/tools/include/linux/btf_ids.h b/tools/include/linux/btf_ids.h +index 2f882d5cb30f..72535f00572f 100644 +--- a/tools/include/linux/btf_ids.h ++++ b/tools/include/linux/btf_ids.h +@@ -8,6 +8,15 @@ struct btf_id_set { + u32 ids[]; + }; + ++struct btf_id_set8 { ++ u32 cnt; ++ u32 flags; ++ struct { ++ u32 id; ++ u32 flags; ++ } pairs[]; ++}; ++ + #ifdef CONFIG_DEBUG_INFO_BTF + + #include /* for __PASTE */ +-- +2.39.3 + + + diff --git a/ci/diffs/0001-tracing-kprobes-Fix-symbol-counting-logic-by-looking.patch b/ci/diffs/0001-tracing-kprobes-Fix-symbol-counting-logic-by-looking.patch new file mode 100644 index 0000000000000..24ebc231056cb --- /dev/null +++ b/ci/diffs/0001-tracing-kprobes-Fix-symbol-counting-logic-by-looking.patch @@ -0,0 +1,65 @@ +From 08969a676d234a178ff9f8c67936a2ad98a741eb Mon Sep 17 00:00:00 2001 +From: Andrii Nakryiko +Date: Fri, 27 Oct 2023 16:22:24 -0700 +Subject: [PATCH] tracing/kprobes: Fix symbol counting logic by looking at + modules as well + +Recent changes to count number of matching symbols when creating +a kprobe event failed to take into account kernel modules. As such, it +breaks kprobes on kernel module symbols, by assuming there is no match. + +Fix this my calling module_kallsyms_on_each_symbol() in addition to +kallsyms_on_each_match_symbol() to perform a proper counting. + +Cc: Francis Laniel +Cc: stable@vger.kernel.org +Cc: Masami Hiramatsu +Cc: Steven Rostedt +Fixes: b022f0c7e404 ("tracing/kprobes: Return EADDRNOTAVAIL when func matches several symbols") +Signed-off-by: Andrii Nakryiko +--- + kernel/trace/trace_kprobe.c | 24 ++++++++++++++++++++---- + 1 file changed, 20 insertions(+), 4 deletions(-) + +diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c +index effcaede4759..1efb27f35963 100644 +--- a/kernel/trace/trace_kprobe.c ++++ b/kernel/trace/trace_kprobe.c +@@ -714,14 +714,30 @@ static int count_symbols(void *data, unsigned long unused) + return 0; + } + ++struct sym_count_ctx { ++ unsigned int count; ++ const char *name; ++}; ++ ++static int count_mod_symbols(void *data, const char *name, unsigned long unused) ++{ ++ struct sym_count_ctx *ctx = data; ++ ++ if (strcmp(name, ctx->name) == 0) ++ ctx->count++; ++ ++ return 0; ++} ++ + static unsigned int number_of_same_symbols(char *func_name) + { +- unsigned int count; ++ struct sym_count_ctx ctx = { .count = 0, .name = func_name }; ++ ++ kallsyms_on_each_match_symbol(count_symbols, func_name, &ctx.count); + +- count = 0; +- kallsyms_on_each_match_symbol(count_symbols, func_name, &count); ++ module_kallsyms_on_each_symbol(NULL, count_mod_symbols, &ctx); + +- return count; ++ return ctx.count; + } + + static int __trace_kprobe_create(int argc, const char *argv[]) +-- +2.34.1 + diff --git a/ci/diffs/0002-tools-resolve_btfids-fix-cross-compilation-to-non-host-endianness.patch b/ci/diffs/0002-tools-resolve_btfids-fix-cross-compilation-to-non-host-endianness.patch new file mode 100644 index 0000000000000..c4d67693bd132 --- /dev/null +++ b/ci/diffs/0002-tools-resolve_btfids-fix-cross-compilation-to-non-host-endianness.patch @@ -0,0 +1,117 @@ +From c3dcadfdf2bf8f01471066700c098b5185240df6 Mon Sep 17 00:00:00 2001 +From: Viktor Malik +Date: Tue, 6 Feb 2024 13:46:10 +0100 +Subject: [PATCH 2/2] tools/resolve_btfids: Fix cross-compilation to non-host + endianness + +The .BTF_ids section is pre-filled with zeroed BTF ID entries during the +build and afterwards patched by resolve_btfids with correct values. +Since resolve_btfids always writes in host-native endianness, it relies +on libelf to do the translation when the target ELF is cross-compiled to +a different endianness (this was introduced in commit 61e8aeda9398 +("bpf: Fix libelf endian handling in resolv_btfids")). + +Unfortunately, the translation will corrupt the flags fields of SET8 +entries because these were written during vmlinux compilation and are in +the correct endianness already. This will lead to numerous selftests +failures such as: + + $ sudo ./test_verifier 502 502 + #502/p sleepable fentry accept FAIL + Failed to load prog 'Invalid argument'! + bpf_fentry_test1 is not sleepable + verification time 34 usec + stack depth 0 + processed 0 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0 + Summary: 0 PASSED, 0 SKIPPED, 1 FAILED + +Since it's not possible to instruct libelf to translate just certain +values, let's manually bswap the flags (both global and entry flags) in +resolve_btfids when needed, so that libelf then translates everything +correctly. + +Fixes: ef2c6f370a63 ("tools/resolve_btfids: Add support for 8-byte BTF sets") +Signed-off-by: Viktor Malik +Signed-off-by: Andrii Nakryiko +Link: https://lore.kernel.org/bpf/7b6bff690919555574ce0f13d2a5996cacf7bf69.1707223196.git.vmalik@redhat.com +--- + tools/bpf/resolve_btfids/main.c | 35 +++++++++++++++++++++++++++++++++ + 1 file changed, 35 insertions(+) + +diff --git a/tools/bpf/resolve_btfids/main.c b/tools/bpf/resolve_btfids/main.c +index 32634f00abba..d9520cb826b3 100644 +--- a/tools/bpf/resolve_btfids/main.c ++++ b/tools/bpf/resolve_btfids/main.c +@@ -90,6 +90,14 @@ + + #define ADDR_CNT 100 + ++#if __BYTE_ORDER == __LITTLE_ENDIAN ++# define ELFDATANATIVE ELFDATA2LSB ++#elif __BYTE_ORDER == __BIG_ENDIAN ++# define ELFDATANATIVE ELFDATA2MSB ++#else ++# error "Unknown machine endianness!" ++#endif ++ + struct btf_id { + struct rb_node rb_node; + char *name; +@@ -117,6 +125,7 @@ struct object { + int idlist_shndx; + size_t strtabidx; + unsigned long idlist_addr; ++ int encoding; + } efile; + + struct rb_root sets; +@@ -320,6 +329,7 @@ static int elf_collect(struct object *obj) + { + Elf_Scn *scn = NULL; + size_t shdrstrndx; ++ GElf_Ehdr ehdr; + int idx = 0; + Elf *elf; + int fd; +@@ -351,6 +361,13 @@ static int elf_collect(struct object *obj) + return -1; + } + ++ if (gelf_getehdr(obj->efile.elf, &ehdr) == NULL) { ++ pr_err("FAILED cannot get ELF header: %s\n", ++ elf_errmsg(-1)); ++ return -1; ++ } ++ obj->efile.encoding = ehdr.e_ident[EI_DATA]; ++ + /* + * Scan all the elf sections and look for save data + * from .BTF_ids section and symbols. +@@ -681,6 +698,24 @@ static int sets_patch(struct object *obj) + */ + BUILD_BUG_ON(set8->pairs != &set8->pairs[0].id); + qsort(set8->pairs, set8->cnt, sizeof(set8->pairs[0]), cmp_id); ++ ++ /* ++ * When ELF endianness does not match endianness of the ++ * host, libelf will do the translation when updating ++ * the ELF. This, however, corrupts SET8 flags which are ++ * already in the target endianness. So, let's bswap ++ * them to the host endianness and libelf will then ++ * correctly translate everything. ++ */ ++ if (obj->efile.encoding != ELFDATANATIVE) { ++ int i; ++ ++ set8->flags = bswap_32(set8->flags); ++ for (i = 0; i < set8->cnt; i++) { ++ set8->pairs[i].flags = ++ bswap_32(set8->pairs[i].flags); ++ } ++ } + } + + pr_debug("sorting addr %5lu: cnt %6d [%s]\n", +-- +2.39.3 + diff --git a/ci/diffs/0099-s390x_nolockdep.diff b/ci/diffs/0099-s390x_nolockdep.diff new file mode 100644 index 0000000000000..44c2d1a520656 --- /dev/null +++ b/ci/diffs/0099-s390x_nolockdep.diff @@ -0,0 +1,48 @@ +From 470d0c7874ac638ea62cddc3a20ec047fa4ab539 Mon Sep 17 00:00:00 2001 +From: Manu Bretelle +Date: Wed, 14 Feb 2024 17:25:35 -0800 +Subject: [PATCH] bpf/selftests: disable lockdep on s390x + +Tests are slow to run on s390x, this should make them faster. + +Signed-off-by: Manu Bretelle +--- + tools/testing/selftests/bpf/config.s390x | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/tools/testing/selftests/bpf/config.s390x b/tools/testing/selftests/bpf/config.s390x +index 706931a8c2c69..67bfd62b0b582 100644 +--- a/tools/testing/selftests/bpf/config.s390x ++++ b/tools/testing/selftests/bpf/config.s390x +@@ -23,11 +23,11 @@ CONFIG_CPUSETS=y + CONFIG_CRASH_DUMP=y + CONFIG_CRYPTO_USER_API_RNG=y + CONFIG_CRYPTO_USER_API_SKCIPHER=y +-CONFIG_DEBUG_ATOMIC_SLEEP=y ++CONFIG_DEBUG_ATOMIC_SLEEP=n + CONFIG_DEBUG_INFO_BTF=y + CONFIG_DEBUG_INFO_DWARF4=y + CONFIG_DEBUG_LIST=y +-CONFIG_DEBUG_LOCKDEP=y ++CONFIG_DEBUG_LOCKDEP=n + CONFIG_DEBUG_NOTIFIERS=y + CONFIG_DEBUG_PAGEALLOC=y + CONFIG_DEBUG_SECTION_MISMATCH=y +@@ -71,7 +71,7 @@ CONFIG_KRETPROBES=y + CONFIG_KSM=y + CONFIG_LATENCYTOP=y + CONFIG_LIVEPATCH=y +-CONFIG_LOCK_STAT=y ++CONFIG_LOCK_STAT=n + CONFIG_MACVLAN=y + CONFIG_MACVTAP=y + CONFIG_MAGIC_SYSRQ=y +@@ -101,7 +101,7 @@ CONFIG_PCI=y + CONFIG_POSIX_MQUEUE=y + CONFIG_PROC_KCORE=y + CONFIG_PROFILING=y +-CONFIG_PROVE_LOCKING=y ++CONFIG_PROVE_LOCKING=n + CONFIG_PTDUMP_DEBUGFS=y + CONFIG_RC_DEVICES=y + CONFIG_RC_LOOPBACK=y diff --git a/ci/diffs/0099-selftest-cross-compile.diff b/ci/diffs/0099-selftest-cross-compile.diff new file mode 100644 index 0000000000000..e8732596bdb3f --- /dev/null +++ b/ci/diffs/0099-selftest-cross-compile.diff @@ -0,0 +1,13 @@ +diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile +index a38a3001527c..af68528cc944 100644 +--- a/tools/testing/selftests/bpf/Makefile ++++ b/tools/testing/selftests/bpf/Makefile +@@ -304,7 +304,7 @@ $(OUTPUT)/test_maps: $(TESTING_HELPERS) + $(OUTPUT)/test_verifier: $(TESTING_HELPERS) $(CAP_HELPERS) $(UNPRIV_HELPERS) + $(OUTPUT)/xsk.o: $(BPFOBJ) + +-BPFTOOL ?= $(DEFAULT_BPFTOOL) ++BPFTOOL ?= $(TRUNNER_BPFTOOL) + $(DEFAULT_BPFTOOL): $(wildcard $(BPFTOOLDIR)/*.[ch] $(BPFTOOLDIR)/Makefile) \ + $(HOST_BPFOBJ) | $(HOST_BUILD_DIR)/bpftool + $(Q)$(MAKE) $(submake_extras) -C $(BPFTOOLDIR) \ diff --git a/ci/diffs/0199-iov_iter-fix-advancing-slot-in-iter_folioq_get_pages.patch b/ci/diffs/0199-iov_iter-fix-advancing-slot-in-iter_folioq_get_pages.patch new file mode 100644 index 0000000000000..b81d22a35322c --- /dev/null +++ b/ci/diffs/0199-iov_iter-fix-advancing-slot-in-iter_folioq_get_pages.patch @@ -0,0 +1,46 @@ +From 0d24852bd71ec85ca0016b6d6fc997e6a3381552 Mon Sep 17 00:00:00 2001 +From: Omar Sandoval +Date: Mon, 30 Sep 2024 11:55:00 -0700 +Subject: [PATCH] iov_iter: fix advancing slot in iter_folioq_get_pages() + +iter_folioq_get_pages() decides to advance to the next folioq slot when +it has reached the end of the current folio. However, it is checking +offset, which is the beginning of the current part, instead of +iov_offset, which is adjusted to the end of the current part, so it +doesn't advance the slot when it's supposed to. As a result, on the next +iteration, we'll use the same folio with an out-of-bounds offset and +return an unrelated page. + +This manifested as various crashes and other failures in 9pfs in drgn's +VM testing setup and BPF CI. + +Fixes: db0aa2e9566f ("mm: Define struct folio_queue and ITER_FOLIOQ to handle a sequence of folios") +Link: https://lore.kernel.org/linux-fsdevel/20240923183432.1876750-1-chantr4@gmail.com/ +Tested-by: Manu Bretelle +Signed-off-by: Omar Sandoval +Link: https://lore.kernel.org/r/cbaf141ba6c0e2e209717d02746584072844841a.1727722269.git.osandov@fb.com +Tested-by: Eduard Zingerman +Tested-by: Leon Romanovsky +Tested-by: Joey Gouly +Acked-by: David Howells +Signed-off-by: Christian Brauner +--- + lib/iov_iter.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/lib/iov_iter.c b/lib/iov_iter.c +index 97003155b..1abb32c0d 100644 +--- a/lib/iov_iter.c ++++ b/lib/iov_iter.c +@@ -1033,7 +1033,7 @@ static ssize_t iter_folioq_get_pages(struct iov_iter *iter, + if (maxpages == 0 || extracted >= maxsize) + break; + +- if (offset >= fsize) { ++ if (iov_offset >= fsize) { + iov_offset = 0; + slot++; + if (slot == folioq_nr_slots(folioq) && folioq->next) { +-- +2.34.1 + diff --git a/ci/diffs/0299-selftests-bpf-Fix-uprobe-consumer-test.patch b/ci/diffs/0299-selftests-bpf-Fix-uprobe-consumer-test.patch new file mode 100644 index 0000000000000..11aa3626f5a81 --- /dev/null +++ b/ci/diffs/0299-selftests-bpf-Fix-uprobe-consumer-test.patch @@ -0,0 +1,58 @@ +From affb32e4f056883f285f8535b766293b85752fb4 Mon Sep 17 00:00:00 2001 +From: Jiri Olsa +Date: Tue, 24 Sep 2024 13:07:30 +0200 +Subject: [PATCH] selftests/bpf: Fix uprobe consumer test + +With newly merged code the uprobe behaviour is slightly different +and affects uprobe consumer test. + +We no longer need to check if the uprobe object is still preserved +after removing last uretprobe, because it stays as long as there's +pending/installed uretprobe instance. + +This allows to run uretprobe consumers registered 'after' uprobe was +hit even if previous uretprobe got unregistered before being hit. + +The uprobe object will be now removed after the last uprobe ref is +released and in such case it's held by ri->uprobe (return instance) +which is released after the uretprobe is hit. + +Reported-by: Ihor Solodrai +Signed-off-by: Jiri Olsa +Signed-off-by: Daniel Borkmann +Tested-by: Ihor Solodrai +Closes: https://lore.kernel.org/bpf/w6U8Z9fdhjnkSp2UaFaV1fGqJXvfLEtDKEUyGDkwmoruDJ_AgF_c0FFhrkeKW18OqiP-05s9yDKiT6X-Ns-avN_ABf0dcUkXqbSJN1TQSXo=@pm.me/ +--- + .../testing/selftests/bpf/prog_tests/uprobe_multi_test.c | 9 +-------- + 1 file changed, 1 insertion(+), 8 deletions(-) + +diff --git a/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c b/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c +index 844f6fc8487b..c1ac813ff9ba 100644 +--- a/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c ++++ b/tools/testing/selftests/bpf/prog_tests/uprobe_multi_test.c +@@ -869,21 +869,14 @@ static void consumer_test(struct uprobe_multi_consumers *skel, + fmt = "prog 0/1: uprobe"; + } else { + /* +- * uprobe return is tricky ;-) +- * + * to trigger uretprobe consumer, the uretprobe needs to be installed, + * which means one of the 'return' uprobes was alive when probe was hit: + * + * idxs: 2/3 uprobe return in 'installed' mask +- * +- * in addition if 'after' state removes everything that was installed in +- * 'before' state, then uprobe kernel object goes away and return uprobe +- * is not installed and we won't hit it even if it's in 'after' state. + */ + unsigned long had_uretprobes = before & 0b1100; /* is uretprobe installed */ +- unsigned long probe_preserved = before & after; /* did uprobe go away */ + +- if (had_uretprobes && probe_preserved && test_bit(idx, after)) ++ if (had_uretprobes && test_bit(idx, after)) + val++; + fmt = "idx 2/3: uretprobe"; + } +-- +2.34.1 + diff --git a/ci/diffs/0399-selftests-sched_ext-fix-build-after-renames-in-sched.patch b/ci/diffs/0399-selftests-sched_ext-fix-build-after-renames-in-sched.patch new file mode 100644 index 0000000000000..ba37429396236 --- /dev/null +++ b/ci/diffs/0399-selftests-sched_ext-fix-build-after-renames-in-sched.patch @@ -0,0 +1,231 @@ +From 5565144e82b97c5d2082ab19866836dfe5b2e592 Mon Sep 17 00:00:00 2001 +From: Ihor Solodrai +Date: Thu, 21 Nov 2024 13:20:46 -0800 +Subject: [PATCH] selftests/sched_ext: fix build after renames in sched_ext API + +The selftests are falining to build on current tip of bpf-next and +sched_ext [1]. This has broken BPF CI [2] after merge from upstream. + +Use appropriate function names in the selftests according to the +recent changes in the sched_ext API [3]. + +[1] +https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git/commit/?id=fc39fb56917bb3cb53e99560ca3612a84456ada2 +[2] https://github.com/kernel-patches/bpf/actions/runs/11959327258/job/33340923745 +[3] https://lore.kernel.org/all/20241109194853.580310-1-tj@kernel.org/ + +Signed-off-by: Ihor Solodrai +--- + .../testing/selftests/sched_ext/ddsp_bogus_dsq_fail.bpf.c | 2 +- + .../selftests/sched_ext/ddsp_vtimelocal_fail.bpf.c | 4 ++-- + tools/testing/selftests/sched_ext/dsp_local_on.bpf.c | 2 +- + .../selftests/sched_ext/enq_select_cpu_fails.bpf.c | 2 +- + tools/testing/selftests/sched_ext/exit.bpf.c | 4 ++-- + tools/testing/selftests/sched_ext/maximal.bpf.c | 4 ++-- + tools/testing/selftests/sched_ext/select_cpu_dfl.bpf.c | 2 +- + .../selftests/sched_ext/select_cpu_dfl_nodispatch.bpf.c | 2 +- + .../testing/selftests/sched_ext/select_cpu_dispatch.bpf.c | 2 +- + .../selftests/sched_ext/select_cpu_dispatch_bad_dsq.bpf.c | 2 +- + .../selftests/sched_ext/select_cpu_dispatch_dbl_dsp.bpf.c | 4 ++-- + tools/testing/selftests/sched_ext/select_cpu_vtime.bpf.c | 8 ++++---- + 12 files changed, 19 insertions(+), 19 deletions(-) + +diff --git a/tools/testing/selftests/sched_ext/ddsp_bogus_dsq_fail.bpf.c b/tools/testing/selftests/sched_ext/ddsp_bogus_dsq_fail.bpf.c +index 37d9bf6fb745..6f4c3f5a1c5d 100644 +--- a/tools/testing/selftests/sched_ext/ddsp_bogus_dsq_fail.bpf.c ++++ b/tools/testing/selftests/sched_ext/ddsp_bogus_dsq_fail.bpf.c +@@ -20,7 +20,7 @@ s32 BPF_STRUCT_OPS(ddsp_bogus_dsq_fail_select_cpu, struct task_struct *p, + * If we dispatch to a bogus DSQ that will fall back to the + * builtin global DSQ, we fail gracefully. + */ +- scx_bpf_dispatch_vtime(p, 0xcafef00d, SCX_SLICE_DFL, ++ scx_bpf_dsq_insert_vtime(p, 0xcafef00d, SCX_SLICE_DFL, + p->scx.dsq_vtime, 0); + return cpu; + } +diff --git a/tools/testing/selftests/sched_ext/ddsp_vtimelocal_fail.bpf.c b/tools/testing/selftests/sched_ext/ddsp_vtimelocal_fail.bpf.c +index dffc97d9cdf1..e4a55027778f 100644 +--- a/tools/testing/selftests/sched_ext/ddsp_vtimelocal_fail.bpf.c ++++ b/tools/testing/selftests/sched_ext/ddsp_vtimelocal_fail.bpf.c +@@ -17,8 +17,8 @@ s32 BPF_STRUCT_OPS(ddsp_vtimelocal_fail_select_cpu, struct task_struct *p, + + if (cpu >= 0) { + /* Shouldn't be allowed to vtime dispatch to a builtin DSQ. */ +- scx_bpf_dispatch_vtime(p, SCX_DSQ_LOCAL, SCX_SLICE_DFL, +- p->scx.dsq_vtime, 0); ++ scx_bpf_dsq_insert_vtime(p, SCX_DSQ_LOCAL, SCX_SLICE_DFL, ++ p->scx.dsq_vtime, 0); + return cpu; + } + +diff --git a/tools/testing/selftests/sched_ext/dsp_local_on.bpf.c b/tools/testing/selftests/sched_ext/dsp_local_on.bpf.c +index 6a7db1502c29..6325bf76f47e 100644 +--- a/tools/testing/selftests/sched_ext/dsp_local_on.bpf.c ++++ b/tools/testing/selftests/sched_ext/dsp_local_on.bpf.c +@@ -45,7 +45,7 @@ void BPF_STRUCT_OPS(dsp_local_on_dispatch, s32 cpu, struct task_struct *prev) + + target = bpf_get_prandom_u32() % nr_cpus; + +- scx_bpf_dispatch(p, SCX_DSQ_LOCAL_ON | target, SCX_SLICE_DFL, 0); ++ scx_bpf_dsq_insert(p, SCX_DSQ_LOCAL_ON | target, SCX_SLICE_DFL, 0); + bpf_task_release(p); + } + +diff --git a/tools/testing/selftests/sched_ext/enq_select_cpu_fails.bpf.c b/tools/testing/selftests/sched_ext/enq_select_cpu_fails.bpf.c +index 1efb50d61040..a7cf868d5e31 100644 +--- a/tools/testing/selftests/sched_ext/enq_select_cpu_fails.bpf.c ++++ b/tools/testing/selftests/sched_ext/enq_select_cpu_fails.bpf.c +@@ -31,7 +31,7 @@ void BPF_STRUCT_OPS(enq_select_cpu_fails_enqueue, struct task_struct *p, + /* Can only call from ops.select_cpu() */ + scx_bpf_select_cpu_dfl(p, 0, 0, &found); + +- scx_bpf_dispatch(p, SCX_DSQ_GLOBAL, SCX_SLICE_DFL, enq_flags); ++ scx_bpf_dsq_insert(p, SCX_DSQ_GLOBAL, SCX_SLICE_DFL, enq_flags); + } + + SEC(".struct_ops.link") +diff --git a/tools/testing/selftests/sched_ext/exit.bpf.c b/tools/testing/selftests/sched_ext/exit.bpf.c +index d75d4faf07f6..4bc36182d3ff 100644 +--- a/tools/testing/selftests/sched_ext/exit.bpf.c ++++ b/tools/testing/selftests/sched_ext/exit.bpf.c +@@ -33,7 +33,7 @@ void BPF_STRUCT_OPS(exit_enqueue, struct task_struct *p, u64 enq_flags) + if (exit_point == EXIT_ENQUEUE) + EXIT_CLEANLY(); + +- scx_bpf_dispatch(p, DSQ_ID, SCX_SLICE_DFL, enq_flags); ++ scx_bpf_dsq_insert(p, DSQ_ID, SCX_SLICE_DFL, enq_flags); + } + + void BPF_STRUCT_OPS(exit_dispatch, s32 cpu, struct task_struct *p) +@@ -41,7 +41,7 @@ void BPF_STRUCT_OPS(exit_dispatch, s32 cpu, struct task_struct *p) + if (exit_point == EXIT_DISPATCH) + EXIT_CLEANLY(); + +- scx_bpf_consume(DSQ_ID); ++ scx_bpf_dsq_move_to_local(DSQ_ID); + } + + void BPF_STRUCT_OPS(exit_enable, struct task_struct *p) +diff --git a/tools/testing/selftests/sched_ext/maximal.bpf.c b/tools/testing/selftests/sched_ext/maximal.bpf.c +index 4d4cd8d966db..4c005fa71810 100644 +--- a/tools/testing/selftests/sched_ext/maximal.bpf.c ++++ b/tools/testing/selftests/sched_ext/maximal.bpf.c +@@ -20,7 +20,7 @@ s32 BPF_STRUCT_OPS(maximal_select_cpu, struct task_struct *p, s32 prev_cpu, + + void BPF_STRUCT_OPS(maximal_enqueue, struct task_struct *p, u64 enq_flags) + { +- scx_bpf_dispatch(p, SCX_DSQ_GLOBAL, SCX_SLICE_DFL, enq_flags); ++ scx_bpf_dsq_insert(p, SCX_DSQ_GLOBAL, SCX_SLICE_DFL, enq_flags); + } + + void BPF_STRUCT_OPS(maximal_dequeue, struct task_struct *p, u64 deq_flags) +@@ -28,7 +28,7 @@ void BPF_STRUCT_OPS(maximal_dequeue, struct task_struct *p, u64 deq_flags) + + void BPF_STRUCT_OPS(maximal_dispatch, s32 cpu, struct task_struct *prev) + { +- scx_bpf_consume(SCX_DSQ_GLOBAL); ++ scx_bpf_dsq_move_to_local(SCX_DSQ_GLOBAL); + } + + void BPF_STRUCT_OPS(maximal_runnable, struct task_struct *p, u64 enq_flags) +diff --git a/tools/testing/selftests/sched_ext/select_cpu_dfl.bpf.c b/tools/testing/selftests/sched_ext/select_cpu_dfl.bpf.c +index f171ac470970..13d0f5be788d 100644 +--- a/tools/testing/selftests/sched_ext/select_cpu_dfl.bpf.c ++++ b/tools/testing/selftests/sched_ext/select_cpu_dfl.bpf.c +@@ -30,7 +30,7 @@ void BPF_STRUCT_OPS(select_cpu_dfl_enqueue, struct task_struct *p, + } + scx_bpf_put_idle_cpumask(idle_mask); + +- scx_bpf_dispatch(p, SCX_DSQ_GLOBAL, SCX_SLICE_DFL, enq_flags); ++ scx_bpf_dsq_insert(p, SCX_DSQ_GLOBAL, SCX_SLICE_DFL, enq_flags); + } + + SEC(".struct_ops.link") +diff --git a/tools/testing/selftests/sched_ext/select_cpu_dfl_nodispatch.bpf.c b/tools/testing/selftests/sched_ext/select_cpu_dfl_nodispatch.bpf.c +index 9efdbb7da928..815f1d5d61ac 100644 +--- a/tools/testing/selftests/sched_ext/select_cpu_dfl_nodispatch.bpf.c ++++ b/tools/testing/selftests/sched_ext/select_cpu_dfl_nodispatch.bpf.c +@@ -67,7 +67,7 @@ void BPF_STRUCT_OPS(select_cpu_dfl_nodispatch_enqueue, struct task_struct *p, + saw_local = true; + } + +- scx_bpf_dispatch(p, dsq_id, SCX_SLICE_DFL, enq_flags); ++ scx_bpf_dsq_insert(p, dsq_id, SCX_SLICE_DFL, enq_flags); + } + + s32 BPF_STRUCT_OPS(select_cpu_dfl_nodispatch_init_task, +diff --git a/tools/testing/selftests/sched_ext/select_cpu_dispatch.bpf.c b/tools/testing/selftests/sched_ext/select_cpu_dispatch.bpf.c +index 59bfc4f36167..4bb99699e920 100644 +--- a/tools/testing/selftests/sched_ext/select_cpu_dispatch.bpf.c ++++ b/tools/testing/selftests/sched_ext/select_cpu_dispatch.bpf.c +@@ -29,7 +29,7 @@ s32 BPF_STRUCT_OPS(select_cpu_dispatch_select_cpu, struct task_struct *p, + cpu = prev_cpu; + + dispatch: +- scx_bpf_dispatch(p, dsq_id, SCX_SLICE_DFL, 0); ++ scx_bpf_dsq_insert(p, dsq_id, SCX_SLICE_DFL, 0); + return cpu; + } + +diff --git a/tools/testing/selftests/sched_ext/select_cpu_dispatch_bad_dsq.bpf.c b/tools/testing/selftests/sched_ext/select_cpu_dispatch_bad_dsq.bpf.c +index 3bbd5fcdfb18..2a75de11b2cf 100644 +--- a/tools/testing/selftests/sched_ext/select_cpu_dispatch_bad_dsq.bpf.c ++++ b/tools/testing/selftests/sched_ext/select_cpu_dispatch_bad_dsq.bpf.c +@@ -18,7 +18,7 @@ s32 BPF_STRUCT_OPS(select_cpu_dispatch_bad_dsq_select_cpu, struct task_struct *p + s32 prev_cpu, u64 wake_flags) + { + /* Dispatching to a random DSQ should fail. */ +- scx_bpf_dispatch(p, 0xcafef00d, SCX_SLICE_DFL, 0); ++ scx_bpf_dsq_insert(p, 0xcafef00d, SCX_SLICE_DFL, 0); + + return prev_cpu; + } +diff --git a/tools/testing/selftests/sched_ext/select_cpu_dispatch_dbl_dsp.bpf.c b/tools/testing/selftests/sched_ext/select_cpu_dispatch_dbl_dsp.bpf.c +index 0fda57fe0ecf..99d075695c97 100644 +--- a/tools/testing/selftests/sched_ext/select_cpu_dispatch_dbl_dsp.bpf.c ++++ b/tools/testing/selftests/sched_ext/select_cpu_dispatch_dbl_dsp.bpf.c +@@ -18,8 +18,8 @@ s32 BPF_STRUCT_OPS(select_cpu_dispatch_dbl_dsp_select_cpu, struct task_struct *p + s32 prev_cpu, u64 wake_flags) + { + /* Dispatching twice in a row is disallowed. */ +- scx_bpf_dispatch(p, SCX_DSQ_GLOBAL, SCX_SLICE_DFL, 0); +- scx_bpf_dispatch(p, SCX_DSQ_GLOBAL, SCX_SLICE_DFL, 0); ++ scx_bpf_dsq_insert(p, SCX_DSQ_GLOBAL, SCX_SLICE_DFL, 0); ++ scx_bpf_dsq_insert(p, SCX_DSQ_GLOBAL, SCX_SLICE_DFL, 0); + + return prev_cpu; + } +diff --git a/tools/testing/selftests/sched_ext/select_cpu_vtime.bpf.c b/tools/testing/selftests/sched_ext/select_cpu_vtime.bpf.c +index e6c67bcf5e6e..bfcb96cd4954 100644 +--- a/tools/testing/selftests/sched_ext/select_cpu_vtime.bpf.c ++++ b/tools/testing/selftests/sched_ext/select_cpu_vtime.bpf.c +@@ -2,8 +2,8 @@ + /* + * A scheduler that validates that enqueue flags are properly stored and + * applied at dispatch time when a task is directly dispatched from +- * ops.select_cpu(). We validate this by using scx_bpf_dispatch_vtime(), and +- * making the test a very basic vtime scheduler. ++ * ops.select_cpu(). We validate this by using scx_bpf_dsq_insert_vtime(), ++ * and making the test a very basic vtime scheduler. + * + * Copyright (c) 2024 Meta Platforms, Inc. and affiliates. + * Copyright (c) 2024 David Vernet +@@ -47,13 +47,13 @@ s32 BPF_STRUCT_OPS(select_cpu_vtime_select_cpu, struct task_struct *p, + cpu = prev_cpu; + scx_bpf_test_and_clear_cpu_idle(cpu); + ddsp: +- scx_bpf_dispatch_vtime(p, VTIME_DSQ, SCX_SLICE_DFL, task_vtime(p), 0); ++ scx_bpf_dsq_insert_vtime(p, VTIME_DSQ, SCX_SLICE_DFL, task_vtime(p), 0); + return cpu; + } + + void BPF_STRUCT_OPS(select_cpu_vtime_dispatch, s32 cpu, struct task_struct *p) + { +- if (scx_bpf_consume(VTIME_DSQ)) ++ if (scx_bpf_dsq_move_to_local(VTIME_DSQ)) + consumed = true; + } + +-- +2.47.0 + diff --git a/ci/diffs/0499-samples-bpf-fix-samples-compilation.patch b/ci/diffs/0499-samples-bpf-fix-samples-compilation.patch new file mode 100644 index 0000000000000..1f95c3c237cb9 --- /dev/null +++ b/ci/diffs/0499-samples-bpf-fix-samples-compilation.patch @@ -0,0 +1,61 @@ +From 80a5958a52b86e39c1a1bf5f4702011c0cf6ab4f Mon Sep 17 00:00:00 2001 +From: Eduard Zingerman +Date: Mon, 2 Dec 2024 12:14:46 -0800 +Subject: [PATCH] samples/bpf: fix samples compilation + +Commit [0] breaks samples build. + +TODO: moar details here + +[0] 13b25489b6f8 ("kbuild: change working directory to external module directory with M=") + +Signed-off-by: Eduard Zingerman +Signed-off-by: Ihor Solodrai +--- + samples/bpf/Makefile | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile +index bcf103a4c14f..ee10dbf1b471 100644 +--- a/samples/bpf/Makefile ++++ b/samples/bpf/Makefile +@@ -146,13 +146,14 @@ ifeq ($(ARCH), x86) + BPF_EXTRA_CFLAGS += -fcf-protection + endif + +-TPROGS_CFLAGS += -Wall -O2 +-TPROGS_CFLAGS += -Wmissing-prototypes +-TPROGS_CFLAGS += -Wstrict-prototypes +-TPROGS_CFLAGS += $(call try-run,\ ++COMMON_CFLAGS += -Wall -O2 ++COMMON_CFLAGS += -Wmissing-prototypes ++COMMON_CFLAGS += -Wstrict-prototypes ++COMMON_CFLAGS += $(call try-run,\ + printf "int main() { return 0; }" |\ + $(CC) -Werror -fsanitize=bounds -x c - -o "$$TMP",-fsanitize=bounds,) + ++TPROGS_CFLAGS += $(COMMON_CFLAGS) + TPROGS_CFLAGS += -I$(objtree)/usr/include + TPROGS_CFLAGS += -I$(srctree)/tools/testing/selftests/bpf/ + TPROGS_CFLAGS += -I$(LIBBPF_INCLUDE) +@@ -229,7 +230,7 @@ clean: + + $(LIBBPF): $(wildcard $(LIBBPF_SRC)/*.[ch] $(LIBBPF_SRC)/Makefile) | $(LIBBPF_OUTPUT) + # Fix up variables inherited from Kbuild that tools/ build system won't like +- $(MAKE) -C $(LIBBPF_SRC) RM='rm -rf' EXTRA_CFLAGS="$(TPROGS_CFLAGS)" \ ++ $(MAKE) -C $(LIBBPF_SRC) RM='rm -rf' EXTRA_CFLAGS="$(COMMON_CFLAGS)" \ + LDFLAGS="$(TPROGS_LDFLAGS)" srctree=$(BPF_SAMPLES_PATH)/../../ \ + O= OUTPUT=$(LIBBPF_OUTPUT)/ DESTDIR=$(LIBBPF_DESTDIR) prefix= \ + $@ install_headers +@@ -305,7 +306,7 @@ $(obj)/$(TRACE_HELPERS): TPROGS_CFLAGS := $(TPROGS_CFLAGS) -D__must_check= + -include $(BPF_SAMPLES_PATH)/Makefile.target + + VMLINUX_BTF_PATHS ?= $(abspath $(if $(O),$(O)/vmlinux)) \ +- $(abspath $(if $(KBUILD_OUTPUT),$(KBUILD_OUTPUT)/vmlinux)) \ ++ $(abspath $(if $(objtree),$(objtree)/vmlinux)) \ + $(abspath ./vmlinux) + VMLINUX_BTF ?= $(abspath $(firstword $(wildcard $(VMLINUX_BTF_PATHS)))) + +-- +2.47.0 + diff --git a/ci/diffs/2000-s390-fgraph-Fix-to-remove-ftrace_test_recursion_tryl.patch b/ci/diffs/2000-s390-fgraph-Fix-to-remove-ftrace_test_recursion_tryl.patch new file mode 100644 index 0000000000000..7e38b1a151a10 --- /dev/null +++ b/ci/diffs/2000-s390-fgraph-Fix-to-remove-ftrace_test_recursion_tryl.patch @@ -0,0 +1,46 @@ +From faf291ff4beaef8dedebd166f11f815cdee257dc Mon Sep 17 00:00:00 2001 +From: "Masami Hiramatsu (Google)" +Date: Wed, 29 Jan 2025 00:29:37 +0900 +Subject: [PATCH 2000/2001] s390: fgraph: Fix to remove + ftrace_test_recursion_trylock() + +Fix to remove ftrace_test_recursion_trylock() from ftrace_graph_func() +because commit d576aec24df9 ("fgraph: Get ftrace recursion lock in +function_graph_enter") has been moved it to function_graph_enter_regs() +already. + +Reported-by: Jiri Olsa +Closes: https://lore.kernel.org/all/Z5O0shrdgeExZ2kF@krava/ +Fixes: d576aec24df9 ("fgraph: Get ftrace recursion lock in function_graph_enter") +Signed-off-by: Masami Hiramatsu (Google) +Tested-by: Jiri Olsa +--- + arch/s390/kernel/ftrace.c | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/arch/s390/kernel/ftrace.c b/arch/s390/kernel/ftrace.c +index c0b2c97efefb..63ba6306632e 100644 +--- a/arch/s390/kernel/ftrace.c ++++ b/arch/s390/kernel/ftrace.c +@@ -266,18 +266,13 @@ void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, + struct ftrace_ops *op, struct ftrace_regs *fregs) + { + unsigned long *parent = &arch_ftrace_regs(fregs)->regs.gprs[14]; +- int bit; + + if (unlikely(ftrace_graph_is_dead())) + return; + if (unlikely(atomic_read(¤t->tracing_graph_pause))) + return; +- bit = ftrace_test_recursion_trylock(ip, *parent); +- if (bit < 0) +- return; + if (!function_graph_enter_regs(*parent, ip, 0, parent, fregs)) + *parent = (unsigned long)&return_to_handler; +- ftrace_test_recursion_unlock(bit); + } + + #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ +-- +2.48.1 + diff --git a/ci/diffs/2001-s390-tracing-Define-ftrace_get_symaddr-for-s390.patch b/ci/diffs/2001-s390-tracing-Define-ftrace_get_symaddr-for-s390.patch new file mode 100644 index 0000000000000..66483206f448f --- /dev/null +++ b/ci/diffs/2001-s390-tracing-Define-ftrace_get_symaddr-for-s390.patch @@ -0,0 +1,28 @@ +From 04fce0d606f59a62105729094013c4784492ec7b Mon Sep 17 00:00:00 2001 +From: "Masami Hiramatsu (Google)" +Date: Wed, 29 Jan 2025 00:29:48 +0900 +Subject: [PATCH 2001/2001] s390: tracing: Define ftrace_get_symaddr() for s390 + +Add ftrace_get_symaddr() for s390, which returns the symbol address +from ftrace's 'ip' parameter. + +Signed-off-by: Masami Hiramatsu (Google) +--- + arch/s390/include/asm/ftrace.h | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/arch/s390/include/asm/ftrace.h b/arch/s390/include/asm/ftrace.h +index a3b73a4f626e..185331e91f83 100644 +--- a/arch/s390/include/asm/ftrace.h ++++ b/arch/s390/include/asm/ftrace.h +@@ -51,6 +51,7 @@ static inline unsigned long ftrace_call_adjust(unsigned long addr) + { + return addr; + } ++#define ftrace_get_symaddr(fentry_ip) ((unsigned long)(fentry_ip)) + + #include + +-- +2.48.1 + diff --git a/ci/diffs/2001-selftests-bpf-add-fno-strict-aliasing-to-BPF_CFLAGS.patch b/ci/diffs/2001-selftests-bpf-add-fno-strict-aliasing-to-BPF_CFLAGS.patch new file mode 100644 index 0000000000000..9b24de70e2846 --- /dev/null +++ b/ci/diffs/2001-selftests-bpf-add-fno-strict-aliasing-to-BPF_CFLAGS.patch @@ -0,0 +1,75 @@ +From f44275e7155dc310d36516fc25be503da099781c Mon Sep 17 00:00:00 2001 +From: Ihor Solodrai +Date: Mon, 6 Jan 2025 20:17:31 +0000 +Subject: [PATCH] selftests/bpf: add -fno-strict-aliasing to BPF_CFLAGS + +Following the discussion at [1], set -fno-strict-aliasing flag for all +BPF object build rules. Remove now unnecessary -CFLAGS variables. + +[1] https://lore.kernel.org/bpf/20250106185447.951609-1-ihor.solodrai@pm.me/ + +CC: Jose E. Marchesi +Signed-off-by: Ihor Solodrai +Acked-by: Eduard Zingerman +Link: https://lore.kernel.org/r/20250106201728.1219791-1-ihor.solodrai@pm.me +Signed-off-by: Alexei Starovoitov +--- + tools/testing/selftests/bpf/Makefile | 28 +--------------------------- + 1 file changed, 1 insertion(+), 27 deletions(-) + +diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile +index eb4d21651aa7..d5be2f94deef 100644 +--- a/tools/testing/selftests/bpf/Makefile ++++ b/tools/testing/selftests/bpf/Makefile +@@ -54,21 +54,6 @@ PCAP_LIBS := $(shell $(PKG_CONFIG) --libs libpcap 2>/dev/null) + LDLIBS += $(PCAP_LIBS) + CFLAGS += $(PCAP_CFLAGS) + +-# The following tests perform type punning and they may break strict +-# aliasing rules, which are exploited by both GCC and clang by default +-# while optimizing. This can lead to broken programs. +-progs/bind4_prog.c-CFLAGS := -fno-strict-aliasing +-progs/bind6_prog.c-CFLAGS := -fno-strict-aliasing +-progs/dynptr_fail.c-CFLAGS := -fno-strict-aliasing +-progs/linked_list_fail.c-CFLAGS := -fno-strict-aliasing +-progs/map_kptr_fail.c-CFLAGS := -fno-strict-aliasing +-progs/syscall.c-CFLAGS := -fno-strict-aliasing +-progs/test_pkt_md_access.c-CFLAGS := -fno-strict-aliasing +-progs/test_sk_lookup.c-CFLAGS := -fno-strict-aliasing +-progs/timer_crash.c-CFLAGS := -fno-strict-aliasing +-progs/test_global_func9.c-CFLAGS := -fno-strict-aliasing +-progs/verifier_nocsr.c-CFLAGS := -fno-strict-aliasing +- + # Some utility functions use LLVM libraries + jit_disasm_helpers.c-CFLAGS = $(LLVM_CFLAGS) + +@@ -103,18 +88,6 @@ progs/btf_dump_test_case_packing.c-bpf_gcc-CFLAGS := -Wno-error + progs/btf_dump_test_case_padding.c-bpf_gcc-CFLAGS := -Wno-error + progs/btf_dump_test_case_syntax.c-bpf_gcc-CFLAGS := -Wno-error + +-# The following tests do type-punning, via the __imm_insn macro, from +-# `struct bpf_insn' to long and then uses the value. This triggers an +-# "is used uninitialized" warning in GCC due to strict-aliasing +-# rules. +-progs/verifier_ref_tracking.c-bpf_gcc-CFLAGS := -fno-strict-aliasing +-progs/verifier_unpriv.c-bpf_gcc-CFLAGS := -fno-strict-aliasing +-progs/verifier_cgroup_storage.c-bpf_gcc-CFLAGS := -fno-strict-aliasing +-progs/verifier_ld_ind.c-bpf_gcc-CFLAGS := -fno-strict-aliasing +-progs/verifier_map_ret_val.c-bpf_gcc-CFLAGS := -fno-strict-aliasing +-progs/verifier_spill_fill.c-bpf_gcc-CFLAGS := -fno-strict-aliasing +-progs/verifier_subprog_precision.c-bpf_gcc-CFLAGS := -fno-strict-aliasing +-progs/verifier_uninit.c-bpf_gcc-CFLAGS := -fno-strict-aliasing + endif + + ifneq ($(CLANG_CPUV4),) +@@ -474,6 +447,7 @@ CLANG_SYS_INCLUDES = $(call get_sys_includes,$(CLANG),$(CLANG_TARGET_ARCH)) + BPF_CFLAGS = -g -Wall -Werror -D__TARGET_ARCH_$(SRCARCH) $(MENDIAN) \ + -I$(INCLUDE_DIR) -I$(CURDIR) -I$(APIDIR) \ + -I$(abspath $(OUTPUT)/../usr/include) \ ++ -fno-strict-aliasing \ + -Wno-compare-distinct-pointer-types + # TODO: enable me -Wsign-compare + +-- +2.47.1 + diff --git a/ci/diffs/2002-selftests-bpf-add-std-gnu11-to-BPF_CFLAGS-and-CFLAGS.patch b/ci/diffs/2002-selftests-bpf-add-std-gnu11-to-BPF_CFLAGS-and-CFLAGS.patch new file mode 100644 index 0000000000000..127b2641dc223 --- /dev/null +++ b/ci/diffs/2002-selftests-bpf-add-std-gnu11-to-BPF_CFLAGS-and-CFLAGS.patch @@ -0,0 +1,63 @@ +From bab18c7db44d3aa6c84450095451580922359c7a Mon Sep 17 00:00:00 2001 +From: Ihor Solodrai +Date: Tue, 7 Jan 2025 23:58:18 +0000 +Subject: [PATCH] selftests/bpf: add -std=gnu11 to BPF_CFLAGS and CFLAGS + +Latest versions of GCC BPF use C23 standard by default. This causes +compilation errors in vmlinux.h due to bool types declarations. + +Add -std=gnu11 to BPF_CFLAGS and CFLAGS. This aligns with the version +of the standard used when building the kernel currently [1]. + +For more details see the discussions at [2] and [3]. + +[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Makefile#n465 +[2] https://lore.kernel.org/bpf/EYcXjcKDCJY7Yb0GGtAAb7nLKPEvrgWdvWpuNzXm2qi6rYMZDixKv5KwfVVMBq17V55xyC-A1wIjrqG3aw-Imqudo9q9X7D7nLU2gWgbN0w=@pm.me/ +[3] https://lore.kernel.org/bpf/20250106202715.1232864-1-ihor.solodrai@pm.me/ + +CC: Jose E. Marchesi +Signed-off-by: Ihor Solodrai +Link: https://lore.kernel.org/r/20250107235813.2964472-1-ihor.solodrai@pm.me +Signed-off-by: Alexei Starovoitov +--- + tools/testing/selftests/bpf/Makefile | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile +index d5be2f94deef..ea9cee5de0f8 100644 +--- a/tools/testing/selftests/bpf/Makefile ++++ b/tools/testing/selftests/bpf/Makefile +@@ -41,7 +41,7 @@ srctree := $(patsubst %/,%,$(dir $(srctree))) + srctree := $(patsubst %/,%,$(dir $(srctree))) + endif + +-CFLAGS += -g $(OPT_FLAGS) -rdynamic \ ++CFLAGS += -g $(OPT_FLAGS) -rdynamic -std=gnu11 \ + -Wall -Werror -fno-omit-frame-pointer \ + $(GENFLAGS) $(SAN_CFLAGS) $(LIBELF_CFLAGS) \ + -I$(CURDIR) -I$(INCLUDE_DIR) -I$(GENDIR) -I$(LIBDIR) \ +@@ -447,6 +447,7 @@ CLANG_SYS_INCLUDES = $(call get_sys_includes,$(CLANG),$(CLANG_TARGET_ARCH)) + BPF_CFLAGS = -g -Wall -Werror -D__TARGET_ARCH_$(SRCARCH) $(MENDIAN) \ + -I$(INCLUDE_DIR) -I$(CURDIR) -I$(APIDIR) \ + -I$(abspath $(OUTPUT)/../usr/include) \ ++ -std=gnu11 \ + -fno-strict-aliasing \ + -Wno-compare-distinct-pointer-types + # TODO: enable me -Wsign-compare +@@ -787,9 +788,12 @@ $(OUTPUT)/xdp_features: xdp_features.c $(OUTPUT)/network_helpers.o $(OUTPUT)/xdp + $(Q)$(CC) $(CFLAGS) $(filter %.a %.o %.c,$^) $(LDLIBS) -o $@ + + # Make sure we are able to include and link libbpf against c++. ++CXXFLAGS += $(CFLAGS) ++CXXFLAGS := $(subst -D_GNU_SOURCE=,,$(CXXFLAGS)) ++CXXFLAGS := $(subst -std=gnu11,-std=gnu++11,$(CXXFLAGS)) + $(OUTPUT)/test_cpp: test_cpp.cpp $(OUTPUT)/test_core_extern.skel.h $(BPFOBJ) + $(call msg,CXX,,$@) +- $(Q)$(CXX) $(subst -D_GNU_SOURCE=,,$(CFLAGS)) $(filter %.a %.o %.cpp,$^) $(LDLIBS) -o $@ ++ $(Q)$(CXX) $(CXXFLAGS) $(filter %.a %.o %.cpp,$^) $(LDLIBS) -o $@ + + # Benchmark runner + $(OUTPUT)/bench_%.o: benchs/bench_%.c bench.h $(BPFOBJ) +-- +2.47.1 + diff --git a/ci/diffs/8888-Revert-netfs-Change-the-read-result-collector-to-onl.patch b/ci/diffs/8888-Revert-netfs-Change-the-read-result-collector-to-onl.patch new file mode 100644 index 0000000000000..049685b69a462 --- /dev/null +++ b/ci/diffs/8888-Revert-netfs-Change-the-read-result-collector-to-onl.patch @@ -0,0 +1,2542 @@ +From c98e72f3806a0d1a1d5aaed9638137b96608b567 Mon Sep 17 00:00:00 2001 +From: Ihor Solodrai +Date: Fri, 24 Jan 2025 07:31:33 -0800 +Subject: [PATCH] Revert "netfs: Change the read result collector to only use + one work item" + +This reverts commit e2d46f2ec332533816417b60933954173f602121. +--- + fs/9p/vfs_addr.c | 3 +- + fs/afs/dir.c | 8 +- + fs/ceph/addr.c | 9 +- + fs/netfs/buffered_read.c | 160 ++++---- + fs/netfs/direct_read.c | 60 ++- + fs/netfs/internal.h | 21 +- + fs/netfs/main.c | 2 +- + fs/netfs/objects.c | 34 +- + fs/netfs/read_collect.c | 716 +++++++++++++++-------------------- + fs/netfs/read_pgpriv2.c | 203 ++++++---- + fs/netfs/read_retry.c | 207 +++++----- + fs/netfs/read_single.c | 37 +- + fs/netfs/write_collect.c | 4 +- + fs/netfs/write_issue.c | 2 +- + fs/netfs/write_retry.c | 14 +- + fs/smb/client/cifssmb.c | 2 - + fs/smb/client/smb2pdu.c | 5 +- + include/linux/netfs.h | 16 +- + include/trace/events/netfs.h | 79 +++- + 19 files changed, 763 insertions(+), 819 deletions(-) + +diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c +index 32619d146cbc..b38be6ff90bc 100644 +--- a/fs/9p/vfs_addr.c ++++ b/fs/9p/vfs_addr.c +@@ -81,7 +81,8 @@ static void v9fs_issue_read(struct netfs_io_subrequest *subreq) + __set_bit(NETFS_SREQ_CLEAR_TAIL, &subreq->flags); + if (pos + total >= i_size_read(rreq->inode)) + __set_bit(NETFS_SREQ_HIT_EOF, &subreq->flags); +- if (!err && total) { ++ ++ if (!err) { + subreq->transferred += total; + __set_bit(NETFS_SREQ_MADE_PROGRESS, &subreq->flags); + } +diff --git a/fs/afs/dir.c b/fs/afs/dir.c +index a843c36fc471..374f82d21902 100644 +--- a/fs/afs/dir.c ++++ b/fs/afs/dir.c +@@ -323,10 +323,8 @@ ssize_t afs_read_dir(struct afs_vnode *dvnode, struct file *file) + * haven't read it yet. + */ + if (test_bit(AFS_VNODE_DIR_VALID, &dvnode->flags) && +- test_bit(AFS_VNODE_DIR_READ, &dvnode->flags)) { +- ret = i_size; ++ test_bit(AFS_VNODE_DIR_READ, &dvnode->flags)) + goto valid; +- } + + up_read(&dvnode->validate_lock); + if (down_write_killable(&dvnode->validate_lock) < 0) +@@ -346,13 +344,11 @@ ssize_t afs_read_dir(struct afs_vnode *dvnode, struct file *file) + + set_bit(AFS_VNODE_DIR_VALID, &dvnode->flags); + set_bit(AFS_VNODE_DIR_READ, &dvnode->flags); +- } else { +- ret = i_size; + } + + downgrade_write(&dvnode->validate_lock); + valid: +- return ret; ++ return i_size; + + error_unlock: + up_write(&dvnode->validate_lock); +diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c +index f5224a566b69..4deb38fa470e 100644 +--- a/fs/ceph/addr.c ++++ b/fs/ceph/addr.c +@@ -223,13 +223,10 @@ static void finish_netfs_read(struct ceph_osd_request *req) + subreq->len, i_size_read(req->r_inode)); + + /* no object means success but no data */ +- if (err == -ENOENT) { +- __set_bit(NETFS_SREQ_CLEAR_TAIL, &subreq->flags); +- __set_bit(NETFS_SREQ_MADE_PROGRESS, &subreq->flags); ++ if (err == -ENOENT) + err = 0; +- } else if (err == -EBLOCKLISTED) { ++ else if (err == -EBLOCKLISTED) + fsc->blocklisted = true; +- } + + if (err >= 0) { + if (sparse && err > 0) +@@ -245,8 +242,6 @@ static void finish_netfs_read(struct ceph_osd_request *req) + if (err > subreq->len) + err = subreq->len; + } +- if (err > 0) +- __set_bit(NETFS_SREQ_CLEAR_TAIL, &subreq->flags); + } + + if (osd_data->type == CEPH_OSD_DATA_TYPE_PAGES) { +diff --git a/fs/netfs/buffered_read.c b/fs/netfs/buffered_read.c +index f761d44b3436..5d7aa1f580f1 100644 +--- a/fs/netfs/buffered_read.c ++++ b/fs/netfs/buffered_read.c +@@ -121,6 +121,12 @@ static ssize_t netfs_prepare_read_iterator(struct netfs_io_subrequest *subreq) + + subreq->io_iter = rreq->buffer.iter; + ++ if (iov_iter_is_folioq(&subreq->io_iter)) { ++ subreq->curr_folioq = (struct folio_queue *)subreq->io_iter.folioq; ++ subreq->curr_folioq_slot = subreq->io_iter.folioq_slot; ++ subreq->curr_folio_order = subreq->curr_folioq->orders[subreq->curr_folioq_slot]; ++ } ++ + iov_iter_truncate(&subreq->io_iter, subreq->len); + rolling_buffer_advance(&rreq->buffer, subreq->len); + return subreq->len; +@@ -141,6 +147,19 @@ static enum netfs_io_source netfs_cache_prepare_read(struct netfs_io_request *rr + + } + ++void netfs_cache_read_terminated(void *priv, ssize_t transferred_or_error, bool was_async) ++{ ++ struct netfs_io_subrequest *subreq = priv; ++ ++ if (transferred_or_error > 0) { ++ subreq->transferred += transferred_or_error; ++ subreq->error = 0; ++ } else { ++ subreq->error = transferred_or_error; ++ } ++ schedule_work(&subreq->work); ++} ++ + /* + * Issue a read against the cache. + * - Eats the caller's ref on subreq. +@@ -155,47 +174,6 @@ static void netfs_read_cache_to_pagecache(struct netfs_io_request *rreq, + netfs_cache_read_terminated, subreq); + } + +-static void netfs_issue_read(struct netfs_io_request *rreq, +- struct netfs_io_subrequest *subreq) +-{ +- struct netfs_io_stream *stream = &rreq->io_streams[0]; +- +- __set_bit(NETFS_SREQ_IN_PROGRESS, &subreq->flags); +- +- /* We add to the end of the list whilst the collector may be walking +- * the list. The collector only goes nextwards and uses the lock to +- * remove entries off of the front. +- */ +- spin_lock(&rreq->lock); +- list_add_tail(&subreq->rreq_link, &stream->subrequests); +- if (list_is_first(&subreq->rreq_link, &stream->subrequests)) { +- stream->front = subreq; +- if (!stream->active) { +- stream->collected_to = stream->front->start; +- /* Store list pointers before active flag */ +- smp_store_release(&stream->active, true); +- } +- } +- +- spin_unlock(&rreq->lock); +- +- switch (subreq->source) { +- case NETFS_DOWNLOAD_FROM_SERVER: +- rreq->netfs_ops->issue_read(subreq); +- break; +- case NETFS_READ_FROM_CACHE: +- netfs_read_cache_to_pagecache(rreq, subreq); +- break; +- default: +- __set_bit(NETFS_SREQ_CLEAR_TAIL, &subreq->flags); +- subreq->error = 0; +- iov_iter_zero(subreq->len, &subreq->io_iter); +- subreq->transferred = subreq->len; +- netfs_read_subreq_terminated(subreq); +- break; +- } +-} +- + /* + * Perform a read to the pagecache from a series of sources of different types, + * slicing up the region to be read according to available cache blocks and +@@ -208,6 +186,8 @@ static void netfs_read_to_pagecache(struct netfs_io_request *rreq) + ssize_t size = rreq->len; + int ret = 0; + ++ atomic_inc(&rreq->nr_outstanding); ++ + do { + struct netfs_io_subrequest *subreq; + enum netfs_io_source source = NETFS_SOURCE_UNKNOWN; +@@ -222,6 +202,14 @@ static void netfs_read_to_pagecache(struct netfs_io_request *rreq) + subreq->start = start; + subreq->len = size; + ++ atomic_inc(&rreq->nr_outstanding); ++ spin_lock(&rreq->lock); ++ list_add_tail(&subreq->rreq_link, &rreq->subrequests); ++ subreq->prev_donated = rreq->prev_donated; ++ rreq->prev_donated = 0; ++ trace_netfs_sreq(subreq, netfs_sreq_trace_added); ++ spin_unlock(&rreq->lock); ++ + source = netfs_cache_prepare_read(rreq, subreq, rreq->i_size); + subreq->source = source; + if (source == NETFS_DOWNLOAD_FROM_SERVER) { +@@ -249,18 +237,17 @@ static void netfs_read_to_pagecache(struct netfs_io_request *rreq) + netfs_stat(&netfs_n_rh_download); + if (rreq->netfs_ops->prepare_read) { + ret = rreq->netfs_ops->prepare_read(subreq); +- if (ret < 0) { +- subreq->error = ret; +- /* Not queued - release both refs. */ +- netfs_put_subrequest(subreq, false, +- netfs_sreq_trace_put_cancel); +- netfs_put_subrequest(subreq, false, +- netfs_sreq_trace_put_cancel); +- break; +- } ++ if (ret < 0) ++ goto prep_failed; + trace_netfs_sreq(subreq, netfs_sreq_trace_prepare); + } +- goto issue; ++ ++ slice = netfs_prepare_read_iterator(subreq); ++ if (slice < 0) ++ goto prep_iter_failed; ++ ++ rreq->netfs_ops->issue_read(subreq); ++ goto done; + } + + fill_with_zeroes: +@@ -268,50 +255,67 @@ static void netfs_read_to_pagecache(struct netfs_io_request *rreq) + subreq->source = NETFS_FILL_WITH_ZEROES; + trace_netfs_sreq(subreq, netfs_sreq_trace_submit); + netfs_stat(&netfs_n_rh_zero); +- goto issue; ++ slice = netfs_prepare_read_iterator(subreq); ++ if (slice < 0) ++ goto prep_iter_failed; ++ __set_bit(NETFS_SREQ_CLEAR_TAIL, &subreq->flags); ++ subreq->error = 0; ++ netfs_read_subreq_terminated(subreq); ++ goto done; + } + + if (source == NETFS_READ_FROM_CACHE) { + trace_netfs_sreq(subreq, netfs_sreq_trace_submit); +- goto issue; ++ slice = netfs_prepare_read_iterator(subreq); ++ if (slice < 0) ++ goto prep_iter_failed; ++ netfs_read_cache_to_pagecache(rreq, subreq); ++ goto done; + } + + pr_err("Unexpected read source %u\n", source); + WARN_ON_ONCE(1); + break; + +- issue: +- slice = netfs_prepare_read_iterator(subreq); +- if (slice < 0) { +- ret = slice; +- subreq->error = ret; +- trace_netfs_sreq(subreq, netfs_sreq_trace_cancel); +- /* Not queued - release both refs. */ +- netfs_put_subrequest(subreq, false, netfs_sreq_trace_put_cancel); +- netfs_put_subrequest(subreq, false, netfs_sreq_trace_put_cancel); +- break; +- } ++ prep_iter_failed: ++ ret = slice; ++ prep_failed: ++ subreq->error = ret; ++ atomic_dec(&rreq->nr_outstanding); ++ netfs_put_subrequest(subreq, false, netfs_sreq_trace_put_cancel); ++ break; ++ ++ done: + size -= slice; + start += slice; +- if (size <= 0) { +- smp_wmb(); /* Write lists before ALL_QUEUED. */ +- set_bit(NETFS_RREQ_ALL_QUEUED, &rreq->flags); +- } +- +- netfs_issue_read(rreq, subreq); + cond_resched(); + } while (size > 0); + +- if (unlikely(size > 0)) { +- smp_wmb(); /* Write lists before ALL_QUEUED. */ +- set_bit(NETFS_RREQ_ALL_QUEUED, &rreq->flags); +- netfs_wake_read_collector(rreq); +- } ++ if (atomic_dec_and_test(&rreq->nr_outstanding)) ++ netfs_rreq_terminated(rreq); + + /* Defer error return as we may need to wait for outstanding I/O. */ + cmpxchg(&rreq->error, 0, ret); + } + ++/* ++ * Wait for the read operation to complete, successfully or otherwise. ++ */ ++static int netfs_wait_for_read(struct netfs_io_request *rreq) ++{ ++ int ret; ++ ++ trace_netfs_rreq(rreq, netfs_rreq_trace_wait_ip); ++ wait_on_bit(&rreq->flags, NETFS_RREQ_IN_PROGRESS, TASK_UNINTERRUPTIBLE); ++ ret = rreq->error; ++ if (ret == 0 && rreq->submitted < rreq->len) { ++ trace_netfs_failure(rreq, NULL, ret, netfs_fail_short_read); ++ ret = -EIO; ++ } ++ ++ return ret; ++} ++ + /** + * netfs_readahead - Helper to manage a read request + * @ractl: The description of the readahead request +@@ -340,8 +344,6 @@ void netfs_readahead(struct readahead_control *ractl) + if (IS_ERR(rreq)) + return; + +- __set_bit(NETFS_RREQ_OFFLOAD_COLLECTION, &rreq->flags); +- + ret = netfs_begin_cache_read(rreq, ictx); + if (ret == -ENOMEM || ret == -EINTR || ret == -ERESTARTSYS) + goto cleanup_free; +@@ -458,7 +460,7 @@ static int netfs_read_gaps(struct file *file, struct folio *folio) + folio_put(sink); + + ret = netfs_wait_for_read(rreq); +- if (ret >= 0) { ++ if (ret == 0) { + flush_dcache_folio(folio); + folio_mark_uptodate(folio); + } +@@ -746,7 +748,7 @@ int netfs_prefetch_for_write(struct file *file, struct folio *folio, + netfs_read_to_pagecache(rreq); + ret = netfs_wait_for_read(rreq); + netfs_put_request(rreq, false, netfs_rreq_trace_put_return); +- return ret < 0 ? ret : 0; ++ return ret; + + error_put: + netfs_put_request(rreq, false, netfs_rreq_trace_put_discard); +diff --git a/fs/netfs/direct_read.c b/fs/netfs/direct_read.c +index 0bf3c2f5a710..1a20cc3979c7 100644 +--- a/fs/netfs/direct_read.c ++++ b/fs/netfs/direct_read.c +@@ -47,11 +47,12 @@ static void netfs_prepare_dio_read_iterator(struct netfs_io_subrequest *subreq) + */ + static int netfs_dispatch_unbuffered_reads(struct netfs_io_request *rreq) + { +- struct netfs_io_stream *stream = &rreq->io_streams[0]; + unsigned long long start = rreq->start; + ssize_t size = rreq->len; + int ret = 0; + ++ atomic_set(&rreq->nr_outstanding, 1); ++ + do { + struct netfs_io_subrequest *subreq; + ssize_t slice; +@@ -66,18 +67,11 @@ static int netfs_dispatch_unbuffered_reads(struct netfs_io_request *rreq) + subreq->start = start; + subreq->len = size; + +- __set_bit(NETFS_SREQ_IN_PROGRESS, &subreq->flags); +- ++ atomic_inc(&rreq->nr_outstanding); + spin_lock(&rreq->lock); +- list_add_tail(&subreq->rreq_link, &stream->subrequests); +- if (list_is_first(&subreq->rreq_link, &stream->subrequests)) { +- stream->front = subreq; +- if (!stream->active) { +- stream->collected_to = stream->front->start; +- /* Store list pointers before active flag */ +- smp_store_release(&stream->active, true); +- } +- } ++ list_add_tail(&subreq->rreq_link, &rreq->subrequests); ++ subreq->prev_donated = rreq->prev_donated; ++ rreq->prev_donated = 0; + trace_netfs_sreq(subreq, netfs_sreq_trace_added); + spin_unlock(&rreq->lock); + +@@ -85,6 +79,7 @@ static int netfs_dispatch_unbuffered_reads(struct netfs_io_request *rreq) + if (rreq->netfs_ops->prepare_read) { + ret = rreq->netfs_ops->prepare_read(subreq); + if (ret < 0) { ++ atomic_dec(&rreq->nr_outstanding); + netfs_put_subrequest(subreq, false, netfs_sreq_trace_put_cancel); + break; + } +@@ -92,32 +87,20 @@ static int netfs_dispatch_unbuffered_reads(struct netfs_io_request *rreq) + + netfs_prepare_dio_read_iterator(subreq); + slice = subreq->len; ++ rreq->netfs_ops->issue_read(subreq); ++ + size -= slice; + start += slice; + rreq->submitted += slice; +- if (size <= 0) { +- smp_wmb(); /* Write lists before ALL_QUEUED. */ +- set_bit(NETFS_RREQ_ALL_QUEUED, &rreq->flags); +- } +- +- rreq->netfs_ops->issue_read(subreq); + +- if (test_bit(NETFS_RREQ_PAUSE, &rreq->flags)) +- netfs_wait_for_pause(rreq); +- if (test_bit(NETFS_RREQ_FAILED, &rreq->flags)) +- break; + if (test_bit(NETFS_RREQ_BLOCKED, &rreq->flags) && + test_bit(NETFS_RREQ_NONBLOCK, &rreq->flags)) + break; + cond_resched(); + } while (size > 0); + +- if (unlikely(size > 0)) { +- smp_wmb(); /* Write lists before ALL_QUEUED. */ +- set_bit(NETFS_RREQ_ALL_QUEUED, &rreq->flags); +- netfs_wake_read_collector(rreq); +- } +- ++ if (atomic_dec_and_test(&rreq->nr_outstanding)) ++ netfs_rreq_terminated(rreq); + return ret; + } + +@@ -150,10 +133,21 @@ static int netfs_unbuffered_read(struct netfs_io_request *rreq, bool sync) + goto out; + } + +- if (sync) +- ret = netfs_wait_for_read(rreq); +- else ++ if (sync) { ++ trace_netfs_rreq(rreq, netfs_rreq_trace_wait_ip); ++ wait_on_bit(&rreq->flags, NETFS_RREQ_IN_PROGRESS, ++ TASK_UNINTERRUPTIBLE); ++ ++ ret = rreq->error; ++ if (ret == 0 && rreq->submitted < rreq->len && ++ rreq->origin != NETFS_DIO_READ) { ++ trace_netfs_failure(rreq, NULL, ret, netfs_fail_short_read); ++ ret = -EIO; ++ } ++ } else { + ret = -EIOCBQUEUED; ++ } ++ + out: + _leave(" = %d", ret); + return ret; +@@ -221,10 +215,8 @@ ssize_t netfs_unbuffered_read_iter_locked(struct kiocb *iocb, struct iov_iter *i + + // TODO: Set up bounce buffer if needed + +- if (!sync) { ++ if (!sync) + rreq->iocb = iocb; +- __set_bit(NETFS_RREQ_OFFLOAD_COLLECTION, &rreq->flags); +- } + + ret = netfs_unbuffered_read(rreq, sync); + if (ret < 0) +diff --git a/fs/netfs/internal.h b/fs/netfs/internal.h +index eb76f98c894b..e236f752af88 100644 +--- a/fs/netfs/internal.h ++++ b/fs/netfs/internal.h +@@ -82,27 +82,20 @@ static inline void netfs_see_request(struct netfs_io_request *rreq, + trace_netfs_rreq_ref(rreq->debug_id, refcount_read(&rreq->ref), what); + } + +-static inline void netfs_see_subrequest(struct netfs_io_subrequest *subreq, +- enum netfs_sreq_ref_trace what) +-{ +- trace_netfs_sreq_ref(subreq->rreq->debug_id, subreq->debug_index, +- refcount_read(&subreq->ref), what); +-} +- + /* + * read_collect.c + */ +-void netfs_read_collection_worker(struct work_struct *work); +-void netfs_wake_read_collector(struct netfs_io_request *rreq); +-void netfs_cache_read_terminated(void *priv, ssize_t transferred_or_error, bool was_async); +-ssize_t netfs_wait_for_read(struct netfs_io_request *rreq); +-void netfs_wait_for_pause(struct netfs_io_request *rreq); ++void netfs_read_termination_worker(struct work_struct *work); ++void netfs_rreq_terminated(struct netfs_io_request *rreq); + + /* + * read_pgpriv2.c + */ +-void netfs_pgpriv2_copy_to_cache(struct netfs_io_request *rreq, struct folio *folio); +-void netfs_pgpriv2_end_copy_to_cache(struct netfs_io_request *rreq); ++void netfs_pgpriv2_mark_copy_to_cache(struct netfs_io_subrequest *subreq, ++ struct netfs_io_request *rreq, ++ struct folio_queue *folioq, ++ int slot); ++void netfs_pgpriv2_write_to_the_cache(struct netfs_io_request *rreq); + bool netfs_pgpriv2_unlock_copied_folios(struct netfs_io_request *wreq); + + /* +diff --git a/fs/netfs/main.c b/fs/netfs/main.c +index 4e3e62040831..16760695e667 100644 +--- a/fs/netfs/main.c ++++ b/fs/netfs/main.c +@@ -71,7 +71,7 @@ static int netfs_requests_seq_show(struct seq_file *m, void *v) + refcount_read(&rreq->ref), + rreq->flags, + rreq->error, +- 0, ++ atomic_read(&rreq->nr_outstanding), + rreq->start, rreq->submitted, rreq->len); + seq_putc(m, '\n'); + return 0; +diff --git a/fs/netfs/objects.c b/fs/netfs/objects.c +index dc6b41ef18b0..dde4a679d9e2 100644 +--- a/fs/netfs/objects.c ++++ b/fs/netfs/objects.c +@@ -48,7 +48,7 @@ struct netfs_io_request *netfs_alloc_request(struct address_space *mapping, + spin_lock_init(&rreq->lock); + INIT_LIST_HEAD(&rreq->io_streams[0].subrequests); + INIT_LIST_HEAD(&rreq->io_streams[1].subrequests); +- init_waitqueue_head(&rreq->waitq); ++ INIT_LIST_HEAD(&rreq->subrequests); + refcount_set(&rreq->ref, 1); + + if (origin == NETFS_READAHEAD || +@@ -56,12 +56,10 @@ struct netfs_io_request *netfs_alloc_request(struct address_space *mapping, + origin == NETFS_READ_GAPS || + origin == NETFS_READ_SINGLE || + origin == NETFS_READ_FOR_WRITE || +- origin == NETFS_DIO_READ) { +- INIT_WORK(&rreq->work, netfs_read_collection_worker); +- rreq->io_streams[0].avail = true; +- } else { ++ origin == NETFS_DIO_READ) ++ INIT_WORK(&rreq->work, NULL); ++ else + INIT_WORK(&rreq->work, netfs_write_collection_worker); +- } + + __set_bit(NETFS_RREQ_IN_PROGRESS, &rreq->flags); + if (file && file->f_flags & O_NONBLOCK) +@@ -95,6 +93,14 @@ void netfs_clear_subrequests(struct netfs_io_request *rreq, bool was_async) + struct netfs_io_stream *stream; + int s; + ++ while (!list_empty(&rreq->subrequests)) { ++ subreq = list_first_entry(&rreq->subrequests, ++ struct netfs_io_subrequest, rreq_link); ++ list_del(&subreq->rreq_link); ++ netfs_put_subrequest(subreq, was_async, ++ netfs_sreq_trace_put_clear); ++ } ++ + for (s = 0; s < ARRAY_SIZE(rreq->io_streams); s++) { + stream = &rreq->io_streams[s]; + while (!list_empty(&stream->subrequests)) { +@@ -186,7 +192,21 @@ struct netfs_io_subrequest *netfs_alloc_subrequest(struct netfs_io_request *rreq + } + + memset(subreq, 0, kmem_cache_size(cache)); +- INIT_WORK(&subreq->work, NULL); ++ ++ switch (rreq->origin) { ++ case NETFS_READAHEAD: ++ case NETFS_READPAGE: ++ case NETFS_READ_GAPS: ++ case NETFS_READ_SINGLE: ++ case NETFS_READ_FOR_WRITE: ++ case NETFS_DIO_READ: ++ INIT_WORK(&subreq->work, netfs_read_subreq_termination_worker); ++ break; ++ default: ++ INIT_WORK(&subreq->work, NULL); ++ break; ++ } ++ + INIT_LIST_HEAD(&subreq->rreq_link); + refcount_set(&subreq->ref, 2); + subreq->rreq = rreq; +diff --git a/fs/netfs/read_collect.c b/fs/netfs/read_collect.c +index f65affa5a9e4..2e9291ab1d62 100644 +--- a/fs/netfs/read_collect.c ++++ b/fs/netfs/read_collect.c +@@ -14,14 +14,6 @@ + #include + #include "internal.h" + +-/* Notes made in the collector */ +-#define HIT_PENDING 0x01 /* A front op was still pending */ +-#define MADE_PROGRESS 0x04 /* Made progress cleaning up a stream or the folio set */ +-#define BUFFERED 0x08 /* The pagecache needs cleaning up */ +-#define NEED_RETRY 0x10 /* A front op requests retrying */ +-#define COPY_TO_CACHE 0x40 /* Need to copy subrequest to cache */ +-#define ABANDON_SREQ 0x80 /* Need to abandon untransferred part of subrequest */ +- + /* + * Clear the unread part of an I/O request. + */ +@@ -39,18 +31,14 @@ static void netfs_clear_unread(struct netfs_io_subrequest *subreq) + * cache the folio, we set the group to NETFS_FOLIO_COPY_TO_CACHE, mark it + * dirty and let writeback handle it. + */ +-static void netfs_unlock_read_folio(struct netfs_io_request *rreq, ++static void netfs_unlock_read_folio(struct netfs_io_subrequest *subreq, ++ struct netfs_io_request *rreq, + struct folio_queue *folioq, + int slot) + { + struct netfs_folio *finfo; + struct folio *folio = folioq_folio(folioq, slot); + +- if (unlikely(folio_pos(folio) < rreq->abandon_to)) { +- trace_netfs_folio(folio, netfs_folio_trace_abandon); +- goto just_unlock; +- } +- + flush_dcache_folio(folio); + folio_mark_uptodate(folio); + +@@ -65,7 +53,7 @@ static void netfs_unlock_read_folio(struct netfs_io_request *rreq, + kfree(finfo); + } + +- if (test_bit(NETFS_RREQ_FOLIO_COPY_TO_CACHE, &rreq->flags)) { ++ if (test_bit(NETFS_SREQ_COPY_TO_CACHE, &subreq->flags)) { + if (!WARN_ON_ONCE(folio_get_private(folio) != NULL)) { + trace_netfs_folio(folio, netfs_folio_trace_copy_to_cache); + folio_attach_private(folio, NETFS_FOLIO_COPY_TO_CACHE); +@@ -78,11 +66,12 @@ static void netfs_unlock_read_folio(struct netfs_io_request *rreq, + folioq_clear(folioq, slot); + } else { + // TODO: Use of PG_private_2 is deprecated. +- if (test_bit(NETFS_RREQ_FOLIO_COPY_TO_CACHE, &rreq->flags)) +- netfs_pgpriv2_copy_to_cache(rreq, folio); ++ if (test_bit(NETFS_SREQ_COPY_TO_CACHE, &subreq->flags)) ++ netfs_pgpriv2_mark_copy_to_cache(subreq, rreq, folioq, slot); ++ else ++ folioq_clear(folioq, slot); + } + +-just_unlock: + if (!test_bit(NETFS_RREQ_DONT_UNLOCK_FOLIOS, &rreq->flags)) { + if (folio->index == rreq->no_unlock_folio && + test_bit(NETFS_RREQ_NO_UNLOCK_FOLIO, &rreq->flags)) { +@@ -92,249 +81,241 @@ static void netfs_unlock_read_folio(struct netfs_io_request *rreq, + folio_unlock(folio); + } + } +- +- folioq_clear(folioq, slot); + } + + /* +- * Unlock any folios we've finished with. ++ * Unlock any folios that are now completely read. Returns true if the ++ * subrequest is removed from the list. + */ +-static void netfs_read_unlock_folios(struct netfs_io_request *rreq, +- unsigned int *notes) ++static bool netfs_consume_read_data(struct netfs_io_subrequest *subreq) + { +- struct folio_queue *folioq = rreq->buffer.tail; +- unsigned long long collected_to = rreq->collected_to; +- unsigned int slot = rreq->buffer.first_tail_slot; +- +- if (rreq->cleaned_to >= rreq->collected_to) +- return; +- +- // TODO: Begin decryption +- +- if (slot >= folioq_nr_slots(folioq)) { +- folioq = rolling_buffer_delete_spent(&rreq->buffer); +- if (!folioq) { +- rreq->front_folio_order = 0; +- return; ++ struct netfs_io_subrequest *prev, *next; ++ struct netfs_io_request *rreq = subreq->rreq; ++ struct folio_queue *folioq = subreq->curr_folioq; ++ size_t avail, prev_donated, next_donated, fsize, part, excess; ++ loff_t fpos, start; ++ loff_t fend; ++ int slot = subreq->curr_folioq_slot; ++ ++ if (WARN(subreq->transferred > subreq->len, ++ "Subreq overread: R%x[%x] %zu > %zu", ++ rreq->debug_id, subreq->debug_index, ++ subreq->transferred, subreq->len)) ++ subreq->transferred = subreq->len; ++ ++ trace_netfs_folioq(folioq, netfs_trace_folioq_read_progress); ++next_folio: ++ fsize = PAGE_SIZE << subreq->curr_folio_order; ++ fpos = round_down(subreq->start + subreq->consumed, fsize); ++ fend = fpos + fsize; ++ ++ if (WARN_ON_ONCE(!folioq) || ++ WARN_ON_ONCE(!folioq_folio(folioq, slot)) || ++ WARN_ON_ONCE(folioq_folio(folioq, slot)->index != fpos / PAGE_SIZE)) { ++ pr_err("R=%08x[%x] s=%llx-%llx ctl=%zx/%zx/%zx sl=%u\n", ++ rreq->debug_id, subreq->debug_index, ++ subreq->start, subreq->start + subreq->transferred - 1, ++ subreq->consumed, subreq->transferred, subreq->len, ++ slot); ++ if (folioq) { ++ struct folio *folio = folioq_folio(folioq, slot); ++ ++ pr_err("folioq: fq=%x orders=%02x%02x%02x%02x %px\n", ++ folioq->debug_id, ++ folioq->orders[0], folioq->orders[1], ++ folioq->orders[2], folioq->orders[3], ++ folioq); ++ if (folio) ++ pr_err("folio: %llx-%llx ix=%llx o=%u qo=%u\n", ++ fpos, fend - 1, folio_pos(folio), folio_order(folio), ++ folioq_folio_order(folioq, slot)); + } +- slot = 0; + } + +- for (;;) { +- struct folio *folio; +- unsigned long long fpos, fend; +- unsigned int order; +- size_t fsize; +- +- if (*notes & COPY_TO_CACHE) +- set_bit(NETFS_RREQ_FOLIO_COPY_TO_CACHE, &rreq->flags); +- +- folio = folioq_folio(folioq, slot); +- if (WARN_ONCE(!folio_test_locked(folio), +- "R=%08x: folio %lx is not locked\n", +- rreq->debug_id, folio->index)) +- trace_netfs_folio(folio, netfs_folio_trace_not_locked); +- +- order = folioq_folio_order(folioq, slot); +- rreq->front_folio_order = order; +- fsize = PAGE_SIZE << order; +- fpos = folio_pos(folio); +- fend = umin(fpos + fsize, rreq->i_size); +- +- trace_netfs_collect_folio(rreq, folio, fend, collected_to); ++donation_changed: ++ /* Try to consume the current folio if we've hit or passed the end of ++ * it. There's a possibility that this subreq doesn't start at the ++ * beginning of the folio, in which case we need to donate to/from the ++ * preceding subreq. ++ * ++ * We also need to include any potential donation back from the ++ * following subreq. ++ */ ++ prev_donated = READ_ONCE(subreq->prev_donated); ++ next_donated = READ_ONCE(subreq->next_donated); ++ if (prev_donated || next_donated) { ++ spin_lock(&rreq->lock); ++ prev_donated = subreq->prev_donated; ++ next_donated = subreq->next_donated; ++ subreq->start -= prev_donated; ++ subreq->len += prev_donated; ++ subreq->transferred += prev_donated; ++ prev_donated = subreq->prev_donated = 0; ++ if (subreq->transferred == subreq->len) { ++ subreq->len += next_donated; ++ subreq->transferred += next_donated; ++ next_donated = subreq->next_donated = 0; ++ } ++ trace_netfs_sreq(subreq, netfs_sreq_trace_add_donations); ++ spin_unlock(&rreq->lock); ++ } + +- /* Unlock any folio we've transferred all of. */ +- if (collected_to < fend) +- break; ++ avail = subreq->transferred; ++ if (avail == subreq->len) ++ avail += next_donated; ++ start = subreq->start; ++ if (subreq->consumed == 0) { ++ start -= prev_donated; ++ avail += prev_donated; ++ } else { ++ start += subreq->consumed; ++ avail -= subreq->consumed; ++ } ++ part = umin(avail, fsize); ++ ++ trace_netfs_progress(subreq, start, avail, part); ++ ++ if (start + avail >= fend) { ++ if (fpos == start) { ++ /* Flush, unlock and mark for caching any folio we've just read. */ ++ subreq->consumed = fend - subreq->start; ++ netfs_unlock_read_folio(subreq, rreq, folioq, slot); ++ folioq_mark2(folioq, slot); ++ if (subreq->consumed >= subreq->len) ++ goto remove_subreq; ++ } else if (fpos < start) { ++ excess = fend - subreq->start; ++ ++ spin_lock(&rreq->lock); ++ /* If we complete first on a folio split with the ++ * preceding subreq, donate to that subreq - otherwise ++ * we get the responsibility. ++ */ ++ if (subreq->prev_donated != prev_donated) { ++ spin_unlock(&rreq->lock); ++ goto donation_changed; ++ } + +- netfs_unlock_read_folio(rreq, folioq, slot); +- WRITE_ONCE(rreq->cleaned_to, fpos + fsize); +- *notes |= MADE_PROGRESS; ++ if (list_is_first(&subreq->rreq_link, &rreq->subrequests)) { ++ spin_unlock(&rreq->lock); ++ pr_err("Can't donate prior to front\n"); ++ goto bad; ++ } + +- clear_bit(NETFS_RREQ_FOLIO_COPY_TO_CACHE, &rreq->flags); ++ prev = list_prev_entry(subreq, rreq_link); ++ WRITE_ONCE(prev->next_donated, prev->next_donated + excess); ++ subreq->start += excess; ++ subreq->len -= excess; ++ subreq->transferred -= excess; ++ trace_netfs_donate(rreq, subreq, prev, excess, ++ netfs_trace_donate_tail_to_prev); ++ trace_netfs_sreq(subreq, netfs_sreq_trace_donate_to_prev); ++ ++ if (subreq->consumed >= subreq->len) ++ goto remove_subreq_locked; ++ spin_unlock(&rreq->lock); ++ } else { ++ pr_err("fpos > start\n"); ++ goto bad; ++ } + +- /* Clean up the head folioq. If we clear an entire folioq, then +- * we can get rid of it provided it's not also the tail folioq +- * being filled by the issuer. +- */ +- folioq_clear(folioq, slot); ++ /* Advance the rolling buffer to the next folio. */ + slot++; + if (slot >= folioq_nr_slots(folioq)) { +- folioq = rolling_buffer_delete_spent(&rreq->buffer); +- if (!folioq) +- goto done; + slot = 0; ++ folioq = folioq->next; ++ subreq->curr_folioq = folioq; + trace_netfs_folioq(folioq, netfs_trace_folioq_read_progress); + } +- +- if (fpos + fsize >= collected_to) +- break; ++ subreq->curr_folioq_slot = slot; ++ if (folioq && folioq_folio(folioq, slot)) ++ subreq->curr_folio_order = folioq->orders[slot]; ++ cond_resched(); ++ goto next_folio; + } + +- rreq->buffer.tail = folioq; +-done: +- rreq->buffer.first_tail_slot = slot; +-} ++ /* Deal with partial progress. */ ++ if (subreq->transferred < subreq->len) ++ return false; + +-/* +- * Collect and assess the results of various read subrequests. We may need to +- * retry some of the results. +- * +- * Note that we have a sequence of subrequests, which may be drawing on +- * different sources and may or may not be the same size or starting position +- * and may not even correspond in boundary alignment. +- */ +-static void netfs_collect_read_results(struct netfs_io_request *rreq) +-{ +- struct netfs_io_subrequest *front, *remove; +- struct netfs_io_stream *stream = &rreq->io_streams[0]; +- unsigned int notes; +- +- _enter("%llx-%llx", rreq->start, rreq->start + rreq->len); +- trace_netfs_rreq(rreq, netfs_rreq_trace_collect); +- trace_netfs_collect(rreq); +- +-reassess: +- if (rreq->origin == NETFS_READAHEAD || +- rreq->origin == NETFS_READPAGE || +- rreq->origin == NETFS_READ_FOR_WRITE) +- notes = BUFFERED; +- else +- notes = 0; +- +- /* Remove completed subrequests from the front of the stream and +- * advance the completion point. We stop when we hit something that's +- * in progress. The issuer thread may be adding stuff to the tail +- * whilst we're doing this. ++ /* Donate the remaining downloaded data to one of the neighbouring ++ * subrequests. Note that we may race with them doing the same thing. + */ +- front = READ_ONCE(stream->front); +- while (front) { +- size_t transferred; +- +- trace_netfs_collect_sreq(rreq, front); +- _debug("sreq [%x] %llx %zx/%zx", +- front->debug_index, front->start, front->transferred, front->len); +- +- if (stream->collected_to < front->start) { +- trace_netfs_collect_gap(rreq, stream, front->start, 'F'); +- stream->collected_to = front->start; +- } +- +- if (test_bit(NETFS_SREQ_IN_PROGRESS, &front->flags)) +- notes |= HIT_PENDING; +- smp_rmb(); /* Read counters after IN_PROGRESS flag. */ +- transferred = READ_ONCE(front->transferred); +- +- /* If we can now collect the next folio, do so. We don't want +- * to defer this as we have to decide whether we need to copy +- * to the cache or not, and that may differ between adjacent +- * subreqs. +- */ +- if (notes & BUFFERED) { +- size_t fsize = PAGE_SIZE << rreq->front_folio_order; +- +- /* Clear the tail of a short read. */ +- if (!(notes & HIT_PENDING) && +- front->error == 0 && +- transferred < front->len && +- (test_bit(NETFS_SREQ_HIT_EOF, &front->flags) || +- test_bit(NETFS_SREQ_CLEAR_TAIL, &front->flags))) { +- netfs_clear_unread(front); +- transferred = front->transferred = front->len; +- trace_netfs_sreq(front, netfs_sreq_trace_clear); +- } ++ spin_lock(&rreq->lock); + +- stream->collected_to = front->start + transferred; +- rreq->collected_to = stream->collected_to; +- +- if (test_bit(NETFS_SREQ_COPY_TO_CACHE, &front->flags)) +- notes |= COPY_TO_CACHE; +- +- if (test_bit(NETFS_SREQ_FAILED, &front->flags)) { +- rreq->abandon_to = front->start + front->len; +- front->transferred = front->len; +- transferred = front->len; +- trace_netfs_rreq(rreq, netfs_rreq_trace_set_abandon); +- } +- if (front->start + transferred >= rreq->cleaned_to + fsize || +- test_bit(NETFS_SREQ_HIT_EOF, &front->flags)) +- netfs_read_unlock_folios(rreq, ¬es); +- } else { +- stream->collected_to = front->start + transferred; +- rreq->collected_to = stream->collected_to; +- } +- +- /* Stall if the front is still undergoing I/O. */ +- if (notes & HIT_PENDING) +- break; +- +- if (test_bit(NETFS_SREQ_FAILED, &front->flags)) { +- if (!stream->failed) { +- stream->error = front->error; +- rreq->error = front->error; +- set_bit(NETFS_RREQ_FAILED, &rreq->flags); +- stream->failed = true; +- } +- notes |= MADE_PROGRESS | ABANDON_SREQ; +- } else if (test_bit(NETFS_SREQ_NEED_RETRY, &front->flags)) { +- stream->need_retry = true; +- notes |= NEED_RETRY | MADE_PROGRESS; +- break; +- } else { +- if (!stream->failed) +- stream->transferred = stream->collected_to - rreq->start; +- notes |= MADE_PROGRESS; +- } +- +- /* Remove if completely consumed. */ +- stream->source = front->source; +- spin_lock(&rreq->lock); +- +- remove = front; +- trace_netfs_sreq(front, netfs_sreq_trace_discard); +- list_del_init(&front->rreq_link); +- front = list_first_entry_or_null(&stream->subrequests, +- struct netfs_io_subrequest, rreq_link); +- stream->front = front; ++ if (subreq->prev_donated != prev_donated || ++ subreq->next_donated != next_donated) { + spin_unlock(&rreq->lock); +- netfs_put_subrequest(remove, false, +- notes & ABANDON_SREQ ? +- netfs_sreq_trace_put_abandon : +- netfs_sreq_trace_put_done); ++ cond_resched(); ++ goto donation_changed; + } + +- trace_netfs_collect_stream(rreq, stream); +- trace_netfs_collect_state(rreq, rreq->collected_to, notes); +- +- if (!(notes & BUFFERED)) +- rreq->cleaned_to = rreq->collected_to; +- +- if (notes & NEED_RETRY) +- goto need_retry; +- if ((notes & MADE_PROGRESS) && test_bit(NETFS_RREQ_PAUSE, &rreq->flags)) { +- trace_netfs_rreq(rreq, netfs_rreq_trace_unpause); +- clear_bit_unlock(NETFS_RREQ_PAUSE, &rreq->flags); +- smp_mb__after_atomic(); /* Set PAUSE before task state */ +- wake_up(&rreq->waitq); ++ /* Deal with the trickiest case: that this subreq is in the middle of a ++ * folio, not touching either edge, but finishes first. In such a ++ * case, we donate to the previous subreq, if there is one and if it is ++ * contiguous, so that the donation is only handled when that completes ++ * - and remove this subreq from the list. ++ * ++ * If the previous subreq finished first, we will have acquired their ++ * donation and should be able to unlock folios and/or donate nextwards. ++ */ ++ if (!subreq->consumed && ++ !prev_donated && ++ !list_is_first(&subreq->rreq_link, &rreq->subrequests) && ++ subreq->start == prev->start + prev->len) { ++ prev = list_prev_entry(subreq, rreq_link); ++ WRITE_ONCE(prev->next_donated, prev->next_donated + subreq->len); ++ subreq->start += subreq->len; ++ subreq->len = 0; ++ subreq->transferred = 0; ++ trace_netfs_donate(rreq, subreq, prev, subreq->len, ++ netfs_trace_donate_to_prev); ++ trace_netfs_sreq(subreq, netfs_sreq_trace_donate_to_prev); ++ goto remove_subreq_locked; + } + +- if (notes & MADE_PROGRESS) { +- //cond_resched(); +- goto reassess; +- } ++ /* If we can't donate down the chain, donate up the chain instead. */ ++ excess = subreq->len - subreq->consumed + next_donated; + +-out: +- _leave(" = %x", notes); +- return; ++ if (!subreq->consumed) ++ excess += prev_donated; + +-need_retry: +- /* Okay... We're going to have to retry parts of the stream. Note +- * that any partially completed op will have had any wholly transferred +- * folios removed from it. ++ if (list_is_last(&subreq->rreq_link, &rreq->subrequests)) { ++ rreq->prev_donated = excess; ++ trace_netfs_donate(rreq, subreq, NULL, excess, ++ netfs_trace_donate_to_deferred_next); ++ } else { ++ next = list_next_entry(subreq, rreq_link); ++ WRITE_ONCE(next->prev_donated, excess); ++ trace_netfs_donate(rreq, subreq, next, excess, ++ netfs_trace_donate_to_next); ++ } ++ trace_netfs_sreq(subreq, netfs_sreq_trace_donate_to_next); ++ subreq->len = subreq->consumed; ++ subreq->transferred = subreq->consumed; ++ goto remove_subreq_locked; ++ ++remove_subreq: ++ spin_lock(&rreq->lock); ++remove_subreq_locked: ++ subreq->consumed = subreq->len; ++ list_del(&subreq->rreq_link); ++ spin_unlock(&rreq->lock); ++ netfs_put_subrequest(subreq, false, netfs_sreq_trace_put_consumed); ++ return true; ++ ++bad: ++ /* Errr... prev and next both donated to us, but insufficient to finish ++ * the folio. + */ +- _debug("retry"); +- netfs_retry_reads(rreq); +- goto out; ++ printk("R=%08x[%x] s=%llx-%llx %zx/%zx/%zx\n", ++ rreq->debug_id, subreq->debug_index, ++ subreq->start, subreq->start + subreq->transferred - 1, ++ subreq->consumed, subreq->transferred, subreq->len); ++ printk("folio: %llx-%llx\n", fpos, fend - 1); ++ printk("donated: prev=%zx next=%zx\n", prev_donated, next_donated); ++ printk("s=%llx av=%zx part=%zx\n", start, avail, part); ++ BUG(); + } + + /* +@@ -343,13 +324,12 @@ static void netfs_collect_read_results(struct netfs_io_request *rreq) + static void netfs_rreq_assess_dio(struct netfs_io_request *rreq) + { + struct netfs_io_subrequest *subreq; +- struct netfs_io_stream *stream = &rreq->io_streams[0]; + unsigned int i; + + /* Collect unbuffered reads and direct reads, adding up the transfer + * sizes until we find the first short or failed subrequest. + */ +- list_for_each_entry(subreq, &stream->subrequests, rreq_link) { ++ list_for_each_entry(subreq, &rreq->subrequests, rreq_link) { + rreq->transferred += subreq->transferred; + + if (subreq->transferred < subreq->len || +@@ -386,12 +366,22 @@ static void netfs_rreq_assess_dio(struct netfs_io_request *rreq) + */ + static void netfs_rreq_assess_single(struct netfs_io_request *rreq) + { ++ struct netfs_io_subrequest *subreq; + struct netfs_io_stream *stream = &rreq->io_streams[0]; + +- if (!rreq->error && stream->source == NETFS_DOWNLOAD_FROM_SERVER && +- fscache_resources_valid(&rreq->cache_resources)) { +- trace_netfs_rreq(rreq, netfs_rreq_trace_dirty); +- netfs_single_mark_inode_dirty(rreq->inode); ++ subreq = list_first_entry_or_null(&stream->subrequests, ++ struct netfs_io_subrequest, rreq_link); ++ if (subreq) { ++ if (test_bit(NETFS_SREQ_FAILED, &subreq->flags)) ++ rreq->error = subreq->error; ++ else ++ rreq->transferred = subreq->transferred; ++ ++ if (!rreq->error && subreq->source == NETFS_DOWNLOAD_FROM_SERVER && ++ fscache_resources_valid(&rreq->cache_resources)) { ++ trace_netfs_rreq(rreq, netfs_rreq_trace_dirty); ++ netfs_single_mark_inode_dirty(rreq->inode); ++ } + } + + if (rreq->iocb) { +@@ -405,32 +395,21 @@ static void netfs_rreq_assess_single(struct netfs_io_request *rreq) + } + + /* +- * Perform the collection of subrequests and folios. ++ * Assess the state of a read request and decide what to do next. + * + * Note that we're in normal kernel thread context at this point, possibly + * running on a workqueue. + */ +-static void netfs_read_collection(struct netfs_io_request *rreq) ++void netfs_rreq_terminated(struct netfs_io_request *rreq) + { +- struct netfs_io_stream *stream = &rreq->io_streams[0]; +- +- netfs_collect_read_results(rreq); ++ trace_netfs_rreq(rreq, netfs_rreq_trace_assess); + +- /* We're done when the app thread has finished posting subreqs and the +- * queue is empty. +- */ +- if (!test_bit(NETFS_RREQ_ALL_QUEUED, &rreq->flags)) +- return; +- smp_rmb(); /* Read ALL_QUEUED before subreq lists. */ ++ //netfs_rreq_is_still_valid(rreq); + +- if (!list_empty(&stream->subrequests)) ++ if (test_and_clear_bit(NETFS_RREQ_NEED_RETRY, &rreq->flags)) { ++ netfs_retry_reads(rreq); + return; +- +- /* Okay, declare that all I/O is complete. */ +- rreq->transferred = stream->transferred; +- trace_netfs_rreq(rreq, netfs_rreq_trace_complete); +- +- //netfs_rreq_is_still_valid(rreq); ++ } + + switch (rreq->origin) { + case NETFS_DIO_READ: +@@ -451,35 +430,8 @@ static void netfs_read_collection(struct netfs_io_request *rreq) + trace_netfs_rreq(rreq, netfs_rreq_trace_done); + netfs_clear_subrequests(rreq, false); + netfs_unlock_abandoned_read_pages(rreq); +- if (unlikely(rreq->copy_to_cache)) +- netfs_pgpriv2_end_copy_to_cache(rreq); +-} +- +-void netfs_read_collection_worker(struct work_struct *work) +-{ +- struct netfs_io_request *rreq = container_of(work, struct netfs_io_request, work); +- +- netfs_see_request(rreq, netfs_rreq_trace_see_work); +- if (test_bit(NETFS_RREQ_IN_PROGRESS, &rreq->flags)) +- netfs_read_collection(rreq); +- netfs_put_request(rreq, false, netfs_rreq_trace_put_work); +-} +- +-/* +- * Wake the collection work item. +- */ +-void netfs_wake_read_collector(struct netfs_io_request *rreq) +-{ +- if (test_bit(NETFS_RREQ_OFFLOAD_COLLECTION, &rreq->flags)) { +- if (!work_pending(&rreq->work)) { +- netfs_get_request(rreq, netfs_rreq_trace_get_work); +- if (!queue_work(system_unbound_wq, &rreq->work)) +- netfs_put_request(rreq, true, netfs_rreq_trace_put_work_nq); +- } +- } else { +- trace_netfs_rreq(rreq, netfs_rreq_trace_wake_queue); +- wake_up(&rreq->waitq); +- } ++ if (unlikely(test_bit(NETFS_RREQ_USE_PGPRIV2, &rreq->flags))) ++ netfs_pgpriv2_write_to_the_cache(rreq); + } + + /** +@@ -495,22 +447,17 @@ void netfs_wake_read_collector(struct netfs_io_request *rreq) + void netfs_read_subreq_progress(struct netfs_io_subrequest *subreq) + { + struct netfs_io_request *rreq = subreq->rreq; +- struct netfs_io_stream *stream = &rreq->io_streams[0]; +- size_t fsize = PAGE_SIZE << rreq->front_folio_order; ++ ++ might_sleep(); + + trace_netfs_sreq(subreq, netfs_sreq_trace_progress); + +- /* If we are at the head of the queue, wake up the collector, +- * getting a ref to it if we were the ones to do so. +- */ +- if (subreq->start + subreq->transferred > rreq->cleaned_to + fsize && ++ if (subreq->transferred > subreq->consumed && + (rreq->origin == NETFS_READAHEAD || + rreq->origin == NETFS_READPAGE || +- rreq->origin == NETFS_READ_FOR_WRITE) && +- list_is_first(&subreq->rreq_link, &stream->subrequests) +- ) { ++ rreq->origin == NETFS_READ_FOR_WRITE)) { ++ netfs_consume_read_data(subreq); + __set_bit(NETFS_SREQ_MADE_PROGRESS, &subreq->flags); +- netfs_wake_read_collector(rreq); + } + } + EXPORT_SYMBOL(netfs_read_subreq_progress); +@@ -534,7 +481,8 @@ EXPORT_SYMBOL(netfs_read_subreq_progress); + void netfs_read_subreq_terminated(struct netfs_io_subrequest *subreq) + { + struct netfs_io_request *rreq = subreq->rreq; +- struct netfs_io_stream *stream = &rreq->io_streams[0]; ++ ++ might_sleep(); + + switch (subreq->source) { + case NETFS_READ_FROM_CACHE: +@@ -547,156 +495,86 @@ void netfs_read_subreq_terminated(struct netfs_io_subrequest *subreq) + break; + } + ++ if (rreq->origin != NETFS_DIO_READ) { ++ /* Collect buffered reads. ++ * ++ * If the read completed validly short, then we can clear the ++ * tail before going on to unlock the folios. ++ */ ++ if (subreq->error == 0 && subreq->transferred < subreq->len && ++ (test_bit(NETFS_SREQ_HIT_EOF, &subreq->flags) || ++ test_bit(NETFS_SREQ_CLEAR_TAIL, &subreq->flags))) { ++ netfs_clear_unread(subreq); ++ subreq->transferred = subreq->len; ++ trace_netfs_sreq(subreq, netfs_sreq_trace_clear); ++ } ++ if (subreq->transferred > subreq->consumed && ++ (rreq->origin == NETFS_READAHEAD || ++ rreq->origin == NETFS_READPAGE || ++ rreq->origin == NETFS_READ_FOR_WRITE)) { ++ netfs_consume_read_data(subreq); ++ __set_bit(NETFS_SREQ_MADE_PROGRESS, &subreq->flags); ++ } ++ rreq->transferred += subreq->transferred; ++ } ++ + /* Deal with retry requests, short reads and errors. If we retry + * but don't make progress, we abandon the attempt. + */ + if (!subreq->error && subreq->transferred < subreq->len) { + if (test_bit(NETFS_SREQ_HIT_EOF, &subreq->flags)) { + trace_netfs_sreq(subreq, netfs_sreq_trace_hit_eof); +- } else if (test_bit(NETFS_SREQ_CLEAR_TAIL, &subreq->flags)) { +- trace_netfs_sreq(subreq, netfs_sreq_trace_need_clear); +- } else if (test_bit(NETFS_SREQ_NEED_RETRY, &subreq->flags)) { +- trace_netfs_sreq(subreq, netfs_sreq_trace_need_retry); +- } else if (test_bit(NETFS_SREQ_MADE_PROGRESS, &subreq->flags)) { +- __set_bit(NETFS_SREQ_NEED_RETRY, &subreq->flags); +- trace_netfs_sreq(subreq, netfs_sreq_trace_partial_read); + } else { +- __set_bit(NETFS_SREQ_FAILED, &subreq->flags); +- subreq->error = -ENODATA; + trace_netfs_sreq(subreq, netfs_sreq_trace_short); ++ if (subreq->transferred > subreq->consumed) { ++ /* If we didn't read new data, abandon retry. */ ++ if (subreq->retry_count && ++ test_bit(NETFS_SREQ_MADE_PROGRESS, &subreq->flags)) { ++ __set_bit(NETFS_SREQ_NEED_RETRY, &subreq->flags); ++ set_bit(NETFS_RREQ_NEED_RETRY, &rreq->flags); ++ } ++ } else if (test_bit(NETFS_SREQ_MADE_PROGRESS, &subreq->flags)) { ++ __set_bit(NETFS_SREQ_NEED_RETRY, &subreq->flags); ++ set_bit(NETFS_RREQ_NEED_RETRY, &rreq->flags); ++ } else { ++ __set_bit(NETFS_SREQ_FAILED, &subreq->flags); ++ subreq->error = -ENODATA; ++ } + } + } + ++ trace_netfs_sreq(subreq, netfs_sreq_trace_terminated); ++ + if (unlikely(subreq->error < 0)) { + trace_netfs_failure(rreq, subreq, subreq->error, netfs_fail_read); + if (subreq->source == NETFS_READ_FROM_CACHE) { + netfs_stat(&netfs_n_rh_read_failed); +- __set_bit(NETFS_SREQ_NEED_RETRY, &subreq->flags); + } else { + netfs_stat(&netfs_n_rh_download_failed); +- __set_bit(NETFS_SREQ_FAILED, &subreq->flags); ++ set_bit(NETFS_RREQ_FAILED, &rreq->flags); ++ rreq->error = subreq->error; + } +- trace_netfs_rreq(rreq, netfs_rreq_trace_set_pause); +- set_bit(NETFS_RREQ_PAUSE, &rreq->flags); + } + +- trace_netfs_sreq(subreq, netfs_sreq_trace_terminated); +- +- clear_bit_unlock(NETFS_SREQ_IN_PROGRESS, &subreq->flags); +- smp_mb__after_atomic(); /* Clear IN_PROGRESS before task state */ ++ if (atomic_dec_and_test(&rreq->nr_outstanding)) ++ netfs_rreq_terminated(rreq); + +- /* If we are at the head of the queue, wake up the collector. */ +- if (list_is_first(&subreq->rreq_link, &stream->subrequests)) +- netfs_wake_read_collector(rreq); +- +- netfs_put_subrequest(subreq, true, netfs_sreq_trace_put_terminated); ++ netfs_put_subrequest(subreq, false, netfs_sreq_trace_put_terminated); + } + EXPORT_SYMBOL(netfs_read_subreq_terminated); + +-/* +- * Handle termination of a read from the cache. ++/** ++ * netfs_read_subreq_termination_worker - Workqueue helper for read termination ++ * @work: The subreq->work in the I/O request that has been terminated. ++ * ++ * Helper function to jump to netfs_read_subreq_terminated() from the ++ * subrequest work item. + */ +-void netfs_cache_read_terminated(void *priv, ssize_t transferred_or_error, bool was_async) ++void netfs_read_subreq_termination_worker(struct work_struct *work) + { +- struct netfs_io_subrequest *subreq = priv; ++ struct netfs_io_subrequest *subreq = ++ container_of(work, struct netfs_io_subrequest, work); + +- if (transferred_or_error > 0) { +- subreq->error = 0; +- if (transferred_or_error > 0) { +- subreq->transferred += transferred_or_error; +- __set_bit(NETFS_SREQ_MADE_PROGRESS, &subreq->flags); +- } +- } else { +- subreq->error = transferred_or_error; +- } + netfs_read_subreq_terminated(subreq); + } +- +-/* +- * Wait for the read operation to complete, successfully or otherwise. +- */ +-ssize_t netfs_wait_for_read(struct netfs_io_request *rreq) +-{ +- struct netfs_io_subrequest *subreq; +- struct netfs_io_stream *stream = &rreq->io_streams[0]; +- DEFINE_WAIT(myself); +- ssize_t ret; +- +- for (;;) { +- trace_netfs_rreq(rreq, netfs_rreq_trace_wait_queue); +- prepare_to_wait(&rreq->waitq, &myself, TASK_UNINTERRUPTIBLE); +- +- subreq = list_first_entry_or_null(&stream->subrequests, +- struct netfs_io_subrequest, rreq_link); +- if (subreq && +- (!test_bit(NETFS_SREQ_IN_PROGRESS, &subreq->flags) || +- test_bit(NETFS_SREQ_MADE_PROGRESS, &subreq->flags))) { +- __set_current_state(TASK_RUNNING); +- netfs_read_collection(rreq); +- continue; +- } +- +- if (!test_bit(NETFS_RREQ_IN_PROGRESS, &rreq->flags)) +- break; +- +- schedule(); +- trace_netfs_rreq(rreq, netfs_rreq_trace_woke_queue); +- } +- +- finish_wait(&rreq->waitq, &myself); +- +- ret = rreq->error; +- if (ret == 0) { +- ret = rreq->transferred; +- switch (rreq->origin) { +- case NETFS_DIO_READ: +- case NETFS_READ_SINGLE: +- ret = rreq->transferred; +- break; +- default: +- if (rreq->submitted < rreq->len) { +- trace_netfs_failure(rreq, NULL, ret, netfs_fail_short_read); +- ret = -EIO; +- } +- break; +- } +- } +- +- return ret; +-} +- +-/* +- * Wait for a paused read operation to unpause or complete in some manner. +- */ +-void netfs_wait_for_pause(struct netfs_io_request *rreq) +-{ +- struct netfs_io_subrequest *subreq; +- struct netfs_io_stream *stream = &rreq->io_streams[0]; +- DEFINE_WAIT(myself); +- +- trace_netfs_rreq(rreq, netfs_rreq_trace_wait_pause); +- +- for (;;) { +- trace_netfs_rreq(rreq, netfs_rreq_trace_wait_queue); +- prepare_to_wait(&rreq->waitq, &myself, TASK_UNINTERRUPTIBLE); +- +- subreq = list_first_entry_or_null(&stream->subrequests, +- struct netfs_io_subrequest, rreq_link); +- if (subreq && +- (!test_bit(NETFS_SREQ_IN_PROGRESS, &subreq->flags) || +- test_bit(NETFS_SREQ_MADE_PROGRESS, &subreq->flags))) { +- __set_current_state(TASK_RUNNING); +- netfs_read_collection(rreq); +- continue; +- } +- +- if (!test_bit(NETFS_RREQ_IN_PROGRESS, &rreq->flags) || +- !test_bit(NETFS_RREQ_PAUSE, &rreq->flags)) +- break; +- +- schedule(); +- trace_netfs_rreq(rreq, netfs_rreq_trace_woke_queue); +- } +- +- finish_wait(&rreq->waitq, &myself); +-} ++EXPORT_SYMBOL(netfs_read_subreq_termination_worker); +diff --git a/fs/netfs/read_pgpriv2.c b/fs/netfs/read_pgpriv2.c +index cf7727060215..9eee5af6b327 100644 +--- a/fs/netfs/read_pgpriv2.c ++++ b/fs/netfs/read_pgpriv2.c +@@ -13,12 +13,54 @@ + #include + #include "internal.h" + ++/* ++ * [DEPRECATED] Mark page as requiring copy-to-cache using PG_private_2. The ++ * third mark in the folio queue is used to indicate that this folio needs ++ * writing. ++ */ ++void netfs_pgpriv2_mark_copy_to_cache(struct netfs_io_subrequest *subreq, ++ struct netfs_io_request *rreq, ++ struct folio_queue *folioq, ++ int slot) ++{ ++ struct folio *folio = folioq_folio(folioq, slot); ++ ++ trace_netfs_folio(folio, netfs_folio_trace_copy_to_cache); ++ folio_start_private_2(folio); ++ folioq_mark3(folioq, slot); ++} ++ ++/* ++ * [DEPRECATED] Cancel PG_private_2 on all marked folios in the event of an ++ * unrecoverable error. ++ */ ++static void netfs_pgpriv2_cancel(struct rolling_buffer *buffer) ++{ ++ struct folio_queue *folioq = buffer->tail; ++ struct folio *folio; ++ int slot; ++ ++ while (folioq) { ++ if (!folioq->marks3) { ++ folioq = folioq->next; ++ continue; ++ } ++ ++ slot = __ffs(folioq->marks3); ++ folio = folioq_folio(folioq, slot); ++ ++ trace_netfs_folio(folio, netfs_folio_trace_cancel_copy); ++ folio_end_private_2(folio); ++ folioq_unmark3(folioq, slot); ++ } ++} ++ + /* + * [DEPRECATED] Copy a folio to the cache with PG_private_2 set. + */ +-static void netfs_pgpriv2_copy_folio(struct netfs_io_request *creq, struct folio *folio) ++static int netfs_pgpriv2_copy_folio(struct netfs_io_request *wreq, struct folio *folio) + { +- struct netfs_io_stream *cache = &creq->io_streams[1]; ++ struct netfs_io_stream *cache = &wreq->io_streams[1]; + size_t fsize = folio_size(folio), flen = fsize; + loff_t fpos = folio_pos(folio), i_size; + bool to_eof = false; +@@ -29,17 +71,17 @@ static void netfs_pgpriv2_copy_folio(struct netfs_io_request *creq, struct folio + * of the page to beyond it, but cannot move i_size into or through the + * page since we have it locked. + */ +- i_size = i_size_read(creq->inode); ++ i_size = i_size_read(wreq->inode); + + if (fpos >= i_size) { + /* mmap beyond eof. */ + _debug("beyond eof"); + folio_end_private_2(folio); +- return; ++ return 0; + } + +- if (fpos + fsize > creq->i_size) +- creq->i_size = i_size; ++ if (fpos + fsize > wreq->i_size) ++ wreq->i_size = i_size; + + if (flen > i_size - fpos) { + flen = i_size - fpos; +@@ -53,10 +95,8 @@ static void netfs_pgpriv2_copy_folio(struct netfs_io_request *creq, struct folio + trace_netfs_folio(folio, netfs_folio_trace_store_copy); + + /* Attach the folio to the rolling buffer. */ +- if (rolling_buffer_append(&creq->buffer, folio, 0) < 0) { +- clear_bit(NETFS_RREQ_FOLIO_COPY_TO_CACHE, &creq->flags); +- return; +- } ++ if (rolling_buffer_append(&wreq->buffer, folio, 0) < 0) ++ return -ENOMEM; + + cache->submit_extendable_to = fsize; + cache->submit_off = 0; +@@ -70,11 +110,11 @@ static void netfs_pgpriv2_copy_folio(struct netfs_io_request *creq, struct folio + do { + ssize_t part; + +- creq->buffer.iter.iov_offset = cache->submit_off; ++ wreq->buffer.iter.iov_offset = cache->submit_off; + +- atomic64_set(&creq->issued_to, fpos + cache->submit_off); ++ atomic64_set(&wreq->issued_to, fpos + cache->submit_off); + cache->submit_extendable_to = fsize - cache->submit_off; +- part = netfs_advance_write(creq, cache, fpos + cache->submit_off, ++ part = netfs_advance_write(wreq, cache, fpos + cache->submit_off, + cache->submit_len, to_eof); + cache->submit_off += part; + if (part > cache->submit_len) +@@ -83,95 +123,98 @@ static void netfs_pgpriv2_copy_folio(struct netfs_io_request *creq, struct folio + cache->submit_len -= part; + } while (cache->submit_len > 0); + +- creq->buffer.iter.iov_offset = 0; +- rolling_buffer_advance(&creq->buffer, fsize); +- atomic64_set(&creq->issued_to, fpos + fsize); ++ wreq->buffer.iter.iov_offset = 0; ++ rolling_buffer_advance(&wreq->buffer, fsize); ++ atomic64_set(&wreq->issued_to, fpos + fsize); + + if (flen < fsize) +- netfs_issue_write(creq, cache); ++ netfs_issue_write(wreq, cache); ++ ++ _leave(" = 0"); ++ return 0; + } + + /* +- * [DEPRECATED] Set up copying to the cache. ++ * [DEPRECATED] Go through the buffer and write any folios that are marked with ++ * the third mark to the cache. + */ +-static struct netfs_io_request *netfs_pgpriv2_begin_copy_to_cache( +- struct netfs_io_request *rreq, struct folio *folio) ++void netfs_pgpriv2_write_to_the_cache(struct netfs_io_request *rreq) + { +- struct netfs_io_request *creq; ++ struct netfs_io_request *wreq; ++ struct folio_queue *folioq; ++ struct folio *folio; ++ int error = 0; ++ int slot = 0; ++ ++ _enter(""); + + if (!fscache_resources_valid(&rreq->cache_resources)) +- goto cancel; ++ goto couldnt_start; + +- creq = netfs_create_write_req(rreq->mapping, NULL, folio_pos(folio), +- NETFS_PGPRIV2_COPY_TO_CACHE); +- if (IS_ERR(creq)) +- goto cancel; ++ /* Need the first folio to be able to set up the op. */ ++ for (folioq = rreq->buffer.tail; folioq; folioq = folioq->next) { ++ if (folioq->marks3) { ++ slot = __ffs(folioq->marks3); ++ break; ++ } ++ } ++ if (!folioq) ++ return; ++ folio = folioq_folio(folioq, slot); + +- if (!creq->io_streams[1].avail) +- goto cancel_put; ++ wreq = netfs_create_write_req(rreq->mapping, NULL, folio_pos(folio), ++ NETFS_PGPRIV2_COPY_TO_CACHE); ++ if (IS_ERR(wreq)) { ++ kleave(" [create %ld]", PTR_ERR(wreq)); ++ goto couldnt_start; ++ } + +- trace_netfs_write(creq, netfs_write_trace_copy_to_cache); ++ trace_netfs_write(wreq, netfs_write_trace_copy_to_cache); + netfs_stat(&netfs_n_wh_copy_to_cache); +- rreq->copy_to_cache = creq; +- return creq; +- +-cancel_put: +- netfs_put_request(creq, false, netfs_rreq_trace_put_return); +-cancel: +- rreq->copy_to_cache = ERR_PTR(-ENOBUFS); +- clear_bit(NETFS_RREQ_FOLIO_COPY_TO_CACHE, &rreq->flags); +- return ERR_PTR(-ENOBUFS); +-} +- +-/* +- * [DEPRECATED] Mark page as requiring copy-to-cache using PG_private_2 and add +- * it to the copy write request. +- */ +-void netfs_pgpriv2_copy_to_cache(struct netfs_io_request *rreq, struct folio *folio) +-{ +- struct netfs_io_request *creq = rreq->copy_to_cache; +- +- if (!creq) +- creq = netfs_pgpriv2_begin_copy_to_cache(rreq, folio); +- if (IS_ERR(creq)) +- return; ++ if (!wreq->io_streams[1].avail) { ++ netfs_put_request(wreq, false, netfs_rreq_trace_put_return); ++ goto couldnt_start; ++ } + +- trace_netfs_folio(folio, netfs_folio_trace_copy_to_cache); +- folio_start_private_2(folio); +- netfs_pgpriv2_copy_folio(creq, folio); +-} ++ for (;;) { ++ error = netfs_pgpriv2_copy_folio(wreq, folio); ++ if (error < 0) ++ break; + +-/* +- * [DEPRECATED] End writing to the cache, flushing out any outstanding writes. +- */ +-void netfs_pgpriv2_end_copy_to_cache(struct netfs_io_request *rreq) +-{ +- struct netfs_io_request *creq = rreq->copy_to_cache; ++ folioq_unmark3(folioq, slot); ++ if (!folioq->marks3) { ++ folioq = folioq->next; ++ if (!folioq) ++ break; ++ } + +- if (IS_ERR_OR_NULL(creq)) +- return; ++ slot = __ffs(folioq->marks3); ++ folio = folioq_folio(folioq, slot); ++ } + +- netfs_issue_write(creq, &creq->io_streams[1]); ++ netfs_issue_write(wreq, &wreq->io_streams[1]); + smp_wmb(); /* Write lists before ALL_QUEUED. */ +- set_bit(NETFS_RREQ_ALL_QUEUED, &creq->flags); ++ set_bit(NETFS_RREQ_ALL_QUEUED, &wreq->flags); + +- netfs_put_request(creq, false, netfs_rreq_trace_put_return); +- creq->copy_to_cache = NULL; ++ netfs_put_request(wreq, false, netfs_rreq_trace_put_return); ++ _leave(" = %d", error); ++couldnt_start: ++ netfs_pgpriv2_cancel(&rreq->buffer); + } + + /* + * [DEPRECATED] Remove the PG_private_2 mark from any folios we've finished + * copying. + */ +-bool netfs_pgpriv2_unlock_copied_folios(struct netfs_io_request *creq) ++bool netfs_pgpriv2_unlock_copied_folios(struct netfs_io_request *wreq) + { +- struct folio_queue *folioq = creq->buffer.tail; +- unsigned long long collected_to = creq->collected_to; +- unsigned int slot = creq->buffer.first_tail_slot; ++ struct folio_queue *folioq = wreq->buffer.tail; ++ unsigned long long collected_to = wreq->collected_to; ++ unsigned int slot = wreq->buffer.first_tail_slot; + bool made_progress = false; + + if (slot >= folioq_nr_slots(folioq)) { +- folioq = rolling_buffer_delete_spent(&creq->buffer); ++ folioq = rolling_buffer_delete_spent(&wreq->buffer); + slot = 0; + } + +@@ -183,16 +226,16 @@ bool netfs_pgpriv2_unlock_copied_folios(struct netfs_io_request *creq) + folio = folioq_folio(folioq, slot); + if (WARN_ONCE(!folio_test_private_2(folio), + "R=%08x: folio %lx is not marked private_2\n", +- creq->debug_id, folio->index)) ++ wreq->debug_id, folio->index)) + trace_netfs_folio(folio, netfs_folio_trace_not_under_wback); + + fpos = folio_pos(folio); + fsize = folio_size(folio); + flen = fsize; + +- fend = min_t(unsigned long long, fpos + flen, creq->i_size); ++ fend = min_t(unsigned long long, fpos + flen, wreq->i_size); + +- trace_netfs_collect_folio(creq, folio, fend, collected_to); ++ trace_netfs_collect_folio(wreq, folio, fend, collected_to); + + /* Unlock any folio we've transferred all of. */ + if (collected_to < fend) +@@ -200,7 +243,7 @@ bool netfs_pgpriv2_unlock_copied_folios(struct netfs_io_request *creq) + + trace_netfs_folio(folio, netfs_folio_trace_end_copy); + folio_end_private_2(folio); +- creq->cleaned_to = fpos + fsize; ++ wreq->cleaned_to = fpos + fsize; + made_progress = true; + + /* Clean up the head folioq. If we clear an entire folioq, then +@@ -210,7 +253,7 @@ bool netfs_pgpriv2_unlock_copied_folios(struct netfs_io_request *creq) + folioq_clear(folioq, slot); + slot++; + if (slot >= folioq_nr_slots(folioq)) { +- folioq = rolling_buffer_delete_spent(&creq->buffer); ++ folioq = rolling_buffer_delete_spent(&wreq->buffer); + if (!folioq) + goto done; + slot = 0; +@@ -220,8 +263,8 @@ bool netfs_pgpriv2_unlock_copied_folios(struct netfs_io_request *creq) + break; + } + +- creq->buffer.tail = folioq; ++ wreq->buffer.tail = folioq; + done: +- creq->buffer.first_tail_slot = slot; ++ wreq->buffer.first_tail_slot = slot; + return made_progress; + } +diff --git a/fs/netfs/read_retry.c b/fs/netfs/read_retry.c +index 2290af0d51ac..9a312a21fc15 100644 +--- a/fs/netfs/read_retry.c ++++ b/fs/netfs/read_retry.c +@@ -12,7 +12,15 @@ + static void netfs_reissue_read(struct netfs_io_request *rreq, + struct netfs_io_subrequest *subreq) + { +- __clear_bit(NETFS_SREQ_MADE_PROGRESS, &subreq->flags); ++ struct iov_iter *io_iter = &subreq->io_iter; ++ ++ if (iov_iter_is_folioq(io_iter)) { ++ subreq->curr_folioq = (struct folio_queue *)io_iter->folioq; ++ subreq->curr_folioq_slot = io_iter->folioq_slot; ++ subreq->curr_folio_order = subreq->curr_folioq->orders[subreq->curr_folioq_slot]; ++ } ++ ++ atomic_inc(&rreq->nr_outstanding); + __set_bit(NETFS_SREQ_IN_PROGRESS, &subreq->flags); + netfs_get_subrequest(subreq, netfs_sreq_trace_get_resubmit); + subreq->rreq->netfs_ops->issue_read(subreq); +@@ -25,12 +33,13 @@ static void netfs_reissue_read(struct netfs_io_request *rreq, + static void netfs_retry_read_subrequests(struct netfs_io_request *rreq) + { + struct netfs_io_subrequest *subreq; +- struct netfs_io_stream *stream = &rreq->io_streams[0]; +- struct list_head *next; ++ struct netfs_io_stream *stream0 = &rreq->io_streams[0]; ++ LIST_HEAD(sublist); ++ LIST_HEAD(queue); + + _enter("R=%x", rreq->debug_id); + +- if (list_empty(&stream->subrequests)) ++ if (list_empty(&rreq->subrequests)) + return; + + if (rreq->netfs_ops->retry_request) +@@ -41,7 +50,9 @@ static void netfs_retry_read_subrequests(struct netfs_io_request *rreq) + */ + if (!rreq->netfs_ops->prepare_read && + !rreq->cache_resources.ops) { +- list_for_each_entry(subreq, &stream->subrequests, rreq_link) { ++ struct netfs_io_subrequest *subreq; ++ ++ list_for_each_entry(subreq, &rreq->subrequests, rreq_link) { + if (test_bit(NETFS_SREQ_FAILED, &subreq->flags)) + break; + if (__test_and_clear_bit(NETFS_SREQ_NEED_RETRY, &subreq->flags)) { +@@ -64,44 +75,48 @@ static void netfs_retry_read_subrequests(struct netfs_io_request *rreq) + * populating with smaller subrequests. In the event that the subreq + * we just launched finishes before we insert the next subreq, it'll + * fill in rreq->prev_donated instead. +- * ++ + * Note: Alternatively, we could split the tail subrequest right before + * we reissue it and fix up the donations under lock. + */ +- next = stream->subrequests.next; ++ list_splice_init(&rreq->subrequests, &queue); + + do { +- struct netfs_io_subrequest *from, *to, *tmp; ++ struct netfs_io_subrequest *from; + struct iov_iter source; + unsigned long long start, len; +- size_t part; ++ size_t part, deferred_next_donated = 0; + bool boundary = false; + + /* Go through the subreqs and find the next span of contiguous + * buffer that we then rejig (cifs, for example, needs the + * rsize renegotiating) and reissue. + */ +- from = list_entry(next, struct netfs_io_subrequest, rreq_link); +- to = from; ++ from = list_first_entry(&queue, struct netfs_io_subrequest, rreq_link); ++ list_move_tail(&from->rreq_link, &sublist); + start = from->start + from->transferred; + len = from->len - from->transferred; + +- _debug("from R=%08x[%x] s=%llx ctl=%zx/%zx", ++ _debug("from R=%08x[%x] s=%llx ctl=%zx/%zx/%zx", + rreq->debug_id, from->debug_index, +- from->start, from->transferred, from->len); ++ from->start, from->consumed, from->transferred, from->len); + + if (test_bit(NETFS_SREQ_FAILED, &from->flags) || + !test_bit(NETFS_SREQ_NEED_RETRY, &from->flags)) + goto abandon; + +- list_for_each_continue(next, &stream->subrequests) { +- subreq = list_entry(next, struct netfs_io_subrequest, rreq_link); +- if (subreq->start + subreq->transferred != start + len || +- test_bit(NETFS_SREQ_BOUNDARY, &subreq->flags) || ++ deferred_next_donated = from->next_donated; ++ while ((subreq = list_first_entry_or_null( ++ &queue, struct netfs_io_subrequest, rreq_link))) { ++ if (subreq->start != start + len || ++ subreq->transferred > 0 || + !test_bit(NETFS_SREQ_NEED_RETRY, &subreq->flags)) + break; +- to = subreq; +- len += to->len; ++ list_move_tail(&subreq->rreq_link, &sublist); ++ len += subreq->len; ++ deferred_next_donated = subreq->next_donated; ++ if (test_bit(NETFS_SREQ_BOUNDARY, &subreq->flags)) ++ break; + } + + _debug(" - range: %llx-%llx %llx", start, start + len - 1, len); +@@ -114,31 +129,38 @@ static void netfs_retry_read_subrequests(struct netfs_io_request *rreq) + source.count = len; + + /* Work through the sublist. */ +- subreq = from; +- list_for_each_entry_from(subreq, &stream->subrequests, rreq_link) { +- if (!len) +- break; ++ while ((subreq = list_first_entry_or_null( ++ &sublist, struct netfs_io_subrequest, rreq_link))) { ++ list_del(&subreq->rreq_link); ++ + subreq->source = NETFS_DOWNLOAD_FROM_SERVER; + subreq->start = start - subreq->transferred; + subreq->len = len + subreq->transferred; ++ stream0->sreq_max_len = subreq->len; ++ + __clear_bit(NETFS_SREQ_NEED_RETRY, &subreq->flags); + __clear_bit(NETFS_SREQ_MADE_PROGRESS, &subreq->flags); + subreq->retry_count++; + ++ spin_lock(&rreq->lock); ++ list_add_tail(&subreq->rreq_link, &rreq->subrequests); ++ subreq->prev_donated += rreq->prev_donated; ++ rreq->prev_donated = 0; + trace_netfs_sreq(subreq, netfs_sreq_trace_retry); ++ spin_unlock(&rreq->lock); ++ ++ BUG_ON(!len); + + /* Renegotiate max_len (rsize) */ +- stream->sreq_max_len = subreq->len; + if (rreq->netfs_ops->prepare_read && + rreq->netfs_ops->prepare_read(subreq) < 0) { + trace_netfs_sreq(subreq, netfs_sreq_trace_reprep_failed); + __set_bit(NETFS_SREQ_FAILED, &subreq->flags); +- goto abandon; + } + +- part = umin(len, stream->sreq_max_len); +- if (unlikely(stream->sreq_max_segs)) +- part = netfs_limit_iter(&source, 0, part, stream->sreq_max_segs); ++ part = umin(len, stream0->sreq_max_len); ++ if (unlikely(rreq->io_streams[0].sreq_max_segs)) ++ part = netfs_limit_iter(&source, 0, part, stream0->sreq_max_segs); + subreq->len = subreq->transferred + part; + subreq->io_iter = source; + iov_iter_truncate(&subreq->io_iter, part); +@@ -148,105 +170,57 @@ static void netfs_retry_read_subrequests(struct netfs_io_request *rreq) + if (!len) { + if (boundary) + __set_bit(NETFS_SREQ_BOUNDARY, &subreq->flags); ++ subreq->next_donated = deferred_next_donated; + } else { + __clear_bit(NETFS_SREQ_BOUNDARY, &subreq->flags); ++ subreq->next_donated = 0; + } + +- netfs_get_subrequest(subreq, netfs_sreq_trace_get_resubmit); + netfs_reissue_read(rreq, subreq); +- if (subreq == to) ++ if (!len) + break; +- } + +- /* If we managed to use fewer subreqs, we can discard the +- * excess; if we used the same number, then we're done. +- */ +- if (!len) { +- if (subreq == to) +- continue; +- list_for_each_entry_safe_from(subreq, tmp, +- &stream->subrequests, rreq_link) { +- trace_netfs_sreq(subreq, netfs_sreq_trace_discard); +- list_del(&subreq->rreq_link); +- netfs_put_subrequest(subreq, false, netfs_sreq_trace_put_done); +- if (subreq == to) +- break; ++ /* If we ran out of subrequests, allocate another. */ ++ if (list_empty(&sublist)) { ++ subreq = netfs_alloc_subrequest(rreq); ++ if (!subreq) ++ goto abandon; ++ subreq->source = NETFS_DOWNLOAD_FROM_SERVER; ++ subreq->start = start; ++ ++ /* We get two refs, but need just one. */ ++ netfs_put_subrequest(subreq, false, netfs_sreq_trace_new); ++ trace_netfs_sreq(subreq, netfs_sreq_trace_split); ++ list_add_tail(&subreq->rreq_link, &sublist); + } +- continue; + } + +- /* We ran out of subrequests, so we need to allocate some more +- * and insert them after. ++ /* If we managed to use fewer subreqs, we can discard the ++ * excess. + */ +- do { +- subreq = netfs_alloc_subrequest(rreq); +- if (!subreq) { +- subreq = to; +- goto abandon_after; +- } +- subreq->source = NETFS_DOWNLOAD_FROM_SERVER; +- subreq->start = start; +- subreq->len = len; +- subreq->debug_index = atomic_inc_return(&rreq->subreq_counter); +- subreq->stream_nr = stream->stream_nr; +- subreq->retry_count = 1; +- +- trace_netfs_sreq_ref(rreq->debug_id, subreq->debug_index, +- refcount_read(&subreq->ref), +- netfs_sreq_trace_new); +- netfs_get_subrequest(subreq, netfs_sreq_trace_get_resubmit); +- +- list_add(&subreq->rreq_link, &to->rreq_link); +- to = list_next_entry(to, rreq_link); +- trace_netfs_sreq(subreq, netfs_sreq_trace_retry); +- +- stream->sreq_max_len = umin(len, rreq->rsize); +- stream->sreq_max_segs = 0; +- if (unlikely(stream->sreq_max_segs)) +- part = netfs_limit_iter(&source, 0, part, stream->sreq_max_segs); +- +- netfs_stat(&netfs_n_rh_download); +- if (rreq->netfs_ops->prepare_read(subreq) < 0) { +- trace_netfs_sreq(subreq, netfs_sreq_trace_reprep_failed); +- __set_bit(NETFS_SREQ_FAILED, &subreq->flags); +- goto abandon; +- } +- +- part = umin(len, stream->sreq_max_len); +- subreq->len = subreq->transferred + part; +- subreq->io_iter = source; +- iov_iter_truncate(&subreq->io_iter, part); +- iov_iter_advance(&source, part); +- +- len -= part; +- start += part; +- if (!len && boundary) { +- __set_bit(NETFS_SREQ_BOUNDARY, &to->flags); +- boundary = false; +- } +- +- netfs_reissue_read(rreq, subreq); +- } while (len); ++ while ((subreq = list_first_entry_or_null( ++ &sublist, struct netfs_io_subrequest, rreq_link))) { ++ trace_netfs_sreq(subreq, netfs_sreq_trace_discard); ++ list_del(&subreq->rreq_link); ++ netfs_put_subrequest(subreq, false, netfs_sreq_trace_put_done); ++ } + +- } while (!list_is_head(next, &stream->subrequests)); ++ } while (!list_empty(&queue)); + + return; + +- /* If we hit an error, fail all remaining incomplete subrequests */ +-abandon_after: +- if (list_is_last(&subreq->rreq_link, &stream->subrequests)) +- return; +- subreq = list_next_entry(subreq, rreq_link); ++ /* If we hit ENOMEM, fail all remaining subrequests */ + abandon: +- list_for_each_entry_from(subreq, &stream->subrequests, rreq_link) { +- if (!subreq->error && +- !test_bit(NETFS_SREQ_FAILED, &subreq->flags) && +- !test_bit(NETFS_SREQ_NEED_RETRY, &subreq->flags)) +- continue; +- subreq->error = -ENOMEM; +- __set_bit(NETFS_SREQ_FAILED, &subreq->flags); ++ list_splice_init(&sublist, &queue); ++ list_for_each_entry(subreq, &queue, rreq_link) { ++ if (!subreq->error) ++ subreq->error = -ENOMEM; ++ __clear_bit(NETFS_SREQ_FAILED, &subreq->flags); + __clear_bit(NETFS_SREQ_NEED_RETRY, &subreq->flags); + } ++ spin_lock(&rreq->lock); ++ list_splice_tail_init(&queue, &rreq->subrequests); ++ spin_unlock(&rreq->lock); + } + + /* +@@ -254,19 +228,14 @@ static void netfs_retry_read_subrequests(struct netfs_io_request *rreq) + */ + void netfs_retry_reads(struct netfs_io_request *rreq) + { +- struct netfs_io_subrequest *subreq; +- struct netfs_io_stream *stream = &rreq->io_streams[0]; ++ trace_netfs_rreq(rreq, netfs_rreq_trace_resubmit); + +- /* Wait for all outstanding I/O to quiesce before performing retries as +- * we may need to renegotiate the I/O sizes. +- */ +- list_for_each_entry(subreq, &stream->subrequests, rreq_link) { +- wait_on_bit(&subreq->flags, NETFS_SREQ_IN_PROGRESS, +- TASK_UNINTERRUPTIBLE); +- } ++ atomic_inc(&rreq->nr_outstanding); + +- trace_netfs_rreq(rreq, netfs_rreq_trace_resubmit); + netfs_retry_read_subrequests(rreq); ++ ++ if (atomic_dec_and_test(&rreq->nr_outstanding)) ++ netfs_rreq_terminated(rreq); + } + + /* +diff --git a/fs/netfs/read_single.c b/fs/netfs/read_single.c +index fea0ecdecc53..2443b6885fd1 100644 +--- a/fs/netfs/read_single.c ++++ b/fs/netfs/read_single.c +@@ -77,7 +77,6 @@ static void netfs_single_read_cache(struct netfs_io_request *rreq, + { + struct netfs_cache_resources *cres = &rreq->cache_resources; + +- _enter("R=%08x[%x]", rreq->debug_id, subreq->debug_index); + netfs_stat(&netfs_n_rh_read); + cres->ops->read(cres, subreq->start, &subreq->io_iter, NETFS_READ_HOLE_FAIL, + netfs_cache_read_terminated, subreq); +@@ -89,28 +88,28 @@ static void netfs_single_read_cache(struct netfs_io_request *rreq, + */ + static int netfs_single_dispatch_read(struct netfs_io_request *rreq) + { +- struct netfs_io_stream *stream = &rreq->io_streams[0]; + struct netfs_io_subrequest *subreq; + int ret = 0; + ++ atomic_set(&rreq->nr_outstanding, 1); ++ + subreq = netfs_alloc_subrequest(rreq); +- if (!subreq) +- return -ENOMEM; ++ if (!subreq) { ++ ret = -ENOMEM; ++ goto out; ++ } + + subreq->source = NETFS_SOURCE_UNKNOWN; + subreq->start = 0; + subreq->len = rreq->len; + subreq->io_iter = rreq->buffer.iter; + +- __set_bit(NETFS_SREQ_IN_PROGRESS, &subreq->flags); ++ atomic_inc(&rreq->nr_outstanding); + +- spin_lock(&rreq->lock); +- list_add_tail(&subreq->rreq_link, &stream->subrequests); ++ spin_lock_bh(&rreq->lock); ++ list_add_tail(&subreq->rreq_link, &rreq->subrequests); + trace_netfs_sreq(subreq, netfs_sreq_trace_added); +- stream->front = subreq; +- /* Store list pointers before active flag */ +- smp_store_release(&stream->active, true); +- spin_unlock(&rreq->lock); ++ spin_unlock_bh(&rreq->lock); + + netfs_single_cache_prepare_read(rreq, subreq); + switch (subreq->source) { +@@ -138,12 +137,14 @@ static int netfs_single_dispatch_read(struct netfs_io_request *rreq) + break; + } + +- smp_wmb(); /* Write lists before ALL_QUEUED. */ +- set_bit(NETFS_RREQ_ALL_QUEUED, &rreq->flags); ++out: ++ if (atomic_dec_and_test(&rreq->nr_outstanding)) ++ netfs_rreq_terminated(rreq); + return ret; + cancel: ++ atomic_dec(&rreq->nr_outstanding); + netfs_put_subrequest(subreq, false, netfs_sreq_trace_put_cancel); +- return ret; ++ goto out; + } + + /** +@@ -184,7 +185,13 @@ ssize_t netfs_read_single(struct inode *inode, struct file *file, struct iov_ite + rreq->buffer.iter = *iter; + netfs_single_dispatch_read(rreq); + +- ret = netfs_wait_for_read(rreq); ++ trace_netfs_rreq(rreq, netfs_rreq_trace_wait_ip); ++ wait_on_bit(&rreq->flags, NETFS_RREQ_IN_PROGRESS, ++ TASK_UNINTERRUPTIBLE); ++ ++ ret = rreq->error; ++ if (ret == 0) ++ ret = rreq->transferred; + netfs_put_request(rreq, true, netfs_rreq_trace_put_return); + return ret; + +diff --git a/fs/netfs/write_collect.c b/fs/netfs/write_collect.c +index 294f67795f79..04d1ca292cf5 100644 +--- a/fs/netfs/write_collect.c ++++ b/fs/netfs/write_collect.c +@@ -323,9 +323,7 @@ static void netfs_collect_write_results(struct netfs_io_request *wreq) + goto need_retry; + if ((notes & MADE_PROGRESS) && test_bit(NETFS_RREQ_PAUSE, &wreq->flags)) { + trace_netfs_rreq(wreq, netfs_rreq_trace_unpause); +- clear_bit_unlock(NETFS_RREQ_PAUSE, &wreq->flags); +- smp_mb__after_atomic(); /* Set PAUSE before task state */ +- wake_up(&wreq->waitq); ++ clear_and_wake_up_bit(NETFS_RREQ_PAUSE, &wreq->flags); + } + + if (notes & NEED_REASSESS) { +diff --git a/fs/netfs/write_issue.c b/fs/netfs/write_issue.c +index 69727411683e..6f14a7c2f040 100644 +--- a/fs/netfs/write_issue.c ++++ b/fs/netfs/write_issue.c +@@ -723,7 +723,7 @@ int netfs_unbuffered_write(struct netfs_io_request *wreq, bool may_wait, size_t + rolling_buffer_advance(&wreq->buffer, part); + if (test_bit(NETFS_RREQ_PAUSE, &wreq->flags)) { + trace_netfs_rreq(wreq, netfs_rreq_trace_wait_pause); +- wait_event(wreq->waitq, !test_bit(NETFS_RREQ_PAUSE, &wreq->flags)); ++ wait_on_bit(&wreq->flags, NETFS_RREQ_PAUSE, TASK_UNINTERRUPTIBLE); + } + if (test_bit(NETFS_RREQ_FAILED, &wreq->flags)) + break; +diff --git a/fs/netfs/write_retry.c b/fs/netfs/write_retry.c +index c841a851dd73..f3d5e37d4698 100644 +--- a/fs/netfs/write_retry.c ++++ b/fs/netfs/write_retry.c +@@ -93,21 +93,15 @@ static void netfs_retry_write_stream(struct netfs_io_request *wreq, + list_for_each_entry_from(subreq, &stream->subrequests, rreq_link) { + if (!len) + break; +- +- subreq->start = start; +- subreq->len = len; ++ /* Renegotiate max_len (wsize) */ ++ trace_netfs_sreq(subreq, netfs_sreq_trace_retry); + __clear_bit(NETFS_SREQ_NEED_RETRY, &subreq->flags); + subreq->retry_count++; +- trace_netfs_sreq(subreq, netfs_sreq_trace_retry); +- +- /* Renegotiate max_len (wsize) */ +- stream->sreq_max_len = len; + stream->prepare_write(subreq); + +- part = umin(len, stream->sreq_max_len); +- if (unlikely(stream->sreq_max_segs)) +- part = netfs_limit_iter(&source, 0, part, stream->sreq_max_segs); ++ part = min(len, stream->sreq_max_len); + subreq->len = part; ++ subreq->start = start; + subreq->transferred = 0; + len -= part; + start += part; +diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c +index 7f1cacc89dbb..f42fdb26954e 100644 +--- a/fs/smb/client/cifssmb.c ++++ b/fs/smb/client/cifssmb.c +@@ -1331,8 +1331,6 @@ cifs_readv_callback(struct mid_q_entry *mid) + } else if (rdata->got_bytes > 0) { + __set_bit(NETFS_SREQ_MADE_PROGRESS, &rdata->subreq.flags); + } +- if (rdata->got_bytes) +- __set_bit(NETFS_SREQ_MADE_PROGRESS, &rdata->subreq.flags); + } + + rdata->credits.value = 0; +diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c +index 9f54596a6866..84ab3138e39c 100644 +--- a/fs/smb/client/smb2pdu.c ++++ b/fs/smb/client/smb2pdu.c +@@ -4607,8 +4607,7 @@ smb2_readv_callback(struct mid_q_entry *mid) + __set_bit(NETFS_SREQ_HIT_EOF, &rdata->subreq.flags); + rdata->result = 0; + } +- if (rdata->got_bytes) +- __set_bit(NETFS_SREQ_MADE_PROGRESS, &rdata->subreq.flags); ++ __set_bit(NETFS_SREQ_MADE_PROGRESS, &rdata->subreq.flags); + } + trace_smb3_rw_credits(rreq_debug_id, subreq_debug_index, rdata->credits.value, + server->credits, server->in_flight, +@@ -4617,7 +4616,7 @@ smb2_readv_callback(struct mid_q_entry *mid) + rdata->subreq.error = rdata->result; + rdata->subreq.transferred += rdata->got_bytes; + trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_progress); +- netfs_read_subreq_terminated(&rdata->subreq); ++ queue_work(cifsiod_wq, &rdata->subreq.work); + release_mid(mid); + trace_smb3_rw_credits(rreq_debug_id, subreq_debug_index, 0, + server->credits, server->in_flight, +diff --git a/include/linux/netfs.h b/include/linux/netfs.h +index 071d05d81d38..27e62f7d2940 100644 +--- a/include/linux/netfs.h ++++ b/include/linux/netfs.h +@@ -181,6 +181,9 @@ struct netfs_io_subrequest { + unsigned long long start; /* Where to start the I/O */ + size_t len; /* Size of the I/O */ + size_t transferred; /* Amount of data transferred */ ++ size_t consumed; /* Amount of read data consumed */ ++ size_t prev_donated; /* Amount of data donated from previous subreq */ ++ size_t next_donated; /* Amount of data donated from next subreq */ + refcount_t ref; + short error; /* 0 or error that occurred */ + unsigned short debug_index; /* Index in list (for debugging output) */ +@@ -188,6 +191,9 @@ struct netfs_io_subrequest { + u8 retry_count; /* The number of retries (0 on initial pass) */ + enum netfs_io_source source; /* Where to read from/write to */ + unsigned char stream_nr; /* I/O stream this belongs to */ ++ unsigned char curr_folioq_slot; /* Folio currently being read */ ++ unsigned char curr_folio_order; /* Order of folio */ ++ struct folio_queue *curr_folioq; /* Queue segment in which current folio resides */ + unsigned long flags; + #define NETFS_SREQ_COPY_TO_CACHE 0 /* Set if should copy the data to the cache */ + #define NETFS_SREQ_CLEAR_TAIL 1 /* Set if the rest of the read should be cleared */ +@@ -230,16 +236,15 @@ struct netfs_io_request { + struct address_space *mapping; /* The mapping being accessed */ + struct kiocb *iocb; /* AIO completion vector */ + struct netfs_cache_resources cache_resources; +- struct netfs_io_request *copy_to_cache; /* Request to write just-read data to the cache */ + struct readahead_control *ractl; /* Readahead descriptor */ + struct list_head proc_link; /* Link in netfs_iorequests */ ++ struct list_head subrequests; /* Contributory I/O operations */ + struct netfs_io_stream io_streams[2]; /* Streams of parallel I/O operations */ + #define NR_IO_STREAMS 2 //wreq->nr_io_streams + struct netfs_group *group; /* Writeback group being written back */ + struct rolling_buffer buffer; /* Unencrypted buffer */ + #define NETFS_ROLLBUF_PUT_MARK ROLLBUF_MARK_1 + #define NETFS_ROLLBUF_PAGECACHE_MARK ROLLBUF_MARK_2 +- wait_queue_head_t waitq; /* Processor waiter */ + void *netfs_priv; /* Private data for the netfs */ + void *netfs_priv2; /* Private data for the netfs */ + struct bio_vec *direct_bv; /* DIO buffer list (when handling iovec-iter) */ +@@ -250,6 +255,7 @@ struct netfs_io_request { + atomic_t subreq_counter; /* Next subreq->debug_index */ + unsigned int nr_group_rel; /* Number of refs to release on ->group */ + spinlock_t lock; /* Lock for queuing subreqs */ ++ atomic_t nr_outstanding; /* Number of ops in progress */ + unsigned long long submitted; /* Amount submitted for I/O so far */ + unsigned long long len; /* Length of the request */ + size_t transferred; /* Amount to be indicated as transferred */ +@@ -261,17 +267,14 @@ struct netfs_io_request { + atomic64_t issued_to; /* Write issuer folio cursor */ + unsigned long long collected_to; /* Point we've collected to */ + unsigned long long cleaned_to; /* Position we've cleaned folios to */ +- unsigned long long abandon_to; /* Position to abandon folios to */ + pgoff_t no_unlock_folio; /* Don't unlock this folio after read */ +- unsigned char front_folio_order; /* Order (size) of front folio */ ++ size_t prev_donated; /* Fallback for subreq->prev_donated */ + refcount_t ref; + unsigned long flags; +-#define NETFS_RREQ_OFFLOAD_COLLECTION 0 /* Offload collection to workqueue */ + #define NETFS_RREQ_NO_UNLOCK_FOLIO 2 /* Don't unlock no_unlock_folio on completion */ + #define NETFS_RREQ_DONT_UNLOCK_FOLIOS 3 /* Don't unlock the folios on completion */ + #define NETFS_RREQ_FAILED 4 /* The request failed */ + #define NETFS_RREQ_IN_PROGRESS 5 /* Unlocked when the request completes */ +-#define NETFS_RREQ_FOLIO_COPY_TO_CACHE 6 /* Copy current folio to cache from read */ + #define NETFS_RREQ_UPLOAD_TO_SERVER 8 /* Need to write to the server */ + #define NETFS_RREQ_NONBLOCK 9 /* Don't block if possible (O_NONBLOCK) */ + #define NETFS_RREQ_BLOCKED 10 /* We blocked */ +@@ -436,6 +439,7 @@ vm_fault_t netfs_page_mkwrite(struct vm_fault *vmf, struct netfs_group *netfs_gr + /* (Sub)request management API. */ + void netfs_read_subreq_progress(struct netfs_io_subrequest *subreq); + void netfs_read_subreq_terminated(struct netfs_io_subrequest *subreq); ++void netfs_read_subreq_termination_worker(struct work_struct *work); + void netfs_get_subrequest(struct netfs_io_subrequest *subreq, + enum netfs_sreq_ref_trace what); + void netfs_put_subrequest(struct netfs_io_subrequest *subreq, +diff --git a/include/trace/events/netfs.h b/include/trace/events/netfs.h +index 6e699cadcb29..6df2e7313371 100644 +--- a/include/trace/events/netfs.h ++++ b/include/trace/events/netfs.h +@@ -50,23 +50,18 @@ + EM(netfs_rreq_trace_assess, "ASSESS ") \ + EM(netfs_rreq_trace_copy, "COPY ") \ + EM(netfs_rreq_trace_collect, "COLLECT") \ +- EM(netfs_rreq_trace_complete, "COMPLET") \ + EM(netfs_rreq_trace_dirty, "DIRTY ") \ + EM(netfs_rreq_trace_done, "DONE ") \ + EM(netfs_rreq_trace_free, "FREE ") \ + EM(netfs_rreq_trace_redirty, "REDIRTY") \ + EM(netfs_rreq_trace_resubmit, "RESUBMT") \ +- EM(netfs_rreq_trace_set_abandon, "S-ABNDN") \ + EM(netfs_rreq_trace_set_pause, "PAUSE ") \ + EM(netfs_rreq_trace_unlock, "UNLOCK ") \ + EM(netfs_rreq_trace_unlock_pgpriv2, "UNLCK-2") \ + EM(netfs_rreq_trace_unmark, "UNMARK ") \ + EM(netfs_rreq_trace_wait_ip, "WAIT-IP") \ + EM(netfs_rreq_trace_wait_pause, "WT-PAUS") \ +- EM(netfs_rreq_trace_wait_queue, "WAIT-Q ") \ + EM(netfs_rreq_trace_wake_ip, "WAKE-IP") \ +- EM(netfs_rreq_trace_wake_queue, "WAKE-Q ") \ +- EM(netfs_rreq_trace_woke_queue, "WOKE-Q ") \ + EM(netfs_rreq_trace_unpause, "UNPAUSE") \ + E_(netfs_rreq_trace_write_done, "WR-DONE") + +@@ -86,7 +81,6 @@ + EM(netfs_sreq_trace_cache_nowrite, "CA-NW") \ + EM(netfs_sreq_trace_cache_prepare, "CA-PR") \ + EM(netfs_sreq_trace_cache_write, "CA-WR") \ +- EM(netfs_sreq_trace_cancel, "CANCL") \ + EM(netfs_sreq_trace_clear, "CLEAR") \ + EM(netfs_sreq_trace_discard, "DSCRD") \ + EM(netfs_sreq_trace_donate_to_prev, "DON-P") \ +@@ -97,9 +91,6 @@ + EM(netfs_sreq_trace_hit_eof, "EOF ") \ + EM(netfs_sreq_trace_io_progress, "IO ") \ + EM(netfs_sreq_trace_limited, "LIMIT") \ +- EM(netfs_sreq_trace_need_clear, "N-CLR") \ +- EM(netfs_sreq_trace_partial_read, "PARTR") \ +- EM(netfs_sreq_trace_need_retry, "NRTRY") \ + EM(netfs_sreq_trace_prepare, "PREP ") \ + EM(netfs_sreq_trace_prep_failed, "PRPFL") \ + EM(netfs_sreq_trace_progress, "PRGRS") \ +@@ -145,7 +136,6 @@ + EM(netfs_sreq_trace_get_submit, "GET SUBMIT") \ + EM(netfs_sreq_trace_get_short_read, "GET SHORTRD") \ + EM(netfs_sreq_trace_new, "NEW ") \ +- EM(netfs_sreq_trace_put_abandon, "PUT ABANDON") \ + EM(netfs_sreq_trace_put_cancel, "PUT CANCEL ") \ + EM(netfs_sreq_trace_put_clear, "PUT CLEAR ") \ + EM(netfs_sreq_trace_put_consumed, "PUT CONSUME") \ +@@ -186,7 +176,6 @@ + EM(netfs_folio_trace_mkwrite, "mkwrite") \ + EM(netfs_folio_trace_mkwrite_plus, "mkwrite+") \ + EM(netfs_folio_trace_not_under_wback, "!wback") \ +- EM(netfs_folio_trace_not_locked, "!locked") \ + EM(netfs_folio_trace_put, "put") \ + EM(netfs_folio_trace_read, "read") \ + EM(netfs_folio_trace_read_done, "read-done") \ +@@ -215,6 +204,7 @@ + EM(netfs_trace_folioq_clear, "clear") \ + EM(netfs_trace_folioq_delete, "delete") \ + EM(netfs_trace_folioq_make_space, "make-space") \ ++ EM(netfs_trace_folioq_prep_write, "prep-wr") \ + EM(netfs_trace_folioq_rollbuf_init, "roll-init") \ + E_(netfs_trace_folioq_read_progress, "r-progress") + +@@ -362,7 +352,7 @@ TRACE_EVENT(netfs_sreq, + __entry->len = sreq->len; + __entry->transferred = sreq->transferred; + __entry->start = sreq->start; +- __entry->slot = sreq->io_iter.folioq_slot; ++ __entry->slot = sreq->curr_folioq_slot; + ), + + TP_printk("R=%08x[%x] %s %s f=%02x s=%llx %zx/%zx s=%u e=%d", +@@ -711,6 +701,71 @@ TRACE_EVENT(netfs_collect_stream, + __entry->collected_to, __entry->front) + ); + ++TRACE_EVENT(netfs_progress, ++ TP_PROTO(const struct netfs_io_subrequest *subreq, ++ unsigned long long start, size_t avail, size_t part), ++ ++ TP_ARGS(subreq, start, avail, part), ++ ++ TP_STRUCT__entry( ++ __field(unsigned int, rreq) ++ __field(unsigned int, subreq) ++ __field(unsigned int, consumed) ++ __field(unsigned int, transferred) ++ __field(unsigned long long, f_start) ++ __field(unsigned int, f_avail) ++ __field(unsigned int, f_part) ++ __field(unsigned char, slot) ++ ), ++ ++ TP_fast_assign( ++ __entry->rreq = subreq->rreq->debug_id; ++ __entry->subreq = subreq->debug_index; ++ __entry->consumed = subreq->consumed; ++ __entry->transferred = subreq->transferred; ++ __entry->f_start = start; ++ __entry->f_avail = avail; ++ __entry->f_part = part; ++ __entry->slot = subreq->curr_folioq_slot; ++ ), ++ ++ TP_printk("R=%08x[%02x] s=%llx ct=%x/%x pa=%x/%x sl=%x", ++ __entry->rreq, __entry->subreq, __entry->f_start, ++ __entry->consumed, __entry->transferred, ++ __entry->f_part, __entry->f_avail, __entry->slot) ++ ); ++ ++TRACE_EVENT(netfs_donate, ++ TP_PROTO(const struct netfs_io_request *rreq, ++ const struct netfs_io_subrequest *from, ++ const struct netfs_io_subrequest *to, ++ size_t amount, ++ enum netfs_donate_trace trace), ++ ++ TP_ARGS(rreq, from, to, amount, trace), ++ ++ TP_STRUCT__entry( ++ __field(unsigned int, rreq) ++ __field(unsigned int, from) ++ __field(unsigned int, to) ++ __field(unsigned int, amount) ++ __field(enum netfs_donate_trace, trace) ++ ), ++ ++ TP_fast_assign( ++ __entry->rreq = rreq->debug_id; ++ __entry->from = from->debug_index; ++ __entry->to = to ? to->debug_index : -1; ++ __entry->amount = amount; ++ __entry->trace = trace; ++ ), ++ ++ TP_printk("R=%08x[%02x] -> [%02x] %s am=%x", ++ __entry->rreq, __entry->from, __entry->to, ++ __print_symbolic(__entry->trace, netfs_donate_traces), ++ __entry->amount) ++ ); ++ + TRACE_EVENT(netfs_folioq, + TP_PROTO(const struct folio_queue *fq, + enum netfs_folioq_trace trace), +-- +2.48.1 + diff --git a/ci/diffs/9998-sched_ext-Fix-invalid-irq-restore-in-scx_ops_bypass.patch b/ci/diffs/9998-sched_ext-Fix-invalid-irq-restore-in-scx_ops_bypass.patch new file mode 100644 index 0000000000000..0f65cb47ce2e6 --- /dev/null +++ b/ci/diffs/9998-sched_ext-Fix-invalid-irq-restore-in-scx_ops_bypass.patch @@ -0,0 +1,56 @@ +From 10e1d78546b3dd4ea9d773c0b0257064a99211e9 Mon Sep 17 00:00:00 2001 +From: Tejun Heo +Date: Wed, 11 Dec 2024 11:01:51 -1000 +Subject: [PATCH] sched_ext: Fix invalid irq restore in scx_ops_bypass() + +While adding outer irqsave/restore locking, 0e7ffff1b811 ("scx: Fix raciness +in scx_ops_bypass()") forgot to convert an inner rq_unlock_irqrestore() to +rq_unlock() which could re-enable IRQ prematurely leading to the following +warning: + + raw_local_irq_restore() called with IRQs enabled + WARNING: CPU: 1 PID: 96 at kernel/locking/irqflag-debug.c:10 warn_bogus_irq_restore+0x30/0x40 + ... + Sched_ext: create_dsq (enabling) + pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) + pc : warn_bogus_irq_restore+0x30/0x40 + lr : warn_bogus_irq_restore+0x30/0x40 + ... + Call trace: + warn_bogus_irq_restore+0x30/0x40 (P) + warn_bogus_irq_restore+0x30/0x40 (L) + scx_ops_bypass+0x224/0x3b8 + scx_ops_enable.isra.0+0x2c8/0xaa8 + bpf_scx_reg+0x18/0x30 + ... + irq event stamp: 33739 + hardirqs last enabled at (33739): [] scx_ops_bypass+0x174/0x3b8 + hardirqs last disabled at (33738): [] _raw_spin_lock_irqsave+0xb4/0xd8 + +Drop the stray _irqrestore(). + +Signed-off-by: Tejun Heo +Reported-by: Ihor Solodrai +Link: http://lkml.kernel.org/r/qC39k3UsonrBYD_SmuxHnZIQLsuuccoCrkiqb_BT7DvH945A1_LZwE4g-5Pu9FcCtqZt4lY1HhIPi0homRuNWxkgo1rgP3bkxa0donw8kV4=@pm.me +Fixes: 0e7ffff1b811 ("scx: Fix raciness in scx_ops_bypass()") +Cc: stable@vger.kernel.org # v6.12 +--- + kernel/sched/ext.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/sched/ext.c b/kernel/sched/ext.c +index 7fff1d045477..98519e6d0dcd 100644 +--- a/kernel/sched/ext.c ++++ b/kernel/sched/ext.c +@@ -4763,7 +4763,7 @@ static void scx_ops_bypass(bool bypass) + * sees scx_rq_bypassing() before moving tasks to SCX. + */ + if (!scx_enabled()) { +- rq_unlock_irqrestore(rq, &rf); ++ rq_unlock(rq, &rf); + continue; + } + +-- +2.47.1 + diff --git a/ci/diffs/9999-scx-Fix-maximal-BPF-selftest-prog.patch b/ci/diffs/9999-scx-Fix-maximal-BPF-selftest-prog.patch new file mode 100644 index 0000000000000..9b5e6d50778e1 --- /dev/null +++ b/ci/diffs/9999-scx-Fix-maximal-BPF-selftest-prog.patch @@ -0,0 +1,56 @@ +From 70414cacbe536a197d56f58a42f9563e5a01b8ec Mon Sep 17 00:00:00 2001 +From: David Vernet +Date: Mon, 9 Dec 2024 09:29:24 -0600 +Subject: [PATCH] scx: Fix maximal BPF selftest prog + +maximal.bpf.c is still dispatching to and consuming from SCX_DSQ_GLOBAL. +Let's have it use its own DSQ to avoid any runtime errors. + +Signed-off-by: David Vernet +--- + tools/testing/selftests/sched_ext/maximal.bpf.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/tools/testing/selftests/sched_ext/maximal.bpf.c b/tools/testing/selftests/sched_ext/maximal.bpf.c +index 4c005fa71810..430f5e13bf55 100644 +--- a/tools/testing/selftests/sched_ext/maximal.bpf.c ++++ b/tools/testing/selftests/sched_ext/maximal.bpf.c +@@ -12,6 +12,8 @@ + + char _license[] SEC("license") = "GPL"; + ++#define DSQ_ID 0 ++ + s32 BPF_STRUCT_OPS(maximal_select_cpu, struct task_struct *p, s32 prev_cpu, + u64 wake_flags) + { +@@ -20,7 +22,7 @@ s32 BPF_STRUCT_OPS(maximal_select_cpu, struct task_struct *p, s32 prev_cpu, + + void BPF_STRUCT_OPS(maximal_enqueue, struct task_struct *p, u64 enq_flags) + { +- scx_bpf_dsq_insert(p, SCX_DSQ_GLOBAL, SCX_SLICE_DFL, enq_flags); ++ scx_bpf_dsq_insert(p, DSQ_ID, SCX_SLICE_DFL, enq_flags); + } + + void BPF_STRUCT_OPS(maximal_dequeue, struct task_struct *p, u64 deq_flags) +@@ -28,7 +30,7 @@ void BPF_STRUCT_OPS(maximal_dequeue, struct task_struct *p, u64 deq_flags) + + void BPF_STRUCT_OPS(maximal_dispatch, s32 cpu, struct task_struct *prev) + { +- scx_bpf_dsq_move_to_local(SCX_DSQ_GLOBAL); ++ scx_bpf_dsq_move_to_local(DSQ_ID); + } + + void BPF_STRUCT_OPS(maximal_runnable, struct task_struct *p, u64 enq_flags) +@@ -123,7 +125,7 @@ void BPF_STRUCT_OPS(maximal_cgroup_set_weight, struct cgroup *cgrp, u32 weight) + + s32 BPF_STRUCT_OPS_SLEEPABLE(maximal_init) + { +- return 0; ++ return scx_bpf_create_dsq(DSQ_ID, -1); + } + + void BPF_STRUCT_OPS(maximal_exit, struct scx_exit_info *info) +-- +2.47.1 + diff --git a/ci/vmtest/configs/DENYLIST b/ci/vmtest/configs/DENYLIST new file mode 100644 index 0000000000000..2f9bf5c0aa016 --- /dev/null +++ b/ci/vmtest/configs/DENYLIST @@ -0,0 +1,15 @@ +# TEMPORARY +btf_dump/btf_dump: syntax +kprobe_multi_bench_attach +core_reloc/enum64val +core_reloc/size___diff_sz +core_reloc/type_based___diff_sz +test_ima # All of CI is broken on it following 6.3-rc1 merge + +lwt_reroute # crashes kernel after netnext merge from 2ab1efad60ad "net/sched: cls_api: complement tcf_tfilter_dump_policy" +tc_links_ingress # started failing after net-next merge from 2ab1efad60ad "net/sched: cls_api: complement tcf_tfilter_dump_policy" +xdp_bonding/xdp_bonding_features # started failing after net merge from 359e54a93ab4 "l2tp: pass correct message length to ip6_append_data" +tc_redirect/tc_redirect_dtime # uapi breakage after net-next commit 885c36e59f46 ("net: Re-use and set mono_delivery_time bit for userspace tstamp packets") +migrate_reuseport/IPv4 TCP_NEW_SYN_RECV reqsk_timer_handler # flaky, under investigation +migrate_reuseport/IPv6 TCP_NEW_SYN_RECV reqsk_timer_handler # flaky, under investigation +connect_force_port # unreliably fails diff --git a/ci/vmtest/configs/DENYLIST.aarch64 b/ci/vmtest/configs/DENYLIST.aarch64 new file mode 100644 index 0000000000000..487b19ede4b61 --- /dev/null +++ b/ci/vmtest/configs/DENYLIST.aarch64 @@ -0,0 +1,4 @@ +cgrp_local_storage # libbpf: prog 'update_cookie_tracing': failed to attach: ERROR: strerror_r(-524)=22 +core_reloc_btfgen # run_core_reloc_tests:FAIL:run_btfgen unexpected error: 32512 (errno 22) +usdt/multispec # usdt_300_bad_attach unexpected pointer: 0x558c63d8f0 +xdp_bonding # whole test suite is very unstable on aarch64 diff --git a/ci/vmtest/configs/DENYLIST.rc b/ci/vmtest/configs/DENYLIST.rc new file mode 100644 index 0000000000000..8aa33e6b71443 --- /dev/null +++ b/ci/vmtest/configs/DENYLIST.rc @@ -0,0 +1,3 @@ +send_signal/send_signal_nmi # PMU events configure correctly but don't trigger NMI's for some reason (AMD nested virt) +send_signal/send_signal_nmi_thread # Same as above +token/obj_priv_implicit_token_envvar # Unknown root cause, but reliably fails diff --git a/ci/vmtest/configs/DENYLIST.s390x b/ci/vmtest/configs/DENYLIST.s390x new file mode 100644 index 0000000000000..9b90b615aea55 --- /dev/null +++ b/ci/vmtest/configs/DENYLIST.s390x @@ -0,0 +1,11 @@ +deny_namespace # not yet in bpf denylist +tc_redirect/tc_redirect_dtime # very flaky +lru_bug # not yet in bpf-next denylist +# Disabled temporarily for a crash. +# https://lore.kernel.org/bpf/c9923c1d-971d-4022-8dc8-1364e929d34c@gmail.com/ +dummy_st_ops/dummy_init_ptr_arg +fexit_bpf2bpf +tailcalls +trace_ext +xdp_bpf2bpf +xdp_metadata diff --git a/ci/vmtest/configs/DENYLIST.test_progs-bpf_gcc b/ci/vmtest/configs/DENYLIST.test_progs-bpf_gcc new file mode 100644 index 0000000000000..a3c745d1f5b52 --- /dev/null +++ b/ci/vmtest/configs/DENYLIST.test_progs-bpf_gcc @@ -0,0 +1,904 @@ +arena_htab +async_stack_depth +bad_struct_ops/invalid_prog_reuse +bpf_cookie +bpf_iter/bpf_hash_map +bpf_iter/ksym +bpf_iter/tcp4 +bpf_iter/tcp6 +bpf_iter/udp4 +bpf_iter/udp6 +bpf_iter/unix +bpf_iter_setsockopt +bpf_iter_setsockopt_unix +bpf_mod_race +bpf_nf/tc-bpf-ct +bpf_nf/xdp-ct +bpf_tcp_ca/cubic +btf_dump/btf_dump: bitfields +btf_dump/btf_dump: packing +btf_dump/btf_dump: padding +btf_dump/btf_dump: syntax +btf_map_in_map +cb_refs +cgroup_get_current_cgroup_id +cgroup_iter/cgroup_iter__self_only_css_task +cgroup_tcp_skb +cgrp_kfunc +cls_redirect/cls_redirect_dynptr +connect_force_port +core_autosize +core_read_macros +core_reloc/type_id +core_reloc/type_id___missing_targets +core_reloc_btfgen/type_id +core_reloc_btfgen/type_id___missing_targets +cpumask/test_acquire_wrong_cpumask +cpumask/test_alloc_double_release +cpumask/test_alloc_free_cpumask +cpumask/test_alloc_no_release +cpumask/test_and_or_xor +cpumask/test_copy_any_anyand +cpumask/test_cpumask_null +cpumask/test_cpumask_weight +cpumask/test_first_firstzero_cpu +cpumask/test_firstand_nocpu +cpumask/test_global_mask_array_l2_rcu +cpumask/test_global_mask_array_one_rcu +cpumask/test_global_mask_array_rcu +cpumask/test_global_mask_nested_deep_array_rcu +cpumask/test_global_mask_nested_deep_rcu +cpumask/test_global_mask_nested_rcu +cpumask/test_global_mask_no_null_check +cpumask/test_global_mask_out_of_rcu +cpumask/test_global_mask_rcu +cpumask/test_global_mask_rcu_no_null_check +cpumask/test_insert_leave +cpumask/test_insert_remove_no_release +cpumask/test_insert_remove_release +cpumask/test_intersects_subset +cpumask/test_invalid_nested_array +cpumask/test_mutate_cpumask +cpumask/test_set_clear_cpu +cpumask/test_setall_clear_cpu +cpumask/test_test_and_set_clear +crypto_basic/crypto_acquire +crypto_sanity +deny_namespace +dummy_st_ops/test_unsupported_field_sleepable +dynptr/add_dynptr_to_map1 +dynptr/add_dynptr_to_map2 +dynptr/clone_invalid1 +dynptr/clone_invalid2 +dynptr/clone_invalidate1 +dynptr/clone_invalidate2 +dynptr/clone_invalidate3 +dynptr/clone_invalidate4 +dynptr/clone_invalidate5 +dynptr/clone_invalidate6 +dynptr/clone_skb_packet_data +dynptr/clone_xdp_packet_data +dynptr/data_slice_missing_null_check1 +dynptr/data_slice_missing_null_check2 +dynptr/data_slice_out_of_bounds_map_value +dynptr/data_slice_out_of_bounds_ringbuf +dynptr/data_slice_out_of_bounds_skb +dynptr/data_slice_use_after_release1 +dynptr/data_slice_use_after_release2 +dynptr/dynptr_adjust_invalid +dynptr/dynptr_from_mem_invalid_api +dynptr/dynptr_invalidate_slice_failure +dynptr/dynptr_invalidate_slice_or_null +dynptr/dynptr_invalidate_slice_reinit +dynptr/dynptr_is_null_invalid +dynptr/dynptr_is_rdonly_invalid +dynptr/dynptr_overwrite_ref +dynptr/dynptr_partial_slot_invalidate +dynptr/dynptr_pruning_overwrite +dynptr/dynptr_pruning_type_confusion +dynptr/dynptr_read_into_slot +dynptr/dynptr_size_invalid +dynptr/dynptr_slice_var_len1 +dynptr/dynptr_slice_var_len2 +dynptr/dynptr_var_off_overwrite +dynptr/global +dynptr/invalid_data_slices +dynptr/invalid_helper1 +dynptr/invalid_helper2 +dynptr/invalid_offset +dynptr/invalid_read1 +dynptr/invalid_read2 +dynptr/invalid_read3 +dynptr/invalid_read4 +dynptr/invalid_slice_rdwr_rdonly +dynptr/invalid_write1 +dynptr/invalid_write2 +dynptr/invalid_write3 +dynptr/invalid_write4 +dynptr/release_twice +dynptr/release_twice_callback +dynptr/ringbuf_invalid_api +dynptr/ringbuf_missing_release1 +dynptr/ringbuf_missing_release2 +dynptr/ringbuf_missing_release_callback +dynptr/ringbuf_release_uninit_dynptr +dynptr/skb_invalid_ctx +dynptr/skb_invalid_ctx_fentry +dynptr/skb_invalid_ctx_fexit +dynptr/skb_invalid_data_slice1 +dynptr/skb_invalid_data_slice2 +dynptr/skb_invalid_data_slice3 +dynptr/skb_invalid_data_slice4 +dynptr/skb_invalid_slice_write +dynptr/test_dynptr_reg_type +dynptr/test_dynptr_skb_no_buff +dynptr/test_dynptr_skb_small_buff +dynptr/test_dynptr_skb_tp_btf +dynptr/test_read_write +dynptr/uninit_write_into_slot +dynptr/use_after_invalid +dynptr/xdp_invalid_ctx +dynptr/xdp_invalid_data_slice1 +dynptr/xdp_invalid_data_slice2 +exceptions/check_assert_eq_int_max +exceptions/check_assert_eq_int_min +exceptions/check_assert_eq_llong_max +exceptions/check_assert_eq_llong_min +exceptions/check_assert_eq_zero +exceptions/check_assert_ge_neg +exceptions/check_assert_ge_pos +exceptions/check_assert_ge_zero +exceptions/check_assert_generic +exceptions/check_assert_gt_neg +exceptions/check_assert_gt_pos +exceptions/check_assert_gt_zero +exceptions/check_assert_le_neg +exceptions/check_assert_le_pos +exceptions/check_assert_le_zero +exceptions/check_assert_lt_neg +exceptions/check_assert_lt_pos +exceptions/check_assert_lt_zero +exceptions/check_assert_range_s64 +exceptions/check_assert_range_u64 +exceptions/check_assert_single_range_s64 +exceptions/check_assert_single_range_u64 +exceptions/check_assert_with_return +exceptions/exception_ext +exceptions/exception_ext_mod_cb_runtime +exceptions/non-throwing extension -> non-throwing subprog +exceptions/non-throwing extension -> throwing global subprog +exceptions/non-throwing fentry -> exception_cb +exceptions/non-throwing fexit -> exception_cb +exceptions/non-throwing fmod_ret -> non-throwing global subprog +exceptions/reject_async_callback_throw +exceptions/reject_exception_throw_cb +exceptions/reject_exception_throw_cb_diff +exceptions/reject_set_exception_cb_bad_ret2 +exceptions/reject_subprog_with_lock +exceptions/reject_subprog_with_rcu_read_lock +exceptions/reject_with_cb +exceptions/reject_with_cb_reference +exceptions/reject_with_lock +exceptions/reject_with_rbtree_add_throw +exceptions/reject_with_rcu_read_lock +exceptions/reject_with_reference +exceptions/reject_with_subprog_reference +exceptions/throwing extension (with custom cb) -> exception_cb +exceptions/throwing extension -> global func in exception_cb +exceptions/throwing extension -> non-throwing global subprog +exceptions/throwing extension -> throwing global subprog +exceptions/throwing fentry -> exception_cb +exceptions/throwing fexit -> exception_cb +failures_wq +fexit_bpf2bpf/fmod_ret_freplace +fexit_bpf2bpf/func_replace +fexit_bpf2bpf/func_replace_global_func +fexit_bpf2bpf/func_replace_multi +fexit_bpf2bpf/func_sockmap_update +fexit_bpf2bpf/target_yes_callees +global_func_dead_code +global_map_resize +inner_array_lookup +irq/irq_flag_overwrite +irq/irq_flag_overwrite_partial +irq/irq_global_subprog +irq/irq_ooo_refs_array +irq/irq_restore_4_subprog +irq/irq_restore_bad_arg +irq/irq_restore_invalid +irq/irq_restore_iter +irq/irq_restore_missing_1_subprog +irq/irq_restore_missing_2 +irq/irq_restore_missing_2_subprog +irq/irq_restore_missing_3 +irq/irq_restore_missing_3_minus_2 +irq/irq_restore_missing_3_minus_2_subprog +irq/irq_restore_missing_3_subprog +irq/irq_restore_ooo +irq/irq_restore_ooo_3 +irq/irq_restore_ooo_3_subprog +irq/irq_save_bad_arg +irq/irq_save_invalid +irq/irq_save_iter +irq/irq_sleepable_helper +irq/irq_sleepable_kfunc +iters/compromise_iter_w_direct_write_and_skip_destroy_fail +iters/compromise_iter_w_direct_write_fail +iters/compromise_iter_w_helper_write_fail +iters/create_and_forget_to_destroy_fail +iters/css_task +iters/delayed_precision_mark +iters/delayed_read_mark +iters/destroy_without_creating_fail +iters/double_create_fail +iters/double_destroy_fail +iters/iter_css_lock_and_unlock +iters/iter_css_task_for_each +iters/iter_css_without_lock +iters/iter_destroy_bad_arg +iters/iter_err_too_permissive1 +iters/iter_err_too_permissive2 +iters/iter_err_too_permissive3 +iters/iter_err_unsafe_asm_loop +iters/iter_err_unsafe_c_loop +iters/iter_nested_iters +iters/iter_new_bad_arg +iters/iter_next_bad_arg +iters/iter_next_ptr_mem_not_trusted +iters/iter_next_rcu_not_trusted +iters/iter_next_rcu_or_null +iters/iter_next_trusted_or_null +iters/iter_obfuscate_counter +iters/iter_subprog_iters +iters/iter_tasks_lock_and_unlock +iters/iter_tasks_without_lock +iters/leak_iter_from_subprog_fail +iters/loop_state_deps1 +iters/loop_state_deps2 +iters/missing_null_check_fail +iters/next_after_destroy_fail +iters/next_without_new_fail +iters/read_from_iter_slot_fail +iters/stacksafe_should_not_conflate_stack_spill_and_iter +iters/testmod_seq_getter_after_bad +iters/testmod_seq_getter_before_bad +iters/wrong_sized_read_fail +jeq_infer_not_null +jit_probe_mem +kfree_skb +kfunc_call/kfunc_call_ctx +kfunc_call/kfunc_call_test1 +kfunc_call/kfunc_call_test2 +kfunc_call/kfunc_call_test4 +kfunc_call/kfunc_call_test_get_mem +kfunc_call/kfunc_call_test_ref_btf_id +kfunc_call/kfunc_call_test_static_unused_arg +kfunc_call/kfunc_syscall_test +kfunc_call/kfunc_syscall_test_null +kfunc_dynptr_param/not_ptr_to_stack +kfunc_dynptr_param/not_valid_dynptr +kfunc_param_nullable/kfunc_dynptr_nullable_test3 +kprobe_multi_test/kprobe_session_return_2 +kptr_xchg_inline +l4lb_all/l4lb_noinline +l4lb_all/l4lb_noinline_dynptr +linked_list +local_kptr_stash/drop_rb_node_off +local_kptr_stash/local_kptr_stash_local_with_root +local_kptr_stash/local_kptr_stash_plain +local_kptr_stash/local_kptr_stash_simple +local_kptr_stash/local_kptr_stash_unstash +local_kptr_stash/refcount_acquire_without_unstash +local_kptr_stash/stash_rb_nodes +log_buf/obj_load_log_buf +log_fixup/bad_core_relo_subprog +log_fixup/bad_core_relo_trunc_full +lru_bug +map_btf +map_in_map/acc_map_in_array +map_in_map/acc_map_in_htab +map_in_map/sleepable_acc_map_in_array +map_in_map/sleepable_acc_map_in_htab +map_kptr/correct_btf_id_check_size +map_kptr/inherit_untrusted_on_walk +map_kptr/kptr_xchg_possibly_null +map_kptr/kptr_xchg_ref_state +map_kptr/mark_ref_as_untrusted_or_null +map_kptr/marked_as_untrusted_or_null +map_kptr/non_const_var_off +map_kptr/non_const_var_off_kptr_xchg +map_kptr/reject_bad_type_xchg +map_kptr/reject_kptr_xchg_on_unref +map_kptr/reject_member_of_ref_xchg +map_kptr/reject_untrusted_xchg +map_kptr/success-map +map_ptr +nested_trust/test_invalid_nested_user_cpus +nested_trust/test_invalid_skb_field +percpu_alloc/array +percpu_alloc/array_sleepable +percpu_alloc/cgrp_local_storage +percpu_alloc/test_array_map_1 +percpu_alloc/test_array_map_2 +percpu_alloc/test_array_map_3 +percpu_alloc/test_array_map_4 +percpu_alloc/test_array_map_5 +percpu_alloc/test_array_map_6 +percpu_alloc/test_array_map_7 +percpu_alloc/test_array_map_8 +perf_branches/perf_branches_no_hw +pkt_access +preempt_lock/preempt_global_subprog_test +preempt_lock/preempt_lock_missing_1 +preempt_lock/preempt_lock_missing_1_subprog +preempt_lock/preempt_lock_missing_2 +preempt_lock/preempt_lock_missing_2_minus_1_subprog +preempt_lock/preempt_lock_missing_2_subprog +preempt_lock/preempt_lock_missing_3 +preempt_lock/preempt_lock_missing_3_minus_2 +preempt_lock/preempt_sleepable_helper +preempt_lock/preempt_sleepable_kfunc +preempted_bpf_ma_op +prog_run_opts +prog_tests_framework +raw_tp_null +rbtree_fail +rbtree_success +recursion +refcounted_kptr +refcounted_kptr_fail +refcounted_kptr_wrong_owner +reference_tracking/sk_lookup_success +ringbuf_multi +setget_sockopt +sk_lookup +skc_to_unix_sock +sock_addr/recvmsg4: attach prog with wrong attach type +sock_addr/recvmsg4: recvfrom (dgram) +sock_addr/recvmsg6: attach prog with wrong attach type +sock_addr/recvmsg6: recvfrom (dgram) +sock_addr/sendmsg4: attach prog with wrong attach type +sock_addr/sendmsg4: kernel_sendmsg (dgram) +sock_addr/sendmsg4: kernel_sendmsg deny (dgram) +sock_addr/sendmsg4: sendmsg (dgram) +sock_addr/sendmsg4: sendmsg deny (dgram) +sock_addr/sendmsg4: sock_sendmsg (dgram) +sock_addr/sendmsg4: sock_sendmsg deny (dgram) +sock_addr/sendmsg6: attach prog with wrong attach type +sock_addr/sendmsg6: kernel_sendmsg (dgram) +sock_addr/sendmsg6: kernel_sendmsg [::] (BSD'ism) (dgram) +sock_addr/sendmsg6: kernel_sendmsg deny (dgram) +sock_addr/sendmsg6: sendmsg (dgram) +sock_addr/sendmsg6: sendmsg IPv4-mapped IPv6 (dgram) +sock_addr/sendmsg6: sendmsg [::] (BSD'ism) (dgram) +sock_addr/sendmsg6: sendmsg deny (dgram) +sock_addr/sendmsg6: sendmsg dst IP = [::] (BSD'ism) (dgram) +sock_addr/sendmsg6: sock_sendmsg (dgram) +sock_addr/sendmsg6: sock_sendmsg [::] (BSD'ism) (dgram) +sock_addr/sendmsg6: sock_sendmsg deny (dgram) +sock_destroy/trace_tcp_destroy_sock +sock_fields +sockmap_listen/sockhash IPv4 TCP test_reuseport_mixed_groups +sockmap_listen/sockhash IPv4 TCP test_reuseport_select_connected +sockmap_listen/sockhash IPv4 UDP test_reuseport_mixed_groups +sockmap_listen/sockhash IPv4 UDP test_reuseport_select_connected +sockmap_listen/sockhash IPv6 TCP test_reuseport_mixed_groups +sockmap_listen/sockhash IPv6 TCP test_reuseport_select_connected +sockmap_listen/sockhash IPv6 UDP test_reuseport_mixed_groups +sockmap_listen/sockhash IPv6 UDP test_reuseport_select_connected +sockmap_listen/sockmap IPv4 TCP test_reuseport_mixed_groups +sockmap_listen/sockmap IPv4 TCP test_reuseport_select_connected +sockmap_listen/sockmap IPv4 UDP test_reuseport_mixed_groups +sockmap_listen/sockmap IPv4 UDP test_reuseport_select_connected +sockmap_listen/sockmap IPv6 TCP test_reuseport_mixed_groups +sockmap_listen/sockmap IPv6 TCP test_reuseport_select_connected +sockmap_listen/sockmap IPv6 UDP test_reuseport_mixed_groups +sockmap_listen/sockmap IPv6 UDP test_reuseport_select_connected +spin_lock +struct_ops_module/unsupported_ops +syscall +tailcalls/classifier_0 +tailcalls/classifier_1 +tailcalls/reject_tail_call_preempt_lock +tailcalls/reject_tail_call_rcu_lock +tailcalls/reject_tail_call_ref +tailcalls/reject_tail_call_spin_lock +tailcalls/tailcall_6 +tailcalls/tailcall_bpf2bpf_2 +tailcalls/tailcall_bpf2bpf_3 +tailcalls/tailcall_bpf2bpf_fentry +tailcalls/tailcall_bpf2bpf_fentry_entry +tailcalls/tailcall_bpf2bpf_fentry_fexit +tailcalls/tailcall_bpf2bpf_fexit +tailcalls/tailcall_bpf2bpf_hierarchy_2 +tailcalls/tailcall_bpf2bpf_hierarchy_3 +task_kfunc +task_local_storage/uptr_across_pages +task_local_storage/uptr_basic +task_local_storage/uptr_kptr_xchg +task_local_storage/uptr_map_failure_e2big +task_local_storage/uptr_map_failure_kstruct +task_local_storage/uptr_map_failure_size0 +task_local_storage/uptr_no_null_check +task_local_storage/uptr_obj_new +task_local_storage/uptr_update_failure +tc_bpf/tc_bpf_non_root +tc_redirect/tc_redirect_dtime +tcp_custom_syncookie +tcp_hdr_options +test_bpf_ma +test_global_funcs/arg_tag_ctx_kprobe +test_global_funcs/arg_tag_ctx_perf +test_global_funcs/arg_tag_ctx_raw_tp +test_global_funcs/global_func1 +test_global_funcs/global_func10 +test_global_funcs/global_func11 +test_global_funcs/global_func12 +test_global_funcs/global_func13 +test_global_funcs/global_func14 +test_global_funcs/global_func15 +test_global_funcs/global_func15_tricky_pruning +test_global_funcs/global_func17 +test_global_funcs/global_func3 +test_global_funcs/global_func5 +test_global_funcs/global_func6 +test_global_funcs/global_func7 +test_lsm/lsm_basic +test_profiler +test_strncmp/strncmp_bad_not_null_term_target +timer +timer_mim +token +tp_btf_nullable/handle_tp_btf_nullable_bare1 +tunnel +uprobe_multi_test/uprobe_sesison_return_2 +user_ringbuf/user_ringbuf_callback_bad_access1 +user_ringbuf/user_ringbuf_callback_bad_access2 +user_ringbuf/user_ringbuf_callback_const_ptr_to_dynptr_reg_off +user_ringbuf/user_ringbuf_callback_discard_dynptr +user_ringbuf/user_ringbuf_callback_invalid_return +user_ringbuf/user_ringbuf_callback_null_context_read +user_ringbuf/user_ringbuf_callback_null_context_write +user_ringbuf/user_ringbuf_callback_reinit_dynptr_mem +user_ringbuf/user_ringbuf_callback_reinit_dynptr_ringbuf +user_ringbuf/user_ringbuf_callback_submit_dynptr +user_ringbuf/user_ringbuf_callback_write_forbidden +verif_scale_pyperf100 +verif_scale_pyperf180 +verif_scale_pyperf600 +verif_scale_pyperf600_nounroll +verif_scale_seg6_loop +verif_scale_strobemeta +verif_scale_strobemeta_nounroll1 +verif_scale_strobemeta_nounroll2 +verif_scale_strobemeta_subprogs +verif_scale_sysctl_loop1 +verif_scale_sysctl_loop2 +verif_scale_xdp_loop +verifier_and/invalid_and_of_negative_number +verifier_and/invalid_range_check +verifier_arena/iter_maps2 +verifier_arena/iter_maps3 +verifier_array_access/a_read_only_array_1_2 +verifier_array_access/a_read_only_array_2_2 +verifier_array_access/a_write_only_array_1_2 +verifier_array_access/a_write_only_array_2_2 +verifier_array_access/an_array_with_a_constant_2 +verifier_array_access/an_array_with_a_register_2 +verifier_array_access/an_array_with_a_variable_2 +verifier_array_access/array_with_no_floor_check +verifier_array_access/with_a_invalid_max_check_1 +verifier_array_access/with_a_invalid_max_check_2 +verifier_basic_stack/invalid_fp_arithmetic +verifier_basic_stack/misaligned_read_from_stack +verifier_basic_stack/stack_out_of_bounds +verifier_bitfield_write +verifier_bits_iter/destroy_uninit +verifier_bits_iter/next_uninit +verifier_bits_iter/no_destroy +verifier_bounds/bounds_map_value_variant_1 +verifier_bounds/bounds_map_value_variant_2 +verifier_bounds/of_boundary_crossing_range_1 +verifier_bounds/of_boundary_crossing_range_2 +verifier_bounds/on_sign_extended_mov_test1 +verifier_bounds/on_sign_extended_mov_test2 +verifier_bounds/reg32_any_reg32_xor_3 +verifier_bounds/reg_any_reg_xor_3 +verifier_bounds/shift_of_maybe_negative_number +verifier_bounds/shift_with_64_bit_input +verifier_bounds/shift_with_oversized_count_operand +verifier_bounds/size_signed_32bit_overflow_test1 +verifier_bounds/size_signed_32bit_overflow_test2 +verifier_bounds/size_signed_32bit_overflow_test3 +verifier_bounds/size_signed_32bit_overflow_test4 +verifier_bounds/var_off_insn_off_test1 +verifier_bounds/var_off_insn_off_test2 +verifier_bounds_deduction/deducing_bounds_from_const_1 +verifier_bounds_deduction/deducing_bounds_from_const_10 +verifier_bounds_deduction/deducing_bounds_from_const_3 +verifier_bounds_deduction/deducing_bounds_from_const_5 +verifier_bounds_deduction/deducing_bounds_from_const_6 +verifier_bounds_deduction/deducing_bounds_from_const_7 +verifier_bounds_deduction/deducing_bounds_from_const_8 +verifier_bounds_deduction/deducing_bounds_from_const_9 +verifier_bounds_mix_sign_unsign/checks_mixing_signed_and_unsigned +verifier_bounds_mix_sign_unsign/signed_and_unsigned_positive_bounds +verifier_bounds_mix_sign_unsign/signed_and_unsigned_variant_10 +verifier_bounds_mix_sign_unsign/signed_and_unsigned_variant_11 +verifier_bounds_mix_sign_unsign/signed_and_unsigned_variant_12 +verifier_bounds_mix_sign_unsign/signed_and_unsigned_variant_13 +verifier_bounds_mix_sign_unsign/signed_and_unsigned_variant_14 +verifier_bounds_mix_sign_unsign/signed_and_unsigned_variant_15 +verifier_bounds_mix_sign_unsign/signed_and_unsigned_variant_2 +verifier_bounds_mix_sign_unsign/signed_and_unsigned_variant_3 +verifier_bounds_mix_sign_unsign/signed_and_unsigned_variant_5 +verifier_bounds_mix_sign_unsign/signed_and_unsigned_variant_6 +verifier_bounds_mix_sign_unsign/signed_and_unsigned_variant_8 +verifier_btf_ctx_access/ctx_access_u32_pointer_reject_16 +verifier_btf_ctx_access/ctx_access_u32_pointer_reject_32 +verifier_btf_ctx_access/ctx_access_u32_pointer_reject_8 +verifier_cfg/conditional_loop +verifier_cfg/loop2_back_edge +verifier_cfg/loop_back_edge +verifier_cfg/out_of_range_jump +verifier_cfg/out_of_range_jump2 +verifier_cfg/uncond_loop_after_cond_jmp +verifier_cfg/uncond_loop_in_subprog_after_cond_jmp +verifier_cfg/unreachable +verifier_cfg/unreachable2 +verifier_cgroup_inv_retcode/with_invalid_return_code_test1 +verifier_cgroup_inv_retcode/with_invalid_return_code_test3 +verifier_cgroup_inv_retcode/with_invalid_return_code_test5 +verifier_cgroup_inv_retcode/with_invalid_return_code_test6 +verifier_cgroup_inv_retcode/with_invalid_return_code_test7 +verifier_cgroup_skb/data_meta_for_cgroup_skb +verifier_cgroup_skb/flow_keys_for_cgroup_skb +verifier_cgroup_skb/napi_id_for_cgroup_skb +verifier_cgroup_skb/tc_classid_for_cgroup_skb +verifier_cgroup_storage/cpu_cgroup_storage_access_1 +verifier_cgroup_storage/cpu_cgroup_storage_access_2 +verifier_cgroup_storage/cpu_cgroup_storage_access_3 +verifier_cgroup_storage/cpu_cgroup_storage_access_4 +verifier_cgroup_storage/cpu_cgroup_storage_access_5 +verifier_cgroup_storage/cpu_cgroup_storage_access_6 +verifier_cgroup_storage/invalid_cgroup_storage_access_1 +verifier_cgroup_storage/invalid_cgroup_storage_access_2 +verifier_cgroup_storage/invalid_cgroup_storage_access_3 +verifier_cgroup_storage/invalid_cgroup_storage_access_4 +verifier_cgroup_storage/invalid_cgroup_storage_access_5 +verifier_cgroup_storage/invalid_cgroup_storage_access_6 +verifier_const/bprm +verifier_const/tcx1 +verifier_const/tcx4 +verifier_const/tcx7 +verifier_const_or/not_bypass_stack_boundary_checks_1 +verifier_const_or/not_bypass_stack_boundary_checks_2 +verifier_ctx/context_stores_via_bpf_atomic +verifier_ctx/ctx_pointer_to_helper_1 +verifier_ctx/ctx_pointer_to_helper_2 +verifier_ctx/ctx_pointer_to_helper_3 +verifier_ctx/make_ptr_to_ctx_unusable +verifier_ctx/null_check_4_ctx_const +verifier_ctx/null_check_8_null_bind +verifier_ctx/or_null_check_3_1 +verifier_ctx_sk_msg/of_size_in_sk_msg +verifier_ctx_sk_msg/past_end_of_sk_msg +verifier_ctx_sk_msg/read_offset_in_sk_msg +verifier_d_path/d_path_reject +verifier_direct_packet_access/access_test15_spill_with_xadd +verifier_direct_packet_access/direct_packet_access_test3 +verifier_direct_packet_access/id_in_regsafe_bad_access +verifier_direct_packet_access/packet_access_test10_write_invalid +verifier_direct_packet_access/pkt_end_reg_bad_access +verifier_direct_packet_access/pkt_end_reg_both_accesses +verifier_direct_packet_access/test16_arith_on_data_end +verifier_direct_packet_access/test23_x_pkt_ptr_4 +verifier_direct_packet_access/test26_marking_on_bad_access +verifier_direct_packet_access/test28_marking_on_bad_access +verifier_direct_stack_access_wraparound +verifier_global_ptr_args +verifier_global_subprogs +verifier_helper_access_var_len/bitwise_and_jmp_wrong_max +verifier_helper_access_var_len/jmp_signed_no_min_check +verifier_helper_access_var_len/map_adjusted_jmp_wrong_max +verifier_helper_access_var_len/memory_map_jmp_wrong_max +verifier_helper_access_var_len/memory_stack_jmp_bounds_offset +verifier_helper_access_var_len/memory_stack_jmp_wrong_max +verifier_helper_access_var_len/ptr_to_mem_or_null_2 +verifier_helper_access_var_len/ptr_to_mem_or_null_8 +verifier_helper_access_var_len/ptr_to_mem_or_null_9 +verifier_helper_access_var_len/stack_jmp_no_max_check +verifier_helper_packet_access/cls_helper_fail_range_1 +verifier_helper_packet_access/cls_helper_fail_range_2 +verifier_helper_packet_access/cls_helper_fail_range_3 +verifier_helper_packet_access/packet_ptr_with_bad_range_1 +verifier_helper_packet_access/packet_ptr_with_bad_range_2 +verifier_helper_packet_access/packet_test2_unchecked_packet_ptr +verifier_helper_packet_access/ptr_with_too_short_range_1 +verifier_helper_packet_access/ptr_with_too_short_range_2 +verifier_helper_packet_access/test11_cls_unsuitable_helper_1 +verifier_helper_packet_access/test12_cls_unsuitable_helper_2 +verifier_helper_packet_access/test15_cls_helper_fail_sub +verifier_helper_packet_access/test20_pkt_end_as_input +verifier_helper_packet_access/test7_cls_unchecked_packet_ptr +verifier_helper_packet_access/to_packet_test21_wrong_reg +verifier_helper_restricted +verifier_helper_value_access/access_to_map_empty_range +verifier_helper_value_access/access_to_map_negative_range +verifier_helper_value_access/access_to_map_possibly_empty_range +verifier_helper_value_access/access_to_map_wrong_size +verifier_helper_value_access/bounds_check_using_bad_access_1 +verifier_helper_value_access/bounds_check_using_bad_access_2 +verifier_helper_value_access/check_using_s_bad_access_1 +verifier_helper_value_access/check_using_s_bad_access_2 +verifier_helper_value_access/const_imm_negative_range_adjustment_1 +verifier_helper_value_access/const_imm_negative_range_adjustment_2 +verifier_helper_value_access/const_reg_negative_range_adjustment_1 +verifier_helper_value_access/const_reg_negative_range_adjustment_2 +verifier_helper_value_access/imm_out_of_bound_1 +verifier_helper_value_access/imm_out_of_bound_2 +verifier_helper_value_access/imm_out_of_bound_range +verifier_helper_value_access/map_out_of_bound_range +verifier_helper_value_access/map_via_variable_empty_range +verifier_helper_value_access/reg_out_of_bound_1 +verifier_helper_value_access/reg_out_of_bound_2 +verifier_helper_value_access/reg_out_of_bound_range +verifier_helper_value_access/via_const_imm_empty_range +verifier_helper_value_access/via_const_reg_empty_range +verifier_helper_value_access/via_variable_no_max_check_1 +verifier_helper_value_access/via_variable_no_max_check_2 +verifier_helper_value_access/via_variable_wrong_max_check_1 +verifier_helper_value_access/via_variable_wrong_max_check_2 +verifier_int_ptr/arg_ptr_to_long_misaligned +verifier_int_ptr/to_long_size_sizeof_long +verifier_iterating_callbacks/bpf_loop_iter_limit_overflow +verifier_iterating_callbacks/check_add_const_3regs +verifier_iterating_callbacks/check_add_const_3regs_2if +verifier_iterating_callbacks/check_add_const_regsafe_off +verifier_iterating_callbacks/iter_limit_bug +verifier_iterating_callbacks/jgt_imm64_and_may_goto +verifier_iterating_callbacks/loop_detection +verifier_iterating_callbacks/may_goto_self +verifier_iterating_callbacks/unsafe_find_vma +verifier_iterating_callbacks/unsafe_for_each_map_elem +verifier_iterating_callbacks/unsafe_on_2nd_iter +verifier_iterating_callbacks/unsafe_on_zero_iter +verifier_iterating_callbacks/unsafe_ringbuf_drain +verifier_jeq_infer_not_null/unchanged_for_jeq_false_branch +verifier_jeq_infer_not_null/unchanged_for_jne_true_branch +verifier_kfunc_prog_types/cgrp_kfunc_raw_tp +verifier_kfunc_prog_types/cpumask_kfunc_raw_tp +verifier_kfunc_prog_types/task_kfunc_raw_tp +verifier_ld_ind/ind_check_calling_conv_r1 +verifier_ld_ind/ind_check_calling_conv_r2 +verifier_ld_ind/ind_check_calling_conv_r3 +verifier_ld_ind/ind_check_calling_conv_r4 +verifier_ld_ind/ind_check_calling_conv_r5 +verifier_leak_ptr/leak_pointer_into_ctx_1 +verifier_leak_ptr/leak_pointer_into_ctx_2 +verifier_linked_scalars +verifier_loops1/bounded_recursion +verifier_loops1/infinite_loop_in_two_jumps +verifier_loops1/infinite_loop_three_jump_trick +verifier_loops1/loop_after_a_conditional_jump +verifier_lsm/bool_retval_test3 +verifier_lsm/bool_retval_test4 +verifier_lsm/disabled_hook_test1 +verifier_lsm/disabled_hook_test2 +verifier_lsm/disabled_hook_test3 +verifier_lsm/errno_zero_retval_test4 +verifier_lsm/errno_zero_retval_test5 +verifier_lsm/errno_zero_retval_test6 +verifier_lwt/not_permitted_for_lwt_prog +verifier_lwt/packet_write_for_lwt_in +verifier_lwt/packet_write_for_lwt_out +verifier_lwt/tc_classid_for_lwt_in +verifier_lwt/tc_classid_for_lwt_out +verifier_lwt/tc_classid_for_lwt_xmit +verifier_map_in_map/invalid_inner_map_pointer +verifier_map_in_map/on_the_inner_map_pointer +verifier_map_ptr/bpf_map_ptr_write_rejected +verifier_map_ptr/read_non_existent_field_rejected +verifier_map_ptr/read_with_negative_offset_rejected +verifier_map_ptr_mixing +verifier_map_ret_val +verifier_meta_access/meta_access_test10 +verifier_meta_access/meta_access_test2 +verifier_meta_access/meta_access_test3 +verifier_meta_access/meta_access_test4 +verifier_meta_access/meta_access_test5 +verifier_meta_access/meta_access_test6 +verifier_meta_access/meta_access_test9 +verifier_netfilter_ctx/with_invalid_ctx_access_test1 +verifier_netfilter_ctx/with_invalid_ctx_access_test2 +verifier_netfilter_ctx/with_invalid_ctx_access_test3 +verifier_netfilter_ctx/with_invalid_ctx_access_test4 +verifier_netfilter_ctx/with_invalid_ctx_access_test5 +verifier_netfilter_retcode/with_invalid_return_code_test1 +verifier_netfilter_retcode/with_invalid_return_code_test4 +verifier_or_jmp32_k +verifier_prevent_map_lookup +verifier_raw_stack/bytes_spilled_regs_corruption_2 +verifier_raw_stack/load_bytes_invalid_access_1 +verifier_raw_stack/load_bytes_invalid_access_2 +verifier_raw_stack/load_bytes_invalid_access_3 +verifier_raw_stack/load_bytes_invalid_access_4 +verifier_raw_stack/load_bytes_invalid_access_5 +verifier_raw_stack/load_bytes_invalid_access_6 +verifier_raw_stack/load_bytes_negative_len_2 +verifier_raw_stack/load_bytes_spilled_regs_corruption +verifier_raw_stack/skb_load_bytes_negative_len +verifier_raw_stack/skb_load_bytes_zero_len +verifier_raw_tp_writable +verifier_ref_tracking +verifier_reg_equal/subreg_equality_2 +verifier_regalloc/regalloc_and_spill_negative +verifier_regalloc/regalloc_negative +verifier_regalloc/regalloc_src_reg_negative +verifier_ringbuf/ringbuf_invalid_reservation_offset_1 +verifier_ringbuf/ringbuf_invalid_reservation_offset_2 +verifier_runtime_jit +verifier_scalar_ids/check_ids_in_regsafe +verifier_scalar_ids/check_ids_in_regsafe_2 +verifier_scalar_ids/linked_regs_broken_link_2 +verifier_search_pruning/for_u32_spills_u64_fill +verifier_search_pruning/liveness_pruning_and_write_screening +verifier_search_pruning/short_loop1 +verifier_search_pruning/should_be_verified_nop_operation +verifier_search_pruning/tracking_for_u32_spill_fill +verifier_search_pruning/varlen_map_value_access_pruning +verifier_sock/bpf_sk_fullsock_skb_sk +verifier_sock/bpf_sk_release_skb_sk +verifier_sock/bpf_tcp_sock_skb_sk +verifier_sock/dst_port_byte_load_invalid +verifier_sock/dst_port_half_load_invalid_1 +verifier_sock/dst_port_half_load_invalid_2 +verifier_sock/invalidate_pkt_pointers_by_tail_call +verifier_sock/invalidate_pkt_pointers_from_global_func +verifier_sock/map_lookup_elem_smap_key +verifier_sock/map_lookup_elem_sockhash_key +verifier_sock/map_lookup_elem_sockmap_key +verifier_sock/no_null_check_on_ret_1 +verifier_sock/no_null_check_on_ret_2 +verifier_sock/of_bpf_skc_to_helpers +verifier_sock/post_bind4_read_mark +verifier_sock/post_bind4_read_src_ip6 +verifier_sock/post_bind6_read_src_ip4 +verifier_sock/sk_1_1_value_1 +verifier_sock/sk_no_skb_sk_check_1 +verifier_sock/sk_no_skb_sk_check_2 +verifier_sock/sk_sk_type_fullsock_field_1 +verifier_sock/skb_sk_beyond_last_field_1 +verifier_sock/skb_sk_beyond_last_field_2 +verifier_sock/skb_sk_no_null_check +verifier_sock/sock_create_read_src_port +verifier_sock_addr/bind4_bad_return_code +verifier_sock_addr/bind6_bad_return_code +verifier_sock_addr/connect4_bad_return_code +verifier_sock_addr/connect6_bad_return_code +verifier_sock_addr/connect_unix_bad_return_code +verifier_sock_addr/getpeername4_bad_return_code +verifier_sock_addr/getpeername6_bad_return_code +verifier_sock_addr/getpeername_unix_bad_return_code +verifier_sock_addr/getsockname4_bad_return_code +verifier_sock_addr/getsockname6_bad_return_code +verifier_sock_addr/getsockname_unix_unix_bad_return_code +verifier_sock_addr/recvmsg4_bad_return_code +verifier_sock_addr/recvmsg6_bad_return_code +verifier_sock_addr/recvmsg_unix_bad_return_code +verifier_sock_addr/sendmsg4_bad_return_code +verifier_sock_addr/sendmsg6_bad_return_code +verifier_sock_addr/sendmsg_unix_bad_return_code +verifier_sockmap_mutate/test_flow_dissector_update +verifier_sockmap_mutate/test_raw_tp_delete +verifier_sockmap_mutate/test_raw_tp_update +verifier_sockmap_mutate/test_sockops_update +verifier_spill_fill/_6_offset_to_skb_data +verifier_spill_fill/addr_offset_to_skb_data +verifier_spill_fill/check_corrupted_spill_fill +verifier_spill_fill/fill_32bit_after_spill_64bit_clear_id +verifier_spill_fill/spill_16bit_of_32bit_fail +verifier_spill_fill/spill_32bit_of_64bit_fail +verifier_spill_fill/u64_offset_to_skb_data +verifier_spill_fill/with_invalid_reg_offset_0 +verifier_spin_lock/call_within_a_locked_region +verifier_spin_lock/lock_test2_direct_ld_st +verifier_spin_lock/lock_test3_direct_ld_st +verifier_spin_lock/lock_test4_direct_ld_st +verifier_spin_lock/lock_test7_unlock_without_lock +verifier_spin_lock/reg_id_for_map_value +verifier_spin_lock/spin_lock_test6_missing_unlock +verifier_spin_lock/spin_lock_test8_double_lock +verifier_spin_lock/spin_lock_test9_different_lock +verifier_spin_lock/test11_ld_abs_under_lock +verifier_stack_ptr/load_bad_alignment_on_off +verifier_stack_ptr/load_bad_alignment_on_reg +verifier_stack_ptr/load_out_of_bounds_high +verifier_stack_ptr/load_out_of_bounds_low +verifier_stack_ptr/to_stack_check_high_4 +verifier_stack_ptr/to_stack_check_high_5 +verifier_stack_ptr/to_stack_check_high_6 +verifier_stack_ptr/to_stack_check_high_7 +verifier_stack_ptr/to_stack_check_low_3 +verifier_stack_ptr/to_stack_check_low_4 +verifier_stack_ptr/to_stack_check_low_5 +verifier_stack_ptr/to_stack_check_low_6 +verifier_stack_ptr/to_stack_check_low_7 +verifier_subprog_precision/callback_precise_return_fail +verifier_tailcall_jit +verifier_uninit +verifier_unpriv +verifier_unpriv_perf +verifier_value/store_of_cleared_call_register +verifier_value_illegal_alu +verifier_value_or_null/map_access_from_else_condition +verifier_value_or_null/map_value_or_null_1 +verifier_value_or_null/map_value_or_null_2 +verifier_value_or_null/map_value_or_null_3 +verifier_value_or_null/multiple_map_lookup_elem_calls +verifier_value_or_null/null_check_ids_in_regsafe +verifier_value_ptr_arith/access_known_scalar_value_ptr_2 +verifier_value_ptr_arith/access_unknown_scalar_value_ptr +verifier_value_ptr_arith/access_value_ptr_known_scalar +verifier_value_ptr_arith/access_value_ptr_unknown_scalar +verifier_value_ptr_arith/access_value_ptr_value_ptr_1 +verifier_value_ptr_arith/access_value_ptr_value_ptr_2 +verifier_value_ptr_arith/lower_oob_arith_test_1 +verifier_value_ptr_arith/to_leak_tainted_dst_reg +verifier_value_ptr_arith/unknown_scalar_value_ptr_4 +verifier_value_ptr_arith/value_ptr_known_scalar_2_1 +verifier_value_ptr_arith/value_ptr_known_scalar_3 +verifier_var_off/access_max_out_of_bound +verifier_var_off/access_min_out_of_bound +verifier_var_off/stack_write_clobbers_spilled_regs +verifier_var_off/variable_offset_ctx_access +verifier_var_off/variable_offset_stack_access_unbounded +verifier_var_off/zero_sized_access_max_out_of_bound +verifier_vfs_reject +verifier_xadd/xadd_w_check_unaligned_map +verifier_xadd/xadd_w_check_unaligned_pkt +verifier_xadd/xadd_w_check_unaligned_stack +verifier_xdp_direct_packet_access/corner_case_1_bad_access_1 +verifier_xdp_direct_packet_access/corner_case_1_bad_access_10 +verifier_xdp_direct_packet_access/corner_case_1_bad_access_11 +verifier_xdp_direct_packet_access/corner_case_1_bad_access_12 +verifier_xdp_direct_packet_access/corner_case_1_bad_access_13 +verifier_xdp_direct_packet_access/corner_case_1_bad_access_14 +verifier_xdp_direct_packet_access/corner_case_1_bad_access_15 +verifier_xdp_direct_packet_access/corner_case_1_bad_access_16 +verifier_xdp_direct_packet_access/corner_case_1_bad_access_2 +verifier_xdp_direct_packet_access/corner_case_1_bad_access_3 +verifier_xdp_direct_packet_access/corner_case_1_bad_access_4 +verifier_xdp_direct_packet_access/corner_case_1_bad_access_5 +verifier_xdp_direct_packet_access/corner_case_1_bad_access_6 +verifier_xdp_direct_packet_access/corner_case_1_bad_access_7 +verifier_xdp_direct_packet_access/corner_case_1_bad_access_8 +verifier_xdp_direct_packet_access/corner_case_1_bad_access_9 +verifier_xdp_direct_packet_access/end_mangling_bad_access_1 +verifier_xdp_direct_packet_access/end_mangling_bad_access_2 +verifier_xdp_direct_packet_access/pkt_data_bad_access_1_1 +verifier_xdp_direct_packet_access/pkt_data_bad_access_1_2 +verifier_xdp_direct_packet_access/pkt_data_bad_access_1_3 +verifier_xdp_direct_packet_access/pkt_data_bad_access_1_4 +verifier_xdp_direct_packet_access/pkt_data_bad_access_2_1 +verifier_xdp_direct_packet_access/pkt_data_bad_access_2_2 +verifier_xdp_direct_packet_access/pkt_data_bad_access_2_3 +verifier_xdp_direct_packet_access/pkt_data_bad_access_2_4 +verifier_xdp_direct_packet_access/pkt_data_bad_access_2_5 +verifier_xdp_direct_packet_access/pkt_data_bad_access_2_6 +verifier_xdp_direct_packet_access/pkt_data_bad_access_2_7 +verifier_xdp_direct_packet_access/pkt_data_bad_access_2_8 +verifier_xdp_direct_packet_access/pkt_end_bad_access_1_1 +verifier_xdp_direct_packet_access/pkt_end_bad_access_1_2 +verifier_xdp_direct_packet_access/pkt_end_bad_access_2_1 +verifier_xdp_direct_packet_access/pkt_end_bad_access_2_2 +verifier_xdp_direct_packet_access/pkt_end_bad_access_2_3 +verifier_xdp_direct_packet_access/pkt_end_bad_access_2_4 +verifier_xdp_direct_packet_access/pkt_meta_bad_access_1_1 +verifier_xdp_direct_packet_access/pkt_meta_bad_access_1_2 +verifier_xdp_direct_packet_access/pkt_meta_bad_access_2_1 +verifier_xdp_direct_packet_access/pkt_meta_bad_access_2_2 +verifier_xdp_direct_packet_access/pkt_meta_bad_access_2_3 +verifier_xdp_direct_packet_access/pkt_meta_bad_access_2_4 +verify_pkcs7_sig +xdp_synproxy diff --git a/ci/vmtest/configs/DENYLIST.x86_64 b/ci/vmtest/configs/DENYLIST.x86_64 new file mode 100644 index 0000000000000..6fc3413daab9f --- /dev/null +++ b/ci/vmtest/configs/DENYLIST.x86_64 @@ -0,0 +1 @@ +netcnt # with kvm enabled, fail with packets unexpected packets: actual 10001 != expected 10000 diff --git a/ci/vmtest/configs/run-vmtest.env b/ci/vmtest/configs/run-vmtest.env new file mode 100644 index 0000000000000..c60f1db6673c7 --- /dev/null +++ b/ci/vmtest/configs/run-vmtest.env @@ -0,0 +1,42 @@ +#!/bin/bash + +# This file is sourced by libbpf/ci/run-vmtest Github Action scripts. +# +# The primary reason it exists is that assembling ALLOWLIST and +# DENYLIST for a particular test run is not a trivial operation. +# +# Users of libbpf/ci/run-vmtest action need to be able to specify a +# list of allow/denylist **files**, that later has to be correctly +# merged into a single allow/denylist passed to a test runner. +# +# Obviously it's perferrable for the scripts merging many lists into +# one to be reusable, and not copy-pasted between repositories which +# use libbpf/ci actions. And specifying the lists should be trivial. +# This file is a solution to that. + +# $SELFTESTS_BPF and $VMTEST_CONFIGS are set in the workflow, before +# libbpf/ci/run-vmtest action is called +# See .github/workflows/kernel-test.yml + +ALLOWLIST_FILES=( + "${SELFTESTS_BPF}/ALLOWLIST" + "${SELFTESTS_BPF}/ALLOWLIST.${ARCH}" + "${VMTEST_CONFIGS}/ALLOWLIST" + "${VMTEST_CONFIGS}/ALLOWLIST.${ARCH}" + "${VMTEST_CONFIGS}/ALLOWLIST.${DEPLOYMENT}" + "${VMTEST_CONFIGS}/ALLOWLIST.${KERNEL_TEST}" +) + +DENYLIST_FILES=( + "${SELFTESTS_BPF}/DENYLIST" + "${SELFTESTS_BPF}/DENYLIST.${ARCH}" + "${VMTEST_CONFIGS}/DENYLIST" + "${VMTEST_CONFIGS}/DENYLIST.${ARCH}" + "${VMTEST_CONFIGS}/DENYLIST.${DEPLOYMENT}" + "${VMTEST_CONFIGS}/DENYLIST.${KERNEL_TEST}" +) + +# Export pipe-separated strings, because bash doesn't support array export +export SELFTESTS_BPF_ALLOWLIST_FILES=$(IFS="|"; echo "${ALLOWLIST_FILES[*]}") +export SELFTESTS_BPF_DENYLIST_FILES=$(IFS="|"; echo "${DENYLIST_FILES[*]}") + diff --git a/ci/vmtest/configs/run_veristat.kernel.cfg b/ci/vmtest/configs/run_veristat.kernel.cfg new file mode 100644 index 0000000000000..807efc251073f --- /dev/null +++ b/ci/vmtest/configs/run_veristat.kernel.cfg @@ -0,0 +1,4 @@ +VERISTAT_OBJECTS_DIR="${SELFTESTS_BPF}" +VERISTAT_OBJECTS_GLOB="*.bpf.o" +VERISTAT_CFG_FILE="${SELFTESTS_BPF}/veristat.cfg" +VERISTAT_OUTPUT="veristat-kernel" diff --git a/ci/vmtest/configs/run_veristat.meta.cfg b/ci/vmtest/configs/run_veristat.meta.cfg new file mode 100644 index 0000000000000..14f08d241d206 --- /dev/null +++ b/ci/vmtest/configs/run_veristat.meta.cfg @@ -0,0 +1,4 @@ +VERISTAT_OBJECTS_DIR="${WORKING_DIR}/bpf_objects" +VERISTAT_OBJECTS_GLOB="*.o" +VERISTAT_OUTPUT="veristat-meta" +VERISTAT_CFG_FILE="${VERISTAT_CONFIGS}/veristat_meta.cfg" diff --git a/ci/vmtest/configs/veristat_meta.cfg b/ci/vmtest/configs/veristat_meta.cfg new file mode 100644 index 0000000000000..a8c25d71cb9e2 --- /dev/null +++ b/ci/vmtest/configs/veristat_meta.cfg @@ -0,0 +1,10 @@ +# List of exceptions we know about that are not going to work with veristat. + +# needs 'migrate_misplaced_page' which went away in +# commit 73eab3ca481e ("mm: migrate: convert migrate_misplaced_page() to migrate_misplaced_folio()") +!numamove_bpf-numamove_bpf.o + +# use non-libbpf loader +!takeover_bpf_lib-takeover.bpf.o +!tcp_tuner_bpf_lib-tcptuner.bpf.o +