diff options
| author | Steven Rostedt <rostedt@goodmis.org> | 2026-09-02 09:55:01 -0400 |
|---|---|---|
| committer | Steven Rostedt <rostedt@goodmis.org> | 2026-09-02 11:08:21 -0400 |
| commit | 4617721c502b2ddaa4e324e86da4997edf738fa5 (patch) | |
| tree | 350aa83b47da0b574a814795392b20b0bed83cbc /tools/perf/scripts/install-build-deps.sh | |
| download | linux-stable-4617721c502b2ddaa4e324e86da4997edf738fa5.tar.gz linux-stable-4617721c502b2ddaa4e324e86da4997edf738fa5.zip | |
ftrace: Synchronize the initialization of ftrace_opsgrafted
There's some internal state that ftrace_ops needs to have set, but since
it can be declared outside of the ftrace.c code, it calls
ftrace_ops_init() on the ops in every global function. The issue is that
if two tasks call it on the same ops at the same time it is possible to
have the initialization of one corrupt the initialization of the other
call.
Create a ops_mutex to use to synchronize every initialization of the
ftrace_ops. The mutex is taken within checking the ftrace_ops flag that
states it was initializied but the flag is checked again after the mutex
has been taken. Checking first outside the mutex allows it to shortcut
having to take the mutex. But then the check needs to be done again after
the mute is taken in case of races.
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20260902095501.6b59af20@gandalf.local.home
Fixes: f04f24fb7e48d ("ftrace, kprobes: Fix a deadlock on ftrace_regex_lock")
Reported-by: sashiko-bot@kernel.org
Close: https://lore.kernel.org/all/20260829025528.49A831F000E9@smtp.kernel.org/
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'tools/perf/scripts/install-build-deps.sh')
| -rwxr-xr-x | tools/perf/scripts/install-build-deps.sh | 603 |
1 files changed, 603 insertions, 0 deletions
diff --git a/tools/perf/scripts/install-build-deps.sh b/tools/perf/scripts/install-build-deps.sh new file mode 100755 index 000000000..d003e7fab --- /dev/null +++ b/tools/perf/scripts/install-build-deps.sh @@ -0,0 +1,603 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# No 'set -e': the script uses explicit checks for its error paths, and +# is also run via '$(SHELL) .../install-build-deps.sh' from the make +# target in tools/perf/Makefile.perf, where a shebang option would be +# ignored anyway, so direct and make-driven runs behave the same. +# +# Install the development packages needed to build tools/perf. +# +# The package set is derived from the feature tests in tools/build/feature/: +# each feature test that perf may compile is mapped to the devel package +# that provides the headers/libraries it checks, so that a subsequent +# 'make -C tools/perf' build enables the corresponding perf features. +# +# Currently supported distros, each validated in a fresh container: +# +# - Fedora, on dnf, validated on Fedora 44, in a toolbx container: +# +# toolbox create fedora:44 +# toolbox enter fedora:44 +# +# - Ubuntu, on apt-get, validated on Ubuntu 26.04, in a distrobox +# container: +# +# distrobox create --image ubuntu:26.04 +# distrobox enter ubuntu-26-04 +# +# The apt-get install runs with a noninteractive debconf frontend: +# default-jdk, needed by the jvmti feature tests, pulls in tzdata, +# which prompts for the timezone on a terminal and would block the +# install, e.g. in a container shared with an interactive session. +# +# - Debian, on apt-get, reusing the Ubuntu mapping, validated on +# Debian 13 (trixie), in a distrobox container: +# +# distrobox create --image debian:trixie +# distrobox enter debian-trixie +# +# - RHEL and its variants (RHEL, CentOS Stream, Rocky Linux, AlmaLinux, +# Oracle Linux), on dnf (RHEL 8 and later), validated on CentOS +# Stream 10, in a distrobox container: +# +# distrobox create --image quay.io/centos/centos:stream10 +# distrobox enter centos-stream10 +# +# The RHEL family reuses most Fedora package names, with these +# differences, handled by probing the enabled repos: +# +# - zlib.h comes from zlib-ng-compat-devel on the RHEL 10 family, +# zlib-devel on RHEL 9 and earlier; +# - the JDK devel package is versioned, there is no +# java-latest-openjdk-devel: java-21-openjdk-devel on the RHEL +# 10 family, java-17-openjdk-devel on RHEL 9, java-11-openjdk- +# devel on RHEL 8; +# - libbpf-devel and capstone-devel are in the CRB repo on RHEL +# and CentOS Stream 10 ('dnf config-manager --set-enabled crb') +# and in EPEL on RHEL 9 and earlier; +# - libbabeltrace2-devel is not packaged on the RHEL 10 family. +# +# On the RHEL family, packages not available on the enabled repos +# are skipped and listed at the end of the run, so that a distro +# with CRB/EPEL enabled gets the full set, and a distro without +# them still installs what it can. +# +# Running inside a container keeps the host system unmodified. +# +# Usage: install-build-deps.sh [OPTIONS] +# +# Options: +# --list list the packages that would be installed, then exit +# --dry-run show the install command that would be run, without +# running it +# --distro ID force a distro: fedora, rhel, ubuntu, debian +# (default: auto-detect) +# -h, --help print this help message +# +# Requires root (or passwordless sudo) to actually install packages. + +set -u + +DISTRO="" + +help() { + cat <<EOF +Usage: $(basename "$0") [--list] [--dry-run] [--distro ID] [-h|--help] + +Install the development packages needed to build tools/perf. + +The package set is derived from the feature tests in tools/build/feature/, +mapping each one with an external dependency to the devel package providing +it, so the corresponding feature gets enabled on a build. + +Options: + --list list the packages that would be installed, then exit + --dry-run show the install command that would be run, without running it + --distro ID force a distro: fedora, rhel, ubuntu, debian + -h, --help print this help message + +Distros supported: Fedora (dnf), validated in a toolbx container on +Fedora 44, Ubuntu (apt-get), validated in a distrobox container on +Ubuntu 26.04, Debian (apt-get), reusing the Ubuntu mapping, validated +in a distrobox container on Debian 13 (trixie), and the RHEL family +(dnf, RHEL 8 and later), validated on CentOS Stream 10 in a distrobox +container. On the RHEL family, packages not available on the enabled +repos are skipped and listed at the end; some there, e.g. +libbpf-devel and capstone-devel, come from the CRB repo on RHEL and +CentOS Stream 10 ('dnf config-manager --set-enabled crb') and from +EPEL on RHEL 9 and earlier. +EOF + exit 0 +} + +# --------------------------------------------------------------------- +# Return the Fedora package(s) providing the devel requirements of a +# feature test in tools/build/feature/. Multiple packages are separated +# by spaces; an empty result means the test has no external devel +# dependency (pure toolchain/glibc, or no equivalent Fedora package). +# +# The mapping was built by checking, for each feature test, which Fedora +# devel package provides the headers the test compiles against. +# --------------------------------------------------------------------- +fedora_pkg_for() { + local feat="$1" + case "$feat" in + libelf|libelf-getphdrnum|libelf-gelf_getnote|libelf-getshdrstrndx) + echo "elfutils-libelf-devel" + ;; + libelf-zstd) + echo "elfutils-libelf-devel libzstd-devel" + ;; + libdw) + echo "elfutils-devel" + ;; + # test-libdebuginfod.c includes <elfutils/debuginfod.h>, which is + # provided by elfutils-debuginfod-client-devel, not elfutils-devel. + libdebuginfod) + echo "elfutils-debuginfod-client-devel" + ;; + libnuma|numa_num_possible_cpus) + echo "numactl-devel" + ;; + libzstd) + echo "libzstd-devel" + ;; + zlib) + echo "zlib-devel" + ;; + lzma) + echo "xz-devel" + ;; + libslang) + echo "slang-devel" + ;; + libcapstone) + echo "capstone-devel" + ;; + libpython) + echo "python3-devel" + ;; + libtraceevent) + echo "libtraceevent-devel" + ;; + cxa-demangle) + echo "libstdc++-devel" + ;; + libbpf) + echo "libbpf-devel" + ;; + babeltrace2-ctf-writer) + echo "libbabeltrace2-devel" + ;; + libopenssl) + echo "openssl-devel" + ;; + libpfm4) + echo "libpfm-devel" + ;; + sdt) + echo "systemtap-sdt-devel" + ;; + clang-bpf-co-re) + echo "clang-devel" + ;; + llvm|llvm-perf) + echo "llvm-devel" + ;; + jvmti|jvmti-cmlr) + echo "java-latest-openjdk-devel" + ;; + esac + # Pure toolchain/libc features (backtrace, eventfd, fortify-source, + # gettid, glibc, hello, reallocarray, pthread-*, stackprotector-all, + # timerfd, scandirat, sched_getcpu, setns, file-handle, + # bionic...) need no external package: their + # requirements are covered by the base packages below. Features that + # perf's own build does not check (libcap, libcheck, libcpupower, + # libtracefs, whose feature tests exist for rtla/bpftool/rv) and the + # opt-in features, which a default build does not enable: the libbfd + # disassembler family (libbfd, libbfd-threadsafe, libbfd-liberty, + # disassembler-*, cplus-demangle), only linked on BUILD_NONDISTRO + # builds and deprecated in favor of capstone, GTK2, LIBPERL and + # LIBUNWIND support (ifdef GTK2 / ifdef LIBPERL / LIBUNWIND=1), + # and CoreSight (ifdef CORESIGHT), are deliberately not mapped. + # libaio is not mapped either: its + # test uses the POSIX AIO API (aio.h, aio_*, -lrt), provided by + # glibc headers (pulled in by the libc headers package) in the + # base set, not the native libaio.h/io_submit API that + # libaio-devel provides. +} + +# --------------------------------------------------------------------- +# Check whether the first argument is provided by the enabled repos, or +# is already installed, returning 0 if so and printing nothing. +# +# dnf repoquery exits 0 even when the pattern does not match anything, +# so availability is judged by the output being non-empty, not by the +# exit code. +# --------------------------------------------------------------------- +pkg_available() { + local p out + for p in "$@"; do + out=$(dnf repoquery --quiet --available "$p" 2>/dev/null) + [ -n "$out" ] || out=$(dnf repoquery --quiet --installed "$p" 2>/dev/null) + [ -n "$out" ] && return 0 + done + return 1 +} + +# --------------------------------------------------------------------- +# Return the first of its arguments that pkg_available() accepts. +# --------------------------------------------------------------------- +pick_available() { + local p + for p in "$@"; do + if pkg_available "$p"; then + echo "$p" + return 0 + fi + done + return 1 +} + +# --------------------------------------------------------------------- +# Return the RHEL-family package(s) providing the devel requirements of +# a feature test. This family reuses the Fedora mapping, whose names +# apply to it as well, except for the features whose Fedora package +# does not exist there, kept in the case below. +# +# Whether the resulting package is actually installable is checked in +# package_set(), as some of these names live in the CRB or EPEL repos, +# which may not be enabled: on the RHEL 10 family libbpf-devel and +# capstone-devel come from CRB, and libbabeltrace2-devel is not +# packaged at all. +# --------------------------------------------------------------------- +rhel_pkg_for() { + local feat="$1" + case "$feat" in + zlib) + # zlib-ng-compat-devel on the RHEL 10 family, zlib-devel on + # RHEL 9 and earlier. If neither is on the enabled repos, + # fall back to the first candidate so that package_set() + # reports it as missing instead of silently dropping the + # feature from the end-of-run note. + pick_available zlib-devel zlib-ng-compat-devel || echo "zlib-devel" + ;; + jvmti|jvmti-cmlr) + # No java-latest-openjdk-devel on the RHEL family: the JDK + # devel package is versioned per release. + pick_available java-latest-openjdk-devel java-21-openjdk-devel java-17-openjdk-devel java-11-openjdk-devel || echo "java-latest-openjdk-devel" + ;; + *) + fedora_pkg_for "$feat" + ;; + esac +} + +# --------------------------------------------------------------------- +# Return the Debian/Ubuntu package(s) providing the devel requirements +# of a feature test in tools/build/feature/. This mapping is shared by +# Debian and Ubuntu, whose package names for these devel packages match, +# and is validated on Ubuntu 26.04 and Debian 13 (trixie). +# --------------------------------------------------------------------- +debian_pkg_for() { + local feat="$1" + case "$feat" in + libelf|libelf-getphdrnum|libelf-gelf_getnote|libelf-getshdrstrndx) + echo "libelf-dev" + ;; + libelf-zstd) + echo "libelf-dev libzstd-dev" + ;; + libdw) + echo "libdw-dev" + ;; + libdebuginfod) + echo "libdebuginfod-dev" + ;; + libnuma|numa_num_possible_cpus) + echo "libnuma-dev" + ;; + libzstd) + echo "libzstd-dev" + ;; + zlib) + echo "zlib1g-dev" + ;; + lzma) + echo "liblzma-dev" + ;; + libslang) + echo "libslang2-dev" + ;; + libcapstone) + echo "libcapstone-dev" + ;; + libpython) + echo "python3-dev" + ;; + libtraceevent) + echo "libtraceevent-dev" + ;; + # The cxa-demangle feature test links against libstdc++ builtin + # demangling, so on Debian-derived distros it is covered by the + # g++ base package below, which pulls in libstdc++-*-dev. + cxa-demangle) + ;; + libbpf) + echo "libbpf-dev" + ;; + babeltrace2-ctf-writer) + echo "libbabeltrace2-dev" + ;; + libopenssl) + echo "libssl-dev" + ;; + libpfm4) + echo "libpfm4-dev" + ;; + sdt) + echo "systemtap-sdt-dev" + ;; + # test-clang-bpf-co-re.c invokes the clang binary (not libclang-cpp), + # so clang suffices; llvm-dev brings llvm-config, needed by the + # llvm/llvm-perf tests below. + clang-bpf-co-re) + echo "clang llvm-dev" + ;; + llvm|llvm-perf) + echo "llvm-dev" + ;; + jvmti|jvmti-cmlr) + echo "default-jdk" + ;; + esac + # Same rationale as in fedora_pkg_for() above for unmapped tests. +} + +# Base packages needed by any perf build, regardless of feature tests: +# compiler, libc headers, flex/bison for the parser, kernel headers +# for UAPI headers with no in-tree copy, e.g. <linux/capability.h>, and +# gcc-c++ (dnf) / g++ (apt) is needed by the C++-based feature tests +# (cxa-demangle, llvm, llvm-perf), compiled with $(CXX), and +# pulls in libstdc++-devel / libstdc++-*-dev. +# python3-setuptools is needed to build the python binding (perf's +# util/setup.py uses it; without it binding is skipped with a warning). +# rust is not a header-based feature test: test-rust.bin just checks +# "$(RUSTC) --version" (tools/build/feature/Makefile), so it is mapped +# here like the other toolchain packages. +fedora_base_pkgs="gcc gcc-c++ make flex bison glibc-devel kernel-headers python3-setuptools rust" +# pkg-config mirrors the pkgconf-pkg-config package that Fedora +# installs by default, needed by the babeltrace2 feature test and +# libopenssl's pkg-config checks. +debian_base_pkgs="gcc g++ make pkg-config flex bison libc6-dev linux-libc-dev python3-setuptools rustc" +# pkg-config: like Fedora, on pkgconf since Fedora 26 / RHEL 8, with +# 'pkgconfig' live only as a virtual Provides of the pkgconf-pkg-config +# subpackage. List it explicitly because, unlike Fedora, a minimal +# RHEL-family container may not have it preinstalled. +rhel_base_pkgs="gcc gcc-c++ make flex bison glibc-devel kernel-headers pkgconf-pkg-config python3-setuptools rust" + +# --------------------------------------------------------------------- +# Distro detection +# --------------------------------------------------------------------- +detect_distro() { + if [ -n "$DISTRO" ]; then + echo "$DISTRO" + return + fi + local id + id=$( . /etc/os-release 2>/dev/null && echo "${ID:-}" ) + case "$id" in + fedora) echo "fedora" ;; + rhel|centos|rocky|almalinux|ol) + # All share the Fedora package names (with the exceptions + # handled by rhel_pkg_for()) and dnf. + echo "rhel" ;; + ubuntu) echo "ubuntu" ;; + debian) echo "debian" ;; + *) echo "" ;; + esac +} + +# --------------------------------------------------------------------- +# Feature test enumeration: mirror of the tests checked during a build, +# from the actual test-*.c / test-*.cpp sources in tools/build/feature/. +# --------------------------------------------------------------------- +feature_tests() { + local srcdir="$1" + local f + for f in "$srcdir"/tools/build/feature/test-*.c "$srcdir"/tools/build/feature/test-*.cpp; do + [ -e "$f" ] || continue + basename "$f" | sed -e 's/^test-//' -e 's/\.c$//' -e 's/\.cpp$//' + done +} + +# --------------------------------------------------------------------- +# Assemble the unique package list. Since the full feature set is mapped +# unconditionally, this installs the complete devel environment; installing +# an already-present package is a no-op for both dnf and apt-get, making +# this idempotent. On the RHEL family, packages not available on the +# enabled repos are skipped and echoed on stderr, reported at the end of +# the run by the caller (package_set() runs in a subshell, so a variable +# would not survive it). +# --------------------------------------------------------------------- +package_set() { + local distro="$1" srcdir="$2" + local feat pkg pkgs base_pkgs missing_pkgs="" + case "$distro" in + fedora) pkgs="$fedora_base_pkgs" ;; + rhel) pkgs="$rhel_base_pkgs" ;; + ubuntu|debian) pkgs="$debian_base_pkgs" ;; + esac + + # The base set must be checked against the enabled repos as well: + # e.g. 'rust' is only shipped as the rust-toolset AppStream module + # on RHEL 8 and 9, where dnf would abort the whole transaction + # with "No match for argument: rust" instead of skipping it, so + # unavailable base packages are skipped and noted like the mapped + # ones below. + if [ "$distro" = "rhel" ]; then + base_pkgs="$pkgs" + pkgs="" + for pkg in $base_pkgs; do + if pkg_available "$pkg"; then + pkgs="$pkgs $pkg" + else + missing_pkgs="$missing_pkgs $pkg" + fi + done + fi + + for feat in $(feature_tests "$srcdir"); do + case "$distro" in + fedora) pkg=$(fedora_pkg_for "$feat") ;; + rhel) pkg=$(rhel_pkg_for "$feat") ;; + *) pkg=$(debian_pkg_for "$feat") ;; + esac + # An empty result means the feature test has no external devel + # dependency (see the unmapped list in fedora_pkg_for()), so + # there is nothing to install and nothing to report as missing: + # packages that are genuinely unavailable on the RHEL family + # surface through rhel_pkg_for() falling back to its first + # candidate, so that the pkg_available() check below catches + # them and adds them to missing_pkgs. + [ -n "$pkg" ] || continue + for pkg in $pkg; do + if [ "$distro" = "rhel" ] && ! pkg_available "$pkg"; then + missing_pkgs="$missing_pkgs $pkg" + continue + fi + case " $pkgs " in + *" $pkg "*) ;; + *) pkgs="$pkgs $pkg" ;; + esac + done + done + [ -n "$missing_pkgs" ] && echo "$missing_pkgs" >&2 + echo "$pkgs" +} + +# --------------------------------------------------------------------- +# Report the RHEL-family packages that were skipped because the enabled +# repos do not provide them. +# --------------------------------------------------------------------- +note_missing() { + [ -n "$1" ] || return 0 + echo "Note: these packages are not available on the enabled repos" >&2 + echo "and were not installed, so the features they enable will stay" >&2 + echo "off in a perf build:" >&2 + echo "$1" | tr ' ' '\n' | grep -v '^$' | sort -u | sed 's/^/ /' >&2 + echo >&2 +} + +# --------------------------------------------------------------------- +# The install command proper for each supported package manager, plus +# the command massaged for --dry-run. +# --------------------------------------------------------------------- +install_cmd() { + local distro="$1"; shift + case "$distro" in + fedora|rhel) + echo "dnf install -y $*" + ;; + ubuntu|debian) + # a fresh container has no package index, so update first; run + # with a noninteractive debconf frontend: default-jdk, used by + # the jvmti feature tests, pulls in tzdata, which prompts for + # the timezone on a terminal and would block the install. The + # env var prefix works with the 'sh -c' invocation below, and + # shows up in --dry-run. + echo "DEBIAN_FRONTEND=noninteractive apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y $*" + ;; + esac +} + +main() { + local action="install" + # Package accumulation happens in package_set(), which, together + # with the *_pkg_for() helpers, declares the per-feature 'pkg' + # locals; main() holds no per-feature package state, just the + # distro-wide list assembled by package_set(). + local srcdir distro pkgs cmd missing_file missing_pkgs + + while [ $# -gt 0 ]; do + case "$1" in + --list) action="list"; shift ;; + --dry-run) action="dry-run"; shift ;; + --distro) + [ $# -ge 2 ] || { + echo "error: --distro requires an argument (fedora, rhel, ubuntu, debian)" >&2 + exit 1 + } + DISTRO="$2"; shift 2 ;; + -h|--help) help ;; + *) echo "error: unknown argument: $1" >&2; exit 1 ;; + esac + done + + srcdir=$(cd "$(dirname "$0")/../../.." && pwd) + distro=$(detect_distro) + case "$distro" in + fedora|rhel|ubuntu|debian) ;; + *) + echo "error: unsupported distro (got '$distro'); the package mapping is not validated on other distros." >&2 + echo "Supported and validated: Fedora 44 (toolbx container), Ubuntu 26.04 and Debian 13 (distrobox containers), and CentOS Stream 10 (distrobox container)." >&2 + exit 1 + ;; + esac + + # The RHEL family mapping probes the enabled repos with dnf + # repoquery and installs with dnf, so reject the yum-only members of + # the family (RHEL 7 and earlier, e.g. Oracle Linux 7) with a clear + # error instead of silently judging every package as unavailable. + if [ "$distro" = "rhel" ] && ! command -v dnf >/dev/null 2>&1; then + echo "error: dnf not found, the RHEL family package mapping requires dnf (RHEL 8 and later)." >&2 + exit 1 + fi + + missing_file=$(mktemp) || { + echo "error: cannot create a temporary file (mktemp failed)" >&2 + exit 1 + } + # package_set() runs in a subshell, doing dnf repoquery loops that + # may be interrupted: a Ctrl-C during those loops hits these traps, + # turning SIGINT/SIGTERM into an exit that triggers the EXIT trap, + # removing the temp file, so the script terminates instead of + # resuming after the interrupted command, leaving no file behind. + trap 'rm -f "$missing_file"' EXIT + trap 'exit 1' INT TERM + pkgs=$(package_set "$distro" "$srcdir" 2>"$missing_file") + missing_pkgs=$(cat "$missing_file") + rm -f "$missing_file" + trap - EXIT INT TERM + + case "$action" in + list) + echo "$pkgs" | tr ' ' '\n' | grep -v '^$' | sort + note_missing "$missing_pkgs" + exit 0 + ;; + dry-run) + install_cmd "$distro" $pkgs + note_missing "$missing_pkgs" + exit 0 + ;; + esac + + echo "The following packages will be installed to enable perf features:" + echo "$pkgs" | tr ' ' '\n' | grep -v '^$' | sort | sed 's/^/ /' + echo + cmd=$(install_cmd "$distro" $pkgs) + if [ "$(id -u)" -eq 0 ]; then + sh -c "$cmd" + else + sudo sh -c "$cmd" + fi || { + echo "error: the install command failed, see the output above" >&2 + exit 1 + } + note_missing "$missing_pkgs" +} + +main "$@" |
