From nobody Sat Oct 24 13:20:37 2026 Received: from mail-dy1-f200.google.com (mail-dy1-f200.google.com [74.125.82.200]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4F5155616DE for ; Tue, 13 Oct 2026 22:26:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.200 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791930401; cv=none; b=NPcRcFXkO9PNnNj3TkE+strSYqxncRR3APQ0PosDBfzKbNqhY6hDgtbT0ZhQLSx+ZuqmPOdW058JkCqIFf5QnoPn4imJWYHSCchSWAAazALP/cLwtu67cJoy0RY7dI4eyfKMWO1QZFVSL+u2Hjh4FnlZ2zaBNcbrVEJ5S3Upwos= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791930401; c=relaxed/simple; bh=x2csqR8dDP2NCSK8ek5vU6PAamZazjSrMmyYhw8xZI4=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=V5b4+dWcD8oG9UK7Bf34j+ETKuRfuZ1WZVKPqqAb9YXjZVSAqWgfIohIyq9xRHsdcU3iEZHKJB6w5o5Et7WryBDM5HupQE7uP4PbanaONd9c1opcE6V23JIdQIwIye2ABH18LKjfpij1VUQ2qE+zLBT+nAJKutvVp+i1slz+Nms= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=BcOVB2V7; arc=none smtp.client-ip=74.125.82.200 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="BcOVB2V7" Received: by mail-dy1-f200.google.com with SMTP id 5a478bee46e88-33c35f5ca6cso7811043eec.1 for ; Tue, 13 Oct 2026 15:26:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1791930399; x=1792535199; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=BZIK7O2vtZmPG/MzaFS6aJid7lIfJvEiqBHfvqhoMys=; b=BcOVB2V7n5cs57M5RRBOzyH9B2VgnrX5qFhul/i1pIdcyiSuaD/A/Lf2BtPKa0hVw3 3y/6RfKnjSbEfROa9Z7dIleKRvqhJ5I9AjuDh1ordEHG6cwGTf2KDGiUcSWKSQCnkofe d58gen8DukTzOzNKNlytzg8A32WzSlhpcWJhkJ5csInbrTpmVL0quPITS8l6fWgbv/u5 uyDfmQk92rvH35yxbLUd2oQLQDhUaUaXrGnru4XS8ewxMJRkRExfd8Qt7QmdwC4go/QF WfZ+47kpdQCOOuTcnSaVzc9/TihShgimpKzaQp0zwZO0SMaQljGKHfL7d7E7QZt4sVKa /7tw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1791930399; x=1792535199; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=BZIK7O2vtZmPG/MzaFS6aJid7lIfJvEiqBHfvqhoMys=; b=wRA75/rhx0DR6eyHVMXYjSv0FSS8D8yisR82e4q5YBv/evoRUdioffE7QRtqxmZzZx q5dyoEZyvfD7JWNKT+kNOfll82S5RPtSpa6oYpfUxU0RNTGQpcUU9C8T7KHK23XpZBpJ NUvGtnkMR6a5GGvFlOm9EicsokrU7C+Hy9NWP198JFTYOMt4v9g3mzN942/a+YbVimIp xEtxODrIQyq+EOjsmX1nUP4DlXvODrfa/DVjvwFAB4kTd+vHnUiTn87LJKcs295dkbZT fGPzHj4nptmeV4OpLC7PGtGGYNe0Ruf3Fz7N+zaC0tFKRilrkDedQJqlaOsEVFJaEmrp uVYw== X-Forwarded-Encrypted: i=1; AKwUvBwPKTCsznjQauSW6meXaCCJWUi8VMe4t1HvZQB+48+5IcZqw9XMQL332uTNx64B3/3NP1qzDPx5hCN3ycw=@vger.kernel.org X-Gm-Message-State: AFq9FYIVfq/5VhwLjoJOCaZYxz27T5AfDjR+Ojcwkt6GiWoiLVZmkYFb bZ7gzQI+WBFzNIueIAQnAz5Wuz4Eq55z/rCG/+fTX6TiiusX36sT3cIPhEkg0ddip4XXn3JMQY1 CujM4BiTBTg== X-Received: from dycal34.prod.google.com ([2002:a05:7301:1ca2:b0:35c:c374:d526]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7301:a0f:b0:315:afc1:72db with SMTP id 5a478bee46e88-3537e046a1dmr18119322eec.9.1791930397618; Tue, 13 Oct 2026 15:26:37 -0700 (PDT) Date: Tue, 13 Oct 2026 15:26:13 -0700 In-Reply-To: <20261013222622.1822619-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20261013182458.1234616-1-irogers@google.com> <20261013222622.1822619-1-irogers@google.com> X-Mailer: git-send-email 2.56.0.385.gd3acb90ef8-goog Message-ID: <20261013222622.1822619-2-irogers@google.com> Subject: [PATCH v2 01/10] compiler-context-analysis: Avoid unused parameter warning in _context_unsafe_alias() From: Ian Rogers To: irogers@google.com, acme@kernel.org, elver@google.com, namhyung@kernel.org Cc: adrian.hunter@intel.com, bvanassche@acm.org, james.clark@linaro.org, jolsa@kernel.org, justinstitt@google.com, linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, ljs@kernel.org, llvm@lists.linux.dev, mingo@redhat.com, morbo@google.com, nathan@kernel.org, ndesaulniers@google.com, peterz@infradead.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" _context_unsafe_alias() does not use its parameter 'p', which triggers -Wunused-parameter when building code that enables -Wextra (such as tools/perf, tools/lib/perf, tools/lib/subcmd, and tools/lib/symbol). Explicitly cast 'p' to void to silence the warning, matching __assume_ctx_lock() and __assume_shared_ctx_lock(). Assisted-by: Antigravity:gemini-3.1-pro Signed-off-by: Ian Rogers Reviewed-by: Marco Elver --- include/linux/compiler-context-analysis.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/compiler-context-analysis.h b/include/linux/comp= iler-context-analysis.h index 8302ebc2ea8c..024e303188ad 100644 --- a/include/linux/compiler-context-analysis.h +++ b/include/linux/compiler-context-analysis.h @@ -243,7 +243,7 @@ * alias as a function argument). */ #define context_unsafe_alias(p) _context_unsafe_alias((void **)&(p)) -static inline void _context_unsafe_alias(void **p) { } +static inline void _context_unsafe_alias(void **p) { (void)p; } =20 /** * token_context_lock() - declare an abstract global context lock instance --=20 2.56.0.385.gd3acb90ef8-goog From nobody Sat Oct 24 13:20:37 2026 Received: from mail-dy1-f199.google.com (mail-dy1-f199.google.com [74.125.82.199]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 953765372C4 for ; Tue, 13 Oct 2026 22:26:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.199 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791930403; cv=none; b=p16v4VvejnY++3GNc618n9YOzu7RD+SnxcAM8nYHsztVfy/zn3XElzV43Xmnu/BsslEJ0UDhzi4jJlNRJsweT2lNb/JEaGmpmyv6KzeNZcaPIebAgaezdRhtSKY/wYOSHjBE3dT7WAFVQvp/MhEXJBGKuMddhpnXP+xD73cqnEo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791930403; c=relaxed/simple; bh=BlhK9sh79umMCWRLraqa7Qbx7ApWW9yCgqHBIgaEtZo=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=p0nkFSRdbuBX1VLK8pOV8WLe3nMk+om7MEslAigCsIWboykHcwuTMRetApc8X9JYqoDKEmxnJG6ml/EWY7XCF2C51eZXFh1Vt+YLTnCkQIw2QR1qWH8XqmilRQyMiMwiC2AUJBnjXYDhKKDLYdYOF0B6lUO5HiWPnUQhoYuWHWw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=VnkYIsmU; arc=none smtp.client-ip=74.125.82.199 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="VnkYIsmU" Received: by mail-dy1-f199.google.com with SMTP id 5a478bee46e88-3552883bd19so4607024eec.1 for ; Tue, 13 Oct 2026 15:26:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1791930401; x=1792535201; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=MAsvADi7aJrmU0fFcmnPh2evEqX3fDBYv6iyZOoloMo=; b=VnkYIsmUKTuDVbm166zxIAGQ+Ot5F+6brfA68o8YFxJGC+pXiuaUEpi4+wcajgXl67 WHd7TZsRDFY0E2Zg+X9BAOerjF8cIL2f/Yhxp7vMOShdN8DT67jzR3YIYsGsYbe+0/Db 8zoGoZW8v3SXmr64v6OdzpQg6+uHmMidbL18ZFirpXsC/TW+DPDvF9TrN5YFdjBaxD92 PENjc/xCvjLn9eIhVA52Vzk5+4n2SqwbytHMJxvrPARrzywwxpx7//deDMouM6v7Lv6i 21EYm+6D+1mw3auVuvx976wk/+wVVnkTImC2aZL9W/OAxnkvsCppJWv66rpR883gwuX6 sQ1A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1791930401; x=1792535201; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=MAsvADi7aJrmU0fFcmnPh2evEqX3fDBYv6iyZOoloMo=; b=Dy6592i8QU0ih4Cxjr9eAV2bj+kXGmDDgUS9nsXcetAWRapCsl6B2cgp/7GHPtIVrD BQ0E2Uots5HioAj0yC68J3jh/VOovA6bpj2gUx1ksGTMCH+FzbIOId8KoFcIJs3JSCeK p3seQlgKHdCTTTvLRNgaDodkVUtoSM42s1toU7MD39yNBmGhK75LpgZaA4hH4UfZ1XJ7 FJCR4HVt/E/qPqxaVcE0+Yo9nO1XlZ+M8l8fc4MLRyMOsuHV51UyOV9Od11QuFxFpa3j O0sQfUymSgjRuu/V3sW8kGlm+TcMySD8O8f3V1HZw0GUNUGMLnlN7BlQhZLA7W0jKQNg 80DA== X-Forwarded-Encrypted: i=1; AKwUvBwUgDSyPmjKGPdKcJ5oia1A9PJTrb+NthJROb2LKjOMP73KZs+W5sEKySsrnIVNMdV70eZgEs7gEWcDiYM=@vger.kernel.org X-Gm-Message-State: AFq9FYKnJGc0wC5GQsf/GyAgbnHGZI5ggGRC15oPKYFnYxOro+53a7er +NTda9vRGytFk076vijG7JxaLk/bet0KdKHNJ4dh61/I1KKHJp4q7FV1Ysn8KFEU/6D0VP5kwdF qnaFOduxYjg== X-Received: from dybmn7.prod.google.com ([2002:a05:7300:d207:b0:353:80d0:4119]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7301:4396:b0:35d:800:6344 with SMTP id 5a478bee46e88-35d08006547mr2758471eec.4.1791930400289; Tue, 13 Oct 2026 15:26:40 -0700 (PDT) Date: Tue, 13 Oct 2026 15:26:14 -0700 In-Reply-To: <20261013222622.1822619-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20261013182458.1234616-1-irogers@google.com> <20261013222622.1822619-1-irogers@google.com> X-Mailer: git-send-email 2.56.0.385.gd3acb90ef8-goog Message-ID: <20261013222622.1822619-3-irogers@google.com> Subject: [PATCH v2 02/10] tools headers compiler: Synchronize compiler_types.h with the kernel sources From: Ian Rogers To: irogers@google.com, acme@kernel.org, elver@google.com, namhyung@kernel.org Cc: adrian.hunter@intel.com, bvanassche@acm.org, james.clark@linaro.org, jolsa@kernel.org, justinstitt@google.com, linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, ljs@kernel.org, llvm@lists.linux.dev, mingo@redhat.com, morbo@google.com, nathan@kernel.org, ndesaulniers@google.com, peterz@infradead.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Synchronize the non-__KERNEL__ sections of tools/include/linux/compiler_types.h and tools/include/linux/compiler-gcc.h with the kernel sources (including ___PASTE/__PASTE, BTF_TYPE_TAG, object-size helpers, asm_goto_output, ASM_INPUT_*, asm_inline, __typeof_unqual__/__unqual_scalar_typeof, __signed_scalar_typeof, __native_word, compiletime_assert, and the __diag pragma helpers required by compiler-context-analysis.h), and remove the duplicated definitions from tools/include/linux/compiler.h. Assisted-by: Antigravity:gemini-3.1-pro Signed-off-by: Ian Rogers --- tools/include/linux/compiler-gcc.h | 55 ++++++- tools/include/linux/compiler.h | 50 +------ tools/include/linux/compiler_types.h | 206 ++++++++++++++++++++++++++- 3 files changed, 258 insertions(+), 53 deletions(-) diff --git a/tools/include/linux/compiler-gcc.h b/tools/include/linux/compi= ler-gcc.h index e20f98e14e81..9213691e8e09 100644 --- a/tools/include/linux/compiler-gcc.h +++ b/tools/include/linux/compiler-gcc.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _TOOLS_LINUX_COMPILER_H_ +#ifndef __LINUX_COMPILER_TYPES_H #error "Please do not include directly, include instead." -#endif +#endif /* __LINUX_COMPILER_TYPES_H */ =20 /* * Common definitions for all gcc versions go here. @@ -33,10 +33,59 @@ #define __packed __attribute__((packed)) #endif #ifndef __noreturn -#define __noreturn __attribute__((noreturn)) +#define __noreturn __attribute__((__noreturn__)) #endif #ifndef __aligned #define __aligned(x) __attribute__((aligned(x))) #endif #define __printf(a, b) __attribute__((format(printf, a, b))) #define __scanf(a, b) __attribute__((format(scanf, a, b))) + +/* + * Turn individual warnings and errors on and off locally, depending + * on version. + */ +#define __diag_str1(s) #s +#define __diag_str(s) __diag_str1(s) + +#ifdef __clang__ +#define __diag_clang(version, severity, s) \ + __diag_clang_ ## version(__diag_clang_ ## severity s) + +/* Severity used in pragma directives */ +#define __diag_clang_ignore ignored +#define __diag_clang_warn warning +#define __diag_clang_error error + +#define __diag(s) _Pragma(__diag_str(clang diagnostic s)) + +#define __diag_clang_all(s) __diag(s) + +#define __diag_ignore_all(option, comment) \ + __diag_clang(all, ignore, option) + +#define CC_HAS_TYPEOF_UNQUAL (__clang_major__ > 19 || (__clang_major__ =3D= =3D 19 && __clang_minor__ > 0)) +#else /* !__clang__ */ +#define __diag_GCC(version, severity, s) \ + __diag_GCC_ ## version(__diag_GCC_ ## severity s) + +/* Severity used in pragma directives */ +#define __diag_GCC_ignore ignored +#define __diag_GCC_warn warning +#define __diag_GCC_error error + +#define __diag(s) _Pragma(__diag_str(GCC diagnostic s)) + +#if GCC_VERSION >=3D 80000 +#define __diag_GCC_8(s) __diag(s) +#else +#define __diag_GCC_8(s) +#endif + +#define __diag_GCC_all(s) __diag(s) + +#define __diag_ignore_all(option, comment) \ + __diag(__diag_GCC_ignore option) + +#define CC_HAS_TYPEOF_UNQUAL (__GNUC__ >=3D 14) +#endif /* __clang__ */ diff --git a/tools/include/linux/compiler.h b/tools/include/linux/compiler.h index f2f54b038168..86d628ba8d60 100644 --- a/tools/include/linux/compiler.h +++ b/tools/include/linux/compiler.h @@ -1,41 +1,11 @@ /* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _TOOLS_LINUX_COMPILER_H_ -#define _TOOLS_LINUX_COMPILER_H_ +#ifndef __LINUX_COMPILER_H +#define __LINUX_COMPILER_H =20 #ifndef __ASSEMBLY__ =20 #include =20 -#ifndef __compiletime_error -# define __compiletime_error(message) -#endif - -#ifdef __OPTIMIZE__ -# define __compiletime_assert(condition, msg, prefix, suffix) \ - do { \ - extern void prefix ## suffix(void) __compiletime_error(msg); \ - if (!(condition)) \ - prefix ## suffix(); \ - } while (0) -#else -# define __compiletime_assert(condition, msg, prefix, suffix) do { } while= (0) -#endif - -#define _compiletime_assert(condition, msg, prefix, suffix) \ - __compiletime_assert(condition, msg, prefix, suffix) - -/** - * compiletime_assert - break build and emit msg if condition is false - * @condition: a compile-time constant condition to check - * @msg: a message to emit if condition is false - * - * In tradition of POSIX assert, this macro will break the build if the - * supplied condition is *false*, emitting the supplied error message if t= he - * compiler has support to do so. - */ -#define compiletime_assert(condition, msg) \ - _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__) - /* Optimization barrier */ /* The "volatile" is due to gcc bugs */ #define barrier() __asm__ __volatile__("": : :"memory") @@ -48,10 +18,6 @@ #define __always_unused __attribute__((__unused__)) #endif =20 -#ifndef __noreturn -#define __noreturn __attribute__((__noreturn__)) -#endif - #ifndef unreachable #define unreachable() __builtin_unreachable() #endif @@ -68,11 +34,6 @@ #define __naked __attribute__((__naked__)) #endif =20 -/* Are two types/vars the same type (ignoring qualifiers)? */ -#ifndef __same_type -# define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(= b)) -#endif - /* * This returns a constant expression while determining if an argument is * a constant expression, most importantly without evaluating the argument. @@ -237,11 +198,6 @@ static __always_inline void __write_once_size(volatile= void *p, void *res, int s __u.__val; \ }) =20 - -/* Indirect macros required for expanded argument pasting, eg. __LINE__. */ -#define ___PASTE(a, b) a##b -#define __PASTE(a, b) ___PASTE(a, b) - #ifndef OPTIMIZER_HIDE_VAR /* Make the optimizer believe the variable can be manipulated arbitrarily.= */ #define OPTIMIZER_HIDE_VAR(var) \ @@ -258,4 +214,4 @@ static __always_inline void __write_once_size(volatile = void *p, void *res, int s =20 #endif /* __ASSEMBLY__ */ =20 -#endif /* _TOOLS_LINUX_COMPILER_H */ +#endif /* __LINUX_COMPILER_H */ diff --git a/tools/include/linux/compiler_types.h b/tools/include/linux/com= piler_types.h index b3adbf5682f0..31e9f7d2a466 100644 --- a/tools/include/linux/compiler_types.h +++ b/tools/include/linux/compiler_types.h @@ -2,8 +2,6 @@ #ifndef __LINUX_COMPILER_TYPES_H #define __LINUX_COMPILER_TYPES_H =20 -/* Builtins */ - /* * __has_builtin is supported on gcc >=3D 10, clang >=3D 3 and icc >=3D 21. * In the meantime, to support gcc < 10, we implement __has_builtin @@ -13,6 +11,23 @@ #define __has_builtin(x) (0) #endif =20 +/* Indirect macros required for expanded argument pasting, eg. __LINE__. */ +#define ___PASTE(a, b) a##b +#define __PASTE(a, b) ___PASTE(a, b) + +#ifndef __ASSEMBLY__ + +/* + * Skipped when running bindgen due to a libclang issue; + * see https://github.com/rust-lang/rust-bindgen/issues/2244. + */ +#if defined(CONFIG_DEBUG_INFO_BTF) && defined(CONFIG_PAHOLE_HAS_BTF_TAG) &= & \ + __has_attribute(btf_type_tag) && !defined(__BINDGEN__) +# define BTF_TYPE_TAG(value) __attribute__((btf_type_tag(#value))) +#else +# define BTF_TYPE_TAG(value) /* nothing */ +#endif + #include =20 /* Compiler specific macros. */ @@ -20,14 +35,101 @@ #include #endif =20 +#ifndef __compiletime_error +# define __compiletime_error(message) +#endif + +#ifndef __noreturn +# define __noreturn __attribute__((__noreturn__)) +#endif + +#endif /* __ASSEMBLY__ */ + +/* + * When the size of an allocated object is needed, use the best available + * mechanism to find it. (For cases where sizeof() cannot be used.) + * + * Optional: only supported since gcc >=3D 12 + * + * gcc: https://gcc.gnu.org/onlinedocs/gcc/Object-Size-Checking.html + * clang: https://clang.llvm.org/docs/LanguageExtensions.html#evaluating-o= bject-size + */ +#if __has_builtin(__builtin_dynamic_object_size) +#define __struct_size(p) __builtin_dynamic_object_size(p, 0) +#define __member_size(p) __builtin_dynamic_object_size(p, 1) +#else +#define __struct_size(p) __builtin_object_size(p, 0) +#define __member_size(p) __builtin_object_size(p, 1) +#endif + +/* + * Determine if an attribute has been applied to a variable. + * Using __annotated needs to check for __annotated being available, + * or negative tests may fail when annotation cannot be checked. For + * example, see the definition of __is_cstr(). + */ +#if __has_builtin(__builtin_has_attribute) +#define __annotated(var, attr) __builtin_has_attribute(var, attr) +#endif + +/* + * Optional: only supported since gcc >=3D 15, clang >=3D 19 + * + * gcc: https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#index-_00= 5f_005fbuiltin_005fcounted_005fby_005fref + * clang: https://clang.llvm.org/docs/LanguageExtensions.html#builtin-coun= ted-by-ref + */ +#if __has_builtin(__builtin_counted_by_ref) && \ + !defined(CONFIG_CC_HAS_BROKEN_COUNTED_BY_REF) +#define __flex_counter(FAM) __builtin_counted_by_ref(FAM) +#else +#define __flex_counter(FAM) ((void *)NULL) +#endif + +/* + * Some versions of gcc do not mark 'asm goto' volatile: + * + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=3D103979 + * + * We do it here by hand, because it doesn't hurt. + */ #ifndef asm_goto_output -#define asm_goto_output(x...) asm goto(x) +#define asm_goto_output(x...) asm volatile goto(x) +#endif + +/* + * Clang has trouble with constraints with multiple + * alternative behaviors ("g" , "rm" and "=3Drm"). + */ +#ifndef ASM_INPUT_G + #define ASM_INPUT_G "g" + #define ASM_INPUT_RM "rm" + #define ASM_OUTPUT_RM "=3Drm" +#endif + +#ifdef CONFIG_CC_HAS_ASM_INLINE +#define asm_inline asm __inline +#else +#define asm_inline asm +#endif + +#ifndef __ASSEMBLY__ +/* + * Use __typeof_unqual__() when available. + */ +#if (defined(CC_HAS_TYPEOF_UNQUAL) && CC_HAS_TYPEOF_UNQUAL) || defined(__C= HECKER__) +# define USE_TYPEOF_UNQUAL 1 +#endif + +/* Are two types/vars the same type (ignoring qualifiers)? */ +#ifndef __same_type +# define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(= b)) #endif =20 /* * __unqual_scalar_typeof(x) - Declare an unqualified scalar type, leaving * non-scalar types unchanged. */ +#ifndef USE_TYPEOF_UNQUAL /* * Prefer C11 _Generic for better compile-times and simpler code. Note: 'c= har' * is not type-compatible with 'signed char', and we define a separate cas= e. @@ -45,5 +147,103 @@ __scalar_type_to_expr_cases(long), \ __scalar_type_to_expr_cases(long long), \ default: (x))) +#else +#define __unqual_scalar_typeof(x) __typeof_unqual__(x) +#endif + +#endif /* !__ASSEMBLY__ */ + +/* + * __signed_scalar_typeof(x) - Declare a signed scalar type, leaving + * non-scalar types unchanged. + */ + +#define __scalar_type_to_signed_cases(type) \ + unsigned type: (signed type)0, \ + signed type: (signed type)0 + +#define __signed_scalar_typeof(x) typeof( \ + _Generic((x), \ + char: (signed char)0, \ + __scalar_type_to_signed_cases(char), \ + __scalar_type_to_signed_cases(short), \ + __scalar_type_to_signed_cases(int), \ + __scalar_type_to_signed_cases(long), \ + __scalar_type_to_signed_cases(long long), \ + default: (x))) + +/* Is this type a native word size -- useful for atomic operations */ +#define __native_word(t) \ + (sizeof(t) =3D=3D sizeof(char) || sizeof(t) =3D=3D sizeof(short) || \ + sizeof(t) =3D=3D sizeof(int) || sizeof(t) =3D=3D sizeof(long)) + +#ifdef __OPTIMIZE__ +/* + * #ifdef __OPTIMIZE__ is only a good approximation; for instance "make + * CFLAGS_foo.o=3D-Og" defines __OPTIMIZE__, does not elide the conditiona= l code + * and can break compilation with wrong error message(s). Combine with + * -U__OPTIMIZE__ when needed. + */ +# define __compiletime_assert(condition, msg, prefix, suffix) \ + do { \ + /* \ + * __noreturn is needed to give the compiler enough \ + * information to avoid certain possibly-uninitialized \ + * warnings (regardless of the build failing). \ + */ \ + __noreturn extern void prefix ## suffix(void) \ + __compiletime_error(msg); \ + if (!(condition)) \ + prefix ## suffix(); \ + } while (0) +#else +# define __compiletime_assert(condition, msg, prefix, suffix) ((void)(cond= ition)) +#endif + +#define _compiletime_assert(condition, msg, prefix, suffix) \ + __compiletime_assert(condition, msg, prefix, suffix) + +/** + * compiletime_assert - break build and emit msg if condition is false + * @condition: a compile-time constant condition to check + * @msg: a message to emit if condition is false + * + * In tradition of POSIX assert, this macro will break the build if the + * supplied condition is *false*, emitting the supplied error message if t= he + * compiler has support to do so. + */ +#define compiletime_assert(condition, msg) \ + _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__) + +#define compiletime_assert_atomic_type(t) \ + compiletime_assert(__native_word(t), \ + "Need native word sized stores/loads for atomicity.") + +/* Helpers for emitting diagnostics in pragmas. */ +#ifndef __diag +#define __diag(string) +#endif + +#ifndef __diag_GCC +#define __diag_GCC(version, severity, string) +#endif + +#ifndef __diag_clang +#define __diag_clang(version, severity, string) +#endif + +#define __diag_push() __diag(push) +#define __diag_pop() __diag(pop) + +#define __diag_ignore(compiler, version, option, comment) \ + __diag_ ## compiler(version, ignore, option) +#define __diag_warn(compiler, version, option, comment) \ + __diag_ ## compiler(version, warn, option) +#define __diag_error(compiler, version, option, comment) \ + __diag_ ## compiler(version, error, option) + +#ifndef __diag_ignore_all +#define __diag_ignore_all(option, comment) +#endif =20 #endif /* __LINUX_COMPILER_TYPES_H */ --=20 2.56.0.385.gd3acb90ef8-goog From nobody Sat Oct 24 13:20:37 2026 Received: from mail-dy1-f200.google.com (mail-dy1-f200.google.com [74.125.82.200]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4BC325625FB for ; Tue, 13 Oct 2026 22:26:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.200 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791930406; cv=none; b=HeEVetTAIBzcj1niHItb+aEx5yvJoQNlp6MstqGUqKidnh2xYfpIWWUA641ZCvxlHrCJRpUEbxGzyywPcv1+WkVWQwRACvURpByJjOik9HXwf4F9aS7qtI9Jp6mjkSIpzLmP3KxMY4cAwIzWnvbopgsJf8Qkg4BmZ0GpCXM2ipA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791930406; c=relaxed/simple; bh=gevvb7bHhYFBjyGLidhmfNLuEdRQ2SS0zDJadhNVoCo=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=YZyJKvZLiyHBDfsnWU2TDP2AYRoucjfMFX4NYDHzQtiNgXKdbseEKYdlkrGtSZ/LUI9xwDf7Owi/dmcjB7RUTWMJBGXix+/8SUui+xVEAhlovTFq0q2Un5lDlSTMQNZqwHBOxLDsQaDXx1Npbb5BugQ5tMEIFYNcs/fcYELDmog= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=ZmqBcbLX; arc=none smtp.client-ip=74.125.82.200 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="ZmqBcbLX" Received: by mail-dy1-f200.google.com with SMTP id 5a478bee46e88-33c35f5ca6cso7811122eec.1 for ; Tue, 13 Oct 2026 15:26:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1791930403; x=1792535203; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=ozfFjnk5qB1WJx1yNE8iXoEJAHneqi+RSXaDHWfrXOg=; b=ZmqBcbLX2v16Rf0q4CrTO1FaPZB5/i1iQ38riuPgofVshB0F2WrJduiLT81uw0d8Tl c3+AM3nP9FwewTvRhTDJz3TZr2CTzatqknekCODk2KY3VSFgsT7Xwl1oxe921yzDk35q 4cV8ilAb++HyP82PlmI3GGzHNdxDMXm6MnU1xzUA0d6DRqlA4Pl/NBU1ZcnE64yqXzr9 WPwnoEqZ8pQSwLv9Pe0NhwqImIQpcAfkjdOpzOEEUdMZD8bLEc85Db5qiSPcGZOP0a3K Q2QxpYJXv5hqvPob4Wmlcnr8hYsfhCpgc09xdgDNSJbHQ0VyJccRJAjjACf/yhF0ON/T oq+g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1791930403; x=1792535203; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=ozfFjnk5qB1WJx1yNE8iXoEJAHneqi+RSXaDHWfrXOg=; b=Uaj4ls40IjTDkfLypb9bg8QpoSQ9YfrYjdYSQk9oe/TCvkaSLSzP/wB4XL5brLBcMr AVSUBMi3KHJD7qzoHXdiAUloLrai8zm9gyP1fk2JLsIoi6fF/ONHkJU3cduZiQjoK3kf WSral2nKPLSw2tfY8VU0ezLBhGACFeCUWiKW12+kiMPIwpMxRN5Gq6qdeVlSah6jCp+4 2LdmcO3XXyCMHcqFvHumLpMDKUSfQQybbhvyqSFLAN54jaJyduXcTPHmWzYzPCZyqsoZ brROy60CUOk3VvxOrn1lRBbuJv6GpmHndaAZ8M4feeviJGzNgk9ZQVytGHYpIxXNm4+V XYxQ== X-Forwarded-Encrypted: i=1; AKwUvBzd1bwb/gmL30M45+pFbOqXdKqWHkKpqRkgRUCa5gXK7N3+iCEyfq33HD5UgXyPPYMSMTtrSp3nx2y4TAk=@vger.kernel.org X-Gm-Message-State: AFq9FYJI1wBIfShYBBiGDHHKijP0epxWnc2tiKhmVwsJNMYyjL/6QPz2 u14YDjTyNCAMXZgt0yZoeGlkBCipGxehImzPd4IyfQSSh/YQew+2pwetMmiI5zk2oRhIqwLpeZf aNftCdI17Lg== X-Received: from dlboz6.prod.google.com ([2002:a05:7022:1306:b0:17d:5c89:d111]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:701b:260d:b0:157:cbf6:89c4 with SMTP id a92af1059eb24-16a5faa76d7mr17664993c88.26.1791930402963; Tue, 13 Oct 2026 15:26:42 -0700 (PDT) Date: Tue, 13 Oct 2026 15:26:15 -0700 In-Reply-To: <20261013222622.1822619-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20261013182458.1234616-1-irogers@google.com> <20261013222622.1822619-1-irogers@google.com> X-Mailer: git-send-email 2.56.0.385.gd3acb90ef8-goog Message-ID: <20261013222622.1822619-4-irogers@google.com> Subject: [PATCH v2 03/10] tools headers: Synchronize linux/compiler-context-analysis.h with the kernel sources From: Ian Rogers To: irogers@google.com, acme@kernel.org, elver@google.com, namhyung@kernel.org Cc: adrian.hunter@intel.com, bvanassche@acm.org, james.clark@linaro.org, jolsa@kernel.org, justinstitt@google.com, linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, ljs@kernel.org, llvm@lists.linux.dev, mingo@redhat.com, morbo@google.com, nathan@kernel.org, ndesaulniers@google.com, peterz@infradead.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Replace the no-op stub tools/include/linux/compiler-context-analysis.h with the full kernel implementation from include/linux/compiler-context-analysis.h and add it to tools/perf/check-headers.sh so future changes are tracked. Assisted-by: Antigravity:gemini-3.1-pro Signed-off-by: Ian Rogers --- .../include/linux/compiler-context-analysis.h | 518 ++++++++++++++++-- tools/perf/check-headers.sh | 1 + 2 files changed, 480 insertions(+), 39 deletions(-) diff --git a/tools/include/linux/compiler-context-analysis.h b/tools/includ= e/linux/compiler-context-analysis.h index 13a9115e9e58..024e303188ad 100644 --- a/tools/include/linux/compiler-context-analysis.h +++ b/tools/include/linux/compiler-context-analysis.h @@ -1,42 +1,482 @@ /* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _TOOLS_LINUX_COMPILER_CONTEXT_ANALYSIS_H -#define _TOOLS_LINUX_COMPILER_CONTEXT_ANALYSIS_H - /* * Macros and attributes for compiler-based static context analysis. - * No-op stubs for tools. - */ - -#define __guarded_by(...) -#define __pt_guarded_by(...) - -#define context_lock_struct(name, ...) struct __VA_ARGS__ name - -#define __no_context_analysis -#define __context_unsafe(comment) -#define context_unsafe(...) ({ __VA_ARGS__; }) -#define context_unsafe_alias(p) -#define disable_context_analysis() -#define enable_context_analysis() - -#define __must_hold(...) -#define __must_not_hold(...) -#define __acquires(...) -#define __cond_acquires(ret, x) -#define __releases(...) -#define __acquire(x) (void)0 -#define __release(x) (void)0 - -#define __must_hold_shared(...) -#define __acquires_shared(...) -#define __cond_acquires_shared(ret, x) -#define __releases_shared(...) -#define __acquire_shared(x) (void)0 -#define __release_shared(x) (void)0 - -#define __acquire_ret(call, expr) (call) -#define __acquire_shared_ret(call, expr) (call) -#define __acquires_ret -#define __acquires_shared_ret - -#endif /* _TOOLS_LINUX_COMPILER_CONTEXT_ANALYSIS_H */ + */ + +#ifndef _LINUX_COMPILER_CONTEXT_ANALYSIS_H +#define _LINUX_COMPILER_CONTEXT_ANALYSIS_H + +#if defined(WARN_CONTEXT_ANALYSIS) && !defined(__CHECKER__) && !defined(__= GENKSYMS__) + +/* + * These attributes define new context lock (Clang: capability) types. + * Internal only. + */ +# define __ctx_lock_type(name) __attribute__((capability(#name))) +# define __reentrant_ctx_lock __attribute__((reentrant_capability)) +# define __acquires_ctx_lock(...) __attribute__((acquire_capability(__VA_= ARGS__))) +# define __acquires_shared_ctx_lock(...) __attribute__((acquire_shared_cap= ability(__VA_ARGS__))) +# define __try_acquires_ctx_lock(ret, var) __attribute__((try_acquire_capa= bility(ret, var))) +# define __try_acquires_shared_ctx_lock(ret, var) __attribute__((try_acqui= re_shared_capability(ret, var))) +# define __releases_ctx_lock(...) __attribute__((release_capability(__VA_= ARGS__))) +# define __releases_shared_ctx_lock(...) __attribute__((release_shared_cap= ability(__VA_ARGS__))) +# define __returns_ctx_lock(var) __attribute__((lock_returned(var))) + +/* + * The below are used to annotate code being checked. Internal only. + */ +# define __excludes_ctx_lock(...) __attribute__((locks_excluded(__VA_ARGS= __))) +# define __requires_ctx_lock(...) __attribute__((requires_capability(__VA= _ARGS__))) +# define __requires_shared_ctx_lock(...) __attribute__((requires_shared_ca= pability(__VA_ARGS__))) + +/* + * The "assert_capability" attribute is a bit confusingly named. It does n= ot + * generate a check. Instead, it tells the analysis to *assume* the capabi= lity + * is held. This is used for augmenting runtime assertions, that can then = help + * with patterns beyond the compiler's static reasoning abilities. + */ +# define __assumes_ctx_lock(...) __attribute__((assert_capability(__VA_AR= GS__))) +# define __assumes_shared_ctx_lock(...) __attribute__((assert_shared_capab= ility(__VA_ARGS__))) + +/** + * __guarded_by() - struct member and globals attribute, declares variable + * only accessible within active context + * @...: context lock instance pointer(s) + * + * Declares that the struct member or global variable is only accessible w= ithin + * the context entered by the given context lock(s). Read operations on th= e data + * require shared access to at least one of the context locks, while write + * operations require exclusive access to all listed context locks. + * + * .. code-block:: c + * + * struct some_state { + * spinlock_t lock; + * long counter __guarded_by(&lock); + * }; + * + * struct some_state { + * spinlock_t lock1, lock2; + * long counter __guarded_by(&lock1, &lock2); + * }; + */ +# define __guarded_by(...) __attribute__((guarded_by(__VA_ARGS__))) + +/** + * __pt_guarded_by() - struct member and globals attribute, declares point= ed-to + * data only accessible within active context + * @...: context lock instance pointer(s) + * + * Declares that the data pointed to by the struct member pointer or global + * pointer is only accessible within the context entered by the given cont= ext + * lock(s). Read operations on the data require shared access to at least = one + * of the context locks, while write operations require exclusive access t= o all + * listed context locks. + * + * .. code-block:: c + * + * struct some_state { + * spinlock_t lock; + * long *counter __pt_guarded_by(&lock); + * }; + * + * struct some_state { + * spinlock_t lock1, lock2; + * long *counter __pt_guarded_by(&lock1, &lock2); + * }; + */ +# define __pt_guarded_by(...) __attribute__((pt_guarded_by(__VA_ARGS__))) + +/** + * context_lock_struct() - declare or define a context lock struct + * @name: struct name + * + * Helper to declare or define a struct type that is also a context lock. + * + * .. code-block:: c + * + * context_lock_struct(my_handle) { + * int foo; + * long bar; + * }; + * + * struct some_state { + * ... + * }; + * // ... declared elsewhere ... + * context_lock_struct(some_state); + * + * Note: The implementation defines several helper functions that can acqu= ire + * and release the context lock. + */ +# define context_lock_struct(name, ...) \ + struct __ctx_lock_type(name) __VA_ARGS__ name; \ + static __always_inline void __acquire_ctx_lock(const struct name *var) = \ + __attribute__((overloadable)) __no_context_analysis __acquires_ctx_lock(= var) { } \ + static __always_inline void __acquire_shared_ctx_lock(const struct name *= var) \ + __attribute__((overloadable)) __no_context_analysis __acquires_shared_ct= x_lock(var) { } \ + static __always_inline bool __try_acquire_ctx_lock(const struct name *var= , bool ret) \ + __attribute__((overloadable)) __no_context_analysis __try_acquires_ctx_l= ock(1, var) \ + { return ret; } \ + static __always_inline bool __try_acquire_shared_ctx_lock(const struct na= me *var, bool ret) \ + __attribute__((overloadable)) __no_context_analysis __try_acquires_share= d_ctx_lock(1, var) \ + { return ret; } \ + static __always_inline void __release_ctx_lock(const struct name *var) = \ + __attribute__((overloadable)) __no_context_analysis __releases_ctx_lock(= var) { } \ + static __always_inline void __release_shared_ctx_lock(const struct name *= var) \ + __attribute__((overloadable)) __no_context_analysis __releases_shared_ct= x_lock(var) { } \ + static __always_inline void __assume_ctx_lock(const struct name *var) \ + __attribute__((overloadable)) __assumes_ctx_lock(var) { } \ + static __always_inline void __assume_shared_ctx_lock(const struct name *v= ar) \ + __attribute__((overloadable)) __assumes_shared_ctx_lock(var) { } \ + struct name + +/** + * disable_context_analysis() - disables context analysis + * + * Disables context analysis. Must be paired with a later + * enable_context_analysis(). + */ +# define disable_context_analysis() \ + __diag_push(); \ + __diag_ignore_all("-Wunknown-warning-option", "") \ + __diag_ignore_all("-Wthread-safety", "") \ + __diag_ignore_all("-Wthread-safety-pointer", "") + +/** + * enable_context_analysis() - re-enables context analysis + * + * Re-enables context analysis. Must be paired with a prior + * disable_context_analysis(). + */ +# define enable_context_analysis() __diag_pop() + +/** + * __no_context_analysis - function attribute, disables context analysis + * + * Function attribute denoting that context analysis is disabled for the + * whole function. Prefer use of `context_unsafe()` where possible. + */ +# define __no_context_analysis __attribute__((no_thread_safety_analysis)) + +#else /* !WARN_CONTEXT_ANALYSIS */ + +# define __ctx_lock_type(name) +# define __reentrant_ctx_lock +# define __acquires_ctx_lock(...) +# define __acquires_shared_ctx_lock(...) +# define __try_acquires_ctx_lock(ret, var) +# define __try_acquires_shared_ctx_lock(ret, var) +# define __releases_ctx_lock(...) +# define __releases_shared_ctx_lock(...) +# define __assumes_ctx_lock(...) +# define __assumes_shared_ctx_lock(...) +# define __returns_ctx_lock(var) +# define __guarded_by(...) +# define __pt_guarded_by(...) +# define __excludes_ctx_lock(...) +# define __requires_ctx_lock(...) +# define __requires_shared_ctx_lock(...) +# define __acquire_ctx_lock(var) do { } while (0) +# define __acquire_shared_ctx_lock(var) do { } while (0) +# define __try_acquire_ctx_lock(var, ret) (ret) +# define __try_acquire_shared_ctx_lock(var, ret) (ret) +# define __release_ctx_lock(var) do { } while (0) +# define __release_shared_ctx_lock(var) do { } while (0) +# define __assume_ctx_lock(var) do { (void)(var); } while (0) +# define __assume_shared_ctx_lock(var) do { (void)(var); } while (0) +# define context_lock_struct(name, ...) struct __VA_ARGS__ name +# define disable_context_analysis() +# define enable_context_analysis() +# define __no_context_analysis + +#endif /* WARN_CONTEXT_ANALYSIS */ + +/** + * context_unsafe() - disable context checking for contained code + * + * Disables context checking for contained statements or expression. + * + * .. code-block:: c + * + * struct some_data { + * spinlock_t lock; + * int counter __guarded_by(&lock); + * }; + * + * int foo(struct some_data *d) + * { + * // ... + * // other code that is still checked ... + * // ... + * return context_unsafe(d->counter); + * } + */ +#define context_unsafe(...) \ +({ \ + disable_context_analysis(); \ + __VA_ARGS__; \ + enable_context_analysis() \ +}) + +/** + * __context_unsafe() - function attribute, disable context checking + * @comment: comment explaining why opt-out is safe + * + * Function attribute denoting that context analysis is disabled for the + * whole function. Forces adding an inline comment as argument. + */ +#define __context_unsafe(comment) __no_context_analysis + +/** + * context_unsafe_alias() - helper to insert a context lock "alias barrier" + * @p: pointer aliasing a context lock or object containing context locks + * + * No-op function that acts as a "context lock alias barrier", where the + * analysis rightfully detects that we're switching aliases, but the switc= h is + * considered safe but beyond the analysis reasoning abilities. + * + * This should be inserted before the first use of such an alias. + * + * Implementation Note: The compiler ignores aliases that may be reassigne= d but + * their value cannot be determined (e.g. when passing a non-const pointer= to an + * alias as a function argument). + */ +#define context_unsafe_alias(p) _context_unsafe_alias((void **)&(p)) +static inline void _context_unsafe_alias(void **p) { (void)p; } + +/** + * token_context_lock() - declare an abstract global context lock instance + * @name: token context lock name + * + * Helper that declares an abstract global context lock instance @name, bu= t not + * backed by a real data structure (linker error if accidentally reference= d). + * The type name is `__ctx_lock_@name`. + */ +#define token_context_lock(name, ...) \ + context_lock_struct(__ctx_lock_##name, ##__VA_ARGS__) {}; \ + extern const struct __ctx_lock_##name *name + +/** + * token_context_lock_instance() - declare another instance of a global co= ntext lock + * @ctx: token context lock previously declared with token_context_lock() + * @name: name of additional global context lock instance + * + * Helper that declares an additional instance @name of the same token con= text + * lock class @ctx. This is helpful where multiple related token contexts = are + * declared, to allow using the same underlying type (`__ctx_lock_@ctx`) as + * function arguments. + */ +#define token_context_lock_instance(ctx, name) \ + extern const struct __ctx_lock_##ctx *name + +/* + * Common keywords for static context analysis. + */ + +/** + * __must_hold() - function attribute, caller must hold exclusive context = lock + * + * Function attribute declaring that the caller must hold the given context + * lock instance(s) exclusively. + */ +#define __must_hold(...) __requires_ctx_lock(__VA_ARGS__) + +/** + * __must_not_hold() - function attribute, caller must not hold context lo= ck + * + * Function attribute declaring that the caller must not hold the given co= ntext + * lock instance(s). + */ +#define __must_not_hold(...) __excludes_ctx_lock(__VA_ARGS__) + +/** + * __acquires() - function attribute, function acquires context lock exclu= sively + * + * Function attribute declaring that the function acquires the given conte= xt + * lock instance(s) exclusively, but does not release them. + */ +#define __acquires(...) __acquires_ctx_lock(__VA_ARGS__) + +/* + * Clang's analysis does not care precisely about the value, only that it = is + * either zero or non-zero. So the __cond_acquires() interface might be + * misleading if we say that @ret is the value returned if acquired. Inste= ad, + * provide symbolic variants which we translate. + */ +#define __cond_acquires_impl_true(x, ...) __try_acquires##__VA_ARGS__#= #_ctx_lock(1, x) +#define __cond_acquires_impl_false(x, ...) __try_acquires##__VA_ARGS__#= #_ctx_lock(0, x) +#define __cond_acquires_impl_nonzero(x, ...) __try_acquires##__VA_ARGS__#= #_ctx_lock(1, x) +#define __cond_acquires_impl_0(x, ...) __try_acquires##__VA_ARGS__#= #_ctx_lock(0, x) +#define __cond_acquires_impl_nonnull(x, ...) __try_acquires##__VA_ARGS__#= #_ctx_lock(1, x) +#define __cond_acquires_impl_NULL(x, ...) __try_acquires##__VA_ARGS__#= #_ctx_lock(0, x) + +/** + * __cond_acquires() - function attribute, function conditionally + * acquires a context lock exclusively + * @ret: abstract value returned by function if context lock acquired + * @x: context lock instance pointer + * + * Function attribute declaring that the function conditionally acquires t= he + * given context lock instance @x exclusively, but does not release it. The + * function return value @ret denotes when the context lock is acquired. + * + * @ret may be one of: true, false, nonzero, 0, nonnull, NULL. + */ +#define __cond_acquires(ret, x) __cond_acquires_impl_##ret(x) + +/** + * __releases() - function attribute, function releases a context lock exc= lusively + * + * Function attribute declaring that the function releases the given conte= xt + * lock instance(s) exclusively. The associated context(s) must be active = on + * entry. + */ +#define __releases(...) __releases_ctx_lock(__VA_ARGS__) + +/* + * Clang's analysis does not care precisely about the value, only that it = is + * either zero or non-zero. So the __cond_acquires() interface might be + * misleading if we say that @ret is the value returned if acquired. Inste= ad, + * provide symbolic variants which we translate. + */ +#define __cond_acquires_impl_not_true(x, ...) __try_acquires##__VA_ARG= S__##_ctx_lock(0, x) +#define __cond_acquires_impl_not_false(x, ...) __try_acquires##__VA_ARG= S__##_ctx_lock(1, x) +#define __cond_acquires_impl_not_nonzero(x, ...) __try_acquires##__VA_ARG= S__##_ctx_lock(0, x) +#define __cond_acquires_impl_not_0(x, ...) __try_acquires##__VA_ARG= S__##_ctx_lock(1, x) +#define __cond_acquires_impl_not_nonnull(x, ...) __try_acquires##__VA_ARG= S__##_ctx_lock(0, x) +#define __cond_acquires_impl_not_NULL(x, ...) __try_acquires##__VA_ARG= S__##_ctx_lock(1, x) + +/** + * __cond_releases() - function attribute, function conditionally + * releases a context lock exclusively + * @ret: abstract value returned by function if context lock releases + * @x: context lock instance pointer + * + * Function attribute declaring that the function conditionally releases t= he + * given context lock instance @x exclusively. The associated context(s) m= ust + * be active on entry. The function return value @ret denotes when the con= text + * lock is released. + * + * @ret may be one of: true, false, nonzero, 0, nonnull, NULL. + * + * NOTE: clang does not have a native attribute for this; instead implement + * it as an unconditional release and a conditional acquire for the + * inverted condition -- which is semantically equivalent. + */ +#define __cond_releases(ret, x) __releases(x) __cond_acquires_impl_not_##r= et(x) + +/** + * __acquire() - function to acquire context lock exclusively + * @x: context lock instance pointer + * + * No-op function that acquires the given context lock instance @x exclusi= vely. + */ +#define __acquire(x) __acquire_ctx_lock(x) + +/** + * __release() - function to release context lock exclusively + * @x: context lock instance pointer + * + * No-op function that releases the given context lock instance @x. + */ +#define __release(x) __release_ctx_lock(x) + +/** + * __must_hold_shared() - function attribute, caller must hold shared cont= ext lock + * + * Function attribute declaring that the caller must hold the given context + * lock instance(s) with shared access. + */ +#define __must_hold_shared(...) __requires_shared_ctx_lock(__VA_ARGS__) + +/** + * __acquires_shared() - function attribute, function acquires context loc= k shared + * + * Function attribute declaring that the function acquires the given + * context lock instance(s) with shared access, but does not release them. + */ +#define __acquires_shared(...) __acquires_shared_ctx_lock(__VA_ARGS__) + +/** + * __cond_acquires_shared() - function attribute, function conditionally + * acquires a context lock shared + * @ret: abstract value returned by function if context lock acquired + * @x: context lock instance pointer + * + * Function attribute declaring that the function conditionally acquires t= he + * given context lock instance @x with shared access, but does not release= it. + * The function return value @ret denotes when the context lock is acquire= d. + * + * @ret may be one of: true, false, nonzero, 0, nonnull, NULL. + */ +#define __cond_acquires_shared(ret, x) __cond_acquires_impl_##ret(x, _shar= ed) + +/** + * __releases_shared() - function attribute, function releases a + * context lock shared + * + * Function attribute declaring that the function releases the given conte= xt + * lock instance(s) with shared access. The associated context(s) must be + * active on entry. + */ +#define __releases_shared(...) __releases_shared_ctx_lock(__VA_ARGS__) + +/** + * __acquire_shared() - function to acquire context lock shared + * @x: context lock instance pointer + * + * No-op function that acquires the given context lock instance @x with sh= ared + * access. + */ +#define __acquire_shared(x) __acquire_shared_ctx_lock(x) + +/** + * __release_shared() - function to release context lock shared + * @x: context lock instance pointer + * + * No-op function that releases the given context lock instance @x with sh= ared + * access. + */ +#define __release_shared(x) __release_shared_ctx_lock(x) + +/** + * __acquire_ret() - helper to acquire context lock of return value + * @call: call expression + * @ret_expr: acquire expression that uses __ret + */ +#define __acquire_ret(call, ret_expr) \ + ({ \ + __auto_type __ret =3D call; \ + __acquire(ret_expr); \ + __ret; \ + }) + +/** + * __acquire_shared_ret() - helper to acquire context lock shared of retur= n value + * @call: call expression + * @ret_expr: acquire shared expression that uses __ret + */ +#define __acquire_shared_ret(call, ret_expr) \ + ({ \ + __auto_type __ret =3D call; \ + __acquire_shared(ret_expr); \ + __ret; \ + }) + +/* + * Attributes to mark functions returning acquired context locks. + * + * This is purely cosmetic to help readability, and should be used with the + * above macros as follows: + * + * struct foo { spinlock_t lock; ... }; + * ... + * #define myfunc(...) __acquire_ret(_myfunc(__VA_ARGS__), &__ret->lock) + * struct foo *_myfunc(int bar) __acquires_ret; + * ... + */ +#define __acquires_ret __no_context_analysis +#define __acquires_shared_ret __no_context_analysis + +#endif /* _LINUX_COMPILER_CONTEXT_ANALYSIS_H */ diff --git a/tools/perf/check-headers.sh b/tools/perf/check-headers.sh index 531c0e0e84df..c6b2ecadf9b1 100755 --- a/tools/perf/check-headers.sh +++ b/tools/perf/check-headers.sh @@ -23,6 +23,7 @@ declare -a FILES=3D( "include/linux/bits.h" "include/vdso/bits.h" "include/linux/cfi_types.h" + "include/linux/compiler-context-analysis.h" "include/linux/const.h" "include/vdso/const.h" "include/vdso/unaligned.h" --=20 2.56.0.385.gd3acb90ef8-goog From nobody Sat Oct 24 13:20:37 2026 Received: from mail-dy1-f197.google.com (mail-dy1-f197.google.com [74.125.82.197]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0D5445625FC for ; Tue, 13 Oct 2026 22:26:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.197 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791930409; cv=none; b=AO8pzkW920J1oMKZqZ3pcLjTgkmrVHGroTjKvJFYZht0ggqvt8csJLOuQ0O/tF0B2kKAPCwER1KMv7Yy9O8+MqYUD88E2K4xLJeVDhWaD8gpNBlE575z3qhZVYpszqwuo1hwJ8KQ7IV6q0wNglM/BCwaDzHH7g72okEa3cf68TQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791930409; c=relaxed/simple; bh=8tzX56A32caS6UYQo7S6LUI2sWnaceFsyPigWewG/TE=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=b8TihkvZWcAmhIY37R5/c+arLlZZnoMH3rF1LSNmQz2+AWjGvgpXeGMShApmYdiw126cgamZeHmkApIUWLt+KilpkUsxeGfoESNMO8mxm9EENwIT6IyiGieSkO0LkdqViHJf0QktQa/zPwSdh0wVaYnkQv4GJ7NhNtxSA0P80T8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=EAICEWW4; arc=none smtp.client-ip=74.125.82.197 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="EAICEWW4" Received: by mail-dy1-f197.google.com with SMTP id 5a478bee46e88-35a4d2e39acso1151016eec.1 for ; Tue, 13 Oct 2026 15:26:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1791930406; x=1792535206; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=VHdExMOnJlSZSSM6L7wDonePKQsGb0yHF23X81O15cQ=; b=EAICEWW4wPsGudSbXcEoOlQBeiLqRnooLxOCeueD3AW5TGe5DI8ODjIusTCAql4haK U31B3JOW3X4wHP/CgOpDjXbd55L7yBBG/7u5CuvcPy/LOk9racRLhdAHw+jtmtQYd6Jf HkaVrdI3Rq4FOqvWs5Enwa3iMb6edddyplmPti2fNS5sHAcFBlL22eFmi97ulJA7bh9U cfysqJSifljm/62nwU7Zw5C4hrSKqORb/o1krK5/PliDGj7YAPE27FaUV807QgIgiXnH eENWk5SivWk1pc4aGWPm5dWiuaZj7e8sdZWGkOs8WmM6Mv0OatzMU+SAhvpVENMdbLB5 V6Hg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1791930406; x=1792535206; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=VHdExMOnJlSZSSM6L7wDonePKQsGb0yHF23X81O15cQ=; b=Qf0XYBoqrcdu5mXgsUvKWfQlk00OGXRoJwWSeDaEJt+prdvVLh5CHDUUvKdD4GPYOQ MGdzrPV9FI21pTBoA4l8OJ4b8vFS3zX0WWmhYbbKCyBN7QGegr+Qh4ue3nxcGgwECSBh XB0m+KK1ZfeOkGmFNaOntl1nDqKypboV21Mmwn0AExbdRYXHcYHmEOximbdOaZLGE5wO 9XXCn8aMKHhg+XIw+BIQ5Nec9YBy9BhbRwR+VwakZK5stpOH5Cs2MNI20BEnLZu6zaRk joTYprZviR6JooaaxVDjFnoNitle/swHnLfXNZ9OH5xAmgsIaYQl4Ml6VGtYtVqWLcPP 3lKw== X-Forwarded-Encrypted: i=1; AKwUvBzH/kyouiW+2GEW2WVvPg1U189+4iqiWrJvtQqsL13yC7PdQHgUurnHM7P2U5R+OYRaGWIL/i2V54zkf6c=@vger.kernel.org X-Gm-Message-State: AFq9FYIq2AePwOIsw42vkwhmdtT1jgrEAZf0mBDa431SuADYxmYlRBpp RMjw7WwHdthgIW/dD7rQfakyHckaG9MbyGVP/I1yu6q4MFrN49lf6TJPDz7GP867MAPUBTKBw5W Nyl196gSwkw== X-Received: from dli22-n1.prod.google.com ([2002:a05:7022:296:10b0:150:117b:cbf8]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:701b:42c9:10b0:15c:705f:b981 with SMTP id a92af1059eb24-16a6043c616mr20628080c88.32.1791930405847; Tue, 13 Oct 2026 15:26:45 -0700 (PDT) Date: Tue, 13 Oct 2026 15:26:16 -0700 In-Reply-To: <20261013222622.1822619-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20261013182458.1234616-1-irogers@google.com> <20261013222622.1822619-1-irogers@google.com> X-Mailer: git-send-email 2.56.0.385.gd3acb90ef8-goog Message-ID: <20261013222622.1822619-5-irogers@google.com> Subject: [PATCH v2 04/10] perf mutex: Use kernel style compiler-context-analysis.h annotations From: Ian Rogers To: irogers@google.com, acme@kernel.org, elver@google.com, namhyung@kernel.org Cc: adrian.hunter@intel.com, bvanassche@acm.org, james.clark@linaro.org, jolsa@kernel.org, justinstitt@google.com, linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, ljs@kernel.org, llvm@lists.linux.dev, mingo@redhat.com, morbo@google.com, nathan@kernel.org, ndesaulniers@google.com, peterz@infradead.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Enable -DWARN_CONTEXT_ANALYSIS alongside -Wthread-safety for Clang builds in tools/perf/Makefile.config, replace the custom lock safety macros in tools/perf with the kernel's compiler-context-analysis.h annotations (context_lock_struct, __guarded_by, __acquires, __acquires_shared, __releases, __releases_shared, __cond_acquires, __must_hold, __must_hold_shared, __must_not_hold, __returns_ctx_lock, __no_context_analysis, and __context_unsafe), and remove the redundant macro definitions from tools/perf/util/mutex.h. Assisted-by: Antigravity:gemini-3.1-pro Signed-off-by: Ian Rogers --- tools/perf/Makefile.config | 2 +- tools/perf/builtin-sched.c | 16 +++---- tools/perf/builtin-top.c | 4 +- tools/perf/util/annotate.c | 4 +- tools/perf/util/annotate.h | 8 ++-- tools/perf/util/comm.c | 4 +- tools/perf/util/dso.c | 26 +++++----- tools/perf/util/dso.h | 8 ++-- tools/perf/util/dsos.c | 6 +-- tools/perf/util/intel-tpebs.c | 6 +-- tools/perf/util/libbfd.c | 4 +- tools/perf/util/mutex.c | 4 +- tools/perf/util/mutex.h | 90 +++-------------------------------- tools/perf/util/rwsem.c | 8 ++-- tools/perf/util/rwsem.h | 10 ++-- tools/perf/util/thread.c | 8 ++-- tools/perf/util/thread.h | 2 +- 17 files changed, 66 insertions(+), 144 deletions(-) diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index cafc7be79643..39442577418e 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -64,7 +64,7 @@ ifeq ($(CC_NO_CLANG), 0) endif =20 # Enabled Wthread-safety analysis for clang builds. - CFLAGS +=3D -Wthread-safety + CFLAGS +=3D -Wthread-safety -DWARN_CONTEXT_ANALYSIS endif =20 include $(srctree)/tools/scripts/Makefile.arch diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 39571f03eda2..ee74a6aa5ea3 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -828,8 +828,8 @@ static void *thread_func(void *ctx) } =20 static void create_tasks(struct perf_sched *sched) - EXCLUSIVE_LOCK_FUNCTION(sched->start_work_mutex) - EXCLUSIVE_LOCK_FUNCTION(sched->work_done_wait_mutex) + __acquires(&sched->start_work_mutex) + __acquires(&sched->work_done_wait_mutex) { struct task_desc *task; pthread_attr_t attr; @@ -858,8 +858,8 @@ static void create_tasks(struct perf_sched *sched) } =20 static void destroy_tasks(struct perf_sched *sched) - UNLOCK_FUNCTION(sched->start_work_mutex) - UNLOCK_FUNCTION(sched->work_done_wait_mutex) + __releases(&sched->start_work_mutex) + __releases(&sched->work_done_wait_mutex) { struct task_desc *task; unsigned long i; @@ -878,8 +878,8 @@ static void destroy_tasks(struct perf_sched *sched) } =20 static void wait_for_tasks(struct perf_sched *sched) - EXCLUSIVE_LOCKS_REQUIRED(sched->work_done_wait_mutex) - EXCLUSIVE_LOCKS_REQUIRED(sched->start_work_mutex) + __must_hold(&sched->work_done_wait_mutex) + __must_hold(&sched->start_work_mutex) { u64 cpu_usage_0, cpu_usage_1; struct task_desc *task; @@ -930,8 +930,8 @@ static void wait_for_tasks(struct perf_sched *sched) } =20 static void run_one_test(struct perf_sched *sched) - EXCLUSIVE_LOCKS_REQUIRED(sched->work_done_wait_mutex) - EXCLUSIVE_LOCKS_REQUIRED(sched->start_work_mutex) + __must_hold(&sched->work_done_wait_mutex) + __must_hold(&sched->start_work_mutex) { u64 T0, T1, delta, avg_delta, fluct; =20 diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index a3442d2d6edf..9049db154fa4 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -201,7 +201,7 @@ static void perf_top__record_precise_ip(struct perf_top= *top, struct hist_entry *he, struct perf_sample *sample, u64 ip) - EXCLUSIVE_LOCKS_REQUIRED(he->hists->lock) + __must_hold(&he->hists->lock) { struct annotation *notes; struct symbol *sym =3D he->ms.sym; @@ -730,7 +730,7 @@ static void *display_thread(void *arg) static int hist_iter__top_callback(struct hist_entry_iter *iter, struct addr_location *al, bool single, void *arg) - EXCLUSIVE_LOCKS_REQUIRED(iter->he->hists->lock) + __must_hold(&iter->he->hists->lock) { struct perf_top *top =3D arg; =20 diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 86a4beec6528..c466757e8508 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -655,7 +655,7 @@ static struct mutex *annotation__get_mutex(const struct= annotation *notes) } =20 void annotation__lock(struct annotation *notes) - NO_THREAD_SAFETY_ANALYSIS + __no_context_analysis { struct mutex *mutex =3D annotation__get_mutex(notes); =20 @@ -664,7 +664,7 @@ void annotation__lock(struct annotation *notes) } =20 void annotation__unlock(struct annotation *notes) - NO_THREAD_SAFETY_ANALYSIS + __no_context_analysis { struct mutex *mutex =3D annotation__get_mutex(notes); =20 diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 1b47c1156b9a..f5465c931721 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -369,7 +369,7 @@ struct annotated_branch { u64 *br_cntr; }; =20 -struct LOCKABLE annotation { +context_lock_struct(annotation) { struct annotated_source *src; struct annotated_branch *branch; }; @@ -379,9 +379,9 @@ static inline void annotation__init(struct annotation *= notes __maybe_unused) } void annotation__exit(struct annotation *notes); =20 -void annotation__lock(struct annotation *notes) EXCLUSIVE_LOCK_FUNCTION(*n= otes); -void annotation__unlock(struct annotation *notes) UNLOCK_FUNCTION(*notes); -bool annotation__trylock(struct annotation *notes) EXCLUSIVE_TRYLOCK_FUNCT= ION(true, *notes); +void annotation__lock(struct annotation *notes) __acquires(notes); +void annotation__unlock(struct annotation *notes) __releases(notes); +bool annotation__trylock(struct annotation *notes) __cond_acquires(true, n= otes); =20 static inline int annotation__cycles_width(struct annotation *notes) { diff --git a/tools/perf/util/comm.c b/tools/perf/util/comm.c index 9880247a2c33..6343a3c9debe 100644 --- a/tools/perf/util/comm.c +++ b/tools/perf/util/comm.c @@ -24,7 +24,7 @@ static struct comm_strs { static void comm_strs__remove_if_last(struct comm_str *cs); =20 static void comm_strs__init(void) - NO_THREAD_SAFETY_ANALYSIS /* Inherently single threaded due to pthread_on= ce. */ + __context_unsafe(/* Inherently single threaded due to pthread_once. */) { init_rwsem(&_comm_strs.lock); _comm_strs.capacity =3D 16; @@ -120,7 +120,7 @@ static void comm_strs__remove_if_last(struct comm_str *= cs) } =20 static struct comm_str *__comm_strs__find(struct comm_strs *comm_strs, con= st char *str) - SHARED_LOCKS_REQUIRED(comm_strs->lock) + __must_hold_shared(&comm_strs->lock) { struct comm_str **result; =20 diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index d3017c82ffb5..ff5b30a3d424 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -525,14 +525,14 @@ void dso__set_module_info(struct dso *dso, struct kmo= d_path *m, */ struct mutex _dso__data_open_lock; static LIST_HEAD(dso__data_open); -static long dso__data_open_cnt GUARDED_BY(_dso__data_open_lock); +static long dso__data_open_cnt __guarded_by(&_dso__data_open_lock); =20 static void dso__data_open_lock_init(void) { mutex_init(&_dso__data_open_lock); } =20 -static struct mutex *dso__data_open_lock(void) LOCK_RETURNED(_dso__data_op= en_lock) +static struct mutex *dso__data_open_lock(void) __returns_ctx_lock(&_dso__d= ata_open_lock) { static pthread_once_t data_open_lock_once =3D PTHREAD_ONCE_INIT; =20 @@ -541,7 +541,7 @@ static struct mutex *dso__data_open_lock(void) LOCK_RET= URNED(_dso__data_open_loc return &_dso__data_open_lock; } =20 -static void dso__list_add(struct dso *dso) EXCLUSIVE_LOCKS_REQUIRED(_dso__= data_open_lock) +static void dso__list_add(struct dso *dso) __must_hold(&_dso__data_open_lo= ck) { list_add_tail(&dso__data(dso)->open_entry, &dso__data_open); #ifdef REFCNT_CHECKING @@ -552,7 +552,7 @@ static void dso__list_add(struct dso *dso) EXCLUSIVE_LO= CKS_REQUIRED(_dso__data_o dso__data_open_cnt++; } =20 -static void dso__list_del(struct dso *dso) EXCLUSIVE_LOCKS_REQUIRED(_dso__= data_open_lock) +static void dso__list_del(struct dso *dso) __must_hold(&_dso__data_open_lo= ck) { list_del_init(&dso__data(dso)->open_entry); #ifdef REFCNT_CHECKING @@ -567,7 +567,7 @@ static void dso__list_del(struct dso *dso) EXCLUSIVE_LO= CKS_REQUIRED(_dso__data_o =20 static void close_first_dso(void); =20 -static int do_open(char *name) EXCLUSIVE_LOCKS_REQUIRED(_dso__data_open_lo= ck) +static int do_open(char *name) __must_hold(&_dso__data_open_lock) { do { int fd =3D open(name, O_RDONLY|O_CLOEXEC); @@ -670,7 +670,7 @@ void dso__put_filename(struct dso *dso __maybe_unused, = char *filename, bool deco } =20 static int __open_dso(struct dso *dso, struct machine *machine) - EXCLUSIVE_LOCKS_REQUIRED(_dso__data_open_lock) + __must_hold(&_dso__data_open_lock) { int fd =3D -EINVAL; char *name; @@ -703,7 +703,7 @@ static void check_data_close(void); * list/count of open DSO objects. */ static int open_dso(struct dso *dso, struct machine *machine) - EXCLUSIVE_LOCKS_REQUIRED(_dso__data_open_lock) + __must_hold(&_dso__data_open_lock) { int fd; struct nscookie nsc; @@ -729,7 +729,7 @@ static int open_dso(struct dso *dso, struct machine *ma= chine) return fd; } =20 -static void close_data_fd(struct dso *dso) EXCLUSIVE_LOCKS_REQUIRED(_dso__= data_open_lock) +static void close_data_fd(struct dso *dso) __must_hold(&_dso__data_open_lo= ck) { if (dso__data(dso)->fd >=3D 0) { close(dso__data(dso)->fd); @@ -746,12 +746,12 @@ static void close_data_fd(struct dso *dso) EXCLUSIVE_= LOCKS_REQUIRED(_dso__data_o * Close @dso's data file descriptor and updates * list/count of open DSO objects. */ -static void close_dso(struct dso *dso) EXCLUSIVE_LOCKS_REQUIRED(_dso__data= _open_lock) +static void close_dso(struct dso *dso) __must_hold(&_dso__data_open_lock) { close_data_fd(dso); } =20 -static void close_first_dso(void) EXCLUSIVE_LOCKS_REQUIRED(_dso__data_open= _lock) +static void close_first_dso(void) __must_hold(&_dso__data_open_lock) { struct dso_data *dso_data; struct dso *dso; @@ -796,7 +796,7 @@ void reset_fd_limit(void) fd_limit =3D 0; } =20 -static bool may_cache_fd(void) EXCLUSIVE_LOCKS_REQUIRED(_dso__data_open_lo= ck) +static bool may_cache_fd(void) __must_hold(&_dso__data_open_lock) { if (!fd_limit) fd_limit =3D get_fd_limit(); @@ -812,7 +812,7 @@ static bool may_cache_fd(void) EXCLUSIVE_LOCKS_REQUIRED= (_dso__data_open_lock) * for opened dso file descriptors. The limit is half * of the RLIMIT_NOFILE files opened. */ -static void check_data_close(void) EXCLUSIVE_LOCKS_REQUIRED(_dso__data_ope= n_lock) +static void check_data_close(void) __must_hold(&_dso__data_open_lock) { bool cache_fd =3D may_cache_fd(); =20 @@ -834,7 +834,7 @@ void dso__data_close(struct dso *dso) } =20 static void try_to_open_dso(struct dso *dso, struct machine *machine) - EXCLUSIVE_LOCKS_REQUIRED(_dso__data_open_lock) + __must_hold(&_dso__data_open_lock) { enum dso_binary_type binary_type_data[] =3D { DSO_BINARY_TYPE__BUILD_ID_CACHE, diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index 3f08d45e7f53..54aaa88f574e 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h @@ -808,7 +808,7 @@ void __dso__improve_id(struct dso *dso, const struct ds= o_id *id); int dso__name_len(const struct dso *dso); =20 struct dso *dso__get(struct dso *dso); -void dso__put(struct dso *dso) LOCKS_EXCLUDED(_dso__data_open_lock); +void dso__put(struct dso *dso) __must_not_hold(&_dso__data_open_lock); =20 static inline void __dso__zput(struct dso **dso) { @@ -918,9 +918,9 @@ void dso__set_module_info(struct dso *dso, struct kmod_= path *m, * TODO */ bool dso__data_get_fd(struct dso *dso, struct machine *machine, int *fd) - EXCLUSIVE_TRYLOCK_FUNCTION(true, _dso__data_open_lock); -void dso__data_put_fd(struct dso *dso) UNLOCK_FUNCTION(_dso__data_open_loc= k); -void dso__data_close(struct dso *dso) LOCKS_EXCLUDED(_dso__data_open_lock); + __cond_acquires(true, &_dso__data_open_lock); +void dso__data_put_fd(struct dso *dso) __releases(&_dso__data_open_lock); +void dso__data_close(struct dso *dso) __must_not_hold(&_dso__data_open_loc= k); =20 int dso__data_file_size(struct dso *dso, struct machine *machine); off_t dso__data_size(struct dso *dso, struct machine *machine); diff --git a/tools/perf/util/dsos.c b/tools/perf/util/dsos.c index e927e707abac..a2cd37bd1660 100644 --- a/tools/perf/util/dsos.c +++ b/tools/perf/util/dsos.c @@ -157,7 +157,7 @@ static struct dso *__dsos__find_by_longname_id(struct d= sos *dsos, const char *name, const struct dso_id *id, bool write_locked) - SHARED_LOCKS_REQUIRED(dsos->lock) + __must_hold_shared(&dsos->lock) { struct dsos__key key =3D { .long_name =3D name, @@ -266,7 +266,7 @@ static int dsos__find_id_cb(struct dso *dso, void *data) =20 static struct dso *__dsos__find_id(struct dsos *dsos, const char *name, co= nst struct dso_id *id, bool cmp_short, bool write_locked) - SHARED_LOCKS_REQUIRED(dsos->lock) + __must_hold_shared(&dsos->lock) { struct dso *res; =20 @@ -330,7 +330,7 @@ static struct dso *__dsos__addnew_id(struct dsos *dsos,= const char *name, const } =20 static struct dso *__dsos__findnew_id(struct dsos *dsos, const char *name,= const struct dso_id *id) - SHARED_LOCKS_REQUIRED(dsos->lock) + __must_hold_shared(&dsos->lock) { struct dso *dso =3D __dsos__find_id(dsos, name, id, false, /*write_locked= =3D*/true); =20 diff --git a/tools/perf/util/intel-tpebs.c b/tools/perf/util/intel-tpebs.c index b41171b5df77..7c0b8b15bd10 100644 --- a/tools/perf/util/intel-tpebs.c +++ b/tools/perf/util/intel-tpebs.c @@ -69,7 +69,7 @@ static struct mutex *tpebs_mtx_get(void) } =20 static struct tpebs_retire_lat *tpebs_retire_lat__find(struct evsel *evsel) - EXCLUSIVE_LOCKS_REQUIRED(tpebs_mtx_get()); + __must_hold(tpebs_mtx_get()); =20 static int evsel__tpebs_start_perf_record(struct evsel *evsel) { @@ -244,7 +244,7 @@ static void *__sample_reader(void *arg __maybe_unused) return NULL; } =20 -static int tpebs_send_record_cmd(const char *msg) EXCLUSIVE_LOCKS_REQUIRED= (tpebs_mtx_get()) +static int tpebs_send_record_cmd(const char *msg) __must_hold(tpebs_mtx_ge= t()) { struct pollfd pollfd =3D { .events =3D POLLIN, }; int ret, len, retries =3D 0; @@ -321,7 +321,7 @@ static int tpebs_send_record_cmd(const char *msg) EXCLU= SIVE_LOCKS_REQUIRED(tpebs /* * tpebs_stop - stop the sample data read thread and the perf record proce= ss. */ -static int tpebs_stop(void) EXCLUSIVE_LOCKS_REQUIRED(tpebs_mtx_get()) +static int tpebs_stop(void) __must_hold(tpebs_mtx_get()) { int ret =3D 0; =20 diff --git a/tools/perf/util/libbfd.c b/tools/perf/util/libbfd.c index a907d7c1ac94..adeb1f1c5016 100644 --- a/tools/perf/util/libbfd.c +++ b/tools/perf/util/libbfd.c @@ -51,13 +51,13 @@ struct a2l_data { asymbol **syms; }; =20 -static bool perf_bfd_lock(void *bfd_mutex) NO_THREAD_SAFETY_ANALYSIS +static bool perf_bfd_lock(void *bfd_mutex) __no_context_analysis { mutex_lock(bfd_mutex); return true; } =20 -static bool perf_bfd_unlock(void *bfd_mutex) NO_THREAD_SAFETY_ANALYSIS +static bool perf_bfd_unlock(void *bfd_mutex) __no_context_analysis { mutex_unlock(bfd_mutex); return true; diff --git a/tools/perf/util/mutex.c b/tools/perf/util/mutex.c index 7aa1f3f55a7d..99965eec983e 100644 --- a/tools/perf/util/mutex.c +++ b/tools/perf/util/mutex.c @@ -56,13 +56,13 @@ void mutex_destroy(struct mutex *mtx) } =20 void mutex_lock(struct mutex *mtx) - NO_THREAD_SAFETY_ANALYSIS + __no_context_analysis { CHECK_ERR(pthread_mutex_lock(&mtx->lock)); } =20 void mutex_unlock(struct mutex *mtx) - NO_THREAD_SAFETY_ANALYSIS + __no_context_analysis { CHECK_ERR(pthread_mutex_unlock(&mtx->lock)); } diff --git a/tools/perf/util/mutex.h b/tools/perf/util/mutex.h index 555493767588..424ce2989b6c 100644 --- a/tools/perf/util/mutex.h +++ b/tools/perf/util/mutex.h @@ -4,91 +4,13 @@ =20 #include #include - -/* - * A function-like feature checking macro that is a wrapper around - * `__has_attribute`, which is defined by GCC 5+ and Clang and evaluates t= o a - * nonzero constant integer if the attribute is supported or 0 if not. - */ -#ifdef __has_attribute -#define HAVE_ATTRIBUTE(x) __has_attribute(x) -#else -#define HAVE_ATTRIBUTE(x) 0 -#endif - -#if HAVE_ATTRIBUTE(guarded_by) && HAVE_ATTRIBUTE(pt_guarded_by) && \ - HAVE_ATTRIBUTE(lockable) && HAVE_ATTRIBUTE(exclusive_lock_function) && \ - HAVE_ATTRIBUTE(exclusive_trylock_function) && HAVE_ATTRIBUTE(exclusive_lo= cks_required) && \ - HAVE_ATTRIBUTE(no_thread_safety_analysis) - -/* Documents if a shared field or global variable needs to be protected by= a mutex. */ -#define GUARDED_BY(x) __attribute__((guarded_by(x))) - -/* - * Documents if the memory location pointed to by a pointer should be guar= ded by - * a mutex when dereferencing the pointer. - */ -#define PT_GUARDED_BY(x) __attribute__((pt_guarded_by(x))) - -/* Documents if a type is a lockable type. */ -#define LOCKABLE __attribute__((lockable)) - -/* Documents a function that expects a lock not to be held prior to entry.= */ -#define LOCKS_EXCLUDED(...) __attribute__((locks_excluded(__VA_ARGS__))) - -/* Documents a function that returns a lock. */ -#define LOCK_RETURNED(x) __attribute__((lock_returned(x))) - -/* Documents functions that acquire a lock in the body of a function, and = do not release it. */ -#define EXCLUSIVE_LOCK_FUNCTION(...) __attribute__((exclusive_lock_functi= on(__VA_ARGS__))) - -/* - * Documents functions that acquire a shared (reader) lock in the body of a - * function, and do not release it. - */ -#define SHARED_LOCK_FUNCTION(...) __attribute__((shared_lock_function(__V= A_ARGS__))) - -/* - * Documents functions that expect a lock to be held on entry to the funct= ion, - * and release it in the body of the function. - */ -#define UNLOCK_FUNCTION(...) __attribute__((unlock_function(__VA_ARGS__))) - -/* Documents functions that try to acquire a lock, and return success or f= ailure. */ -#define EXCLUSIVE_TRYLOCK_FUNCTION(...) \ - __attribute__((exclusive_trylock_function(__VA_ARGS__))) - -/* Documents a function that expects a mutex to be held prior to entry. */ -#define EXCLUSIVE_LOCKS_REQUIRED(...) __attribute__((exclusive_locks_requi= red(__VA_ARGS__))) - -/* Documents a function that expects a shared (reader) lock to be held pri= or to entry. */ -#define SHARED_LOCKS_REQUIRED(...) __attribute__((shared_locks_required(__= VA_ARGS__))) - -/* Turns off thread safety checking within the body of a particular functi= on. */ -#define NO_THREAD_SAFETY_ANALYSIS __attribute__((no_thread_safety_analysis= )) - -#else - -#define GUARDED_BY(x) -#define PT_GUARDED_BY(x) -#define LOCKABLE -#define LOCKS_EXCLUDED(...) -#define LOCK_RETURNED(x) -#define EXCLUSIVE_LOCK_FUNCTION(...) -#define SHARED_LOCK_FUNCTION(...) -#define UNLOCK_FUNCTION(...) -#define EXCLUSIVE_TRYLOCK_FUNCTION(...) -#define EXCLUSIVE_LOCKS_REQUIRED(...) -#define SHARED_LOCKS_REQUIRED(...) -#define NO_THREAD_SAFETY_ANALYSIS - -#endif +#include =20 /* * A wrapper around the mutex implementation that allows perf to error che= ck * usage, etc. */ -struct LOCKABLE mutex { +context_lock_struct(mutex) { pthread_mutex_t lock; }; =20 @@ -144,10 +66,10 @@ void mutex_init_pshared(struct mutex *mtx); void mutex_init_recursive(struct mutex *mtx); void mutex_destroy(struct mutex *mtx); =20 -void mutex_lock(struct mutex *mtx) EXCLUSIVE_LOCK_FUNCTION(*mtx); -void mutex_unlock(struct mutex *mtx) UNLOCK_FUNCTION(*mtx); +void mutex_lock(struct mutex *mtx) __acquires(mtx); +void mutex_unlock(struct mutex *mtx) __releases(mtx); /* Tries to acquire the lock and returns true on success. */ -bool mutex_trylock(struct mutex *mtx) EXCLUSIVE_TRYLOCK_FUNCTION(true, *mt= x); +bool mutex_trylock(struct mutex *mtx) __cond_acquires(true, mtx); =20 /* Default initialize the cond struct. */ void cond_init(struct cond *cnd); @@ -158,7 +80,7 @@ void cond_init(struct cond *cnd); void cond_init_pshared(struct cond *cnd); void cond_destroy(struct cond *cnd); =20 -void cond_wait(struct cond *cnd, struct mutex *mtx) EXCLUSIVE_LOCKS_REQUIR= ED(mtx); +void cond_wait(struct cond *cnd, struct mutex *mtx) __must_hold(mtx); void cond_signal(struct cond *cnd); void cond_broadcast(struct cond *cnd); =20 diff --git a/tools/perf/util/rwsem.c b/tools/perf/util/rwsem.c index 9d26832398db..cc720b482333 100644 --- a/tools/perf/util/rwsem.c +++ b/tools/perf/util/rwsem.c @@ -27,7 +27,7 @@ int exit_rwsem(struct rw_semaphore *sem) } =20 int down_read(struct rw_semaphore *sem) - NO_THREAD_SAFETY_ANALYSIS + __no_context_analysis { #if RWS_ERRORCHECK mutex_lock(&sem->mtx); @@ -38,7 +38,7 @@ int down_read(struct rw_semaphore *sem) } =20 int up_read(struct rw_semaphore *sem) - NO_THREAD_SAFETY_ANALYSIS + __no_context_analysis { #if RWS_ERRORCHECK mutex_unlock(&sem->mtx); @@ -49,7 +49,7 @@ int up_read(struct rw_semaphore *sem) } =20 int down_write(struct rw_semaphore *sem) - NO_THREAD_SAFETY_ANALYSIS + __no_context_analysis { #if RWS_ERRORCHECK mutex_lock(&sem->mtx); @@ -60,7 +60,7 @@ int down_write(struct rw_semaphore *sem) } =20 int up_write(struct rw_semaphore *sem) - NO_THREAD_SAFETY_ANALYSIS + __no_context_analysis { #if RWS_ERRORCHECK mutex_unlock(&sem->mtx); diff --git a/tools/perf/util/rwsem.h b/tools/perf/util/rwsem.h index b102d8143181..235bb63c92d0 100644 --- a/tools/perf/util/rwsem.h +++ b/tools/perf/util/rwsem.h @@ -10,7 +10,7 @@ */ #define RWS_ERRORCHECK 0 =20 -struct LOCKABLE rw_semaphore { +context_lock_struct(rw_semaphore) { #if RWS_ERRORCHECK struct mutex mtx; #else @@ -21,10 +21,10 @@ struct LOCKABLE rw_semaphore { int init_rwsem(struct rw_semaphore *sem); int exit_rwsem(struct rw_semaphore *sem); =20 -int down_read(struct rw_semaphore *sem) SHARED_LOCK_FUNCTION(sem); -int up_read(struct rw_semaphore *sem) UNLOCK_FUNCTION(sem); +int down_read(struct rw_semaphore *sem) __acquires_shared(sem); +int up_read(struct rw_semaphore *sem) __releases_shared(sem); =20 -int down_write(struct rw_semaphore *sem) EXCLUSIVE_LOCK_FUNCTION(sem); -int up_write(struct rw_semaphore *sem) UNLOCK_FUNCTION(sem); +int down_write(struct rw_semaphore *sem) __acquires(sem); +int up_write(struct rw_semaphore *sem) __releases(sem); =20 #endif /* _PERF_RWSEM_H */ diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 91118c301913..616d5bf87baf 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -41,7 +41,7 @@ int thread__init_maps(struct thread *thread, struct machi= ne *machine) } =20 struct thread *thread__new(pid_t pid, pid_t tid) - NO_THREAD_SAFETY_ANALYSIS /* Allocation/creation is inherently single thr= eaded. */ + __context_unsafe(/* Allocation/creation is inherently single threaded. */) { RC_STRUCT(thread) *_thread =3D zalloc(sizeof(*_thread)); struct thread *thread; @@ -203,7 +203,7 @@ int thread__set_namespaces(struct thread *thread, u64 t= imestamp, } =20 static struct comm *__thread__comm(struct thread *thread) - SHARED_LOCKS_REQUIRED(thread__comm_lock(thread)) + __must_hold_shared(thread__comm_lock(thread)) { if (list_empty(thread__comm_list(thread))) return NULL; @@ -250,7 +250,7 @@ struct comm *thread__exec_comm(struct thread *thread) =20 static int ____thread__set_comm(struct thread *thread, const char *str, u64 timestamp, bool exec) - EXCLUSIVE_LOCKS_REQUIRED(thread__comm_lock(thread)) + __must_hold(thread__comm_lock(thread)) { struct comm *new, *curr =3D __thread__comm(thread); =20 @@ -308,7 +308,7 @@ int thread__set_comm_from_proc(struct thread *thread) } =20 static const char *__thread__comm_str(struct thread *thread) - SHARED_LOCKS_REQUIRED(thread__comm_lock(thread)) + __must_hold_shared(thread__comm_lock(thread)) { const struct comm *comm =3D __thread__comm(thread); =20 diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index d82fce8173ae..9d0ce7742c06 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -251,7 +251,7 @@ static inline struct rw_semaphore *thread__comm_lock(st= ruct thread *thread) } =20 static inline struct list_head *thread__comm_list(struct thread *thread) - SHARED_LOCKS_REQUIRED(thread__comm_lock(thread)) + __must_hold_shared(thread__comm_lock(thread)) { return &RC_CHK_ACCESS(thread)->comm_list; } --=20 2.56.0.385.gd3acb90ef8-goog From nobody Sat Oct 24 13:20:37 2026 Received: from mail-dl1-f70.google.com (mail-dl1-f70.google.com [74.125.82.70]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9D970562610 for ; Tue, 13 Oct 2026 22:26:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.70 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791930411; cv=none; b=cF1KGfsdVbJazR88xeDLaOF4Wih13DpImIDxopB1rIkaB5FnWY/oSJ60QF5W5r2YCiAPQIff+Q+06pHQbjsjuExwkS3fEzcwmJYr8MlPT7S792oZ8N+3ZdRgDqU3CClZAVdIgblXhY9jLx/tMIPzaQr9UNFKgxeXuT8ZXVBiuiI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791930411; c=relaxed/simple; bh=ASSO9Yhh3x4l2aj4p4LjjHkOJ/UB3ZSeE8UNpeDAMHA=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=nLbIhiqAN+JZZ+hRMSEtauf8hwZDb2F4nyrL1c+RYcjVt2xP5cVQh7AwH0XDKrV5jU4SZQHfU4xalCY60Jk8is/0u+rB2cS7yr93wv/yx7ssQRBQmwJFZPn8p79Lx3Zw12mbih1fI9XX+84c2Lz0JCk2miF1hVCi5YvB4J/57lk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=FYWn+rBX; arc=none smtp.client-ip=74.125.82.70 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="FYWn+rBX" Received: by mail-dl1-f70.google.com with SMTP id a92af1059eb24-17188d538c7so6033790c88.0 for ; Tue, 13 Oct 2026 15:26:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1791930409; x=1792535209; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=vK8eM9wlcN4Kfzlfrk2Po0YSpGR23CvMBC4OejD2aUs=; b=FYWn+rBX7g8gdvYD005gY3CsGJU0m/aniH1dQI5voYi1XmtthlfvysK5zrdSmzhJ/P Tx+QA+Dt8lcdKggt3e3yc4B6rjZr/NQ/Gq+aVrA3ZYhNuXFYqP/rlPcyAhxjIHjZYoK5 UGKYQoqCMYigHwwcAiyLWXPtr0q1qvOXnzkO/EGpvRQMt+ZKS9bG+gCDqbYbGuzGfEMg bT+w3R+GCOgpxG2uROqQ72zID9e36Nlt723nrZmUmy+Z+w4YFrewLEB2pTDqFOvWObdv ReY0RtTAuXuLrILPSC3XV/YiRqvLnOMIxqoXgBXPn6iHyWiUbWHd0aNSkyp5gPG/v0DR EUyg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1791930409; x=1792535209; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=vK8eM9wlcN4Kfzlfrk2Po0YSpGR23CvMBC4OejD2aUs=; b=MK5cguGGvrKWDzmjcfJgAHUvif1HL7IONSBFpCHi1qjZzGsJaczO69WWVB2gYon4/D FYjpf15csURhtEqnsrEHnAz+1ufaFXlwcMpTvLYuX0XBSaHBRu+CmQvWQDFXrXr4hBZ3 /n18fZc0GX1P6b5sNxpjecCAkwijGSv+1rl+IUS1H87cBvAHqetjD8RTGha8ksrMGg7r 9Cc8m8Li7+JlGBfjK9zpTCy/iQA2GP+VE8bNehTHISvyvOW3KF0zhoG+Tfw3yAOZyzXW c4ucxddnh2JpyruZubd65sALaExzFm74oXT10gkF5M601mIS63nCbvrla5SFm3LDDr7G jTPw== X-Forwarded-Encrypted: i=1; AKwUvBzP5W1Ac2W73d2sFkWLLMLRyiu9LZdw6czvuuu6rBUO6owOO5KaHk51mRpjF0m27qEUBtNkWuEo21uAMmI=@vger.kernel.org X-Gm-Message-State: AFq9FYJZAbcp2mWIjNVwtVT6WzaoNkFajPb36pmwPpSzrw4DxSXHbqay huSWGf1W81XBNxejpXzxWImIoxYgjKCnEPwgEKgiFy6+3uNibLboGd1cVcXKj3IdA72zoulfoTw HnCzrEfm0Rw== X-Received: from dloo7-n2.prod.google.com ([2002:a05:7023:a47:20b0:168:9e52:72b9]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:701b:2309:b0:14a:5284:1bff with SMTP id a92af1059eb24-16a5f4e8824mr22840937c88.34.1791930408253; Tue, 13 Oct 2026 15:26:48 -0700 (PDT) Date: Tue, 13 Oct 2026 15:26:17 -0700 In-Reply-To: <20261013222622.1822619-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20261013182458.1234616-1-irogers@google.com> <20261013222622.1822619-1-irogers@google.com> X-Mailer: git-send-email 2.56.0.385.gd3acb90ef8-goog Message-ID: <20261013222622.1822619-6-irogers@google.com> Subject: [PATCH v2 05/10] perf build: Enable additional Clang thread-safety flags From: Ian Rogers To: irogers@google.com, acme@kernel.org, elver@google.com, namhyung@kernel.org Cc: adrian.hunter@intel.com, bvanassche@acm.org, james.clark@linaro.org, jolsa@kernel.org, justinstitt@google.com, linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, ljs@kernel.org, llvm@lists.linux.dev, mingo@redhat.com, morbo@google.com, nathan@kernel.org, ndesaulniers@google.com, peterz@infradead.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Align tools/perf's Clang thread-safety flags with the kernel's scripts/Makefile.context-analysis by adding -Wthread-safety-pointer, -Wthread-safety-beta, and (when supported by the compiler) -fexperimental-late-parse-attributes. Assisted-by: Antigravity:gemini-3.1-pro Signed-off-by: Ian Rogers --- tools/perf/Makefile.config | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config index 39442577418e..a5bd160c03da 100644 --- a/tools/perf/Makefile.config +++ b/tools/perf/Makefile.config @@ -64,7 +64,10 @@ ifeq ($(CC_NO_CLANG), 0) endif =20 # Enabled Wthread-safety analysis for clang builds. - CFLAGS +=3D -Wthread-safety -DWARN_CONTEXT_ANALYSIS + CFLAGS +=3D -DWARN_CONTEXT_ANALYSIS -Wthread-safety -Wthread-safety-poin= ter -Wthread-safety-beta + ifeq ($(shell $(CC) -Werror -fexperimental-late-parse-attributes -c -x c= /dev/null -o /dev/null >/dev/null 2>&1 && echo 1), 1) + CFLAGS +=3D -fexperimental-late-parse-attributes + endif endif =20 include $(srctree)/tools/scripts/Makefile.arch --=20 2.56.0.385.gd3acb90ef8-goog From nobody Sat Oct 24 13:20:37 2026 Received: from mail-dl1-f72.google.com (mail-dl1-f72.google.com [74.125.82.72]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0AEE0563281 for ; Tue, 13 Oct 2026 22:26:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.72 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791930413; cv=none; b=pciKrkOhKuWTNPhC23Qmtk8txrPO4fUPosFT+dZQcP+j7fjB/wD/E3Sabs+Zpry3yuy+TEk8BaIklnaMm0owXL7tlMPMHfzo+lOAg0ZdfDK8hSDq6+3fgboVCg93We8EBPr60/vUT+4cZXNr/i6RaDALHROd2qyU4BuseQTpG10= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791930413; c=relaxed/simple; bh=qz98LWjBN7vuyhktaur2iXpicZss29gzxpSAse2Me08=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=l2R4hhaf/7WDXWCa8KP4RWZY5iczrgF3yCxQ+LUtyfGzFjyzvWFcdnuOY+XeyqNnvYsKv7ZJbSQNDr7WcGLJ6fpwvdkiaffol0EPzqx2ZA61oLAVG+Qv14wVDFaZyC6aBfeFUctLvWT9x3eBSHLYoDMjTdVEjvG1CgX7P7N5oa8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=iOIXhUzo; arc=none smtp.client-ip=74.125.82.72 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="iOIXhUzo" Received: by mail-dl1-f72.google.com with SMTP id a92af1059eb24-1383723dfddso662289c88.0 for ; Tue, 13 Oct 2026 15:26:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1791930411; x=1792535211; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=DM2MthsEYIVhdmp2494m0lpQjS73jUhrnW6tHHeF46g=; b=iOIXhUzo1LqxuFMuH8DEPr5YpMoQlaaNdQCuHaN7JxGK0lRPwcRgtKm64F8UiHjdtZ 26qnGOYGfNff9Qv/z0ZLY896xWo/3wWYTfrsCq2wy1s4wAK613MTyacVgqOak++khgIL qD5CawjKhjZM3Til328R0he+pOpa1MFCU196hM6mBBqgXAcfMz34k6eB7ZfxWhLabPjE mpFSd6rld3EpTLoWKB9MuC2rbM9Bo9nQn7o5UdzhKMOlNMvefXgmKQJkD0nAGEs6kR3v niHxgexE9/VRLNtFLPNvBWrA0p+5jaUo8HZRd4bQSQ2LqUWx2pflAgKQQgfCm16rouix AC3A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1791930411; x=1792535211; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=DM2MthsEYIVhdmp2494m0lpQjS73jUhrnW6tHHeF46g=; b=Y3Kqo2xZG7A3c9K/1EfJxxSDng4l8JJROAwNlofMa+PkDaAhIUsx8rnwBwvWsu2MS1 aEVmzKERAYc4/Xbi2o/qG8P8nLwdSq+WUh8w4p1QvWY9AgHgbhTKPvWS8IOzwGiVul/x 644ILvu1z4EuAbLZGbNUQ4abtaBgkqGy7+b1/2+Xn/u6D197gvtGitEhTwjVSzZZGfPj xqp7Yy30shrUzrWniXMf8BuwtpWMkHBf3fljHSJd9PSa42zrpfg7xrCJaxgz+RXbF7y7 YDhO71Ya9jg4feUK+0Mbia87h0xnSlkB3qf4TYzaelO/50kIhWALxp9tV+oTUMU8oYtS XzCw== X-Forwarded-Encrypted: i=1; AKwUvBzoJiD0BFTaqeCLhQ0vDtB9TjjLUzJosxLZ+rGSHYewBRQ2xQeauWaSIUCO/KUUaHeLroJI7X/Q8V7O+Ro=@vger.kernel.org X-Gm-Message-State: AFq9FYJ9S5EdM8HpwgR8sDVX9iE7iEI7R7vXcCDAOI/MOgU0GefwuGWI qxCvZJmjs6PjJAn5qZdG5uYSjquAYhWs1cv/GHMrWBJEspK3G4Wo6V/ymFddNEQAeXnDQGmg9aI tY0wQjtbiMA== X-Received: from dldyr19-n2.prod.google.com ([2002:a05:701b:4513:20b0:143:75c2:6d21]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:701b:2412:b0:137:fa50:a242 with SMTP id a92af1059eb24-16a586a3183mr17963824c88.1.1791930410665; Tue, 13 Oct 2026 15:26:50 -0700 (PDT) Date: Tue, 13 Oct 2026 15:26:18 -0700 In-Reply-To: <20261013222622.1822619-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20261013182458.1234616-1-irogers@google.com> <20261013222622.1822619-1-irogers@google.com> X-Mailer: git-send-email 2.56.0.385.gd3acb90ef8-goog Message-ID: <20261013222622.1822619-7-irogers@google.com> Subject: [PATCH v2 06/10] perf comm: Add __guarded_by annotations to struct comm_strs From: Ian Rogers To: irogers@google.com, acme@kernel.org, elver@google.com, namhyung@kernel.org Cc: adrian.hunter@intel.com, bvanassche@acm.org, james.clark@linaro.org, jolsa@kernel.org, justinstitt@google.com, linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, ljs@kernel.org, llvm@lists.linux.dev, mingo@redhat.com, morbo@google.com, nathan@kernel.org, ndesaulniers@google.com, peterz@infradead.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Annotate strs, num_strs, and capacity in struct comm_strs with __guarded_by(&lock) and __pt_guarded_by(&lock) so Clang verifies all accesses hold comm_strs->lock. Assisted-by: Antigravity:gemini-3.1-pro Signed-off-by: Ian Rogers --- tools/perf/util/comm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/perf/util/comm.c b/tools/perf/util/comm.c index 6343a3c9debe..9fc4e91a36e9 100644 --- a/tools/perf/util/comm.c +++ b/tools/perf/util/comm.c @@ -16,9 +16,9 @@ DECLARE_RC_STRUCT(comm_str) { =20 static struct comm_strs { struct rw_semaphore lock; - struct comm_str **strs; - int num_strs; - int capacity; + struct comm_str **strs __pt_guarded_by(&lock) __guarded_by(&lock); + int num_strs __guarded_by(&lock); + int capacity __guarded_by(&lock); } _comm_strs; =20 static void comm_strs__remove_if_last(struct comm_str *cs); --=20 2.56.0.385.gd3acb90ef8-goog From nobody Sat Oct 24 13:20:37 2026 Received: from mail-dy1-f198.google.com (mail-dy1-f198.google.com [74.125.82.198]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C49DA5632A9 for ; Tue, 13 Oct 2026 22:26:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.198 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791930417; cv=none; b=jMLYqtoGV0bSeZoFAZvZ70EqLOyVNRpkQorRvkPeVWEpgh17v23IfftL1WxyZXnX+LPvGyQMAi77KLb4G6qWEZmcZyXaS9jIFmqixGO1NYzEt1WqeGbcBhg91krHjtVz/DWsxui5vdMVlilEQGjJh8gC1OJCByFt0ZW9zt2fYmw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791930417; c=relaxed/simple; bh=y3F9Xy4dskAVm4223YtE9IjPGvPgI5+h696DQ/KHXJQ=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=nbvrejZ50DYi4djdaLRtwFYjZh7CIb/5dXJHSeda5LjLe9p0owKpzS2UnEzY+9Y9J4GI63xZB2bALJ/sO/xZoxpBfX4apOwJjVsgnCnxxybNuwzVviBrtwAfwOlUoX3LGlB3UP7K2uNaQrnSNsA7Yeg9LILHTvP4nKKIlnWu1bA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=rGGYEutI; arc=none smtp.client-ip=74.125.82.198 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="rGGYEutI" Received: by mail-dy1-f198.google.com with SMTP id 5a478bee46e88-35c3c370b17so2424540eec.0 for ; Tue, 13 Oct 2026 15:26:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1791930414; x=1792535214; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=akhiltbw0LF7IWKPfQyuqpmH/j7Qc/MOnF0HaTFVPUE=; b=rGGYEutI7Oy5YnaxsNO03LRhvila+awMyIPIoXRTq1z18CxaJB5N9aszDzzeIQkIi5 +em9tbq5OM5UFfeIyKSILX4Hjlz8K55gwMmOhFut3Aw5xMo7AmSxP9mNBpBplpirk5eO WYbe68Fd/VT73incXErAxkqO0sOhNgjdsaYnWVs2Xgp7Urim34pzykyzEg5IR8GtiYAc WVD6VV2ZWs86AmMIx9j5NTpToIOn4d37dGctI27Jo/O1LqsSiec9dNvngW/KU5FdMDAk Dqtv662gpdoNXlyrRQ8pODh5+7pMor/wMqcqn2/v6oLZwCrwgwBlQ3E/c0/iGA8nqx0m lT0A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1791930414; x=1792535214; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=akhiltbw0LF7IWKPfQyuqpmH/j7Qc/MOnF0HaTFVPUE=; b=yXaSRKLgUtG/Avmb0ejiN2i73SeMAXAesi2Hoi8oJkIOkC+3WijkYCXU2/eOX1bJcU Tna+zWX9fGCFO1+5EgGy578rfRRTfr4ZUTgfDqWS6KmL1nqvXx1eWypZNt5sE6ctiwTK m7Jf5aZigCBkaq+m86V34NVPeGZjCgYyPOxP8JOsEYSEclXZUFpzpLyXbOIRHEEJPh75 pQbP4jYjxwLvjwDTQtBj8Ca8TRUjh//NzImx3s6UEDS545vPW+utS93w6xAEpplH913Z tOOq8X8xnjMAHvaZ2L5QO03at7dTrK32Bt56JsAJz6ixX/ZdQd8VasBFBt/tVe4G4gZz QUug== X-Forwarded-Encrypted: i=1; AKwUvBxgzoorxbtYKfub5uzLoVQwiLe+SddKGtESJBauqOkssqRagH1wrBAfVXe9951d77/8LT3jVbIsU7EIBzE=@vger.kernel.org X-Gm-Message-State: AFq9FYI3wp9deKQbYY01/M+IhMroTmOOaJyZRLYVMDr/XVtJu1NoKKxb h1nsRj9ny2siV15GHbyYz4KamF0covnzSymcgA2ZY+fc9IGvqoa0uE3UUAbv8Ng/C8THmJh00N7 xXsonsMumwQ== X-Received: from dlbts25-n2.prod.google.com ([2002:a05:7022:b059:20b0:168:46d:d4f5]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7022:1713:b0:14d:3c0c:79ec with SMTP id a92af1059eb24-16a5dbfddf2mr15065047c88.9.1791930413307; Tue, 13 Oct 2026 15:26:53 -0700 (PDT) Date: Tue, 13 Oct 2026 15:26:19 -0700 In-Reply-To: <20261013222622.1822619-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20261013182458.1234616-1-irogers@google.com> <20261013222622.1822619-1-irogers@google.com> X-Mailer: git-send-email 2.56.0.385.gd3acb90ef8-goog Message-ID: <20261013222622.1822619-8-irogers@google.com> Subject: [PATCH v2 07/10] perf dso: Fix unlocked __dsos__add() in vdso and expand lock annotations From: Ian Rogers To: irogers@google.com, acme@kernel.org, elver@google.com, namhyung@kernel.org Cc: adrian.hunter@intel.com, bvanassche@acm.org, james.clark@linaro.org, jolsa@kernel.org, justinstitt@google.com, linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, ljs@kernel.org, llvm@lists.linux.dev, mingo@redhat.com, morbo@google.com, nathan@kernel.org, ndesaulniers@google.com, peterz@infradead.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" __machine__addnew_vdso() called __dsos__add(&machine->dsos, dso) without holding machine->dsos.lock. Acquire machine->dsos.lock in write mode, double-check __dsos__find() to avoid inserting duplicate VDSO entries when racing with another thread, and set the long name before calling __dsos__add(). In dsos__findnew_id(), try finding the DSO under the read lock first and only acquire the write lock when a new DSO must be inserted or an existing DSO needs its ID updated (checked via dso__needs_improve_id()). In dso__list_del(), release the REFCNT_CHECKING reference directly via refcount_dec_and_test() and RC_CHK_PUT() instead of unlocking dso__data_open_lock to call dso__put(), keeping dso__data_open_lock held continuously across try_to_open_dso() and avoiding lock-order inversions and races during EMFILE eviction. Also replace _dso__data_open_lock and its pthread_once() wrapper with DEFINE_MUTEX(dso__data_open_lock), annotate struct dsos fields with __guarded_by(&lock), add __returns_ctx_lock() to dso__lock(), annotate dso__data_open and fd_limit in util/dso.c with __guarded_by(&dso__data_open_lock), and tighten __dsos__findnew_id() and __dsos__addnew_id() from shared to exclusive lock requirements. Assisted-by: Antigravity:gemini-3.1-pro Signed-off-by: Ian Rogers --- tools/perf/tests/dso-data.c | 4 ++ tools/perf/util/dso.c | 93 ++++++++++++++++++------------------- tools/perf/util/dso.h | 12 +++-- tools/perf/util/dsos.c | 31 +++++++++++-- tools/perf/util/dsos.h | 12 +++-- tools/perf/util/vdso.c | 17 ++++++- 6 files changed, 106 insertions(+), 63 deletions(-) diff --git a/tools/perf/tests/dso-data.c b/tools/perf/tests/dso-data.c index 46bc3f597260..6753380f36ab 100644 --- a/tools/perf/tests/dso-data.c +++ b/tools/perf/tests/dso-data.c @@ -116,12 +116,14 @@ static int dso__data_fd(struct dso *dso, struct machi= ne *machine) =20 static void dsos__delete(struct dsos *dsos) { + down_write(&dsos->lock); for (unsigned int i =3D 0; i < dsos->cnt; i++) { struct dso *dso =3D dsos->dsos[i]; =20 dso__data_close(dso); unlink(dso__name(dso)); } + up_write(&dsos->lock); dsos__exit(dsos); } =20 @@ -247,6 +249,7 @@ static int set_fd_limit(int n) } =20 static int test__dso_data_cache(struct test_suite *test __maybe_unused, in= t subtest __maybe_unused) + __context_unsafe(/* single-threaded test */) { struct machine machine; long nr_end, nr =3D open_files_cnt(); @@ -317,6 +320,7 @@ static long new_limit(int count) } =20 static int test__dso_data_reopen(struct test_suite *test __maybe_unused, i= nt subtest __maybe_unused) + __context_unsafe(/* single-threaded test */) { struct machine machine; long nr_end, nr =3D open_files_cnt(), lim =3D new_limit(3); diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index ff5b30a3d424..21491625ec82 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -523,25 +523,12 @@ void dso__set_module_info(struct dso *dso, struct kmo= d_path *m, /* * Global list of open DSOs and the counter. */ -struct mutex _dso__data_open_lock; -static LIST_HEAD(dso__data_open); -static long dso__data_open_cnt __guarded_by(&_dso__data_open_lock); +DEFINE_MUTEX(dso__data_open_lock); +static struct list_head dso__data_open __guarded_by(&dso__data_open_lock) = =3D + LIST_HEAD_INIT(dso__data_open); +static long dso__data_open_cnt __guarded_by(&dso__data_open_lock); =20 -static void dso__data_open_lock_init(void) -{ - mutex_init(&_dso__data_open_lock); -} - -static struct mutex *dso__data_open_lock(void) __returns_ctx_lock(&_dso__d= ata_open_lock) -{ - static pthread_once_t data_open_lock_once =3D PTHREAD_ONCE_INIT; - - pthread_once(&data_open_lock_once, dso__data_open_lock_init); - - return &_dso__data_open_lock; -} - -static void dso__list_add(struct dso *dso) __must_hold(&_dso__data_open_lo= ck) +static void dso__list_add(struct dso *dso) __must_hold(&dso__data_open_loc= k) { list_add_tail(&dso__data(dso)->open_entry, &dso__data_open); #ifdef REFCNT_CHECKING @@ -552,13 +539,13 @@ static void dso__list_add(struct dso *dso) __must_hol= d(&_dso__data_open_lock) dso__data_open_cnt++; } =20 -static void dso__list_del(struct dso *dso) __must_hold(&_dso__data_open_lo= ck) +static void dso__list_del(struct dso *dso) __must_hold(&dso__data_open_loc= k) { list_del_init(&dso__data(dso)->open_entry); #ifdef REFCNT_CHECKING - mutex_unlock(dso__data_open_lock()); - dso__put(dso__data(dso)->dso); - mutex_lock(dso__data_open_lock()); + BUG_ON(refcount_dec_and_test(&RC_CHK_ACCESS(dso)->refcnt)); + RC_CHK_PUT(dso__data(dso)->dso); + dso__data(dso)->dso =3D NULL; #endif WARN_ONCE(dso__data_open_cnt <=3D 0, "DSO data fd counter out of bounds."); @@ -567,7 +554,7 @@ static void dso__list_del(struct dso *dso) __must_hold(= &_dso__data_open_lock) =20 static void close_first_dso(void); =20 -static int do_open(char *name) __must_hold(&_dso__data_open_lock) +static int do_open(char *name) __must_hold(&dso__data_open_lock) { do { int fd =3D open(name, O_RDONLY|O_CLOEXEC); @@ -670,7 +657,7 @@ void dso__put_filename(struct dso *dso __maybe_unused, = char *filename, bool deco } =20 static int __open_dso(struct dso *dso, struct machine *machine) - __must_hold(&_dso__data_open_lock) + __must_hold(&dso__data_open_lock) { int fd =3D -EINVAL; char *name; @@ -703,7 +690,7 @@ static void check_data_close(void); * list/count of open DSO objects. */ static int open_dso(struct dso *dso, struct machine *machine) - __must_hold(&_dso__data_open_lock) + __must_hold(&dso__data_open_lock) { int fd; struct nscookie nsc; @@ -729,7 +716,7 @@ static int open_dso(struct dso *dso, struct machine *ma= chine) return fd; } =20 -static void close_data_fd(struct dso *dso) __must_hold(&_dso__data_open_lo= ck) +static void close_data_fd(struct dso *dso) __must_hold(&dso__data_open_loc= k) { if (dso__data(dso)->fd >=3D 0) { close(dso__data(dso)->fd); @@ -746,12 +733,12 @@ static void close_data_fd(struct dso *dso) __must_hol= d(&_dso__data_open_lock) * Close @dso's data file descriptor and updates * list/count of open DSO objects. */ -static void close_dso(struct dso *dso) __must_hold(&_dso__data_open_lock) +static void close_dso(struct dso *dso) __must_hold(&dso__data_open_lock) { close_data_fd(dso); } =20 -static void close_first_dso(void) __must_hold(&_dso__data_open_lock) +static void close_first_dso(void) __must_hold(&dso__data_open_lock) { struct dso_data *dso_data; struct dso *dso; @@ -784,7 +771,7 @@ static rlim_t get_fd_limit(void) return limit; } =20 -static rlim_t fd_limit; +static rlim_t fd_limit __guarded_by(&dso__data_open_lock); =20 /* * Used only by tests/dso-data.c to reset the environment @@ -793,10 +780,11 @@ static rlim_t fd_limit; */ void reset_fd_limit(void) { - fd_limit =3D 0; + /* Only called by single-threaded test setup. */ + context_unsafe(fd_limit =3D 0); } =20 -static bool may_cache_fd(void) __must_hold(&_dso__data_open_lock) +static bool may_cache_fd(void) __must_hold(&dso__data_open_lock) { if (!fd_limit) fd_limit =3D get_fd_limit(); @@ -812,7 +800,7 @@ static bool may_cache_fd(void) __must_hold(&_dso__data_= open_lock) * for opened dso file descriptors. The limit is half * of the RLIMIT_NOFILE files opened. */ -static void check_data_close(void) __must_hold(&_dso__data_open_lock) +static void check_data_close(void) __must_hold(&dso__data_open_lock) { bool cache_fd =3D may_cache_fd(); =20 @@ -828,13 +816,13 @@ static void check_data_close(void) __must_hold(&_dso_= _data_open_lock) */ void dso__data_close(struct dso *dso) { - mutex_lock(dso__data_open_lock()); + mutex_lock(&dso__data_open_lock); close_dso(dso); - mutex_unlock(dso__data_open_lock()); + mutex_unlock(&dso__data_open_lock); } =20 static void try_to_open_dso(struct dso *dso, struct machine *machine) - __must_hold(&_dso__data_open_lock) + __must_hold(&dso__data_open_lock) { enum dso_binary_type binary_type_data[] =3D { DSO_BINARY_TYPE__BUILD_ID_CACHE, @@ -882,7 +870,7 @@ bool dso__data_get_fd(struct dso *dso, struct machine *= machine, int *fd) if (dso__data(dso)->status =3D=3D DSO_DATA_STATUS_ERROR) return false; =20 - mutex_lock(dso__data_open_lock()); + mutex_lock(&dso__data_open_lock); =20 try_to_open_dso(dso, machine); =20 @@ -890,13 +878,13 @@ bool dso__data_get_fd(struct dso *dso, struct machine= *machine, int *fd) if (*fd >=3D 0) return true; =20 - mutex_unlock(dso__data_open_lock()); + mutex_unlock(&dso__data_open_lock); return false; } =20 void dso__data_put_fd(struct dso *dso __maybe_unused) { - mutex_unlock(dso__data_open_lock()); + mutex_unlock(&dso__data_open_lock); } =20 bool dso__data_status_seen(struct dso *dso, enum dso_data_status_seen by) @@ -1067,7 +1055,7 @@ static ssize_t file_read(struct dso *dso, struct mach= ine *machine, { ssize_t ret; =20 - mutex_lock(dso__data_open_lock()); + mutex_lock(&dso__data_open_lock); =20 /* * dso__data(dso)->fd might be closed if other thread opened another @@ -1083,7 +1071,7 @@ static ssize_t file_read(struct dso *dso, struct mach= ine *machine, =20 ret =3D pread(dso__data(dso)->fd, data, DSO__DATA_CACHE_SIZE, offset); out: - mutex_unlock(dso__data_open_lock()); + mutex_unlock(&dso__data_open_lock); return ret; } =20 @@ -1190,7 +1178,7 @@ static int file_size(struct dso *dso, struct machine = *machine) int ret =3D 0; struct stat st; =20 - mutex_lock(dso__data_open_lock()); + mutex_lock(&dso__data_open_lock); =20 /* * dso__data(dso)->fd might be closed if other thread opened another @@ -1213,7 +1201,7 @@ static int file_size(struct dso *dso, struct machine = *machine) dso__data(dso)->file_size =3D st.st_size; =20 out: - mutex_unlock(dso__data_open_lock()); + mutex_unlock(&dso__data_open_lock); return ret; } =20 @@ -1417,7 +1405,7 @@ uint16_t dso__e_machine_endian(struct dso *dso, struc= t machine *machine, uint32_ return EM_NONE; } =20 - mutex_lock(dso__data_open_lock()); + mutex_lock(&dso__data_open_lock); =20 /* * dso__data(dso)->fd might be closed if other thread opened another @@ -1430,7 +1418,7 @@ uint16_t dso__e_machine_endian(struct dso *dso, struc= t machine *machine, uint32_ else if (e_flags) *e_flags =3D 0; =20 - mutex_unlock(dso__data_open_lock()); + mutex_unlock(&dso__data_open_lock); return e_machine; } =20 @@ -1596,6 +1584,15 @@ const struct dso_id dso_id_empty =3D { } }; =20 +bool dso__needs_improve_id(const struct dso *dso, const struct dso_id *id) +{ + const struct dso_id *dso_id =3D dso__id_const(dso); + + return (id->mmap2_valid && !dso_id->mmap2_valid) || + (id->mmap2_ino_generation_valid && !dso_id->mmap2_ino_generation_v= alid) || + (build_id__is_defined(&id->build_id) && !build_id__is_defined(&dso= _id->build_id)); +} + void __dso__improve_id(struct dso *dso, const struct dso_id *id) { struct dsos *dsos =3D dso__dsos(dso); @@ -1620,8 +1617,10 @@ void __dso__improve_id(struct dso *dso, const struct= dso_id *id) dso_id->build_id =3D id->build_id; changed =3D true; } - if (changed && dsos) - dsos->sorted =3D false; + if (changed && dsos) { + /* dsos write lock held by caller. */ + context_unsafe(dsos->sorted =3D false); + } } =20 int dso_id__cmp(const struct dso_id *a, const struct dso_id *b) @@ -1805,7 +1804,7 @@ struct dso *dso__get(struct dso *dso) void dso__put(struct dso *dso) { #ifdef REFCNT_CHECKING - if (dso && dso__data(dso) && refcount_read(&RC_CHK_ACCESS(dso)->refcnt) = =3D=3D 2) + if (dso && dso__data(dso)->dso && refcount_read(&RC_CHK_ACCESS(dso)->refc= nt) =3D=3D 2) dso__data_close(dso); #endif if (dso && refcount_dec_and_test(&RC_CHK_ACCESS(dso)->refcnt)) diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h index 54aaa88f574e..3ad6ab5272bb 100644 --- a/tools/perf/util/dso.h +++ b/tools/perf/util/dso.h @@ -356,7 +356,7 @@ DECLARE_RC_STRUCT(dso) { char name[]; }; =20 -extern struct mutex _dso__data_open_lock; +extern struct mutex dso__data_open_lock; extern const struct dso_id dso_id_empty; =20 int dso_id__cmp(const struct dso_id *a, const struct dso_id *b); @@ -628,6 +628,7 @@ static inline void dso__set_loaded(struct dso *dso) } =20 static inline struct mutex *dso__lock(struct dso *dso) + __returns_ctx_lock(&RC_CHK_ACCESS(dso)->lock) { return &RC_CHK_ACCESS(dso)->lock; } @@ -803,12 +804,13 @@ void dso__delete(struct dso *dso); int dso__cmp_id(struct dso *a, struct dso *b); void dso__set_short_name(struct dso *dso, const char *name, bool name_allo= cated); void dso__set_long_name(struct dso *dso, const char *name, bool name_alloc= ated); +bool dso__needs_improve_id(const struct dso *dso, const struct dso_id *id); void __dso__improve_id(struct dso *dso, const struct dso_id *id); =20 int dso__name_len(const struct dso *dso); =20 struct dso *dso__get(struct dso *dso); -void dso__put(struct dso *dso) __must_not_hold(&_dso__data_open_lock); +void dso__put(struct dso *dso) __must_not_hold(&dso__data_open_lock); =20 static inline void __dso__zput(struct dso **dso) { @@ -918,9 +920,9 @@ void dso__set_module_info(struct dso *dso, struct kmod_= path *m, * TODO */ bool dso__data_get_fd(struct dso *dso, struct machine *machine, int *fd) - __cond_acquires(true, &_dso__data_open_lock); -void dso__data_put_fd(struct dso *dso) __releases(&_dso__data_open_lock); -void dso__data_close(struct dso *dso) __must_not_hold(&_dso__data_open_loc= k); + __cond_acquires(true, &dso__data_open_lock); +void dso__data_put_fd(struct dso *dso) __releases(&dso__data_open_lock); +void dso__data_close(struct dso *dso) __must_not_hold(&dso__data_open_lock= ); =20 int dso__data_file_size(struct dso *dso, struct machine *machine); off_t dso__data_size(struct dso *dso, struct machine *machine); diff --git a/tools/perf/util/dsos.c b/tools/perf/util/dsos.c index a2cd37bd1660..0e4307e35768 100644 --- a/tools/perf/util/dsos.c +++ b/tools/perf/util/dsos.c @@ -12,6 +12,7 @@ #include =20 void dsos__init(struct dsos *dsos) + __context_unsafe(/* initialization */) { init_rwsem(&dsos->lock); =20 @@ -50,6 +51,7 @@ void dsos__exit(struct dsos *dsos) static int __dsos__for_each_dso(struct dsos *dsos, int (*cb)(struct dso *dso, void *data), void *data) + __must_hold_shared(&dsos->lock) { for (unsigned int i =3D 0; i < dsos->cnt; i++) { struct dso *dso =3D dsos->dsos[i]; @@ -182,7 +184,8 @@ static struct dso *__dsos__find_by_longname_id(struct d= sos *dsos, } qsort(dsos->dsos, dsos->cnt, sizeof(struct dso *), dsos__cmp_long_name_id_short_name); - dsos->sorted =3D true; + /* write_locked is true, so dsos->lock is held exclusively. */ + context_unsafe(dsos->sorted =3D true); } =20 res =3D bsearch(&key, dsos->dsos, dsos->cnt, sizeof(struct dso *), @@ -194,6 +197,7 @@ static struct dso *__dsos__find_by_longname_id(struct d= sos *dsos, } =20 int __dsos__add(struct dsos *dsos, struct dso *dso) + __must_hold(&dsos->lock) { if (!dso) return -EINVAL; @@ -284,12 +288,18 @@ static struct dso *__dsos__find_id(struct dsos *dsos,= const char *name, const st return res; } =20 +struct dso *__dsos__find(struct dsos *dsos, const char *name, bool cmp_sho= rt) + __must_hold_shared(&dsos->lock) +{ + return __dsos__find_id(dsos, name, &dso_id_empty, cmp_short, /*write_lock= ed=3D*/false); +} + struct dso *dsos__find(struct dsos *dsos, const char *name, bool cmp_short) { struct dso *res; =20 down_read(&dsos->lock); - res =3D __dsos__find_id(dsos, name, &dso_id_empty, cmp_short, /*write_loc= ked=3D*/false); + res =3D __dsos__find(dsos, name, cmp_short); up_read(&dsos->lock); return res; } @@ -314,6 +324,7 @@ static void dso__set_basename(struct dso *dso) } =20 static struct dso *__dsos__addnew_id(struct dsos *dsos, const char *name, = const struct dso_id *id) + __must_hold(&dsos->lock) { struct dso *dso =3D dso__new_id(name, id); =20 @@ -330,7 +341,7 @@ static struct dso *__dsos__addnew_id(struct dsos *dsos,= const char *name, const } =20 static struct dso *__dsos__findnew_id(struct dsos *dsos, const char *name,= const struct dso_id *id) - __must_hold_shared(&dsos->lock) + __must_hold(&dsos->lock) { struct dso *dso =3D __dsos__find_id(dsos, name, id, false, /*write_locked= =3D*/true); =20 @@ -343,8 +354,20 @@ static struct dso *__dsos__findnew_id(struct dsos *dso= s, const char *name, const struct dso *dsos__findnew_id(struct dsos *dsos, const char *name, const st= ruct dso_id *id) { struct dso *dso; + + down_read(&dsos->lock); + dso =3D __dsos__find_id(dsos, name, id, false, /*write_locked=3D*/false); + if (dso && !dso__needs_improve_id(dso, id)) { + up_read(&dsos->lock); + return dso; + } + up_read(&dsos->lock); + down_write(&dsos->lock); - dso =3D __dsos__findnew_id(dsos, name, id); + if (dso) + __dso__improve_id(dso, id); + else + dso =3D __dsos__findnew_id(dsos, name, id); up_write(&dsos->lock); return dso; } diff --git a/tools/perf/util/dsos.h b/tools/perf/util/dsos.h index a26774950866..418899c17233 100644 --- a/tools/perf/util/dsos.h +++ b/tools/perf/util/dsos.h @@ -19,17 +19,19 @@ struct machine; */ struct dsos { struct rw_semaphore lock; - struct dso **dsos; - unsigned int cnt; - unsigned int allocated; - bool sorted; + struct dso **dsos __pt_guarded_by(&lock) __guarded_by(&lock); + unsigned int cnt __guarded_by(&lock); + unsigned int allocated __guarded_by(&lock); + bool sorted __guarded_by(&lock); }; =20 void dsos__init(struct dsos *dsos); void dsos__exit(struct dsos *dsos); =20 -int __dsos__add(struct dsos *dsos, struct dso *dso); +int __dsos__add(struct dsos *dsos, struct dso *dso) __must_hold(&dsos->loc= k); int dsos__add(struct dsos *dsos, struct dso *dso); +struct dso *__dsos__find(struct dsos *dsos, const char *name, bool cmp_sho= rt) + __must_hold_shared(&dsos->lock); struct dso *dsos__find(struct dsos *dsos, const char *name, bool cmp_short= ); =20 struct dso *dsos__findnew_id(struct dsos *dsos, const char *name, const st= ruct dso_id *id); diff --git a/tools/perf/util/vdso.c b/tools/perf/util/vdso.c index c12f5d8c4bf6..5f84cc789cf6 100644 --- a/tools/perf/util/vdso.c +++ b/tools/perf/util/vdso.c @@ -127,13 +127,26 @@ void machine__exit_vdso(struct machine *machine) static struct dso *__machine__addnew_vdso(struct machine *machine, const c= har *short_name, const char *long_name) { - struct dso *dso; + struct dso *dso, *existing; + + down_write(&machine->dsos.lock); + existing =3D __dsos__find(&machine->dsos, short_name, true); + if (existing) { + up_write(&machine->dsos.lock); + return existing; + } =20 dso =3D dso__new(short_name); if (dso !=3D NULL) { - __dsos__add(&machine->dsos, dso); + /* + * Set the long name before adding to machine->dsos so that + * __dsos__add() inserts it in sorted order without needing to + * re-take machine->dsos.lock. + */ dso__set_long_name(dso, long_name, false); + __dsos__add(&machine->dsos, dso); } + up_write(&machine->dsos.lock); =20 return dso; } --=20 2.56.0.385.gd3acb90ef8-goog From nobody Sat Oct 24 13:20:37 2026 Received: from mail-dy1-f200.google.com (mail-dy1-f200.google.com [74.125.82.200]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C78605625EF for ; Tue, 13 Oct 2026 22:26:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.200 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791930419; cv=none; b=sFeqECPsVmd157VwbLo5sDTzJnjLnF3mOGb4q6QJGclmvBXNCyNB1ScNum9znP0txED3bzf3haDnFLSeECUWPI3qixpEr/mRgqrsuh83JZxmIPIp5R2ACmEQDz5gso0H31PLwIkZjPMtpFPDrOWUoD+TNBZOy4asjzyuDLj8Fcw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791930419; c=relaxed/simple; bh=7US1K91tc/xAY0auUwgzNKlEZEip4CvIibxK9/lCxAI=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=Zq5wnOEctPtrCt4pZi3n1ofizH978DKxaT4aC6n/x9SD0P3xwxfaGBaw+hPY7jP5Do7A9AbttOoqW5iUxh0dq46oRYdZkmC3JwRmgZZU5Vl1MUVoo/NDu+SI4qKaJDOaapdIssrToxX1cVt1UPrwPygvSV61mDqjTyiFw7247Ds= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=J6l5DEg9; arc=none smtp.client-ip=74.125.82.200 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="J6l5DEg9" Received: by mail-dy1-f200.google.com with SMTP id 5a478bee46e88-33c35f5ca6cso7811495eec.1 for ; Tue, 13 Oct 2026 15:26:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1791930417; x=1792535217; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=Eg1RxKBzAbpEvTU/GlXM2uZlQTXEQK/Sj0ELzD775os=; b=J6l5DEg9hh9IMH/vf4nPH2n9K+JS+qOZjXwA3eDeaFYZ0k8p+1MiHOeYbnxoLsQTmq o7xWp9qi4XM/jbC9bsOSj001HHkgqgtOQE9+pCktp3rJVzSU1XQVVS73IPuhgEJb8Bdp td7rDnHRjNbR+BaxVA/Ma/WofXd1tyBOzJ/tt/11Griz1i04rWeGeTx4YLFLeEnTZvTn CnDle7OK4Hzk1N18uiBTxCRN52D8BChms2QLKdEOfEww6qW5qeMKXyjUyyrjPB65L1iM 2Ac7EQAjlp94tV6E47ozztt/IzSUFlLMARHcD9DXGJGl3kvVKa0thjDXdP0FghKAljZe 46aQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1791930417; x=1792535217; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=Eg1RxKBzAbpEvTU/GlXM2uZlQTXEQK/Sj0ELzD775os=; b=PdehjI2T0u3/DVYcfnEdZxWAugjxW6a95p3nNCr9hF1TgYB6GUV2NBwR0TYFQm2bos 566CPTfYP1+PAVL4tnw3SpbLcjJ1copFR6m3O6jt34nHEvIq/WOamIaXmQvkLLYSXYr3 7pcO3edmRVba/GBeitkb0cdxtquXjP7wslfyIOMZsnN8TLL4zBTegOX7yGOy3NYOTZqQ yggA9s0cqtSLf7SUh8eAqK8Hz2XRoZ31co+Q4CJryPE+Ls2GGy60CHLdAWErT6ONCFeS nuwPgGYzfGWC5lO0/4Q81AsVXdqK8g+fuXh9cTcnxgbyVfYTEk8dBZx2O1wZ4yERGzrc 2KbA== X-Forwarded-Encrypted: i=1; AKwUvBxBLRA5GCTLd5EG5T4yshLYZr7nxA+61yqA8NoS25wTy598h9wvBOEtUnhC5Wg+KqaZOHhB9Yg5BAQ/J9I=@vger.kernel.org X-Gm-Message-State: AFq9FYIj7t5S0kIB93I03fjEaFOacE/8MT6WES27YTTfDaow++kauFH5 tmVhySFyj/1MSzVaTj0mfbri+ALr1G5eD/Dw6+fqWfbOrkDh/bg45hJCJ+7HT3zZC9BIE1ZODe7 MDxBVmUsQjg== X-Received: from dyr7.prod.google.com ([2002:a05:693c:4007:b0:359:72f9:2aab]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7301:1a3:b0:35b:7dcd:dd57 with SMTP id 5a478bee46e88-35b7ddd267emr6892890eec.10.1791930416351; Tue, 13 Oct 2026 15:26:56 -0700 (PDT) Date: Tue, 13 Oct 2026 15:26:20 -0700 In-Reply-To: <20261013222622.1822619-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20261013182458.1234616-1-irogers@google.com> <20261013222622.1822619-1-irogers@google.com> X-Mailer: git-send-email 2.56.0.385.gd3acb90ef8-goog Message-ID: <20261013222622.1822619-9-irogers@google.com> Subject: [PATCH v2 08/10] perf thread: Expand context analysis annotations to threads and namespaces_lock From: Ian Rogers To: irogers@google.com, acme@kernel.org, elver@google.com, namhyung@kernel.org Cc: adrian.hunter@intel.com, bvanassche@acm.org, james.clark@linaro.org, jolsa@kernel.org, justinstitt@google.com, linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, ljs@kernel.org, llvm@lists.linux.dev, mingo@redhat.com, morbo@google.com, nathan@kernel.org, ndesaulniers@google.com, peterz@infradead.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Annotate shard and last_match in struct threads_table_entry with __guarded_by(&lock) and add __must_hold_shared()/__must_hold() to the last_match helpers in util/threads.c. In util/thread.h and util/thread.c, add __returns_ctx_lock() to thread__namespaces_lock() and thread__comm_lock(), annotate namespaces_list and comm_list with __guarded_by(), and add __must_hold_shared()/__must_hold() to the namespaces_list helpers. Assisted-by: Antigravity:gemini-3.1-pro Signed-off-by: Ian Rogers --- tools/perf/util/thread.c | 2 ++ tools/perf/util/thread.h | 28 +++++++++++++++++----------- tools/perf/util/threads.c | 4 ++++ tools/perf/util/threads.h | 6 +++--- 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index 616d5bf87baf..af761b1fc5d5 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -149,6 +149,7 @@ void thread__put(struct thread *thread) } =20 static struct namespaces *__thread__namespaces(struct thread *thread) + __must_hold_shared(thread__namespaces_lock(thread)) { if (list_empty(thread__namespaces_list(thread))) return NULL; @@ -169,6 +170,7 @@ struct namespaces *thread__namespaces(struct thread *th= read) =20 static int __thread__set_namespaces(struct thread *thread, u64 timestamp, struct perf_record_namespaces *event) + __must_hold(thread__namespaces_lock(thread)) { struct namespaces *new, *curr =3D __thread__namespaces(thread); =20 diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index 9d0ce7742c06..a7850eebce4e 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h @@ -48,10 +48,10 @@ DECLARE_RC_STRUCT(thread) { bool exited; bool comm_set; int comm_len; - struct list_head namespaces_list; struct rw_semaphore namespaces_lock; - struct list_head comm_list; + struct list_head namespaces_list __guarded_by(&namespaces_lock); struct rw_semaphore comm_lock; + struct list_head comm_list __guarded_by(&comm_lock); u64 db_id; =20 void *priv; @@ -230,30 +230,36 @@ static inline void thread__set_comm_len(struct thread= *thread, int len) RC_CHK_ACCESS(thread)->comm_len =3D len; } =20 -static inline struct list_head *thread__namespaces_list(struct thread *thr= ead) +static inline struct rw_semaphore *thread__namespaces_lock(const struct th= read *thread) + __returns_ctx_lock(&RC_CHK_ACCESS(thread)->namespaces_lock) { - return &RC_CHK_ACCESS(thread)->namespaces_list; + return (struct rw_semaphore *)&RC_CHK_ACCESS(thread)->namespaces_lock; } =20 -static inline int thread__namespaces_list_empty(const struct thread *threa= d) +static inline struct list_head *thread__namespaces_list(struct thread *thr= ead) + __must_hold_shared(thread__namespaces_lock(thread)) { - return list_empty(&RC_CHK_ACCESS(thread)->namespaces_list); + /* Readers hold the shared lock; writers hold the exclusive lock. */ + return context_unsafe(&RC_CHK_ACCESS(thread)->namespaces_list); } =20 -static inline struct rw_semaphore *thread__namespaces_lock(struct thread *= thread) +static inline int thread__namespaces_list_empty(const struct thread *threa= d) + __must_hold_shared(thread__namespaces_lock(thread)) { - return &RC_CHK_ACCESS(thread)->namespaces_lock; + return list_empty(&RC_CHK_ACCESS(thread)->namespaces_list); } =20 -static inline struct rw_semaphore *thread__comm_lock(struct thread *thread) +static inline struct rw_semaphore *thread__comm_lock(const struct thread *= thread) + __returns_ctx_lock(&RC_CHK_ACCESS(thread)->comm_lock) { - return &RC_CHK_ACCESS(thread)->comm_lock; + return (struct rw_semaphore *)&RC_CHK_ACCESS(thread)->comm_lock; } =20 static inline struct list_head *thread__comm_list(struct thread *thread) __must_hold_shared(thread__comm_lock(thread)) { - return &RC_CHK_ACCESS(thread)->comm_list; + /* Readers hold the shared lock; writers hold the exclusive lock. */ + return context_unsafe(&RC_CHK_ACCESS(thread)->comm_list); } =20 static inline u64 thread__db_id(const struct thread *thread) diff --git a/tools/perf/util/threads.c b/tools/perf/util/threads.c index 6ca0b178fb6c..39b3c420635a 100644 --- a/tools/perf/util/threads.c +++ b/tools/perf/util/threads.c @@ -21,6 +21,7 @@ static bool key_equal(long key1, long key2, void *ctx __m= aybe_unused) } =20 void threads__init(struct threads *threads) + __context_unsafe(/* initialization */) { for (int i =3D 0; i < THREADS__TABLE_SIZE; i++) { struct threads_table_entry *table =3D &threads->table[i]; @@ -32,6 +33,7 @@ void threads__init(struct threads *threads) } =20 void threads__exit(struct threads *threads) + __context_unsafe(/* teardown */) { threads__remove_all_threads(threads); for (int i =3D 0; i < THREADS__TABLE_SIZE; i++) { @@ -63,6 +65,7 @@ size_t threads__nr(struct threads *threads) */ static struct thread *__threads_table_entry__get_last_match(struct threads= _table_entry *table, pid_t tid) + __must_hold_shared(&table->lock) { struct thread *th, *res =3D NULL; =20 @@ -76,6 +79,7 @@ static struct thread *__threads_table_entry__get_last_mat= ch(struct threads_table =20 static void __threads_table_entry__set_last_match(struct threads_table_ent= ry *table, struct thread *th) + __must_hold(&table->lock) { thread__put(table->last_match); table->last_match =3D thread__get(th); diff --git a/tools/perf/util/threads.h b/tools/perf/util/threads.h index da68d2223f18..54fba16657db 100644 --- a/tools/perf/util/threads.h +++ b/tools/perf/util/threads.h @@ -11,10 +11,10 @@ struct thread; #define THREADS__TABLE_SIZE (1 << THREADS__TABLE_BITS) =20 struct threads_table_entry { - /* Key is tid, value is struct thread. */ - struct hashmap shard; struct rw_semaphore lock; - struct thread *last_match; + /* Key is tid, value is struct thread. */ + struct hashmap shard __guarded_by(&lock); + struct thread *last_match __guarded_by(&lock); }; =20 struct threads { --=20 2.56.0.385.gd3acb90ef8-goog From nobody Sat Oct 24 13:20:37 2026 Received: from mail-dy1-f199.google.com (mail-dy1-f199.google.com [74.125.82.199]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 50098563287 for ; Tue, 13 Oct 2026 22:27:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.82.199 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791930423; cv=none; b=kfcTcvMFILI43N8MqcXUg7esOaGyaKBo5x4uPRpopOUbruZCRmZneQbtpqhdG56OADkeo6sdUMMRK1P9aioCyCbjEvHglhteDN+/X5fipyfbNRXo5fDYfZ6RB5T0p+g1YuWYZGcXiu1Apl62qNw0Gx64haHgIFvjAvTnTRKeI0g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791930423; c=relaxed/simple; bh=MQEx+L+bTgjB6LpKQWr8rX315xWt6W85M+PsrrZl3Ww=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=OVwMBdfBioJqvib2pYMFiehN0ESJqJmc4y21lW2TKMeFZwFEI2C3o9fgZ2zJVsp3CJLsLTGljde+zb7yCUfd+lrW/zCsgyh/dfJgIHEE7p7kCKX2wcodoeDkHJNYFVcm9gsKY9JSorDcv4ZQMK06etYImwFlrLcIaQw84RYrae0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=ZqM9/oFw; arc=none smtp.client-ip=74.125.82.199 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="ZqM9/oFw" Received: by mail-dy1-f199.google.com with SMTP id 5a478bee46e88-3552883bd19so4608020eec.1 for ; Tue, 13 Oct 2026 15:27:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1791930419; x=1792535219; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=ZE4+oqWgjisY7ML1bRCEEvBwOPAJPrHwRyt4cCLc/JY=; b=ZqM9/oFwL+mP6BKiC/oNjSxOy39hNWIu1UCxC2CrF39MGRWjTsnbykXbavGLK1KBjp r5tolgpO7VvKjW7aeFQWzar1bjhS+Xsd6kYlTW1aXcn3IGoQCAe9Uj/gtpXzaDmViDly ga8iNkJxrb00BYjj7D3MWcx/Cc3QkU3lLvr78y7OA5cqdPufSa+bKCT7iV1bDXts0Sfr BJt82VslL38H1vuJtaKqC5rqJ6q+t52mUThldiR4cxLCtPucM/xC2YlkxgaCkCuXqrSa cnK/GyeRir2467pxMb57ftIamkR8fDpSMVs9Xp9VUE3wPWBbeyPKISGDmyPP6TJm2alM DQng== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1791930419; x=1792535219; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=ZE4+oqWgjisY7ML1bRCEEvBwOPAJPrHwRyt4cCLc/JY=; b=SeqopS9wQ/nUys5T6WLuMP/BRl7BZS6aTmE0ctpmt+qGSy7Ty2i+ShOWyNKsllAwtU PwtPtLjsXXRTwNgzC0CZszQdK9EgXTiAWCf4AhAsl7d6a7y/hTdqm2Z6evNi0TugfKeQ +j41qTbjHcUkUJYqUVpkmx2TiMu/jgDkSDBACgTRSAufiLr+LA3ciYx7A/od4Dl+H5ze mqxs/gkUmJRrXtEHQ7aMintc5/4W2dQWME47iHo/Vg+dQ9tkfCAtl4ou0f6rLhbcK68b 11BXokCUlmpN5Rw7MC9nUItLS44M+KhK/J2hPJvFqUcB/rRcYh3EW3UKoD72KWHHPYAz /kCA== X-Forwarded-Encrypted: i=1; AKwUvBx+xw4A9izI1hq8DcAuW0pY5Kk8B1bhQCM9XKlFMKq1g72Sn2XKcFGy43X4gsttNfYTSyYC7LzttcQt8ss=@vger.kernel.org X-Gm-Message-State: AFq9FYJadCeQ/G5VSy7dLOXEGBewz2asO4uIXmSx12bDHoCEcZc6wSEI noFmHj57o42VWGrenxVZkZImT5LDTZC0dZ5ax8WlXgxCaPVVj5bbn3XnjLu0Rdl05dJVv9rzPb7 lactHVzUekw== X-Received: from dycmq7.prod.google.com ([2002:a05:7301:787:b0:35a:3045:15e9]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a05:7301:db81:b0:35c:73bb:a81 with SMTP id 5a478bee46e88-35c73bb0d65mr4282758eec.36.1791930419031; Tue, 13 Oct 2026 15:26:59 -0700 (PDT) Date: Tue, 13 Oct 2026 15:26:21 -0700 In-Reply-To: <20261013222622.1822619-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20261013182458.1234616-1-irogers@google.com> <20261013222622.1822619-1-irogers@google.com> X-Mailer: git-send-email 2.56.0.385.gd3acb90ef8-goog Message-ID: <20261013222622.1822619-10-irogers@google.com> Subject: [PATCH v2 09/10] perf config, intel-tpebs, env: Add __guarded_by and __must_hold annotations From: Ian Rogers To: irogers@google.com, acme@kernel.org, elver@google.com, namhyung@kernel.org Cc: adrian.hunter@intel.com, bvanassche@acm.org, james.clark@linaro.org, jolsa@kernel.org, justinstitt@google.com, linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, ljs@kernel.org, llvm@lists.linux.dev, mingo@redhat.com, morbo@google.com, nathan@kernel.org, ndesaulniers@google.com, peterz@infradead.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add __guarded_by() and __must_hold() annotations to static parser and config state in util/config.c, TPEBS state in util/intel-tpebs.c (replacing tpebs_mtx_get() and its pthread_once() init with DEFINE_MUTEX(tpebs_mtx), fixing an unlocked read of tpebs_reader_thread in tpebs_stop(), and transferring tpebs_cmd.out ownership to __sample_reader() so it is not double-closed in tpebs_stop()), and bpf_progs and cgroups trees in struct perf_env. Assisted-by: Antigravity:gemini-3.1-pro Signed-off-by: Ian Rogers --- tools/perf/util/bpf-event.h | 5 +- tools/perf/util/config.c | 43 +++++++++------ tools/perf/util/env.c | 1 + tools/perf/util/env.h | 19 ++++--- tools/perf/util/intel-tpebs.c | 98 ++++++++++++++++------------------- 5 files changed, 87 insertions(+), 79 deletions(-) diff --git a/tools/perf/util/bpf-event.h b/tools/perf/util/bpf-event.h index da4eeb4a1a73..3f3323f98f49 100644 --- a/tools/perf/util/bpf-event.h +++ b/tools/perf/util/bpf-event.h @@ -6,11 +6,11 @@ #include #include #include +#include "env.h" =20 struct bpf_prog_info; struct machine; union perf_event; -struct perf_env; struct perf_sample; struct perf_session; struct record_opts; @@ -42,7 +42,8 @@ int machine__process_bpf(struct machine *machine, union p= erf_event *event, int evlist__add_bpf_sb_event(struct evlist *evlist, struct perf_env *env); void __bpf_event__print_bpf_prog_info(struct perf_bpil *info_linear, struct perf_env *env, - FILE *fp); + FILE *fp) + __must_hold_shared(&env->bpf_progs.lock); void bpf_metadata_free(struct bpf_metadata *metadata); #else static inline int machine__process_bpf(struct machine *machine __maybe_unu= sed, diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index 287401f159e6..a55f7062a09b 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c @@ -64,15 +64,29 @@ struct perf_stat_config stat_config =3D { =20 char buildid_dir[MAXPATHLEN]; /* root dir for buildid, binary cache */ =20 -static FILE *config_file; -static const char *config_file_name; -static int config_linenr; -static int config_file_eof; -static struct perf_config_set *config_set; +/* Parsing and rewriting share the static parser state. */ +static DEFINE_MUTEX(config_mutex); + +/* Serializes whole perf_config__set_variable() updates. */ +static DEFINE_MUTEX(config_update_mutex); + +/* + * Protects the global config_set. Separate from config_mutex because + * initializing config_set parses the config files, which acquires + * config_mutex. + */ +static DEFINE_MUTEX(config_set_mutex); + +static FILE *config_file __guarded_by(&config_mutex); +static const char *config_file_name __guarded_by(&config_mutex); +static int config_linenr __guarded_by(&config_mutex); +static int config_file_eof __guarded_by(&config_mutex); +static struct perf_config_set *config_set __guarded_by(&config_set_mutex); =20 const char *config_exclusive_filename; =20 static int get_next_char(void) + __must_hold(&config_mutex) { int c; FILE *f; @@ -99,6 +113,7 @@ static int get_next_char(void) } =20 static char *parse_value(void) + __must_hold(&config_mutex) { static char value[1024]; int quote =3D 0, comment =3D 0, space =3D 0; @@ -170,6 +185,7 @@ static inline int iskeychar(int c) } =20 static int get_value(config_fn_t fn, void *data, char *name, unsigned int = len) + __must_hold(&config_mutex) { int c; char *value; @@ -201,6 +217,7 @@ static int get_value(config_fn_t fn, void *data, char *= name, unsigned int len) } =20 static int get_extended_base_var(char *name, int baselen, int c) + __must_hold(&config_mutex) { do { if (c =3D=3D '\n') @@ -237,6 +254,7 @@ static int get_extended_base_var(char *name, int basele= n, int c) } =20 static int get_base_var(char *name) + __must_hold(&config_mutex) { int baselen =3D 0; =20 @@ -257,6 +275,7 @@ static int get_base_var(char *name) } =20 static int perf_parse_file(config_fn_t fn, void *data) + __must_hold(&config_mutex) { int comment =3D 0; int baselen =3D 0; @@ -549,12 +568,6 @@ int perf_default_config(const char *var, const char *v= alue, return 0; } =20 -/* Parsing and rewriting share the static parser state. */ -static DEFINE_MUTEX(config_mutex); - -/* Serializes whole perf_config__set_variable() updates. */ -static DEFINE_MUTEX(config_update_mutex); - static int perf_config_from_file(config_fn_t fn, const char *filename, voi= d *data) { int ret; @@ -737,6 +750,7 @@ static int set_value(struct perf_config_item *item, con= st char *value) =20 static int collect_config(const char *var, const char *value, void *perf_config_set) + __must_hold(&config_mutex) { int ret =3D -1; char *ptr, *key; @@ -853,11 +867,8 @@ struct perf_config_set *perf_config_set__load_file(con= st char *file) return set; } =20 -/* Not config_mutex: building the set parses the config files, which takes= it. */ -static DEFINE_MUTEX(config_set_mutex); - -/* Called with config_set_mutex held. */ static int perf_config__init(void) + __must_hold(&config_set_mutex) { if (config_set =3D=3D NULL) config_set =3D perf_config_set__new(); @@ -975,7 +986,7 @@ int perf_config__set_variable(const char *var, const ch= ar *value) =20 /* Static: the parser publishes it as config_file_name. */ { - static char path[PATH_MAX]; + static char path[PATH_MAX] __guarded_by(&config_update_mutex); char *user_config =3D mkpath(path, sizeof(path), "%s/.perfconfig", geten= v("HOME")); =20 config_filename =3D config_exclusive_filename ?: user_config; diff --git a/tools/perf/util/env.c b/tools/perf/util/env.c index 50993b0dedc5..9e8e5d1d822a 100644 --- a/tools/perf/util/env.c +++ b/tools/perf/util/env.c @@ -302,6 +302,7 @@ void perf_env__exit(struct perf_env *env) } =20 void perf_env__init(struct perf_env *env) + __context_unsafe(/* initialization */) { memset(env, 0, sizeof(*env)); #ifdef HAVE_LIBBPF_SUPPORT diff --git a/tools/perf/util/env.h b/tools/perf/util/env.h index 23d35425efe3..6b2083e3640c 100644 --- a/tools/perf/util/env.h +++ b/tools/perf/util/env.h @@ -139,16 +139,16 @@ struct perf_env { */ struct { struct rw_semaphore lock; - struct rb_root infos; - u32 infos_cnt; - struct rb_root btfs; - u32 btfs_cnt; + struct rb_root infos __guarded_by(&lock); + u32 infos_cnt __guarded_by(&lock); + struct rb_root btfs __guarded_by(&lock); + u32 btfs_cnt __guarded_by(&lock); } bpf_progs; #endif // HAVE_LIBBPF_SUPPORT /* same reason as above (for perf-top) */ struct { struct rw_semaphore lock; - struct rb_root tree; + struct rb_root tree __guarded_by(&lock); } cgroups; =20 /* For fast cpu to numa node lookup via perf_env__numa_node */ @@ -223,7 +223,8 @@ int perf_env__nr_cpus_avail(struct perf_env *env); void perf_env__init(struct perf_env *env); #ifdef HAVE_LIBBPF_SUPPORT bool __perf_env__insert_bpf_prog_info(struct perf_env *env, - struct bpf_prog_info_node *info_node); + struct bpf_prog_info_node *info_node) + __must_hold(&env->bpf_progs.lock); bool perf_env__insert_bpf_prog_info(struct perf_env *env, struct bpf_prog_info_node *info_node); struct bpf_prog_info_node *perf_env__find_bpf_prog_info(struct perf_env *e= nv, @@ -233,9 +234,11 @@ void perf_env__iterate_bpf_prog_info(struct perf_env *= env, void *data), void *data); bool perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_node); -bool __perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_nod= e); +bool __perf_env__insert_btf(struct perf_env *env, struct btf_node *btf_nod= e) + __must_hold(&env->bpf_progs.lock); struct btf_node *perf_env__find_btf(struct perf_env *env, __u32 btf_id); -struct btf_node *__perf_env__find_btf(struct perf_env *env, __u32 btf_id); +struct btf_node *__perf_env__find_btf(struct perf_env *env, __u32 btf_id) + __must_hold_shared(&env->bpf_progs.lock); #endif // HAVE_LIBBPF_SUPPORT =20 int perf_env__numa_node(struct perf_env *env, struct perf_cpu cpu); diff --git a/tools/perf/util/intel-tpebs.c b/tools/perf/util/intel-tpebs.c index 7c0b8b15bd10..85dcf4f64697 100644 --- a/tools/perf/util/intel-tpebs.c +++ b/tools/perf/util/intel-tpebs.c @@ -32,12 +32,12 @@ =20 bool tpebs_recording; enum tpebs_mode tpebs_mode; -static LIST_HEAD(tpebs_results); -static pthread_t tpebs_reader_thread; +static DEFINE_MUTEX(tpebs_mtx); +static struct list_head tpebs_results __guarded_by(&tpebs_mtx) =3D LIST_HE= AD_INIT(tpebs_results); +static pthread_t tpebs_reader_thread __guarded_by(&tpebs_mtx); static struct child_process tpebs_cmd; -static int control_fd[2], ack_fd[2]; -static struct mutex tpebs_mtx; -static bool tpebs_stopping; +static int control_fd[2] =3D { -1, -1 }, ack_fd[2] =3D { -1, -1 }; +static bool tpebs_stopping __guarded_by(&tpebs_mtx); =20 struct tpebs_retire_lat { struct list_head nd; @@ -53,25 +53,11 @@ struct tpebs_retire_lat { bool started; }; =20 -static void tpebs_init(void) -{ - mutex_init(&tpebs_mtx); - control_fd[0] =3D control_fd[1] =3D -1; - ack_fd[0] =3D ack_fd[1] =3D -1; -} - -static struct mutex *tpebs_mtx_get(void) -{ - static pthread_once_t tpebs_once =3D PTHREAD_ONCE_INIT; - - pthread_once(&tpebs_once, tpebs_init); - return &tpebs_mtx; -} - static struct tpebs_retire_lat *tpebs_retire_lat__find(struct evsel *evsel) - __must_hold(tpebs_mtx_get()); + __must_hold(&tpebs_mtx); =20 static int evsel__tpebs_start_perf_record(struct evsel *evsel) + __must_hold(&tpebs_mtx) { const char **record_argv; int tpebs_event_size =3D 0, i =3D 0, ret; @@ -194,19 +180,19 @@ static int process_sample_event(const struct perf_too= l *tool __maybe_unused, { struct tpebs_retire_lat *t; =20 - mutex_lock(tpebs_mtx_get()); + mutex_lock(&tpebs_mtx); if (tpebs_cmd.pid =3D=3D 0) { /* Record has terminated. */ - mutex_unlock(tpebs_mtx_get()); + mutex_unlock(&tpebs_mtx); return 0; } t =3D tpebs_retire_lat__find(sample->evsel); if (!t) { - mutex_unlock(tpebs_mtx_get()); + mutex_unlock(&tpebs_mtx); return -EINVAL; } if (should_ignore_sample(sample, t)) { - mutex_unlock(tpebs_mtx_get()); + mutex_unlock(&tpebs_mtx); return 0; } /* @@ -216,17 +202,17 @@ static int process_sample_event(const struct perf_too= l *tool __maybe_unused, */ t->last =3D sample->weight3; update_stats(&t->stats, sample->weight3); - mutex_unlock(tpebs_mtx_get()); + mutex_unlock(&tpebs_mtx); return 0; } =20 -static void *__sample_reader(void *arg __maybe_unused) +static void *__sample_reader(void *arg) { struct perf_session *session; struct perf_data data =3D { .mode =3D PERF_DATA_MODE_READ, .path =3D PERF_DATA, - .file.fd =3D tpebs_cmd.out, + .file.fd =3D (int)(intptr_t)arg, }; struct perf_tool tool; =20 @@ -236,15 +222,17 @@ static void *__sample_reader(void *arg __maybe_unused) tool.attr =3D perf_event__process_attr; =20 session =3D perf_session__new(&data, &tool); - if (IS_ERR(session)) + if (IS_ERR(session)) { + close(data.file.fd); return NULL; + } perf_session__process_events(session); perf_session__delete(session); =20 return NULL; } =20 -static int tpebs_send_record_cmd(const char *msg) __must_hold(tpebs_mtx_ge= t()) +static int tpebs_send_record_cmd(const char *msg) __must_hold(&tpebs_mtx) { struct pollfd pollfd =3D { .events =3D POLLIN, }; int ret, len, retries =3D 0; @@ -258,7 +246,7 @@ static int tpebs_send_record_cmd(const char *msg) __mus= t_hold(tpebs_mtx_get()) * Let go of the lock while sending/receiving as blocking can starve the * sample reading thread. */ - mutex_unlock(tpebs_mtx_get()); + mutex_unlock(&tpebs_mtx); =20 /* Send perf record command.*/ len =3D strlen(msg); @@ -314,14 +302,14 @@ static int tpebs_send_record_cmd(const char *msg) __m= ust_hold(tpebs_mtx_get()) pr_err("tpebs: perf record control ack failed\n"); out: /* Re-take lock as expected by caller. */ - mutex_lock(tpebs_mtx_get()); + mutex_lock(&tpebs_mtx); return ret; } =20 /* * tpebs_stop - stop the sample data read thread and the perf record proce= ss. */ -static int tpebs_stop(void) __must_hold(tpebs_mtx_get()) +static int tpebs_stop(void) __must_hold(&tpebs_mtx) { int ret =3D 0; =20 @@ -331,13 +319,15 @@ static int tpebs_stop(void) __must_hold(tpebs_mtx_get= ()) /* Like tpebs_start, we should only run tpebs_end once. */ if (tpebs_cmd.pid !=3D 0) { pid_t actual_pid =3D tpebs_cmd.pid; + pthread_t reader_thread; =20 tpebs_stopping =3D true; tpebs_send_record_cmd(EVLIST_CTL_CMD_STOP_TAG); tpebs_cmd.pid =3D 0; - mutex_unlock(tpebs_mtx_get()); - pthread_join(tpebs_reader_thread, NULL); - mutex_lock(tpebs_mtx_get()); + reader_thread =3D tpebs_reader_thread; + mutex_unlock(&tpebs_mtx); + pthread_join(reader_thread, NULL); + mutex_lock(&tpebs_mtx); if (control_fd[0] >=3D 0) { close(control_fd[0]); control_fd[0] =3D -1; @@ -473,20 +463,20 @@ static int evsel__tpebs_prepare(struct evsel *evsel) struct evsel *pos; struct tpebs_retire_lat *tpebs_event; =20 - mutex_lock(tpebs_mtx_get()); + mutex_lock(&tpebs_mtx); tpebs_event =3D tpebs_retire_lat__find(evsel); if (tpebs_event) { /* evsel, or an identically named one, was already prepared. */ - mutex_unlock(tpebs_mtx_get()); + mutex_unlock(&tpebs_mtx); return 0; } tpebs_event =3D tpebs_retire_lat__new(evsel); if (!tpebs_event) { - mutex_unlock(tpebs_mtx_get()); + mutex_unlock(&tpebs_mtx); return -ENOMEM; } list_add_tail(&tpebs_event->nd, &tpebs_results); - mutex_unlock(tpebs_mtx_get()); + mutex_unlock(&tpebs_mtx); =20 /* * Eagerly prepare all other evsels on the list to try to ensure that by @@ -520,9 +510,9 @@ int evsel__tpebs_open(struct evsel *evsel) if (!tpebs_recording) return 0; =20 - mutex_lock(tpebs_mtx_get()); + mutex_lock(&tpebs_mtx); if (tpebs_stopping) { - mutex_unlock(tpebs_mtx_get()); + mutex_unlock(&tpebs_mtx); return -EBUSY; } /* Only start the events once. */ @@ -532,17 +522,17 @@ int evsel__tpebs_open(struct evsel *evsel) =20 t =3D tpebs_retire_lat__find(evsel); valid =3D t && t->started; - mutex_unlock(tpebs_mtx_get()); + mutex_unlock(&tpebs_mtx); /* May fail as the event wasn't started. */ return valid ? 0 : -EBUSY; } - mutex_unlock(tpebs_mtx_get()); + mutex_unlock(&tpebs_mtx); =20 ret =3D evsel__tpebs_prepare(evsel); if (ret) return ret; =20 - mutex_lock(tpebs_mtx_get()); + mutex_lock(&tpebs_mtx); if (tpebs_stopping || tpebs_cmd.pid !=3D 0) { ret =3D -EBUSY; goto out; @@ -567,12 +557,14 @@ int evsel__tpebs_open(struct evsel *evsel) goto out; =20 if (pthread_create(&tpebs_reader_thread, /*attr=3D*/NULL, __sample_reade= r, - /*arg=3D*/NULL)) { + (void *)(intptr_t)tpebs_cmd.out)) { kill(tpebs_cmd.pid, SIGTERM); pr_err("Could not create thread to process sample data.\n"); ret =3D -1; goto out; } + /* __sample_reader now owns and closes the output fd. */ + tpebs_cmd.out =3D -1; ret =3D tpebs_send_record_cmd(EVLIST_CTL_CMD_ENABLE_TAG); } out: @@ -612,7 +604,7 @@ int evsel__tpebs_open(struct evsel *evsel) } } } - mutex_unlock(tpebs_mtx_get()); + mutex_unlock(&tpebs_mtx); return ret; } =20 @@ -632,7 +624,7 @@ int evsel__tpebs_read(struct evsel *evsel, int cpu_map_= idx, int thread) =20 count =3D perf_counts(evsel->counts, cpu_map_idx, thread); =20 - mutex_lock(tpebs_mtx_get()); + mutex_lock(&tpebs_mtx); t =3D tpebs_retire_lat__find(evsel); /* * If reading the first tpebs result, send a ping to the record @@ -641,10 +633,10 @@ int evsel__tpebs_read(struct evsel *evsel, int cpu_ma= p_idx, int thread) */ if (t && &t->nd =3D=3D tpebs_results.next) { ret =3D tpebs_send_record_cmd(EVLIST_CTL_CMD_PING_TAG); - mutex_unlock(tpebs_mtx_get()); + mutex_unlock(&tpebs_mtx); if (ret) return ret; - mutex_lock(tpebs_mtx_get()); + mutex_lock(&tpebs_mtx); } if (t =3D=3D NULL || t->stats.n =3D=3D 0) { /* No sample data, use default. */ @@ -683,7 +675,7 @@ int evsel__tpebs_read(struct evsel *evsel, int cpu_map_= idx, int thread) break; } } - mutex_unlock(tpebs_mtx_get()); + mutex_unlock(&tpebs_mtx); =20 if (old_count) { count->val =3D old_count->val + val; @@ -708,7 +700,7 @@ void evsel__tpebs_close(struct evsel *evsel) { struct tpebs_retire_lat *t; =20 - mutex_lock(tpebs_mtx_get()); + mutex_lock(&tpebs_mtx); t =3D tpebs_retire_lat__find(evsel); if (t) { list_del_init(&t->nd); @@ -717,5 +709,5 @@ void evsel__tpebs_close(struct evsel *evsel) if (list_empty(&tpebs_results)) tpebs_stop(); } - mutex_unlock(tpebs_mtx_get()); + mutex_unlock(&tpebs_mtx); } --=20 2.56.0.385.gd3acb90ef8-goog From nobody Sat Oct 24 13:20:37 2026 Received: from mail-pj1-f69.google.com (mail-pj1-f69.google.com [209.85.216.69]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 65697563FAB for ; Tue, 13 Oct 2026 22:27:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.69 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791930425; cv=none; b=gNzw65v+2wy8A2KWtnivcQsN0m1C4UOyzvjNfP/bwPuHBr+7h5cCLVJ31ALcLDfSYys4Hk+W8+p90IiGOYHCDmOaU/HoHSxJeDRTIoCUSVgAFtYnsxmNeJKXqTtyIzO91Tfsv5o+U0ANyGgOOSweUBuqSNAnT5LUwcmQ8BjBIYg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1791930425; c=relaxed/simple; bh=/oE8Za8Al66xFuzM309DpYsREdet+rjMBycsCITcv8M=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=fNl+qepOrULaH1oQ5VpfovtOM2SzqEeckixmUJb0A0bZ7wjF7QuOi29rY6+fU//r4FzNpfkUYTv36+bbD4Qot4oyPzNOEmUUp/LoymDdaEDj4ljofBW9x00K/phiIg8QBeTAcE2NcxxgCVhX0WXL09QhGBwvHWvRe4u3+2BQfRQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=i6VmSa4Q; arc=none smtp.client-ip=209.85.216.69 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--irogers.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="i6VmSa4Q" Received: by mail-pj1-f69.google.com with SMTP id 98e67ed59e1d1-39512608fb1so434110a91.1 for ; Tue, 13 Oct 2026 15:27:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20251104; t=1791930422; x=1792535222; darn=vger.kernel.org; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:from:to:cc:subject:date:message-id:reply-to :content-type; bh=9IpZwxzmHKgK8o+ihHmL9BU0fEDLXdmVQL7+jWxEh3s=; b=i6VmSa4QuZu295q2ZoibJn0N4MIWkna+LK1WKRTy4bkraAs2mNLelKIOBkS+dveD6z cKQ9dgXBv6UogcwJ9aHDTIlpwrkUgpnxTD+s/bPzlBtnDhhQOMZoCYUN/rh97p8mx5YO 1I05ct8t18Mx6b6GF+8HoOqlycM1I9I5p7CU+y6ZdLsna4Sr8zKHTRyhyHSharFi7d04 rZmiaDP1nUfJ41PxXhCx3hiR4JSPzLDj/3QUFhZpqKYbnvPAS4YzEqXg7q/sdA9WByIX ZlYNrSgRItxU8w1NhjBPvinixvAnLvPG3neGqNprx9I1qVi0WOAsmp3jfIvS7aUpiPLn uyyg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1791930422; x=1792535222; h=content-type:cc:to:from:subject:message-id:references:mime-version :in-reply-to:date:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=9IpZwxzmHKgK8o+ihHmL9BU0fEDLXdmVQL7+jWxEh3s=; b=ySRa42y/ONrOlvagRqQnIUPf/3LNmbVGsctBaf6C9yOnPPbQ+G26sEca7zP4iVSwAO HWQ8uod1EM/t+1btC08PwiWyyZripOaJwmkRw386x2LmGYb8MEuzbMLu13T2rG27RkEM X+0cVRyCkPBx4/rZunQdsAUNr03ucSa1wfi81OGj6Hye9PzinWWyAGIitPjH/uZGGSIf t+B73TaQ8IbmqF4DoratDE1DtOc/FopGZsOq7rEPR7BiQ7sGT2zpV9xRo6U4dVvfsBK6 tde9C0+Tbrqgk2DuqmMelA3Jv33wjUxG3ynvMlu7TS2eJNeGLFxFg2wmORGlYxqkee6x 0XTQ== X-Forwarded-Encrypted: i=1; AKwUvBydlIrgNDYiytw+TyFoPEEBRfITO4q0EZDAa04Zm5ISqSja7HzpZju68OWZ1eLY6BsNppsYCOWdGjCWFwQ=@vger.kernel.org X-Gm-Message-State: AFq9FYKmXlR0GcyoPZDME355KzJlgTgViEiqhYXZpXdgV+Lt+qgfI8aA AiWyg7YJTZGrMirQbKzsigE6DWHzF8g/e6TSJM3p6Q2+2FX0FuFR+pSBwv6z8EV4tr240zQ1uwv zjV32rACw3A== X-Received: from pgbcr2.prod.google.com ([2002:a05:6a02:4102:b0:cc7:81a1:7ffa]) (user=irogers job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:384b:b0:3aa:548f:eb7d with SMTP id 98e67ed59e1d1-3ab3a955ademr11075568a91.20.1791930421455; Tue, 13 Oct 2026 15:27:01 -0700 (PDT) Date: Tue, 13 Oct 2026 15:26:22 -0700 In-Reply-To: <20261013222622.1822619-1-irogers@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20261013182458.1234616-1-irogers@google.com> <20261013222622.1822619-1-irogers@google.com> X-Mailer: git-send-email 2.56.0.385.gd3acb90ef8-goog Message-ID: <20261013222622.1822619-11-irogers@google.com> Subject: [PATCH v2 10/10] perf maps: Add context analysis annotations From: Ian Rogers To: irogers@google.com, acme@kernel.org, elver@google.com, namhyung@kernel.org Cc: adrian.hunter@intel.com, bvanassche@acm.org, james.clark@linaro.org, jolsa@kernel.org, justinstitt@google.com, linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, ljs@kernel.org, llvm@lists.linux.dev, mingo@redhat.com, morbo@google.com, nathan@kernel.org, ndesaulniers@google.com, peterz@infradead.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add __returns_ctx_lock() to maps__lock(), annotate DECLARE_RC_STRUCT(maps) members protected by lock with __guarded_by(&lock), and annotate internal maps helpers with __must_hold() and __must_hold_shared(). Also in maps__load_first(), take a reference to the first map and drop the read lock before calling map__load() to avoid a read-to-write self-deadlock if map__load() inserts extra kernel maps. Assisted-by: Antigravity:gemini-3.1-pro Signed-off-by: Ian Rogers --- tools/perf/util/maps.c | 133 ++++++++++++++++++++++++++--------------- 1 file changed, 86 insertions(+), 47 deletions(-) diff --git a/tools/perf/util/maps.c b/tools/perf/util/maps.c index f808df2fe77b..faa15ded788d 100644 --- a/tools/perf/util/maps.c +++ b/tools/perf/util/maps.c @@ -30,12 +30,12 @@ DECLARE_RC_STRUCT(maps) { * @maps_by_address: array of maps sorted by their starting address if * maps_by_address_sorted is true. */ - struct map **maps_by_address; + struct map **maps_by_address __guarded_by(&lock); /** * @maps_by_name: optional array of maps sorted by their dso name if * maps_by_name_sorted is true. */ - struct map **maps_by_name; + struct map **maps_by_name __guarded_by(&lock); struct machine *machine; #ifdef HAVE_LIBUNWIND_SUPPORT void *addr_space; @@ -50,26 +50,33 @@ DECLARE_RC_STRUCT(maps) { * @nr_maps: number of maps_by_address, and possibly maps_by_name, * entries that contain maps. */ - unsigned int nr_maps; + unsigned int nr_maps __guarded_by(&lock); /** * @nr_maps_allocated: number of entries in maps_by_address and possibly * maps_by_name. */ - unsigned int nr_maps_allocated; + unsigned int nr_maps_allocated __guarded_by(&lock); /** * @last_search_by_name_idx: cache of last found by name entry's index * as frequent searches for the same dso name are common. */ unsigned int last_search_by_name_idx; /** @maps_by_address_sorted: is maps_by_address sorted. */ - bool maps_by_address_sorted; + bool maps_by_address_sorted __guarded_by(&lock); /** @maps_by_name_sorted: is maps_by_name sorted. */ - bool maps_by_name_sorted; + bool maps_by_name_sorted __guarded_by(&lock); /** @ends_broken: does the map contain a map where end values are unset/u= nsorted? */ - bool ends_broken; + bool ends_broken __guarded_by(&lock); }; =20 +static struct rw_semaphore *maps__lock(const struct maps *maps) + __returns_ctx_lock(&RC_CHK_ACCESS(maps)->lock) +{ + return (struct rw_semaphore *)&RC_CHK_ACCESS(maps)->lock; +} + static void check_invariants(const struct maps *maps __maybe_unused) + __must_hold_shared(maps__lock(maps)) { #ifndef NDEBUG assert(RC_CHK_ACCESS(maps)->nr_maps <=3D RC_CHK_ACCESS(maps)->nr_maps_all= ocated); @@ -119,55 +126,65 @@ static void check_invariants(const struct maps *maps = __maybe_unused) } =20 static struct map **maps__maps_by_address(const struct maps *maps) + __must_hold_shared(maps__lock(maps)) { return RC_CHK_ACCESS(maps)->maps_by_address; } =20 static void maps__set_maps_by_address(struct maps *maps, struct map **new) + __must_hold(maps__lock(maps)) { RC_CHK_ACCESS(maps)->maps_by_address =3D new; =20 } =20 static void maps__set_nr_maps_allocated(struct maps *maps, unsigned int nr= _maps_allocated) + __must_hold(maps__lock(maps)) { RC_CHK_ACCESS(maps)->nr_maps_allocated =3D nr_maps_allocated; } =20 static void maps__set_nr_maps(struct maps *maps, unsigned int nr_maps) + __must_hold(maps__lock(maps)) { RC_CHK_ACCESS(maps)->nr_maps =3D nr_maps; } =20 /* Not in the header, to aid reference counting. */ static struct map **maps__maps_by_name(const struct maps *maps) + __must_hold_shared(maps__lock(maps)) { return RC_CHK_ACCESS(maps)->maps_by_name; =20 } =20 static void maps__set_maps_by_name(struct maps *maps, struct map **new) + __must_hold(maps__lock(maps)) { RC_CHK_ACCESS(maps)->maps_by_name =3D new; =20 } =20 static bool maps__maps_by_address_sorted(const struct maps *maps) + __must_hold_shared(maps__lock(maps)) { return RC_CHK_ACCESS(maps)->maps_by_address_sorted; } =20 static void maps__set_maps_by_address_sorted(struct maps *maps, bool value) + __must_hold(maps__lock(maps)) { RC_CHK_ACCESS(maps)->maps_by_address_sorted =3D value; } =20 static bool maps__maps_by_name_sorted(const struct maps *maps) + __must_hold_shared(maps__lock(maps)) { return RC_CHK_ACCESS(maps)->maps_by_name_sorted; } =20 static void maps__set_maps_by_name_sorted(struct maps *maps, bool value) + __must_hold(maps__lock(maps)) { RC_CHK_ACCESS(maps)->maps_by_name_sorted =3D value; } @@ -177,11 +194,22 @@ struct machine *maps__machine(const struct maps *maps) return RC_CHK_ACCESS(maps)->machine; } =20 -unsigned int maps__nr_maps(const struct maps *maps) +static unsigned int __maps__nr_maps(const struct maps *maps) + __must_hold_shared(maps__lock(maps)) { return RC_CHK_ACCESS(maps)->nr_maps; } =20 +unsigned int maps__nr_maps(const struct maps *maps) +{ + unsigned int nr; + + down_read(maps__lock(maps)); + nr =3D __maps__nr_maps(maps); + up_read(maps__lock(maps)); + return nr; +} + refcount_t *maps__refcnt(struct maps *maps) { return &RC_CHK_ACCESS(maps)->refcnt; @@ -220,12 +248,8 @@ void maps__set_libdw_addr_space_dwfl(struct maps *maps= , void *dwfl) } #endif =20 -static struct rw_semaphore *maps__lock(struct maps *maps) -{ - return &RC_CHK_ACCESS(maps)->lock; -} - static void maps__init(struct maps *maps, struct machine *machine) + __context_unsafe(/* initialization */) { init_rwsem(maps__lock(maps)); RC_CHK_ACCESS(maps)->maps_by_address =3D NULL; @@ -247,11 +271,12 @@ static void maps__init(struct maps *maps, struct mach= ine *machine) } =20 static void maps__exit(struct maps *maps) + __context_unsafe(/* teardown */) { struct map **maps_by_address =3D maps__maps_by_address(maps); struct map **maps_by_name =3D maps__maps_by_name(maps); =20 - for (unsigned int i =3D 0; i < maps__nr_maps(maps); i++) { + for (unsigned int i =3D 0; i < __maps__nr_maps(maps); i++) { map__zput(maps_by_address[i]); if (maps_by_name) map__zput(maps_by_name[i]); @@ -300,6 +325,7 @@ void maps__put(struct maps *maps) } =20 static void __maps__free_maps_by_name(struct maps *maps) + __must_hold(maps__lock(maps)) { if (!maps__maps_by_name(maps)) return; @@ -307,7 +333,7 @@ static void __maps__free_maps_by_name(struct maps *maps) /* * Free everything to try to do it from the rbtree in the next search */ - for (unsigned int i =3D 0; i < maps__nr_maps(maps); i++) + for (unsigned int i =3D 0; i < __maps__nr_maps(maps); i++) map__put(maps__maps_by_name(maps)[i]); =20 zfree(&RC_CHK_ACCESS(maps)->maps_by_name); @@ -340,12 +366,13 @@ static int map__start_cmp(const void *a, const void *= b) } =20 static void __maps__sort_by_address(struct maps *maps) + __must_hold(maps__lock(maps)) { if (maps__maps_by_address_sorted(maps)) return; =20 qsort(maps__maps_by_address(maps), - maps__nr_maps(maps), + __maps__nr_maps(maps), sizeof(struct map *), map__start_cmp); maps__set_maps_by_address_sorted(maps, true); @@ -388,7 +415,7 @@ static int maps__sort_by_name(struct maps *maps) err =3D -ENOMEM; else { struct map **maps_by_address =3D maps__maps_by_address(maps); - unsigned int n =3D maps__nr_maps(maps); + unsigned int n =3D __maps__nr_maps(maps); =20 maps__set_maps_by_name(maps, maps_by_name); for (unsigned int i =3D 0; i < n; i++) @@ -397,7 +424,7 @@ static int maps__sort_by_name(struct maps *maps) } if (!err) { qsort(maps_by_name, - maps__nr_maps(maps), + __maps__nr_maps(maps), sizeof(struct map *), map__strcmp); maps__set_maps_by_name_sorted(maps, true); @@ -409,18 +436,19 @@ static int maps__sort_by_name(struct maps *maps) } =20 static unsigned int maps__by_address_index(const struct maps *maps, const = struct map *map) + __must_hold_shared(maps__lock(maps)) { struct map **maps_by_address =3D maps__maps_by_address(maps); =20 if (maps__maps_by_address_sorted(maps)) { struct map **mapp =3D - bsearch(&map, maps__maps_by_address(maps), maps__nr_maps(maps), + bsearch(&map, maps__maps_by_address(maps), __maps__nr_maps(maps), sizeof(*mapp), map__start_cmp); =20 if (mapp) return mapp - maps_by_address; } else { - for (unsigned int i =3D 0; i < maps__nr_maps(maps); i++) { + for (unsigned int i =3D 0; i < __maps__nr_maps(maps); i++) { if (RC_CHK_ACCESS(maps_by_address[i]) =3D=3D RC_CHK_ACCESS(map)) return i; } @@ -430,18 +458,19 @@ static unsigned int maps__by_address_index(const stru= ct maps *maps, const struct } =20 static unsigned int maps__by_name_index(const struct maps *maps, const str= uct map *map) + __must_hold_shared(maps__lock(maps)) { struct map **maps_by_name =3D maps__maps_by_name(maps); =20 if (maps__maps_by_name_sorted(maps)) { struct map **mapp =3D - bsearch(&map, maps_by_name, maps__nr_maps(maps), + bsearch(&map, maps_by_name, __maps__nr_maps(maps), sizeof(*mapp), map__strcmp); =20 if (mapp) return mapp - maps_by_name; } else { - for (unsigned int i =3D 0; i < maps__nr_maps(maps); i++) { + for (unsigned int i =3D 0; i < __maps__nr_maps(maps); i++) { if (RC_CHK_ACCESS(maps_by_name[i]) =3D=3D RC_CHK_ACCESS(map)) return i; } @@ -470,10 +499,11 @@ static void map__set_kmap_maps(struct map *map, struc= t maps *maps) } =20 static int __maps__insert(struct maps *maps, struct map *new) + __must_hold(maps__lock(maps)) { struct map **maps_by_address =3D maps__maps_by_address(maps); struct map **maps_by_name =3D maps__maps_by_name(maps); - unsigned int nr_maps =3D maps__nr_maps(maps); + unsigned int nr_maps =3D __maps__nr_maps(maps); unsigned int nr_allocate =3D RC_CHK_ACCESS(maps)->nr_maps_allocated; =20 if (nr_maps + 1 > nr_allocate) { @@ -540,10 +570,11 @@ int maps__insert(struct maps *maps, struct map *map) } =20 static void __maps__remove(struct maps *maps, struct map *map) + __must_hold(maps__lock(maps)) { struct map **maps_by_address =3D maps__maps_by_address(maps); struct map **maps_by_name =3D maps__maps_by_name(maps); - unsigned int nr_maps =3D maps__nr_maps(maps); + unsigned int nr_maps =3D __maps__nr_maps(maps); unsigned int address_idx; =20 /* Slide later mappings over the one to remove */ @@ -623,7 +654,7 @@ bool maps__empty(struct maps *maps) bool res; =20 down_read(maps__lock(maps)); - res =3D maps__nr_maps(maps) =3D=3D 0; + res =3D __maps__nr_maps(maps) =3D=3D 0; up_read(maps__lock(maps)); =20 return res; @@ -651,7 +682,7 @@ int maps__for_each_map(struct maps *maps, int (*cb)(str= uct map *map, void *data) * the array - this may cause maps to be skipped or * repeated. */ - for (unsigned int i =3D 0; i < maps__nr_maps(maps); i++) { + for (unsigned int i =3D 0; i < __maps__nr_maps(maps); i++) { struct map **maps_by_address =3D maps__maps_by_address(maps); struct map *map =3D maps_by_address[i]; =20 @@ -678,7 +709,7 @@ int maps__load_maps(struct maps *maps) return 0; =20 down_read(maps__lock(maps)); - nr_maps =3D maps__nr_maps(maps); + nr_maps =3D __maps__nr_maps(maps); if (nr_maps =3D=3D 0) { up_read(maps__lock(maps)); return 0; @@ -711,7 +742,7 @@ void maps__remove_maps(struct maps *maps, bool (*cb)(st= ruct map *map, void *data down_write(maps__lock(maps)); =20 maps_by_address =3D maps__maps_by_address(maps); - for (unsigned int i =3D 0; i < maps__nr_maps(maps);) { + for (unsigned int i =3D 0; i < __maps__nr_maps(maps);) { if (cb(maps_by_address[i], data)) { __maps__remove(maps, maps_by_address[i]); removed =3D true; @@ -765,7 +796,7 @@ struct symbol *maps__find_symbol_by_name(struct maps *m= aps, const char *name, st * This prevents deadlocking if iteration triggers further map insertions. */ down_read(maps__lock(maps)); - nr_maps =3D maps__nr_maps(maps); + nr_maps =3D __maps__nr_maps(maps); maps_copy =3D calloc(nr_maps, sizeof(*maps_copy)); if (maps_copy) { for (unsigned int i =3D 0; i < nr_maps; i++) { @@ -850,9 +881,10 @@ size_t maps__fprintf(struct maps *maps, FILE *fp) * Same as find_vma() in kernel. */ static unsigned int first_ending_after(struct maps *maps, const struct map= *map) + __must_hold_shared(maps__lock(maps)) { struct map **maps_by_address =3D maps__maps_by_address(maps); - int low =3D 0, high =3D (int)maps__nr_maps(maps) - 1, first =3D high + 1; + int low =3D 0, high =3D (int)__maps__nr_maps(maps) - 1, first =3D high + = 1; =20 assert(maps__maps_by_address_sorted(maps)); if (low <=3D high && map__end(maps_by_address[0]) > map__start(map)) @@ -877,10 +909,11 @@ static unsigned int first_ending_after(struct maps *m= aps, const struct map *map) =20 static int __maps__insert_sorted(struct maps *maps, unsigned int first_aft= er_index, struct map *new1, struct map *new2) + __must_hold(maps__lock(maps)) { struct map **maps_by_address =3D maps__maps_by_address(maps); struct map **maps_by_name =3D maps__maps_by_name(maps); - unsigned int nr_maps =3D maps__nr_maps(maps); + unsigned int nr_maps =3D __maps__nr_maps(maps); unsigned int nr_allocate =3D RC_CHK_ACCESS(maps)->nr_maps_allocated; unsigned int to_add =3D new2 ? 2 : 1; =20 @@ -937,6 +970,7 @@ static int __maps__insert_sorted(struct maps *maps, uns= igned int first_after_ind * adjusted or removed so that new fits without overlapping any entries. */ static int __maps__fixup_overlap_and_insert(struct maps *maps, struct map = *new) + __must_hold(maps__lock(maps)) { int err =3D 0; unsigned int i, ni =3D INT_MAX; // Some gcc complain, but depends on maps= _by_name... @@ -948,7 +982,7 @@ static int __maps__fixup_overlap_and_insert(struct maps= *maps, struct map *new) * Iterate through entries where the end of the existing entry is * greater-than the new map's start. */ - for (i =3D first_ending_after(maps, new); i < maps__nr_maps(maps); ) { + for (i =3D first_ending_after(maps, new); i < __maps__nr_maps(maps); ) { struct map **maps_by_address =3D maps__maps_by_address(maps); struct map **maps_by_name =3D maps__maps_by_name(maps); struct map *pos =3D maps_by_address[i]; @@ -1059,7 +1093,7 @@ static int __maps__fixup_overlap_and_insert(struct ma= ps *maps, struct map *new) return err; } else { struct map *next =3D NULL; - unsigned int nr_maps =3D maps__nr_maps(maps); + unsigned int nr_maps =3D __maps__nr_maps(maps); =20 if (i + 1 < nr_maps) next =3D maps_by_address[i + 1]; @@ -1143,8 +1177,8 @@ int maps__copy_from(struct maps *dest, struct maps *p= arent) } #endif parent_maps_by_address =3D maps__maps_by_address(parent); - n =3D maps__nr_maps(parent); - if (maps__nr_maps(dest) =3D=3D 0) { + n =3D __maps__nr_maps(parent); + if (__maps__nr_maps(dest) =3D=3D 0) { /* No existing mappings so just copy from parent to avoid reallocs in in= sert. */ unsigned int nr_maps_allocated =3D RC_CHK_ACCESS(parent)->nr_maps_alloca= ted; struct map **dest_maps_by_address =3D @@ -1228,7 +1262,7 @@ struct map *maps__find(struct maps *maps, u64 ip) if (maps__maps_by_address_sorted(maps)) { struct map **mapp =3D NULL; struct map **maps_by_address =3D maps__maps_by_address(maps); - unsigned int nr_maps =3D maps__nr_maps(maps); + unsigned int nr_maps =3D __maps__nr_maps(maps); =20 if (maps_by_address && nr_maps) mapp =3D bsearch(&ip, maps_by_address, nr_maps, sizeof(*mapp), @@ -1264,7 +1298,7 @@ struct map *maps__find_by_name(struct maps *maps, con= st char *name) =20 /* First check last found entry. */ i =3D RC_CHK_ACCESS(maps)->last_search_by_name_idx; - if (i < maps__nr_maps(maps) && maps__maps_by_name(maps)) { + if (i < __maps__nr_maps(maps) && maps__maps_by_name(maps)) { struct dso *dso =3D map__dso(maps__maps_by_name(maps)[i]); =20 if (dso && strcmp(dso__short_name(dso), name) =3D=3D 0) { @@ -1276,7 +1310,7 @@ struct map *maps__find_by_name(struct maps *maps, con= st char *name) /* Second search sorted array. */ if (!done && maps__maps_by_name_sorted(maps)) { struct map **mapp =3D - bsearch(name, maps__maps_by_name(maps), maps__nr_maps(maps), + bsearch(name, maps__maps_by_name(maps), __maps__nr_maps(maps), sizeof(*mapp), map__strcmp_name); =20 if (mapp) { @@ -1299,7 +1333,7 @@ struct map *maps__find_by_name(struct maps *maps, con= st char *name) =20 down_read(maps__lock(maps)); maps_by_address =3D maps__maps_by_address(maps); - n =3D maps__nr_maps(maps); + n =3D __maps__nr_maps(maps); for (i =3D 0; i < n; i++) { struct map *pos =3D maps_by_address[i]; struct dso *dso =3D map__dso(pos); @@ -1329,7 +1363,7 @@ struct map *maps__find_next_entry(struct maps *maps, = struct map *map) down_read(maps__lock(maps)); } i =3D maps__by_address_index(maps, map); - if (++i < maps__nr_maps(maps)) + if (++i < __maps__nr_maps(maps)) result =3D map__get(maps__maps_by_address(maps)[i]); =20 up_read(maps__lock(maps)); @@ -1346,7 +1380,7 @@ void maps__fixup_end(struct maps *maps) __maps__sort_by_address(maps); =20 maps_by_address =3D maps__maps_by_address(maps); - n =3D maps__nr_maps(maps); + n =3D __maps__nr_maps(maps); for (unsigned int i =3D 1; i < n; i++) { struct map *prev =3D maps_by_address[i - 1]; struct map *curr =3D maps_by_address[i]; @@ -1393,7 +1427,7 @@ int maps__merge_in(struct maps *kmaps, struct map *ne= w_map) first_after_ =3D first_ending_after(kmaps, new_map); kmaps_maps_by_address =3D maps__maps_by_address(kmaps); =20 - if (first_after_ >=3D maps__nr_maps(kmaps) || + if (first_after_ >=3D __maps__nr_maps(kmaps) || map__start(kmaps_maps_by_address[first_after_]) >=3D map__end(new_map= )) { /* No overlap so regular insert suffices. */ up_read(maps__lock(kmaps)); @@ -1408,7 +1442,7 @@ int maps__merge_in(struct maps *kmaps, struct map *ne= w_map) =20 first_after_ =3D first_ending_after(kmaps, new_map); kmaps_maps_by_address =3D maps__maps_by_address(kmaps); - kmaps__nr_maps =3D maps__nr_maps(kmaps); + kmaps__nr_maps =3D __maps__nr_maps(kmaps); =20 if (first_after_ >=3D kmaps__nr_maps || map__start(kmaps_maps_by_address[first_after_]) >=3D map__end(new_map= )) { @@ -1459,10 +1493,15 @@ int maps__merge_in(struct maps *kmaps, struct map *= new_map) =20 void maps__load_first(struct maps *maps) { - down_read(maps__lock(maps)); - - if (maps__nr_maps(maps) > 0) - map__load(maps__maps_by_address(maps)[0]); + struct map *first =3D NULL; =20 + down_read(maps__lock(maps)); + if (__maps__nr_maps(maps) > 0) + first =3D map__get(maps__maps_by_address(maps)[0]); up_read(maps__lock(maps)); + + if (first) { + map__load(first); + map__put(first); + } } --=20 2.56.0.385.gd3acb90ef8-goog