From nobody Thu May 7 18:25:53 2026 Received: from mail-ed1-f73.google.com (mail-ed1-f73.google.com [209.85.208.73]) (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 15F0E1FCFCC for ; Tue, 4 Mar 2025 09:25:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080315; cv=none; b=CNaWuGu7ax7jbhjJEh8aSnD387+1EtdqVgpR4D+RX2+QM01v9Eb/8p4L7uWiQFLltpZgkf/jyhagRD+yFH/g9TOeZEkxj8d+KCpNP9zgPQXo/kEZWUqaUsbhN3MlYboBe4XvBGdGNZ6bc+Ldpg1vcI1WKcsTxJzHcfuX2W3Kszo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080315; c=relaxed/simple; bh=0WzzU6roBd+wb4BiPZv1ShxdEyf/59sH8xjJyNyyB/o=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=Em0KnUEEbwZ4GTK0UGIInaIEIFG7gQhCLGm3gn0PGUkXG6YvLmtLHh7tX6+6SNqywqAXpRJgFuRa54WsjIblVj3xkMu1yLPyB+OX5sQ3HHiDBAAeX5vo1YYRpgbQo+XzRNUpvQiImeQ81sdBMxoA9TpSybzuCsDujmgiB6vXIZo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--elver.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=wh0p7d1m; arc=none smtp.client-ip=209.85.208.73 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--elver.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="wh0p7d1m" Received: by mail-ed1-f73.google.com with SMTP id 4fb4d7f45d1cf-5e4c5225b64so5329980a12.2 for ; Tue, 04 Mar 2025 01:25:12 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1741080311; x=1741685111; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=NQzJ/uCYeuflL88Y+3MrtFVv4DOW+ANfKOTFJKL+x3k=; b=wh0p7d1mjdtMiWzX6JifVSMlyDbfquromP2hXI9swu0UckrXjg+KapyWKe4+isArG5 +WQTOi0BO0kSQQrQBCGflLtx+0A71hf6+xdEQkCrRln8Bqvu8tdARqkv5ukxp8G3e/k7 iSiXeN/vXRN10lnnGKwQu+jP+3OZPgKWcqMbzNGOsFTavr82IrCscNunXuuXzj+HvrhX 8Rxp3/c3CZC+Av8z4pNssAcHPbtWFZuYEMo29Eh57WTdbMp2HI7z3kmaaP18tPND6/wn ZVy8i8KUp6sIeXDWBayZHFgIt0D08SiE1NOnjm+sof8Prrll8Jd00oukEmJrFpUiDXjc ZQsw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741080311; x=1741685111; h=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; bh=NQzJ/uCYeuflL88Y+3MrtFVv4DOW+ANfKOTFJKL+x3k=; b=EutrqwB5EbfUKRmLqQkPXJBFBrBUP6tyFcm/IyK/7n4r8venw1L49xmb2P4xF5l5b3 od+GPzE5dDipMBnfWRz3/sqLAHcynfAkRN8MEnSnSfvwmKbw1YxkAePUqvRgapkENVZq gCSckWJLC/uGirea+drdHxJkFr1ZKDjTayvZ36Y2nsuXSCpDFy56YjI2uwJszQOSlg6B N/XFkmRnvfJ7guQGv6/I/m5UWTWejzLzGBkFJxkAHSph6zdypIYtdKyJUNjapAPqVRq5 CvwWUQndo1PiX5bAhcm8ffmKuIA0Y5/5bEJHrTd1SpRE/WZ7nq7ae5Y8XNMwFobQmW3i 1cpg== X-Forwarded-Encrypted: i=1; AJvYcCX+sLwgyObJLm5L5d96BDU6PYTAyygSTgrpQRN8E1FlylkhsPYFgBSTD6qczCcTQeRs98AwiC5n56O+HEw=@vger.kernel.org X-Gm-Message-State: AOJu0Yw5KCMrqMdzz78u6wdWwTdCUTLa/cZ8kNCv6Zz7Apqc79EKkF4v OEGuVjA9zhCE7l6PNmEMUYS624FgB+6YV2vgASCtjOwrtwMKyCjCEdSXBDzJst5AUTQ4EO6XUA= = X-Google-Smtp-Source: AGHT+IEscl/eFn4ca6UhacAGwIAp5Klg5dZiDSUgtMEvBWdRgY7g8fjyLx/wTScj6YAQy9EZGzNV9TOR0A== X-Received: from edbfd23.prod.google.com ([2002:a05:6402:3897:b0:5e4:d495:16dd]) (user=elver job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6402:268f:b0:5e0:3f83:92ab with SMTP id 4fb4d7f45d1cf-5e4d6b87d70mr17084911a12.30.1741080311449; Tue, 04 Mar 2025 01:25:11 -0800 (PST) Date: Tue, 4 Mar 2025 10:21:00 +0100 In-Reply-To: <20250304092417.2873893-1-elver@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250304092417.2873893-1-elver@google.com> X-Mailer: git-send-email 2.48.1.711.g2feabab25a-goog Message-ID: <20250304092417.2873893-2-elver@google.com> Subject: [PATCH v2 01/34] compiler_types: Move lock checking attributes to compiler-capability-analysis.h From: Marco Elver To: elver@google.com Cc: "David S. Miller" , Luc Van Oostenryck , "Paul E. McKenney" , Alexander Potapenko , Arnd Bergmann , Bart Van Assche , Bill Wendling , Boqun Feng , Dmitry Vyukov , Eric Dumazet , Frederic Weisbecker , Greg Kroah-Hartman , Herbert Xu , Ingo Molnar , Jann Horn , Jiri Slaby , Joel Fernandes , Jonathan Corbet , Josh Triplett , Justin Stitt , Kees Cook , Kentaro Takeda , Mark Rutland , Mathieu Desnoyers , Miguel Ojeda , Nathan Chancellor , Neeraj Upadhyay , Peter Zijlstra , Steven Rostedt , Tetsuo Handa , Thomas Gleixner , Uladzislau Rezki , Waiman Long , Will Deacon , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org, llvm@lists.linux.dev, rcu@vger.kernel.org, linux-crypto@vger.kernel.org, linux-serial@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The conditional definition of lock checking macros and attributes is about to become more complex. Factor them out into their own header for better readability, and to make it obvious which features are supported by which mode (currently only Sparse). This is the first step towards generalizing towards "capability analysis". No functional change intended. Signed-off-by: Marco Elver Reviewed-by: Bart Van Assche --- include/linux/compiler-capability-analysis.h | 32 ++++++++++++++++++++ include/linux/compiler_types.h | 18 ++--------- 2 files changed, 34 insertions(+), 16 deletions(-) create mode 100644 include/linux/compiler-capability-analysis.h diff --git a/include/linux/compiler-capability-analysis.h b/include/linux/c= ompiler-capability-analysis.h new file mode 100644 index 000000000000..7546ddb83f86 --- /dev/null +++ b/include/linux/compiler-capability-analysis.h @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Macros and attributes for compiler-based static capability analysis. + */ + +#ifndef _LINUX_COMPILER_CAPABILITY_ANALYSIS_H +#define _LINUX_COMPILER_CAPABILITY_ANALYSIS_H + +#ifdef __CHECKER__ + +/* Sparse context/lock checking support. */ +# define __must_hold(x) __attribute__((context(x,1,1))) +# define __acquires(x) __attribute__((context(x,0,1))) +# define __cond_acquires(x) __attribute__((context(x,0,-1))) +# define __releases(x) __attribute__((context(x,1,0))) +# define __acquire(x) __context__(x,1) +# define __release(x) __context__(x,-1) +# define __cond_lock(x, c) ((c) ? ({ __acquire(x); 1; }) : 0) + +#else /* !__CHECKER__ */ + +# define __must_hold(x) +# define __acquires(x) +# define __cond_acquires(x) +# define __releases(x) +# define __acquire(x) (void)0 +# define __release(x) (void)0 +# define __cond_lock(x, c) (c) + +#endif /* __CHECKER__ */ + +#endif /* _LINUX_COMPILER_CAPABILITY_ANALYSIS_H */ diff --git a/include/linux/compiler_types.h b/include/linux/compiler_types.h index 981cc3d7e3aa..4a458e41293c 100644 --- a/include/linux/compiler_types.h +++ b/include/linux/compiler_types.h @@ -24,6 +24,8 @@ # define BTF_TYPE_TAG(value) /* nothing */ #endif =20 +#include + /* sparse defines __CHECKER__; see Documentation/dev-tools/sparse.rst */ #ifdef __CHECKER__ /* address spaces */ @@ -34,14 +36,6 @@ # define __rcu __attribute__((noderef, address_space(__rcu))) static inline void __chk_user_ptr(const volatile void __user *ptr) { } static inline void __chk_io_ptr(const volatile void __iomem *ptr) { } -/* context/locking */ -# define __must_hold(x) __attribute__((context(x,1,1))) -# define __acquires(x) __attribute__((context(x,0,1))) -# define __cond_acquires(x) __attribute__((context(x,0,-1))) -# define __releases(x) __attribute__((context(x,1,0))) -# define __acquire(x) __context__(x,1) -# define __release(x) __context__(x,-1) -# define __cond_lock(x,c) ((c) ? ({ __acquire(x); 1; }) : 0) /* other */ # define __force __attribute__((force)) # define __nocast __attribute__((nocast)) @@ -62,14 +56,6 @@ static inline void __chk_io_ptr(const volatile void __io= mem *ptr) { } =20 # define __chk_user_ptr(x) (void)0 # define __chk_io_ptr(x) (void)0 -/* context/locking */ -# define __must_hold(x) -# define __acquires(x) -# define __cond_acquires(x) -# define __releases(x) -# define __acquire(x) (void)0 -# define __release(x) (void)0 -# define __cond_lock(x,c) (c) /* other */ # define __force # define __nocast --=20 2.48.1.711.g2feabab25a-goog From nobody Thu May 7 18:25:53 2026 Received: from mail-ed1-f73.google.com (mail-ed1-f73.google.com [209.85.208.73]) (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 A51FB1FCFFB for ; Tue, 4 Mar 2025 09:25:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080318; cv=none; b=W+MLzSJ3j57xQ/Tejx482z5h3LQTqh/TtMU7qWeQEJ/kOdhRA0zwm/US9WIn5m9UxGMiYzs1/QZ+Mpo6KurGDnSeBQlB9pCKQC6e7fy3SAdX/l4tfVVhth/6mFGkM/Uz5PNo9gDZbnha45un24PJZukGz4heluC0wFuRsOLo7X8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080318; c=relaxed/simple; bh=VkhGfiuUn9q3goIt57XdzrI3URDD6c72kbPHwbG20Kk=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=fHziU9dFz6aeL2L8KwV8HP+u8qBfCVcf2F91/AIO/pRiD83pD1ulsKmDHArlIOgDxCFz0ypcOlHs2X4ZWtJg8ffzOkKpCKJazr8no8tgwTLOt9FWoFQ5Cn6xbJtatIpy2TduCI1dr52kM5PAJ60ogEjdsP07Di36aDO1xQ3Mhh8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--elver.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=EpVXu9GH; arc=none smtp.client-ip=209.85.208.73 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--elver.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="EpVXu9GH" Received: by mail-ed1-f73.google.com with SMTP id 4fb4d7f45d1cf-5e583e090deso1142193a12.1 for ; Tue, 04 Mar 2025 01:25:15 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1741080314; x=1741685114; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=kWljJ6Cp78z9nBpFGSGBuSflIksXCmyHBsRMDURZjlg=; b=EpVXu9GHTe+vx/EncDjznPM2GWDfHbqt9gHkGG7s19t9GBeywtJdwxQHoHjPN+sFFs QIq6AibOd0XH3U1+7PZKLmys1WSwL/iFxFV9ZIpYKqKqnAful0wGQPPTJfc2fQO/zWI9 kTInNW5zMevM3WusoY5Ge1/XXkrhACqW8NA7VrobJceaEcRVJR2XMAmCaywAeeHAzEkF WLF7U75P6D9CwAuiNMoEEV46gaPvIQU2YG/DSSWCZlOWLs6w/ZIRBdo2DnUkyJDuIKQf MV4QwVgHbh0+mw9eJ0KOoITP9yZvgkI5Td2wBASLp2cbrVJObLW6VDHdw0dE6s9QHfWI uxaw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741080314; x=1741685114; h=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; bh=kWljJ6Cp78z9nBpFGSGBuSflIksXCmyHBsRMDURZjlg=; b=q9cbw7CVKNnoaAh/jqAXl19vFhAyRWl7V5vNSZavcD9+XWA64VlJiwQ+QOd7WUNtWn oLzWNe/HeVRIgn8O6lxSo7UrVlncWjeMu5nyGL9MZPfkYK5gEee8zWx203LNxlTcQhR3 lTbxGh2BRbXuMVIz3xc4tiT9bkcIK6WcVPy9zDtXW+lTHmtiI3ji8RzsVIlpn9iBgw4b MBUB6ZD+DpS96paakm5xrtYIL1bgrYxGsXCDkqGrJtc8pR4f/J6guGzxEIfcY+M47VWP QRBRVR0ynXI6L0ET18ZP8wWYAYKIHgJIGqdHezcY1XY3w40XrYo+nbo84kQ3vjvsPLSb 26nQ== X-Forwarded-Encrypted: i=1; AJvYcCUqYosmv3aiF5/Nxo5mgqCojaVv9jRL4UgL4ONCiaPfjqh3WbVieiYvSMkWNWybhCoGAczL9P97ljOD4b8=@vger.kernel.org X-Gm-Message-State: AOJu0YxyGgu7GKBplyi08cQXe0R9yovmEDU3HUsLNFM5hZFtIxmliw8C 2P7AamRHC6qc7DhweM7DXjbYAZcegy18yMdRPe1cO4LGb5KiLGPqOjIHqDBE3UUmdOCQsFzK6g= = X-Google-Smtp-Source: AGHT+IFx2ou/QuAFmIUAlqle5Ae6nVXYkQFWvjC1m14ueuW175sGb3meshCyQWIZnxw9rj/A84+OtDA02Q== X-Received: from edxn3.prod.google.com ([2002:a05:6402:5c3:b0:5e4:cc5d:aa63]) (user=elver job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6402:26c2:b0:5db:f423:19c5 with SMTP id 4fb4d7f45d1cf-5e4d6ac4066mr16631161a12.5.1741080314075; Tue, 04 Mar 2025 01:25:14 -0800 (PST) Date: Tue, 4 Mar 2025 10:21:01 +0100 In-Reply-To: <20250304092417.2873893-1-elver@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250304092417.2873893-1-elver@google.com> X-Mailer: git-send-email 2.48.1.711.g2feabab25a-goog Message-ID: <20250304092417.2873893-3-elver@google.com> Subject: [PATCH v2 02/34] compiler-capability-analysis: Add infrastructure for Clang's capability analysis From: Marco Elver To: elver@google.com Cc: "David S. Miller" , Luc Van Oostenryck , "Paul E. McKenney" , Alexander Potapenko , Arnd Bergmann , Bart Van Assche , Bill Wendling , Boqun Feng , Dmitry Vyukov , Eric Dumazet , Frederic Weisbecker , Greg Kroah-Hartman , Herbert Xu , Ingo Molnar , Jann Horn , Jiri Slaby , Joel Fernandes , Jonathan Corbet , Josh Triplett , Justin Stitt , Kees Cook , Kentaro Takeda , Mark Rutland , Mathieu Desnoyers , Miguel Ojeda , Nathan Chancellor , Neeraj Upadhyay , Peter Zijlstra , Steven Rostedt , Tetsuo Handa , Thomas Gleixner , Uladzislau Rezki , Waiman Long , Will Deacon , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org, llvm@lists.linux.dev, rcu@vger.kernel.org, linux-crypto@vger.kernel.org, linux-serial@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Capability analysis is a C language extension, which enables statically checking that user-definable "capabilities" are acquired and released where required. An obvious application is lock-safety checking for the kernel's various synchronization primitives (each of which represents a "capability"= ), and checking that locking rules are not violated. Clang originally called the feature "Thread Safety Analysis" [1], with some terminology still using the thread-safety-analysis-only names. This was later changed and the feature became more flexible, gaining the ability to define custom "capabilities". Its foundations can be found in "capability systems", used to specify the permissibility of operations to depend on some capability being held (or not held). [1] https://clang.llvm.org/docs/ThreadSafetyAnalysis.html [2] https://www.cs.cornell.edu/talc/papers/capabilities.pdf Because the feature is not just able to express capabilities related to synchronization primitives, the naming chosen for the kernel departs from Clang's initial "Thread Safety" nomenclature and refers to the feature as "Capability Analysis" to avoid confusion. The implementation still makes references to the older terminology in some places, such as `-Wthread-safety` being the warning enabled option that also still appears in diagnostic messages. See more details in the kernel-doc documentation added in this and the subsequent changes. A Clang version that supports -Wthread-safety-pointer is recommended, but not required: https://github.com/llvm/llvm-project/commit/de10e44b6fe7 Signed-off-by: Marco Elver --- v2: * New -Wthread-safety feature rename to -Wthread-safety-pointer (was -Wthread-safety-addressof). * Introduce __capability_unsafe() function attribute. * Rename __var_guarded_by to simply __guarded_by. The initial idea was to be explicit if the variable or pointed-to data is guarded by, but having a shorter attribute name is likely better long-term. * Rename __ref_guarded_by to __pt_guarded_by (pointed-to guarded by). --- Makefile | 1 + include/linux/compiler-capability-analysis.h | 394 ++++++++++++++++++- lib/Kconfig.debug | 29 ++ scripts/Makefile.capability-analysis | 7 + scripts/Makefile.lib | 10 + 5 files changed, 434 insertions(+), 7 deletions(-) create mode 100644 scripts/Makefile.capability-analysis diff --git a/Makefile b/Makefile index 70bdbf2218fc..3a945098515e 100644 --- a/Makefile +++ b/Makefile @@ -1082,6 +1082,7 @@ include-$(CONFIG_KCOV) +=3D scripts/Makefile.kcov include-$(CONFIG_RANDSTRUCT) +=3D scripts/Makefile.randstruct include-$(CONFIG_AUTOFDO_CLANG) +=3D scripts/Makefile.autofdo include-$(CONFIG_PROPELLER_CLANG) +=3D scripts/Makefile.propeller +include-$(CONFIG_WARN_CAPABILITY_ANALYSIS) +=3D scripts/Makefile.capabilit= y-analysis include-$(CONFIG_GCC_PLUGINS) +=3D scripts/Makefile.gcc-plugins =20 include $(addprefix $(srctree)/, $(include-y)) diff --git a/include/linux/compiler-capability-analysis.h b/include/linux/c= ompiler-capability-analysis.h index 7546ddb83f86..c47d9ed18303 100644 --- a/include/linux/compiler-capability-analysis.h +++ b/include/linux/compiler-capability-analysis.h @@ -6,26 +6,406 @@ #ifndef _LINUX_COMPILER_CAPABILITY_ANALYSIS_H #define _LINUX_COMPILER_CAPABILITY_ANALYSIS_H =20 +#if defined(WARN_CAPABILITY_ANALYSIS) + +/* + * The below attributes are used to define new capability types. Internal = only. + */ +# define __cap_type(name) __attribute__((capability(#name))) +# define __acquires_cap(var) __attribute__((acquire_capability(var))) +# define __acquires_shared_cap(var) __attribute__((acquire_shared_capabil= ity(var))) +# define __try_acquires_cap(ret, var) __attribute__((try_acquire_capabili= ty(ret, var))) +# define __try_acquires_shared_cap(ret, var) __attribute__((try_acquire_sh= ared_capability(ret, var))) +# define __releases_cap(var) __attribute__((release_capability(var))) +# define __releases_shared_cap(var) __attribute__((release_shared_capabil= ity(var))) +# define __asserts_cap(var) __attribute__((assert_capability(var))) +# define __asserts_shared_cap(var) __attribute__((assert_shared_capabilit= y(var))) +# define __returns_cap(var) __attribute__((lock_returned(var))) + +/* + * The below are used to annotate code being checked. Internal only. + */ +# define __excludes_cap(var) __attribute__((locks_excluded(var))) +# define __requires_cap(var) __attribute__((requires_capability(var))) +# define __requires_shared_cap(var) __attribute__((requires_shared_capabil= ity(var))) + +/** + * __guarded_by - struct member and globals attribute, declares variable + * protected by capability + * @var: the capability instance that guards the member or global + * + * Declares that the struct member or global variable must be guarded by t= he + * given capability @var. Read operations on the data require shared acces= s, + * while write operations require exclusive access. + * + * .. code-block:: c + * + * struct some_state { + * spinlock_t lock; + * long counter __guarded_by(&lock); + * }; + */ +# define __guarded_by(var) __attribute__((guarded_by(var))) + +/** + * __pt_guarded_by - struct member and globals attribute, declares pointed= -to + * data is protected by capability + * @var: the capability instance that guards the member or global + * + * Declares that the data pointed to by the struct member pointer or global + * pointer must be guarded by the given capability @var. Read operations o= n the + * data require shared access, while write operations require exclusive ac= cess. + * + * .. code-block:: c + * + * struct some_state { + * spinlock_t lock; + * long *counter __pt_guarded_by(&lock); + * }; + */ +# define __pt_guarded_by(var) __attribute__((pt_guarded_by(var))) + +/** + * struct_with_capability() - declare or define a capability struct + * @name: struct name + * + * Helper to declare or define a struct type with capability of the same n= ame. + * + * .. code-block:: c + * + * struct_with_capability(my_handle) { + * int foo; + * long bar; + * }; + * + * struct some_state { + * ... + * }; + * // ... declared elsewhere ... + * struct_with_capability(some_state); + * + * Note: The implementation defines several helper functions that can acqu= ire, + * release, and assert the capability. + */ +# define struct_with_capability(name) \ + struct __cap_type(name) name; \ + static __always_inline void __acquire_cap(const struct name *var) \ + __attribute__((overloadable)) __no_capability_analysis __acquires_cap(va= r) { } \ + static __always_inline void __acquire_shared_cap(const struct name *var) = \ + __attribute__((overloadable)) __no_capability_analysis __acquires_shared= _cap(var) { } \ + static __always_inline bool __try_acquire_cap(const struct name *var, boo= l ret) \ + __attribute__((overloadable)) __no_capability_analysis __try_acquires_ca= p(1, var) \ + { return ret; } \ + static __always_inline bool __try_acquire_shared_cap(const struct name *v= ar, bool ret) \ + __attribute__((overloadable)) __no_capability_analysis __try_acquires_sh= ared_cap(1, var) \ + { return ret; } \ + static __always_inline void __release_cap(const struct name *var) \ + __attribute__((overloadable)) __no_capability_analysis __releases_cap(va= r) { } \ + static __always_inline void __release_shared_cap(const struct name *var) = \ + __attribute__((overloadable)) __no_capability_analysis __releases_shared= _cap(var) { } \ + static __always_inline void __assert_cap(const struct name *var) \ + __attribute__((overloadable)) __asserts_cap(var) { } \ + static __always_inline void __assert_shared_cap(const struct name *var) = \ + __attribute__((overloadable)) __asserts_shared_cap(var) { } \ + struct name + +/** + * disable_capability_analysis() - disables capability analysis + * + * Disables capability analysis. Must be paired with a later + * enable_capability_analysis(). + */ +# define disable_capability_analysis() \ + __diag_push(); \ + __diag_ignore_all("-Wunknown-warning-option", "") \ + __diag_ignore_all("-Wthread-safety", "") \ + __diag_ignore_all("-Wthread-safety-pointer", "") + +/** + * enable_capability_analysis() - re-enables capability analysis + * + * Re-enables capability analysis. Must be paired with a prior + * disable_capability_analysis(). + */ +# define enable_capability_analysis() __diag_pop() + +/** + * __no_capability_analysis - function attribute, disables capability anal= ysis + * + * Function attribute denoting that capability analysis is disabled for the + * whole function. Prefer use of `capability_unsafe()` where possible. + */ +# define __no_capability_analysis __attribute__((no_thread_safety_analysis= )) + +#else /* !WARN_CAPABILITY_ANALYSIS */ + +# define __cap_type(name) +# define __acquires_cap(var) +# define __acquires_shared_cap(var) +# define __try_acquires_cap(ret, var) +# define __try_acquires_shared_cap(ret, var) +# define __releases_cap(var) +# define __releases_shared_cap(var) +# define __asserts_cap(var) +# define __asserts_shared_cap(var) +# define __returns_cap(var) +# define __guarded_by(var) +# define __pt_guarded_by(var) +# define __excludes_cap(var) +# define __requires_cap(var) +# define __requires_shared_cap(var) +# define __acquire_cap(var) do { } while (0) +# define __acquire_shared_cap(var) do { } while (0) +# define __try_acquire_cap(var, ret) (ret) +# define __try_acquire_shared_cap(var, ret) (ret) +# define __release_cap(var) do { } while (0) +# define __release_shared_cap(var) do { } while (0) +# define __assert_cap(var) do { (void)(var); } while (0) +# define __assert_shared_cap(var) do { (void)(var); } while (0) +# define struct_with_capability(name) struct name +# define disable_capability_analysis() +# define enable_capability_analysis() +# define __no_capability_analysis + +#endif /* WARN_CAPABILITY_ANALYSIS */ + +/** + * capability_unsafe() - disable capability checking for contained code + * + * Disables capability 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 capability_unsafe(d->counter); + * } + */ +#define capability_unsafe(...) \ +({ \ + disable_capability_analysis(); \ + __VA_ARGS__; \ + enable_capability_analysis() \ +}) + +/** + * __capability_unsafe() - function attribute, disable capability checking + * @comment: comment explaining why opt-out is safe + * + * Function attribute denoting that capability analysis is disabled for the + * whole function. Forces adding an inline comment as argument. + */ +#define __capability_unsafe(comment) __no_capability_analysis + +/** + * token_capability() - declare an abstract global capability instance + * @name: token capability name + * + * Helper that declares an abstract global capability instance @name that = can be + * used as a token capability, but not backed by a real data structure (li= nker + * error if accidentally referenced). The type name is `__capability_@name= `. + */ +#define token_capability(name) \ + struct_with_capability(__capability_##name) {}; \ + extern const struct __capability_##name *name + +/** + * token_capability_instance() - declare another instance of a global capa= bility + * @cap: token capability previously declared with token_capability() + * @name: name of additional global capability instance + * + * Helper that declares an additional instance @name of the same token + * capability class @name. This is helpful where multiple related token + * capabilities are declared, as it also allows using the same underlying = type + * (`__capability_@cap`) as function arguments. + */ +#define token_capability_instance(cap, name) \ + extern const struct __capability_##cap *name + +/* + * Common keywords for static capability analysis. Both Clang's capability + * analysis and Sparse's context tracking are currently supported. + */ #ifdef __CHECKER__ =20 /* Sparse context/lock checking support. */ # define __must_hold(x) __attribute__((context(x,1,1))) +# define __must_not_hold(x) # define __acquires(x) __attribute__((context(x,0,1))) # define __cond_acquires(x) __attribute__((context(x,0,-1))) # define __releases(x) __attribute__((context(x,1,0))) # define __acquire(x) __context__(x,1) # define __release(x) __context__(x,-1) # define __cond_lock(x, c) ((c) ? ({ __acquire(x); 1; }) : 0) +/* For Sparse, there's no distinction between exclusive and shared locks. = */ +# define __must_hold_shared __must_hold +# define __acquires_shared __acquires +# define __cond_acquires_shared __cond_acquires +# define __releases_shared __releases +# define __acquire_shared __acquire +# define __release_shared __release +# define __cond_lock_shared __cond_acquire =20 #else /* !__CHECKER__ */ =20 -# define __must_hold(x) -# define __acquires(x) -# define __cond_acquires(x) -# define __releases(x) -# define __acquire(x) (void)0 -# define __release(x) (void)0 -# define __cond_lock(x, c) (c) +/** + * __must_hold() - function attribute, caller must hold exclusive capabili= ty + * @x: capability instance pointer + * + * Function attribute declaring that the caller must hold the given capabi= lity + * instance @x exclusively. + */ +# define __must_hold(x) __requires_cap(x) + +/** + * __must_not_hold() - function attribute, caller must not hold capability + * @x: capability instance pointer + * + * Function attribute declaring that the caller must not hold the given + * capability instance @x. + */ +# define __must_not_hold(x) __excludes_cap(x) + +/** + * __acquires() - function attribute, function acquires capability exclusi= vely + * @x: capability instance pointer + * + * Function attribute declaring that the function acquires the given + * capability instance @x exclusively, but does not release it. + */ +# define __acquires(x) __acquires_cap(x) + +/** + * __cond_acquires() - function attribute, function conditionally + * acquires a capability exclusively + * @x: capability instance pointer + * + * Function attribute declaring that the function conditionally acquires t= he + * given capability instance @x exclusively, but does not release it. + */ +# define __cond_acquires(x) __try_acquires_cap(1, x) + +/** + * __releases() - function attribute, function releases a capability exclu= sively + * @x: capability instance pointer + * + * Function attribute declaring that the function releases the given capab= ility + * instance @x exclusively. The capability must be held on entry. + */ +# define __releases(x) __releases_cap(x) + +/** + * __acquire() - function to acquire capability exclusively + * @x: capability instance pinter + * + * No-op function that acquires the given capability instance @x exclusive= ly. + */ +# define __acquire(x) __acquire_cap(x) + +/** + * __release() - function to release capability exclusively + * @x: capability instance pinter + * + * No-op function that releases the given capability instance @x. + */ +# define __release(x) __release_cap(x) + +/** + * __cond_lock() - function that conditionally acquires a capability + * exclusively + * @x: capability instance pinter + * @c: boolean expression + * + * Return: result of @c + * + * No-op function that conditionally acquires capability instance @x + * exclusively, if the boolean expression @c is true. The result of @c is = the + * return value, to be able to create a capability-enabled interface; for + * example: + * + * .. code-block:: c + * + * #define spin_trylock(l) __cond_lock(&lock, _spin_trylock(&lock)) + */ +# define __cond_lock(x, c) __try_acquire_cap(x, c) + +/** + * __must_hold_shared() - function attribute, caller must hold shared capa= bility + * @x: capability instance pointer + * + * Function attribute declaring that the caller must hold the given capabi= lity + * instance @x with shared access. + */ +# define __must_hold_shared(x) __requires_shared_cap(x) + +/** + * __acquires_shared() - function attribute, function acquires capability = shared + * @x: capability instance pointer + * + * Function attribute declaring that the function acquires the given + * capability instance @x with shared access, but does not release it. + */ +# define __acquires_shared(x) __acquires_shared_cap(x) + +/** + * __cond_acquires_shared() - function attribute, function conditionally + * acquires a capability shared + * @x: capability instance pointer + * + * Function attribute declaring that the function conditionally acquires t= he + * given capability instance @x with shared access, but does not release i= t. + */ +# define __cond_acquires_shared(x) __try_acquires_shared_cap(1, x) + +/** + * __releases_shared() - function attribute, function releases a + * capability shared + * @x: capability instance pointer + * + * Function attribute declaring that the function releases the given capab= ility + * instance @x with shared access. The capability must be held on entry. + */ +# define __releases_shared(x) __releases_shared_cap(x) + +/** + * __acquire_shared() - function to acquire capability shared + * @x: capability instance pinter + * + * No-op function that acquires the given capability instance @x with shar= ed + * access. + */ +# define __acquire_shared(x) __acquire_shared_cap(x) + +/** + * __release_shared() - function to release capability shared + * @x: capability instance pinter + * + * No-op function that releases the given capability instance @x with shar= ed + * access. + */ +# define __release_shared(x) __release_shared_cap(x) + +/** + * __cond_lock_shared() - function that conditionally acquires a capability + * shared + * @x: capability instance pinter + * @c: boolean expression + * + * Return: result of @c + * + * No-op function that conditionally acquires capability instance @x with = shared + * access, if the boolean expression @c is true. The result of @c is the r= eturn + * value, to be able to create a capability-enabled interface. + */ +# define __cond_lock_shared(x, c) __try_acquire_shared_cap(x, c) =20 #endif /* __CHECKER__ */ =20 diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 1af972a92d06..f30099051294 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -603,6 +603,35 @@ config DEBUG_FORCE_WEAK_PER_CPU To ensure that generic code follows the above rules, this option forces all percpu variables to be defined as weak. =20 +config WARN_CAPABILITY_ANALYSIS + bool "Compiler capability-analysis warnings" + depends on CC_IS_CLANG && $(cc-option,-Wthread-safety -fexperimental-late= -parse-attributes) + # Branch profiling re-defines "if", which messes with the compiler's + # ability to analyze __cond_acquires(..), resulting in false positives. + depends on !TRACE_BRANCH_PROFILING + default y + help + Capability analysis is a C language extension, which enables + statically checking that user-definable "capabilities" are acquired + and released where required. + + Clang's name of the feature ("Thread Safety Analysis") refers to + the original name of the feature; it was later expanded to be a + generic "Capability Analysis" framework. + + Produces warnings by default. Select CONFIG_WERROR if you wish to + turn these warnings into errors. + +config WARN_CAPABILITY_ANALYSIS_ALL + bool "Enable capability analysis for all source files" + depends on WARN_CAPABILITY_ANALYSIS + depends on EXPERT && !COMPILE_TEST + help + Enable tree-wide capability analysis. This is likely to produce a + large number of false positives - enable at your own risk. + + If unsure, say N. + endmenu # "Compiler options" =20 menu "Generic Kernel Debugging Instruments" diff --git a/scripts/Makefile.capability-analysis b/scripts/Makefile.capabi= lity-analysis new file mode 100644 index 000000000000..b7b36cca47f4 --- /dev/null +++ b/scripts/Makefile.capability-analysis @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 + +capability-analysis-cflags :=3D -DWARN_CAPABILITY_ANALYSIS \ + -fexperimental-late-parse-attributes -Wthread-safety \ + $(call cc-option,-Wthread-safety-pointer) + +export CFLAGS_CAPABILITY_ANALYSIS :=3D $(capability-analysis-cflags) diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index cad20f0e66ee..08910001ee64 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -191,6 +191,16 @@ _c_flags +=3D $(if $(patsubst n%,, \ -D__KCSAN_INSTRUMENT_BARRIERS__) endif =20 +# +# Enable capability analysis flags only where explicitly opted in. +# (depends on variables CAPABILITY_ANALYSIS_obj.o, CAPABILITY_ANALYSIS) +# +ifeq ($(CONFIG_WARN_CAPABILITY_ANALYSIS),y) +_c_flags +=3D $(if $(patsubst n%,, \ + $(CAPABILITY_ANALYSIS_$(target-stem).o)$(CAPABILITY_ANALYSIS)$(if $(is-k= ernel-object),$(CONFIG_WARN_CAPABILITY_ANALYSIS_ALL))), \ + $(CFLAGS_CAPABILITY_ANALYSIS)) +endif + # # Enable AutoFDO build flags except some files or directories we don't wan= t to # enable (depends on variables AUTOFDO_PROFILE_obj.o and AUTOFDO_PROFILE). --=20 2.48.1.711.g2feabab25a-goog From nobody Thu May 7 18:25:53 2026 Received: from mail-wr1-f74.google.com (mail-wr1-f74.google.com [209.85.221.74]) (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 826AB1FDE1E for ; Tue, 4 Mar 2025 09:25:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080321; cv=none; b=hTEedRhjZ8v1tkKvNpnsvO0zQmOBslt/LcE0zbdj9DbObJuzhIKUjwh9df4Zalf4JDpRXHoajgOh//qqEIblAVb/TRm21Nx+5duImt1Wmv6GLprUJS7UAIbf5kyaThzvqUhS1xVcX7Z2TQfLi9NLt/C73FQkJWClAm9zBqbNxUQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080321; c=relaxed/simple; bh=D2pcj7eNNhKsXgn3XF0f/0vqaucKJ4Nfaio7BEZzV6o=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=EeMSVlOi9DduwyjppWR/pMzI+D4UFDSvhZbi3OgCiLG/pqtpxCUR5nw2IpgHM8foKKQ1sNg4ZuYU8AzXFSRkxVyUcY2vXiigo8EDs0eDX6Hx5Mz2XCEsy1nl5tTO5zAhnVv28LK5iXIkrKcgc4JfxUEGjREwGkwC9hRlsKslOeM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--elver.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=vs8i/HV6; arc=none smtp.client-ip=209.85.221.74 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--elver.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="vs8i/HV6" Received: by mail-wr1-f74.google.com with SMTP id ffacd0b85a97d-390e003c1easo2439787f8f.1 for ; Tue, 04 Mar 2025 01:25:18 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1741080317; x=1741685117; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=pBc/zi9P1R3Zwtykno3mWYwrt7ORJZX5qCpzJBRDBb8=; b=vs8i/HV6DjeHWQAQxEQCNitaVYS8XL9+trpbOHP1l4G/my82PKizypDOWhD/EgaXqc 0Hv33SmCakD1i6cHlzoK8Yn7WvrMaaIkN2PMzPNNHBXVWIJK3xkk7h2jmxM7dmPFzjC0 caWTr6DUwaCVPNegfLSC+pZIR546MFC1tX1MNwmUMOUeShMUlskTlTwTVKibldL11QN2 WNsd8wjtP7TpVaHFIWP3ktrz/KR+6HvqpaAJTzg+2IqG/h1RiB8TtjUT06o0O6X8lohU KA4KZ9F7ML3czkQk2twoOEfRLhVUEs10pKfabJzKEIVXaQ5LE9fsvHDAls9+qXN2qF45 JNfw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741080317; x=1741685117; h=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; bh=pBc/zi9P1R3Zwtykno3mWYwrt7ORJZX5qCpzJBRDBb8=; b=AImqLGB31eGBHgj9XQDOYy08c+WyPrG5YzfbjyyEEf4BmLZffGI7czf/Tv+9vXCE5N YmDoAkOpS6O61Qw9SH1hoAsyytgmdOgxzxXoiayRLelDOX3C0FnWBtwYR4UnTBXqhdih k2NjyDqfmZ1JlBx810M3dsHfeVlIZrqQAm54I+UJshtOaYk1hFVmJp/AIWfgrW5ivB/n AnlppGku64oLGBNyEEEluAQmHaWkXcNZpSQx3GUBDh6G5XB7Peb7pT3snvsA0XlBnJSz A1DLChdFK9utzrun3KtyrzwWFHjPc5dvnc4oaVnYON1X+IW1l2itwMc87+c9nlwXLdep jYXA== X-Forwarded-Encrypted: i=1; AJvYcCUc4vB8t/yVPpCHZaFdAViCOYv9SPJeULs8JVBQaA+DU5fQNYC60JQuGLGZhD9nYAwcYS/tMRn7c/j2Qsc=@vger.kernel.org X-Gm-Message-State: AOJu0YyC3eKJYjqvY+BSiNrnBM0Pw74KiUpOMJwJmcmtXUMaRZWPYzvW vHM7wYU6YHyVTSQgUSb8Loeb0bRmxQSBftIPxI9MG8crtL+TWKTfH98in8y7DhM4WwD4YW685g= = X-Google-Smtp-Source: AGHT+IGQB/YIYjs3mcCeFc0d30zRBIg9YuV3qxz71mKDL9Wrd0L0zSrw4Y93Il/Zy6Ca4Q/8RxD18WTRwQ== X-Received: from wmbfp9.prod.google.com ([2002:a05:600c:6989:b0:43b:c927:5a4d]) (user=elver job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6000:186c:b0:390:f0ff:2c10 with SMTP id ffacd0b85a97d-3911561abacmr1839931f8f.19.1741080316822; Tue, 04 Mar 2025 01:25:16 -0800 (PST) Date: Tue, 4 Mar 2025 10:21:02 +0100 In-Reply-To: <20250304092417.2873893-1-elver@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250304092417.2873893-1-elver@google.com> X-Mailer: git-send-email 2.48.1.711.g2feabab25a-goog Message-ID: <20250304092417.2873893-4-elver@google.com> Subject: [PATCH v2 03/34] compiler-capability-analysis: Add test stub From: Marco Elver To: elver@google.com Cc: "David S. Miller" , Luc Van Oostenryck , "Paul E. McKenney" , Alexander Potapenko , Arnd Bergmann , Bart Van Assche , Bill Wendling , Boqun Feng , Dmitry Vyukov , Eric Dumazet , Frederic Weisbecker , Greg Kroah-Hartman , Herbert Xu , Ingo Molnar , Jann Horn , Jiri Slaby , Joel Fernandes , Jonathan Corbet , Josh Triplett , Justin Stitt , Kees Cook , Kentaro Takeda , Mark Rutland , Mathieu Desnoyers , Miguel Ojeda , Nathan Chancellor , Neeraj Upadhyay , Peter Zijlstra , Steven Rostedt , Tetsuo Handa , Thomas Gleixner , Uladzislau Rezki , Waiman Long , Will Deacon , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org, llvm@lists.linux.dev, rcu@vger.kernel.org, linux-crypto@vger.kernel.org, linux-serial@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add a simple test stub where we will add common supported patterns that should not generate false positive of each new supported capability. Signed-off-by: Marco Elver --- lib/Kconfig.debug | 14 ++++++++++++++ lib/Makefile | 3 +++ lib/test_capability-analysis.c | 18 ++++++++++++++++++ 3 files changed, 35 insertions(+) create mode 100644 lib/test_capability-analysis.c diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index f30099051294..8abaf7dab3f8 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -2764,6 +2764,20 @@ config LINEAR_RANGES_TEST =20 If unsure, say N. =20 +config CAPABILITY_ANALYSIS_TEST + bool "Compiler capability-analysis warnings test" + depends on EXPERT + help + This builds the test for compiler-based capability analysis. The test + does not add executable code to the kernel, but is meant to test that + common patterns supported by the analysis do not result in false + positive warnings. + + When adding support for new capabilities, it is strongly recommended + to add supported patterns to this test. + + If unsure, say N. + config CMDLINE_KUNIT_TEST tristate "KUnit test for cmdline API" if !KUNIT_ALL_TESTS depends on KUNIT diff --git a/lib/Makefile b/lib/Makefile index d5cfc7afbbb8..1dbb59175eb0 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -394,6 +394,9 @@ obj-$(CONFIG_CRC_KUNIT_TEST) +=3D crc_kunit.o obj-$(CONFIG_SIPHASH_KUNIT_TEST) +=3D siphash_kunit.o obj-$(CONFIG_USERCOPY_KUNIT_TEST) +=3D usercopy_kunit.o =20 +CAPABILITY_ANALYSIS_test_capability-analysis.o :=3D y +obj-$(CONFIG_CAPABILITY_ANALYSIS_TEST) +=3D test_capability-analysis.o + obj-$(CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED) +=3D devmem_is_allowed.o =20 obj-$(CONFIG_FIRMWARE_TABLE) +=3D fw_table.o diff --git a/lib/test_capability-analysis.c b/lib/test_capability-analysis.c new file mode 100644 index 000000000000..a0adacce30ff --- /dev/null +++ b/lib/test_capability-analysis.c @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Compile-only tests for common patterns that should not generate false + * positive errors when compiled with Clang's capability analysis. + */ + +#include + +/* + * Test that helper macros work as expected. + */ +static void __used test_common_helpers(void) +{ + BUILD_BUG_ON(capability_unsafe(3) !=3D 3); /* plain expression */ + BUILD_BUG_ON(capability_unsafe((void)2; 3;) !=3D 3); /* does not swallow = semi-colon */ + BUILD_BUG_ON(capability_unsafe((void)2, 3) !=3D 3); /* does not swallow c= ommas */ + capability_unsafe(do { } while (0)); /* works with void statements */ +} --=20 2.48.1.711.g2feabab25a-goog From nobody Thu May 7 18:25:53 2026 Received: from mail-ej1-f73.google.com (mail-ej1-f73.google.com [209.85.218.73]) (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 689631FE46C for ; Tue, 4 Mar 2025 09:25:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080323; cv=none; b=qc9ENf4xSzIOmGhwLBVNBLO18cQYxqX70Trs8VFzKMzuLPDAfsp9pzi6i+rLdRiILfbbQh0TOvGa9sgCNljF861goti4ues7yO2ebStdcaPruOsqvPpDAmJb4IMdR/8aQvhRYXCXPaim9DK/6k1jQciYQyAk4ybMuZ/Hv0vnM10= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080323; c=relaxed/simple; bh=L0OuX4zhmaM9o60FzP1sUh13J+x81eZXc+z1+4sEu8M=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=tKVQOkJWc1ReTlPeY0D6rOGDt3OGIMs+bj/xrx9oF1as+iU1BSUn732YBuPDYi69GOecQNm6dHG2fVG1WrEHUOaapNPnX2BUxV5YKqfvYHlKomqbobEzkasaWWrrUo/g5FuH7VuR/EO9sC/2JuawJdp6F6eZ8cvYcW9EO/nHzjE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--elver.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=3u9RpHWN; arc=none smtp.client-ip=209.85.218.73 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--elver.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="3u9RpHWN" Received: by mail-ej1-f73.google.com with SMTP id a640c23a62f3a-ac1e442740cso150015866b.1 for ; Tue, 04 Mar 2025 01:25:21 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1741080320; x=1741685120; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=dE96AlLyXfE4zcTJ3mSZ7GpwRWlrYm2AzYTGYdTipys=; b=3u9RpHWNJVC4bujyG0x5symrpir4WGvkxxJFEURU98IJwPWUCEL4tCt3vMWwRHO9nR +T9joHTUNAoTaJpA7RfMqvMRjsED63vyY/49glLKweDl6ig85bzn28wrMQHRfYfu5lY5 CkW7CXe2cxIXEjO8JDij2VWMBZkaymaOUAJ0JfxTZiRShFzAgZfag+ZbZdfJyYF2ZGjU YkbjRy0RexytNYf2ZMMjQBxXP7RAx2L3p93P9VdLedYCgHamg4HOb99L/Mx/IQdQ9Chy 5yuF20tQpLYM/uzjeT8Q4E5SLro6XBT4JWI9uvnfFRkii88YC5ElwATpMHs2j8q2qUxN q3aA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741080320; x=1741685120; h=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; bh=dE96AlLyXfE4zcTJ3mSZ7GpwRWlrYm2AzYTGYdTipys=; b=R0jKFWYNlr88UzSuTEIZImDqcLV266DheFIVvb7L60uuEYobHZtEVxH1EEeYgBYKjW I1/UbQAhKM+lAhF972jFpXdSBA1gfsQSVvapOQuupSMWmGPX8eLaJ4cr78CWssXigXyb xCJ2T2LqiY335A+c34R92Yw0gbLYx3IkrmgBvuA/NTGyW41l/TfGkj8pXHjsgqLxGSY9 SzByXHhGyeBQc2vUiQULja5Kv0eivFH6PWchia6OrJpRsSyRYz08dPWHP3nmGJApfiWE 9Ep2jb7CR+ILuMkEGNsl49QKj4vQa2zoE2lPxfo8rqsDz2i/Polt05qPAvnhnnyHQI6z amOw== X-Forwarded-Encrypted: i=1; AJvYcCWBTsP5JnoFnKRfsWjuWmRxzW2bOhvb9+rFzZvs3h1Z67GYVbeyYD7H095ZS7F3p23r791VQYpmV9lWzk8=@vger.kernel.org X-Gm-Message-State: AOJu0Yx7B9M4VHjf66eqbHxkewvp4dH/lI4zv2hVVgYjcGsDNFWTGODL gwi5+POq0sOL0XxLZTTTtwzofZXJveiglqDVC9QY5kXXiApi5tpweOO58woUIpAQf0E9Yj6tWw= = X-Google-Smtp-Source: AGHT+IFuP8M1dqAoGU6qLKH3+wWDWdvdL8t6wTEGZDy32MKEUcqZYenf1bVQSLxNtJzzOQKE63o3FVdKMg== X-Received: from ejcti14.prod.google.com ([2002:a17:907:c20e:b0:abf:6ebf:550f]) (user=elver job=prod-delivery.src-stubby-dispatcher) by 2002:a17:907:6d0f:b0:abf:7a26:c47c with SMTP id a640c23a62f3a-abf7a26c669mr613682066b.47.1741080319651; Tue, 04 Mar 2025 01:25:19 -0800 (PST) Date: Tue, 4 Mar 2025 10:21:03 +0100 In-Reply-To: <20250304092417.2873893-1-elver@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250304092417.2873893-1-elver@google.com> X-Mailer: git-send-email 2.48.1.711.g2feabab25a-goog Message-ID: <20250304092417.2873893-5-elver@google.com> Subject: [PATCH v2 04/34] Documentation: Add documentation for Compiler-Based Capability Analysis From: Marco Elver To: elver@google.com Cc: "David S. Miller" , Luc Van Oostenryck , "Paul E. McKenney" , Alexander Potapenko , Arnd Bergmann , Bart Van Assche , Bill Wendling , Boqun Feng , Dmitry Vyukov , Eric Dumazet , Frederic Weisbecker , Greg Kroah-Hartman , Herbert Xu , Ingo Molnar , Jann Horn , Jiri Slaby , Joel Fernandes , Jonathan Corbet , Josh Triplett , Justin Stitt , Kees Cook , Kentaro Takeda , Mark Rutland , Mathieu Desnoyers , Miguel Ojeda , Nathan Chancellor , Neeraj Upadhyay , Peter Zijlstra , Steven Rostedt , Tetsuo Handa , Thomas Gleixner , Uladzislau Rezki , Waiman Long , Will Deacon , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org, llvm@lists.linux.dev, rcu@vger.kernel.org, linux-crypto@vger.kernel.org, linux-serial@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Adds documentation in Documentation/dev-tools/capability-analysis.rst, and adds it to the index and cross-references from Sparse's document. Signed-off-by: Marco Elver --- v2: * Remove cross-reference to Sparse, since we plan to remove Sparse support anyway. * Mention __no_capability_analysis should be avoided. --- .../dev-tools/capability-analysis.rst | 145 ++++++++++++++++++ Documentation/dev-tools/index.rst | 1 + 2 files changed, 146 insertions(+) create mode 100644 Documentation/dev-tools/capability-analysis.rst diff --git a/Documentation/dev-tools/capability-analysis.rst b/Documentatio= n/dev-tools/capability-analysis.rst new file mode 100644 index 000000000000..4b9c93cc8fcd --- /dev/null +++ b/Documentation/dev-tools/capability-analysis.rst @@ -0,0 +1,145 @@ +.. SPDX-License-Identifier: GPL-2.0 +.. Copyright (C) 2025, Google LLC. + +.. _capability-analysis: + +Compiler-Based Capability Analysis +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Capability analysis is a C language extension, which enables statically +checking that user-definable "capabilities" are acquired and released where +required. An obvious application is lock-safety checking for the kernel's +various synchronization primitives (each of which represents a "capability= "), +and checking that locking rules are not violated. + +The Clang compiler currently supports the full set of capability analysis +features. To enable for Clang, configure the kernel with:: + + CONFIG_WARN_CAPABILITY_ANALYSIS=3Dy + +The analysis is *opt-in by default*, and requires declaring which modules = and +subsystems should be analyzed in the respective `Makefile`:: + + CAPABILITY_ANALYSIS_mymodule.o :=3D y + +Or for all translation units in the directory:: + + CAPABILITY_ANALYSIS :=3D y + +It is possible to enable the analysis tree-wide, however, which will resul= t in +numerous false positive warnings currently and is *not* generally recommen= ded:: + + CONFIG_WARN_CAPABILITY_ANALYSIS_ALL=3Dy + +Programming Model +----------------- + +The below describes the programming model around using capability-enabled +types. + +.. note:: + Enabling capability analysis can be seen as enabling a dialect of Linux= C with + a Capability System. Some valid patterns involving complex control-flow= are + constrained (such as conditional acquisition and later conditional rele= ase + in the same function, or returning pointers to capabilities from functi= ons. + +Capability analysis is a way to specify permissibility of operations to de= pend +on capabilities being held (or not held). Typically we are interested in +protecting data and code by requiring some capability to be held, for exam= ple a +specific lock. The analysis ensures that the caller cannot perform the +operation without holding the appropriate capability. + +Capabilities are associated with named structs, along with functions that +operate on capability-enabled struct instances to acquire and release the +associated capability. + +Capabilities can be held either exclusively or shared. This mechanism allo= ws +assign more precise privileges when holding a capability, typically to +distinguish where a thread may only read (shared) or also write (exclusive= ) to +guarded data. + +The set of capabilities that are actually held by a given thread at a given +point in program execution is a run-time concept. The static analysis work= s by +calculating an approximation of that set, called the capability environmen= t. +The capability environment is calculated for every program point, and desc= ribes +the set of capabilities that are statically known to be held, or not held,= at +that particular point. This environment is a conservative approximation of= the +full set of capabilities that will actually held by a thread at run-time. + +More details are also documented `here +`_. + +.. note:: + Clang's analysis explicitly does not infer capabilities acquired or rel= eased + by inline functions. It requires explicit annotations to (a) assert that + it's not a bug if a capability is released or acquired, and (b) to reta= in + consistency between inline and non-inline function declarations. + +Supported Kernel Primitives +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. Currently the following synchronization primitives are supported: + +For capabilities with an initialization function (e.g., `spin_lock_init()`= ), +calling this function on the capability instance before initializing any +guarded members or globals prevents the compiler from issuing warnings abo= ut +unguarded initialization. + +Lockdep assertions, such as `lockdep_assert_held()`, inform the compiler's +capability analysis that the associated synchronization primitive is held = after +the assertion. This avoids false positives in complex control-flow scenari= os +and encourages the use of Lockdep where static analysis is limited. For +example, this is useful when a function doesn't *always* require a lock, m= aking +`__must_hold()` inappropriate. + +Keywords +~~~~~~~~ + +.. kernel-doc:: include/linux/compiler-capability-analysis.h + :identifiers: struct_with_capability + token_capability token_capability_instance + __guarded_by __pt_guarded_by + __must_hold + __must_not_hold + __acquires + __cond_acquires + __releases + __must_hold_shared + __acquires_shared + __cond_acquires_shared + __releases_shared + __acquire + __release + __cond_lock + __acquire_shared + __release_shared + __cond_lock_shared + capability_unsafe + __capability_unsafe + disable_capability_analysis enable_capability_analysis + +.. note:: + The function attribute `__no_capability_analysis` is reserved for inter= nal + implementation of capability-enabled primitives, and should be avoided = in + normal code. + +Background +---------- + +Clang originally called the feature `Thread Safety Analysis +`_, with some +terminology still using the thread-safety-analysis-only names. This was la= ter +changed and the feature became more flexible, gaining the ability to define +custom "capabilities". + +Indeed, its foundations can be found in `capability systems +`_, used to speci= fy +the permissibility of operations to depend on some capability being held (= or +not held). + +Because the feature is not just able to express capabilities related to +synchronization primitives, the naming chosen for the kernel departs from +Clang's initial "Thread Safety" nomenclature and refers to the feature as +"Capability Analysis" to avoid confusion. The implementation still makes +references to the older terminology in some places, such as `-Wthread-safe= ty` +being the warning option that also still appears in diagnostic messages. diff --git a/Documentation/dev-tools/index.rst b/Documentation/dev-tools/in= dex.rst index 65c54b27a60b..62ac23f797cd 100644 --- a/Documentation/dev-tools/index.rst +++ b/Documentation/dev-tools/index.rst @@ -18,6 +18,7 @@ Documentation/process/debugging/index.rst :maxdepth: 2 =20 testing-overview + capability-analysis checkpatch clang-format coccinelle --=20 2.48.1.711.g2feabab25a-goog From nobody Thu May 7 18:25:53 2026 Received: from mail-ed1-f73.google.com (mail-ed1-f73.google.com [209.85.208.73]) (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 DBB6C1FECCF for ; Tue, 4 Mar 2025 09:25:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080325; cv=none; b=ffV3ZSjP+k51SpeMWDOQZfRJV7mVVxiU2shLq7xbxJFqi0XQ55WBpMQi+GqnRVhUyma+KGRQllSjmUY3yJYRip5qZQzBsD710gIyjcq+qGjuWMbhSxTYxpfnEuetsx7yNuBi7V5AcbxFCab0XQju5gRTbD7nsjBsKcGy+ivWR0E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080325; c=relaxed/simple; bh=StYpncqzFSXHEYm8ZOW/8xsOKbkMA3l0kvQy8Snle/I=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=TKKFuj9+PUPBhJsOdM7A/l7xHXGYVYjgSMePeRw+at6mDaNq15Wt56Bs36YUPPwYk95UuzDVmckQRqBqeEmPVEdXyDlg9fpXxiSGt15agf04BzMC+hzJirWODNM+s1VaR40wlR8jFQSFNkhVRtDBeOuWKegXuTyDSEwl1vgO4Zs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--elver.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=scVZ+iz5; arc=none smtp.client-ip=209.85.208.73 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--elver.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="scVZ+iz5" Received: by mail-ed1-f73.google.com with SMTP id 4fb4d7f45d1cf-5e4becb4582so7133075a12.3 for ; Tue, 04 Mar 2025 01:25:23 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1741080322; x=1741685122; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=Pp+E8sKoonvgdGAMVoQXSiL/gMXgRdJZHQEkz4wDB8k=; b=scVZ+iz51d3NKfYcrDAT7foKOBgwosQbwsV6wvyQNI64abLBrDh3kInDKqEL2XZ2yI i/QZrCOLpx273bv8NHyFfMkQaEWrn+gVldrsOScezd369MRxCkFon/5fDKG3/J6LLe2Y /Rt2C3SRfGIkS4ckhqBpP2oarSPq8DXVGzU83CN+VTEPdX6PELSIYgXMFiA5JrRwOvRw qJcNkstNO1s+24/ilf3YPA860LBYfj+jGrKgER2EpZJ30Mu3wnVVCtrUgCVx+9zW6f58 bbuk0W9+4Yn8rXXv+O7ED6LSWG+ZGH4EFSkSprX9pQazlOX1H+ktLbCGNglRfh7f3OmK q0Zw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741080322; x=1741685122; h=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; bh=Pp+E8sKoonvgdGAMVoQXSiL/gMXgRdJZHQEkz4wDB8k=; b=q40HlcBJu+LUaaZxsIZqpgHzQS4ih0ek7i4ONBZSQ087S1NlQZpQEn53gU3R5iPqYh yq/zoqz9DhY5cNoT5DY2XPB1Tahk/ykKttasVJH85huJhRldfK6QJdnW94u7snKCbbBW bxgxdJEdFfxKNqL3UqhIeiCpUCb92niWAHrUFqPWVfiBZuixPvMrR2oqO8UYVLTJcQ/s T6wFSR9dfngyK3ri7PAi2ez7cteyuf6yOHA5tsoHj+BA6okUwqn3FnW90oQrMXNK8RE1 ekbiT+qrmK/edv/36WtR1yWv7wd7zppcnKh+iCQMw+A3ygwv/Q68CYqLjbBxgldWK5M8 yQNA== X-Forwarded-Encrypted: i=1; AJvYcCU/HlNVKuo9WJVaAEIyPKYyjVo6n1K3St4fOxgI2q5pGS/3QYOhxW3+SQJsQk1nh30kgWBQmR0ysq+PSd8=@vger.kernel.org X-Gm-Message-State: AOJu0YyEBcMiAhT0cGZB7Mr78w8Iw7kY5d+TJUDQK+XLHNLgBQCwM4pr Gq7D3KhByN3kniSOzga1yXx7GkmaBq6nV957NEs5WrpM+Xu+j+I3lnD9mkKesbqUNMw5ip6Ggw= = X-Google-Smtp-Source: AGHT+IH9KyF8MJ1v+l119Ih9d9zKK6oLF4W3jM8vNIisJnYl0p8zp9JkukwRd5xgRYNmt/zF9O2bCVvi1Q== X-Received: from edpr11.prod.google.com ([2002:aa7:c14b:0:b0:5dc:578d:62e9]) (user=elver job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6402:3487:b0:5de:3478:269b with SMTP id 4fb4d7f45d1cf-5e4d6b75ef2mr15880706a12.32.1741080322290; Tue, 04 Mar 2025 01:25:22 -0800 (PST) Date: Tue, 4 Mar 2025 10:21:04 +0100 In-Reply-To: <20250304092417.2873893-1-elver@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250304092417.2873893-1-elver@google.com> X-Mailer: git-send-email 2.48.1.711.g2feabab25a-goog Message-ID: <20250304092417.2873893-6-elver@google.com> Subject: [PATCH v2 05/34] checkpatch: Warn about capability_unsafe() without comment From: Marco Elver To: elver@google.com Cc: "David S. Miller" , Luc Van Oostenryck , "Paul E. McKenney" , Alexander Potapenko , Arnd Bergmann , Bart Van Assche , Bill Wendling , Boqun Feng , Dmitry Vyukov , Eric Dumazet , Frederic Weisbecker , Greg Kroah-Hartman , Herbert Xu , Ingo Molnar , Jann Horn , Jiri Slaby , Joel Fernandes , Jonathan Corbet , Josh Triplett , Justin Stitt , Kees Cook , Kentaro Takeda , Mark Rutland , Mathieu Desnoyers , Miguel Ojeda , Nathan Chancellor , Neeraj Upadhyay , Peter Zijlstra , Steven Rostedt , Tetsuo Handa , Thomas Gleixner , Uladzislau Rezki , Waiman Long , Will Deacon , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org, llvm@lists.linux.dev, rcu@vger.kernel.org, linux-crypto@vger.kernel.org, linux-serial@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Warn about applications of capability_unsafe() without a comment, to encourage documenting the reasoning behind why it was deemed safe. Signed-off-by: Marco Elver --- scripts/checkpatch.pl | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 7b28ad331742..c28efdb1d404 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -6693,6 +6693,14 @@ sub process { } } =20 +# check for capability_unsafe without a comment. + if ($line =3D~ /\bcapability_unsafe\b/) { + if (!ctx_has_comment($first_line, $linenr)) { + WARN("CAPABILITY_UNSAFE", + "capability_unsafe without comment\n" . $herecurr); + } + } + # check of hardware specific defines if ($line =3D~ m@^.\s*\#\s*if.*\b(__i386__|__powerpc64__|__sun__|__s390x= __)\b@ && $realfile !~ m@include/asm-@) { CHK("ARCH_DEFINES", --=20 2.48.1.711.g2feabab25a-goog From nobody Thu May 7 18:25:53 2026 Received: from mail-ed1-f73.google.com (mail-ed1-f73.google.com [209.85.208.73]) (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 BFF681FF1D5 for ; Tue, 4 Mar 2025 09:25:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080328; cv=none; b=a1nr6JT6yxwb5VX9Y7IX9TQVdMOqhVT2X9QZi0kuo3oaWLezzC8a8Z/MoKdK/qnv1qQwk9XJS6Q8avxQyRTmoUKv/u3iGrM9IDeTbV6mo9ZNZtpOA/jMLnzoNNCyKrZRxmP573PIyZXZGHu22UkoNLYst6x0WjxcqRq7iCILiKQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080328; c=relaxed/simple; bh=c8IW28x9pVJ3uD+41rCTL2BIJUzCYO63UJBK2wSfgWE=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=k77hb8Zwkqo3OsDu7mJCgmd1kCo9oOaSRG5JbSP2Z9+3ENvrp+9I1Cnkf6EqvZYlMoZZn8HKBZHaoXJsugEv7z4+7EUV51j+05u8GKayABoyAGEZqeQX0vZpIawZX3M9gQvZ/zcbsR/Uhoo/Rwju/yoV6CsZ4MdBUZfeo2+9GmA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--elver.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=wwmCoPb3; arc=none smtp.client-ip=209.85.208.73 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--elver.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="wwmCoPb3" Received: by mail-ed1-f73.google.com with SMTP id 4fb4d7f45d1cf-5df498f31ccso6644817a12.1 for ; Tue, 04 Mar 2025 01:25:26 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1741080325; x=1741685125; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=07Wov0mqGRdlTFI57GwZAG7K2eg+AiDKRE973TUpU6Y=; b=wwmCoPb3qLLTEYW/WcADCR3xvRECMJ9cOezsDVAeenYh9GN/cSmysNRy53gcYBJWC2 DU9pRWn2oETv/8OMUw9Ik7kPCkZjLSmmbEYbWB9RddeXh+b6GctlXzW+/oxzJTMxRF3W LU6wS25irtT2044gfoAJoHLKBQcbAdfXjVL0RE/kgIWx5EZTFkDokfZDjGEhY6BBzU43 Gn8DiRFoiuX003/Hnsuuu9ELZQQmNN9Nm5xnbhheXEbWOPeHbrGlDGWW9xyghJJTrOZl c1l1cU+njNMlUPVLZieIBIQVylT0VsMc+hINqS1TKw12NRDtdmtg3UJ11ESJ7NZtgOK5 bAMQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741080325; x=1741685125; h=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; bh=07Wov0mqGRdlTFI57GwZAG7K2eg+AiDKRE973TUpU6Y=; b=Z8mxQbiVNUASfd02fNyhbqTP2UIGwa4Q87GoWrd297j5SD9STuk/48BPbX/vl3ydMI zmrtMvqHCCk/r0RRVWTUswMMahnQ/rZWSJoXilU8c33YQIUFwaZHTkJ66CkvsIUvrI0o 0XQ9MSufAAQT1EXbgqKdiBA2IFPn2n8qDk9S7iZdEeMLo4lKf5xtK44c5941RYUP0pb3 BvHRazErMeEwr6hfbKFEb4oYbXBZuljGMKVYuK7wKZHsropmVT4FaCxQ4sQYpX1ppFtp kglz59WcXL2v2wtfTNwur9uifhjrdd4WxeHI7mBCE/Z6jgI1QiuR9leCyMeS/hBmP48f QcIw== X-Forwarded-Encrypted: i=1; AJvYcCWQ+L6+zdtCjwSeAMLJAirx2FiCoQbhLYedWr1LGsVT/bQbybQQEtlxX62XkeUrTQVGta/D8q+9bcUuLbI=@vger.kernel.org X-Gm-Message-State: AOJu0YzC7j5TT3BsIU+S/k2cUbqMXb+uB0Tc9dmYFcJgiUbzkpcdauFv rQdO9UK4azYe4ZcMpuiTDVr4Ce26v6sF96GSc+OnenBEr8g67SKI3jlfXbSnZyjJuy55F0ghpA= = X-Google-Smtp-Source: AGHT+IEBgXpXhg9C+r+XZJg0OX31obTvbu83kkqSV+WpLbyK2OQUzgWPpBMR/CJkehpBgNUdfJdDgye1dw== X-Received: from ejcvg16.prod.google.com ([2002:a17:907:d310:b0:abf:62a3:633f]) (user=elver job=prod-delivery.src-stubby-dispatcher) by 2002:a17:906:2801:b0:abf:4647:a8cb with SMTP id a640c23a62f3a-abf4647a9d8mr1347716166b.44.1741080325134; Tue, 04 Mar 2025 01:25:25 -0800 (PST) Date: Tue, 4 Mar 2025 10:21:05 +0100 In-Reply-To: <20250304092417.2873893-1-elver@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250304092417.2873893-1-elver@google.com> X-Mailer: git-send-email 2.48.1.711.g2feabab25a-goog Message-ID: <20250304092417.2873893-7-elver@google.com> Subject: [PATCH v2 06/34] cleanup: Basic compatibility with capability analysis From: Marco Elver To: elver@google.com Cc: "David S. Miller" , Luc Van Oostenryck , "Paul E. McKenney" , Alexander Potapenko , Arnd Bergmann , Bart Van Assche , Bill Wendling , Boqun Feng , Dmitry Vyukov , Eric Dumazet , Frederic Weisbecker , Greg Kroah-Hartman , Herbert Xu , Ingo Molnar , Jann Horn , Jiri Slaby , Joel Fernandes , Jonathan Corbet , Josh Triplett , Justin Stitt , Kees Cook , Kentaro Takeda , Mark Rutland , Mathieu Desnoyers , Miguel Ojeda , Nathan Chancellor , Neeraj Upadhyay , Peter Zijlstra , Steven Rostedt , Tetsuo Handa , Thomas Gleixner , Uladzislau Rezki , Waiman Long , Will Deacon , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org, llvm@lists.linux.dev, rcu@vger.kernel.org, linux-crypto@vger.kernel.org, linux-serial@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Due to the scoped cleanup helpers used for lock guards wrapping acquire/release around their own constructors/destructors that store pointers to the passed locks in a separate struct, we currently cannot accurately annotate *destructors* which lock was released. While it's possible to annotate the constructor to say which lock was acquired, that alone would result in false positives claiming the lock was not released on function return. Instead, to avoid false positives, we can claim that the constructor "asserts" that the taken lock is held. This will ensure we can still benefit from the analysis where scoped guards are used to protect access to guarded variables, while avoiding false positives. The only downside are false negatives where we might accidentally lock the same lock again: raw_spin_lock(&my_lock); ... guard(raw_spinlock)(&my_lock); // no warning Arguably, lockdep will immediately catch issues like this. While Clang's analysis supports scoped guards in C++ [1], there's no way to apply this to C right now. Better support for Linux's scoped guard design could be added in future if deemed critical. [1] https://clang.llvm.org/docs/ThreadSafetyAnalysis.html#scoped-capability Signed-off-by: Marco Elver Reviewed-by: Bart Van Assche --- include/linux/cleanup.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/include/linux/cleanup.h b/include/linux/cleanup.h index ec00e3f7af2b..93a166549add 100644 --- a/include/linux/cleanup.h +++ b/include/linux/cleanup.h @@ -223,7 +223,7 @@ const volatile void * __must_check_fn(const volatile vo= id *val) * @exit is an expression using '_T' -- similar to FREE above. * @init is an expression in @init_args resulting in @type * - * EXTEND_CLASS(name, ext, init, init_args...): + * EXTEND_CLASS(name, ext, ctor_attrs, init, init_args...): * extends class @name to @name@ext with the new constructor * * CLASS(name, var)(args...): @@ -243,15 +243,18 @@ const volatile void * __must_check_fn(const volatile = void *val) #define DEFINE_CLASS(_name, _type, _exit, _init, _init_args...) \ typedef _type class_##_name##_t; \ static inline void class_##_name##_destructor(_type *p) \ + __no_capability_analysis \ { _type _T =3D *p; _exit; } \ static inline _type class_##_name##_constructor(_init_args) \ + __no_capability_analysis \ { _type t =3D _init; return t; } =20 -#define EXTEND_CLASS(_name, ext, _init, _init_args...) \ +#define EXTEND_CLASS(_name, ext, ctor_attrs, _init, _init_args...) \ typedef class_##_name##_t class_##_name##ext##_t; \ static inline void class_##_name##ext##_destructor(class_##_name##_t *p)\ { class_##_name##_destructor(p); } \ static inline class_##_name##_t class_##_name##ext##_constructor(_init_arg= s) \ + __no_capability_analysis ctor_attrs \ { class_##_name##_t t =3D _init; return t; } =20 #define CLASS(_name, var) \ @@ -299,7 +302,7 @@ static __maybe_unused const bool class_##_name##_is_con= ditional =3D _is_cond =20 #define DEFINE_GUARD_COND(_name, _ext, _condlock) \ __DEFINE_CLASS_IS_CONDITIONAL(_name##_ext, true); \ - EXTEND_CLASS(_name, _ext, \ + EXTEND_CLASS(_name, _ext,, \ ({ void *_t =3D _T; if (_T && !(_condlock)) _t =3D NULL; _t; }), \ class_##_name##_t _T) \ static inline void * class_##_name##_ext##_lock_ptr(class_##_name##_t *_T= ) \ @@ -371,6 +374,7 @@ typedef struct { \ } class_##_name##_t; \ \ static inline void class_##_name##_destructor(class_##_name##_t *_T) \ + __no_capability_analysis \ { \ if (_T->lock) { _unlock; } \ } \ @@ -383,6 +387,7 @@ static inline void *class_##_name##_lock_ptr(class_##_n= ame##_t *_T) \ =20 #define __DEFINE_LOCK_GUARD_1(_name, _type, _lock) \ static inline class_##_name##_t class_##_name##_constructor(_type *l) \ + __no_capability_analysis __asserts_cap(l) \ { \ class_##_name##_t _t =3D { .lock =3D l }, *_T =3D &_t; \ _lock; \ @@ -391,6 +396,7 @@ static inline class_##_name##_t class_##_name##_constru= ctor(_type *l) \ =20 #define __DEFINE_LOCK_GUARD_0(_name, _lock) \ static inline class_##_name##_t class_##_name##_constructor(void) \ + __no_capability_analysis \ { \ class_##_name##_t _t =3D { .lock =3D (void*)1 }, \ *_T __maybe_unused =3D &_t; \ @@ -410,7 +416,7 @@ __DEFINE_LOCK_GUARD_0(_name, _lock) =20 #define DEFINE_LOCK_GUARD_1_COND(_name, _ext, _condlock) \ __DEFINE_CLASS_IS_CONDITIONAL(_name##_ext, true); \ - EXTEND_CLASS(_name, _ext, \ + EXTEND_CLASS(_name, _ext, __asserts_cap(l), \ ({ class_##_name##_t _t =3D { .lock =3D l }, *_T =3D &_t;\ if (_T->lock && !(_condlock)) _T->lock =3D NULL; \ _t; }), \ --=20 2.48.1.711.g2feabab25a-goog From nobody Thu May 7 18:25:53 2026 Received: from mail-ej1-f74.google.com (mail-ej1-f74.google.com [209.85.218.74]) (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 903CA1FF7A9 for ; Tue, 4 Mar 2025 09:25:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080331; cv=none; b=Kzxes4Lde6QYufj6fy7aLe8jzFxyDVhP84lS9LJo58XuTZfX3UCso8ywfFPRfOjyywzVvRDLoFOQGP1LqAAa0qt/4in/VGZrtCg66CCgt97choiHXTBXCisGfo2veoowXv01nBFxpJ07WcNmgJhMw1lHxfmQPnOrsThuddcbT68= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080331; c=relaxed/simple; bh=JTYS1SwFh7lVbtLZ9XjE7s+Wpaj5PCO/80LIOe8cNq0=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=n1BGikpSJXJ+MJRreQkgNZmC0C3zR31T3KbiTaSqkE9ZTBPo00QcS4QcBLzRnDKLZmJxwW1GENUjsHgsEnvw4CNvgLftgNyurLvtQuVL4KIKbpDjGMQU0MEp7ke/UH2c2rcG6FvBWY8uuDfB2yNmejQ2AszY/vY7e+br9wiykK8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--elver.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=Thrf+cOt; arc=none smtp.client-ip=209.85.218.74 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--elver.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="Thrf+cOt" Received: by mail-ej1-f74.google.com with SMTP id a640c23a62f3a-abf5fc8f157so27125566b.1 for ; Tue, 04 Mar 2025 01:25:29 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1741080328; x=1741685128; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=Dvm+2kORFqwesy5wYS8KGKPET1JeCxDND2kfg3G9ty8=; b=Thrf+cOt4yD3t7IuGDdnAoKCfa+jTwi7ZNa+b1ouWFnpMd1DiiIQKtxNikQ7MCbXdN XyuQOgoH/ubYonca3m4hfniY1E5bvcjjcqGhtzc0o7kA4l3DZaEgV7RjI96IKCmZX0RC OTQGTdH3b28Wc04rKYA752c/jlWNQ4I58oVg5V5YTHDzCRtKX8NOLtsjpvVYWkz+KscK mdF8TdUlC5uMCRfb9dS/EoDi/l131zhonJREOhzxIhatXNvBUj44AQjcN9QO1e266qsi hwaYfoweXVunVGWmX11YL10wusS13jk8rc4Pi/UIAb/LBX4hVb5gikePwgQg1z9uXP/v WRtw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741080328; x=1741685128; h=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; bh=Dvm+2kORFqwesy5wYS8KGKPET1JeCxDND2kfg3G9ty8=; b=nWggij3S0TVVHzcynuFqpcQHrtSYjBiNBD5nFaNfQbVKlxl34zSg0GEMaCR9AGd1fI N6AMXYwb/Zot8Ya2UpcPKKdQPBADYcWTC5LNzc7XfS6QIaJvFlOf6l5OFp8E/Q3Ho9Dd fiyatCpM5fuVuyFuYg5CfEFZ0tpFaKKFdQbmEmdwIYetdLxys5P0hp/OhLHusIwsWKfA rEZw+/Ca5Gu7jXcs71yukfqttCuhK64ff5J49+E1uJS/qQ2dLmKLXIKddzAav5uS+o4t yZdEbSDXCzbDY2JXV/mQ77UX9jLM07W58OQcNp5Ra5Fl+1MnngCQWtXbFQm9UbXWZA5o QS2w== X-Forwarded-Encrypted: i=1; AJvYcCXHUuuNEIsFX+pwp22Knj2SsddUGO+6o9ha7hEjOBKnihypk1y8mAidJ1PNZNvibrlcWxcd3wrN0rsU2iA=@vger.kernel.org X-Gm-Message-State: AOJu0YxsQV6vRoQbWHBe0pxkGDcrY93jBZc0ypq/QLjPPkczmf8tprtu aBSUMf6rG1BDxxl1rnhgcgie8HdkvEmSGPoubwggP2Ok8kdmyGwq3qUY6y7AA3YEQPV5xx/jaQ= = X-Google-Smtp-Source: AGHT+IFvA+/G/Do4B2YEZ6UDOEYzOzvbOome5BWE9wuc2tz5n6hXXyO5SQ6HDKTmum5Vyn1BFOAEC7kT8w== X-Received: from ejctn9.prod.google.com ([2002:a17:907:c409:b0:abf:6374:f45c]) (user=elver job=prod-delivery.src-stubby-dispatcher) by 2002:a17:907:72c2:b0:ab7:cf4d:9b2d with SMTP id a640c23a62f3a-abf261f9df4mr2143998366b.30.1741080327941; Tue, 04 Mar 2025 01:25:27 -0800 (PST) Date: Tue, 4 Mar 2025 10:21:06 +0100 In-Reply-To: <20250304092417.2873893-1-elver@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250304092417.2873893-1-elver@google.com> X-Mailer: git-send-email 2.48.1.711.g2feabab25a-goog Message-ID: <20250304092417.2873893-8-elver@google.com> Subject: [PATCH v2 07/34] lockdep: Annotate lockdep assertions for capability analysis From: Marco Elver To: elver@google.com Cc: "David S. Miller" , Luc Van Oostenryck , "Paul E. McKenney" , Alexander Potapenko , Arnd Bergmann , Bart Van Assche , Bill Wendling , Boqun Feng , Dmitry Vyukov , Eric Dumazet , Frederic Weisbecker , Greg Kroah-Hartman , Herbert Xu , Ingo Molnar , Jann Horn , Jiri Slaby , Joel Fernandes , Jonathan Corbet , Josh Triplett , Justin Stitt , Kees Cook , Kentaro Takeda , Mark Rutland , Mathieu Desnoyers , Miguel Ojeda , Nathan Chancellor , Neeraj Upadhyay , Peter Zijlstra , Steven Rostedt , Tetsuo Handa , Thomas Gleixner , Uladzislau Rezki , Waiman Long , Will Deacon , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org, llvm@lists.linux.dev, rcu@vger.kernel.org, linux-crypto@vger.kernel.org, linux-serial@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Clang's capability analysis can be made aware of functions that assert that capabilities/locks are held. Presence of these annotations causes the analysis to assume the capability is held after calls to the annotated function, and avoid false positives with complex control-flow; for example, where not all control-flow paths in a function require a held lock, and therefore marking the function with __must_hold(..) is inappropriate. Signed-off-by: Marco Elver --- include/linux/lockdep.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index 67964dc4db95..5cea929b2219 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h @@ -282,16 +282,16 @@ extern void lock_unpin_lock(struct lockdep_map *lock,= struct pin_cookie); do { WARN_ON_ONCE(debug_locks && !(cond)); } while (0) =20 #define lockdep_assert_held(l) \ - lockdep_assert(lockdep_is_held(l) !=3D LOCK_STATE_NOT_HELD) + do { lockdep_assert(lockdep_is_held(l) !=3D LOCK_STATE_NOT_HELD); __asser= t_cap(l); } while (0) =20 #define lockdep_assert_not_held(l) \ lockdep_assert(lockdep_is_held(l) !=3D LOCK_STATE_HELD) =20 #define lockdep_assert_held_write(l) \ - lockdep_assert(lockdep_is_held_type(l, 0)) + do { lockdep_assert(lockdep_is_held_type(l, 0)); __assert_cap(l); } while= (0) =20 #define lockdep_assert_held_read(l) \ - lockdep_assert(lockdep_is_held_type(l, 1)) + do { lockdep_assert(lockdep_is_held_type(l, 1)); __assert_shared_cap(l); = } while (0) =20 #define lockdep_assert_held_once(l) \ lockdep_assert_once(lockdep_is_held(l) !=3D LOCK_STATE_NOT_HELD) @@ -389,10 +389,10 @@ extern int lockdep_is_held(const void *); #define lockdep_assert(c) do { } while (0) #define lockdep_assert_once(c) do { } while (0) =20 -#define lockdep_assert_held(l) do { (void)(l); } while (0) +#define lockdep_assert_held(l) __assert_cap(l) #define lockdep_assert_not_held(l) do { (void)(l); } while (0) -#define lockdep_assert_held_write(l) do { (void)(l); } while (0) -#define lockdep_assert_held_read(l) do { (void)(l); } while (0) +#define lockdep_assert_held_write(l) __assert_cap(l) +#define lockdep_assert_held_read(l) __assert_shared_cap(l) #define lockdep_assert_held_once(l) do { (void)(l); } while (0) #define lockdep_assert_none_held_once() do { } while (0) =20 --=20 2.48.1.711.g2feabab25a-goog From nobody Thu May 7 18:25:53 2026 Received: from mail-ed1-f74.google.com (mail-ed1-f74.google.com [209.85.208.74]) (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 23B0B1FCFD2 for ; Tue, 4 Mar 2025 09:25:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080335; cv=none; b=jWgHtRjGbhnoj+yvs+8vW2e4jhBX3P34z7qmJha1C+OkNis3ZS85+udyIIyaa+dxOOArpU5vWwTanbIoNpWLURT3qm/nqrufNDQ1WPGaaDpMmeqr4YxDDBILZvbo6rijTMWz+ibrbuMua2WdKVCSI9yoSyJ9XhTDWNI6wji7zAI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080335; c=relaxed/simple; bh=+0AhSChSdbaQqCdL8eyMWAMV0x5uSNgRkyq4GhMylgY=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=ncl50EFgdP8+/FcFSmaXJffeuY0Yy9p7gcwf/ypXXUsCvSLT+/YBtTZNdQkKGncPWriAFAvOyuyApkYp5PX7PFVDhNZ5aXQQq4OdCrBdn6YoLru+hVepL05hv0QrK7DDS7woLPb4EQ/2/tqzTjaxnCYF0RkTWb96xdi6kRicAlY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--elver.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=Bb1nBASW; arc=none smtp.client-ip=209.85.208.74 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--elver.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="Bb1nBASW" Received: by mail-ed1-f74.google.com with SMTP id 4fb4d7f45d1cf-5e4b3da6b49so5227685a12.2 for ; Tue, 04 Mar 2025 01:25:32 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1741080331; x=1741685131; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=c9Cj4Mr4frgnHfVo0V+RYccK4MiV1UgllCsbw+qa66U=; b=Bb1nBASWDmiZNZzrXsJJPRcYeogyI1al6Ek0KrmmrG7nApQgFmtcsw/JFayZ4ieQ9X xVz3Qe0xFdtu9qdm/UAIFhzVX8pQRuZRg+WiYYvPi8zM9o6rAdtWUlyYsm20p5o5pGIg dPSEIdBQt3HDBblrFg3WL/4m3h7vydCPdwi3BVcTmbeitr7c0K8whIm4lfhiHN+Y9/BZ s0O7M3dgj0qfkhKddO5gklnGceBQZ+qgpSHss4NOgBpX6vsLuCc9SpOOciKZ5bfInh9J AwW6rBrS4WEmQBSCSrdaQinu3rVYoB30NG7Jl2I8osspYez2S4o6G7bCDqMHCqoQDppL QfIA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741080331; x=1741685131; h=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; bh=c9Cj4Mr4frgnHfVo0V+RYccK4MiV1UgllCsbw+qa66U=; b=u3nj9qj+YceCxyaSgAKI7jg5LULEwSz5jlilQPZEETr2bVFqhcB2fiQ4uAfMvyH2zA 2yv1iOR5+5w1WG4YtufjC+VuHx1gd6t9C1K5Cq75WFGlaWWOXVIwFsoRy0b2bQKoy8Gb 5V6s6S5GDJnXYKbyxMblUmHYWGskuxrcWd+/f4szlWYt1HsV5bYslFLRChXVUMpj+NF/ 4ZceoZC+YU5kIReYXg67LIbZ0os3zBde8Esx5zhMd5LfS0GjGZvEEWA+RTOMectV/Sly /ftS9xJbZsFUxGDedJft85RjQlUUI7hCdOI3yTXunkPHQDM022BJOHlNo8ZyenB88+9c Etdg== X-Forwarded-Encrypted: i=1; AJvYcCUm/e5mLpBsy3dz6Ocf2boOEYzPtmp0nv6YUPg0LzJa1n4rw5dQAnilxf0x+vh4PsIF8K+vgn3Ti5XCdes=@vger.kernel.org X-Gm-Message-State: AOJu0YzglLuEVvBi1QnqQu7KHYKrPQXhYppXL3XOQfprt4MruXPom3hY PXasPZB1F4k6ZvBdpFZPOF5P1mWXXLmzWdjG8hL2TKtTHX9su+hCEHhQ9KxWMICjej3+a4EwBg= = X-Google-Smtp-Source: AGHT+IHQbWJyFQ0C6C1mK2P03rC9H96qYVYwUBdsPTyym958FynWJNhHUNNysiX6I1GEsmf9CPyg23q+UA== X-Received: from ejbps10.prod.google.com ([2002:a17:906:bf4a:b0:abf:4a05:fc97]) (user=elver job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6402:5203:b0:5e4:9348:72e3 with SMTP id 4fb4d7f45d1cf-5e4d6b4c2f8mr42858591a12.21.1741080330671; Tue, 04 Mar 2025 01:25:30 -0800 (PST) Date: Tue, 4 Mar 2025 10:21:07 +0100 In-Reply-To: <20250304092417.2873893-1-elver@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250304092417.2873893-1-elver@google.com> X-Mailer: git-send-email 2.48.1.711.g2feabab25a-goog Message-ID: <20250304092417.2873893-9-elver@google.com> Subject: [PATCH v2 08/34] locking/rwlock, spinlock: Support Clang's capability analysis From: Marco Elver To: elver@google.com Cc: "David S. Miller" , Luc Van Oostenryck , "Paul E. McKenney" , Alexander Potapenko , Arnd Bergmann , Bart Van Assche , Bill Wendling , Boqun Feng , Dmitry Vyukov , Eric Dumazet , Frederic Weisbecker , Greg Kroah-Hartman , Herbert Xu , Ingo Molnar , Jann Horn , Jiri Slaby , Joel Fernandes , Jonathan Corbet , Josh Triplett , Justin Stitt , Kees Cook , Kentaro Takeda , Mark Rutland , Mathieu Desnoyers , Miguel Ojeda , Nathan Chancellor , Neeraj Upadhyay , Peter Zijlstra , Steven Rostedt , Tetsuo Handa , Thomas Gleixner , Uladzislau Rezki , Waiman Long , Will Deacon , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org, llvm@lists.linux.dev, rcu@vger.kernel.org, linux-crypto@vger.kernel.org, linux-serial@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add support for Clang's capability analysis for raw_spinlock_t, spinlock_t, and rwlock. This wholesale conversion is required because all three of them are interdependent. To avoid warnings in constructors, the initialization functions mark a capability as acquired when initialized before guarded variables. The test verifies that common patterns do not generate false positives. Signed-off-by: Marco Elver --- .../dev-tools/capability-analysis.rst | 3 +- include/linux/rwlock.h | 25 ++-- include/linux/rwlock_api_smp.h | 29 +++- include/linux/rwlock_rt.h | 35 +++-- include/linux/rwlock_types.h | 10 +- include/linux/spinlock.h | 45 +++--- include/linux/spinlock_api_smp.h | 14 +- include/linux/spinlock_api_up.h | 71 +++++----- include/linux/spinlock_rt.h | 21 +-- include/linux/spinlock_types.h | 10 +- include/linux/spinlock_types_raw.h | 5 +- lib/test_capability-analysis.c | 128 ++++++++++++++++++ 12 files changed, 299 insertions(+), 97 deletions(-) diff --git a/Documentation/dev-tools/capability-analysis.rst b/Documentatio= n/dev-tools/capability-analysis.rst index 4b9c93cc8fcd..ddda3dc0d8d3 100644 --- a/Documentation/dev-tools/capability-analysis.rst +++ b/Documentation/dev-tools/capability-analysis.rst @@ -78,7 +78,8 @@ More details are also documented `here Supported Kernel Primitives ~~~~~~~~~~~~~~~~~~~~~~~~~~~ =20 -.. Currently the following synchronization primitives are supported: +Currently the following synchronization primitives are supported: +`raw_spinlock_t`, `spinlock_t`, `rwlock_t`. =20 For capabilities with an initialization function (e.g., `spin_lock_init()`= ), calling this function on the capability instance before initializing any diff --git a/include/linux/rwlock.h b/include/linux/rwlock.h index 5b87c6f4a243..3c8971201ec7 100644 --- a/include/linux/rwlock.h +++ b/include/linux/rwlock.h @@ -22,23 +22,24 @@ do { \ static struct lock_class_key __key; \ \ __rwlock_init((lock), #lock, &__key); \ + __assert_cap(lock); \ } while (0) #else # define rwlock_init(lock) \ - do { *(lock) =3D __RW_LOCK_UNLOCKED(lock); } while (0) + do { *(lock) =3D __RW_LOCK_UNLOCKED(lock); __assert_cap(lock); } while (0) #endif =20 #ifdef CONFIG_DEBUG_SPINLOCK - extern void do_raw_read_lock(rwlock_t *lock) __acquires(lock); + extern void do_raw_read_lock(rwlock_t *lock) __acquires_shared(lock); extern int do_raw_read_trylock(rwlock_t *lock); - extern void do_raw_read_unlock(rwlock_t *lock) __releases(lock); + extern void do_raw_read_unlock(rwlock_t *lock) __releases_shared(lock); extern void do_raw_write_lock(rwlock_t *lock) __acquires(lock); extern int do_raw_write_trylock(rwlock_t *lock); extern void do_raw_write_unlock(rwlock_t *lock) __releases(lock); #else -# define do_raw_read_lock(rwlock) do {__acquire(lock); arch_read_lock(&(rw= lock)->raw_lock); } while (0) +# define do_raw_read_lock(rwlock) do {__acquire_shared(lock); arch_read_lo= ck(&(rwlock)->raw_lock); } while (0) # define do_raw_read_trylock(rwlock) arch_read_trylock(&(rwlock)->raw_lock) -# define do_raw_read_unlock(rwlock) do {arch_read_unlock(&(rwlock)->raw_lo= ck); __release(lock); } while (0) +# define do_raw_read_unlock(rwlock) do {arch_read_unlock(&(rwlock)->raw_lo= ck); __release_shared(lock); } while (0) # define do_raw_write_lock(rwlock) do {__acquire(lock); arch_write_lock(&(= rwlock)->raw_lock); } while (0) # define do_raw_write_trylock(rwlock) arch_write_trylock(&(rwlock)->raw_lo= ck) # define do_raw_write_unlock(rwlock) do {arch_write_unlock(&(rwlock)->raw_= lock); __release(lock); } while (0) @@ -49,7 +50,7 @@ do { \ * regardless of whether CONFIG_SMP or CONFIG_PREEMPT are set. The various * methods are defined as nops in the case they are not required. */ -#define read_trylock(lock) __cond_lock(lock, _raw_read_trylock(lock)) +#define read_trylock(lock) __cond_lock_shared(lock, _raw_read_trylock(lock= )) #define write_trylock(lock) __cond_lock(lock, _raw_write_trylock(lock)) =20 #define write_lock(lock) _raw_write_lock(lock) @@ -112,12 +113,12 @@ do { \ } while (0) #define write_unlock_bh(lock) _raw_write_unlock_bh(lock) =20 -#define write_trylock_irqsave(lock, flags) \ -({ \ - local_irq_save(flags); \ - write_trylock(lock) ? \ - 1 : ({ local_irq_restore(flags); 0; }); \ -}) +#define write_trylock_irqsave(lock, flags) \ + __cond_lock(lock, ({ \ + local_irq_save(flags); \ + _raw_write_trylock(lock) ? \ + 1 : ({ local_irq_restore(flags); 0; }); \ + })) =20 #ifdef arch_rwlock_is_contended #define rwlock_is_contended(lock) \ diff --git a/include/linux/rwlock_api_smp.h b/include/linux/rwlock_api_smp.h index 31d3d1116323..3e975105a606 100644 --- a/include/linux/rwlock_api_smp.h +++ b/include/linux/rwlock_api_smp.h @@ -15,12 +15,12 @@ * Released under the General Public License (GPL). */ =20 -void __lockfunc _raw_read_lock(rwlock_t *lock) __acquires(lock); +void __lockfunc _raw_read_lock(rwlock_t *lock) __acquires_shared(lock); void __lockfunc _raw_write_lock(rwlock_t *lock) __acquires(lock); void __lockfunc _raw_write_lock_nested(rwlock_t *lock, int subclass) __acq= uires(lock); -void __lockfunc _raw_read_lock_bh(rwlock_t *lock) __acquires(lock); +void __lockfunc _raw_read_lock_bh(rwlock_t *lock) __acquires_shared(lock); void __lockfunc _raw_write_lock_bh(rwlock_t *lock) __acquires(lock); -void __lockfunc _raw_read_lock_irq(rwlock_t *lock) __acquires(lock); +void __lockfunc _raw_read_lock_irq(rwlock_t *lock) __acquires_shared(lock); void __lockfunc _raw_write_lock_irq(rwlock_t *lock) __acquires(lock); unsigned long __lockfunc _raw_read_lock_irqsave(rwlock_t *lock) __acquires(lock); @@ -28,11 +28,11 @@ unsigned long __lockfunc _raw_write_lock_irqsave(rwlock= _t *lock) __acquires(lock); int __lockfunc _raw_read_trylock(rwlock_t *lock); int __lockfunc _raw_write_trylock(rwlock_t *lock); -void __lockfunc _raw_read_unlock(rwlock_t *lock) __releases(lock); +void __lockfunc _raw_read_unlock(rwlock_t *lock) __releases_shared(lock); void __lockfunc _raw_write_unlock(rwlock_t *lock) __releases(lock); -void __lockfunc _raw_read_unlock_bh(rwlock_t *lock) __releases(lock); +void __lockfunc _raw_read_unlock_bh(rwlock_t *lock) __releases_shared(lock= ); void __lockfunc _raw_write_unlock_bh(rwlock_t *lock) __releases(lock); -void __lockfunc _raw_read_unlock_irq(rwlock_t *lock) __releases(lock); +void __lockfunc _raw_read_unlock_irq(rwlock_t *lock) __releases_shared(loc= k); void __lockfunc _raw_write_unlock_irq(rwlock_t *lock) __releases(lock); void __lockfunc _raw_read_unlock_irqrestore(rwlock_t *lock, unsigned long flags) @@ -145,6 +145,7 @@ static inline int __raw_write_trylock(rwlock_t *lock) #if !defined(CONFIG_GENERIC_LOCKBREAK) || defined(CONFIG_DEBUG_LOCK_ALLOC) =20 static inline void __raw_read_lock(rwlock_t *lock) + __acquires_shared(lock) __no_capability_analysis { preempt_disable(); rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_); @@ -152,6 +153,7 @@ static inline void __raw_read_lock(rwlock_t *lock) } =20 static inline unsigned long __raw_read_lock_irqsave(rwlock_t *lock) + __acquires_shared(lock) __no_capability_analysis { unsigned long flags; =20 @@ -163,6 +165,7 @@ static inline unsigned long __raw_read_lock_irqsave(rwl= ock_t *lock) } =20 static inline void __raw_read_lock_irq(rwlock_t *lock) + __acquires_shared(lock) __no_capability_analysis { local_irq_disable(); preempt_disable(); @@ -171,6 +174,7 @@ static inline void __raw_read_lock_irq(rwlock_t *lock) } =20 static inline void __raw_read_lock_bh(rwlock_t *lock) + __acquires_shared(lock) __no_capability_analysis { __local_bh_disable_ip(_RET_IP_, SOFTIRQ_LOCK_OFFSET); rwlock_acquire_read(&lock->dep_map, 0, 0, _RET_IP_); @@ -178,6 +182,7 @@ static inline void __raw_read_lock_bh(rwlock_t *lock) } =20 static inline unsigned long __raw_write_lock_irqsave(rwlock_t *lock) + __acquires(lock) __no_capability_analysis { unsigned long flags; =20 @@ -189,6 +194,7 @@ static inline unsigned long __raw_write_lock_irqsave(rw= lock_t *lock) } =20 static inline void __raw_write_lock_irq(rwlock_t *lock) + __acquires(lock) __no_capability_analysis { local_irq_disable(); preempt_disable(); @@ -197,6 +203,7 @@ static inline void __raw_write_lock_irq(rwlock_t *lock) } =20 static inline void __raw_write_lock_bh(rwlock_t *lock) + __acquires(lock) __no_capability_analysis { __local_bh_disable_ip(_RET_IP_, SOFTIRQ_LOCK_OFFSET); rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_); @@ -204,6 +211,7 @@ static inline void __raw_write_lock_bh(rwlock_t *lock) } =20 static inline void __raw_write_lock(rwlock_t *lock) + __acquires(lock) __no_capability_analysis { preempt_disable(); rwlock_acquire(&lock->dep_map, 0, 0, _RET_IP_); @@ -211,6 +219,7 @@ static inline void __raw_write_lock(rwlock_t *lock) } =20 static inline void __raw_write_lock_nested(rwlock_t *lock, int subclass) + __acquires(lock) __no_capability_analysis { preempt_disable(); rwlock_acquire(&lock->dep_map, subclass, 0, _RET_IP_); @@ -220,6 +229,7 @@ static inline void __raw_write_lock_nested(rwlock_t *lo= ck, int subclass) #endif /* !CONFIG_GENERIC_LOCKBREAK || CONFIG_DEBUG_LOCK_ALLOC */ =20 static inline void __raw_write_unlock(rwlock_t *lock) + __releases(lock) { rwlock_release(&lock->dep_map, _RET_IP_); do_raw_write_unlock(lock); @@ -227,6 +237,7 @@ static inline void __raw_write_unlock(rwlock_t *lock) } =20 static inline void __raw_read_unlock(rwlock_t *lock) + __releases_shared(lock) { rwlock_release(&lock->dep_map, _RET_IP_); do_raw_read_unlock(lock); @@ -235,6 +246,7 @@ static inline void __raw_read_unlock(rwlock_t *lock) =20 static inline void __raw_read_unlock_irqrestore(rwlock_t *lock, unsigned long flags) + __releases_shared(lock) { rwlock_release(&lock->dep_map, _RET_IP_); do_raw_read_unlock(lock); @@ -243,6 +255,7 @@ __raw_read_unlock_irqrestore(rwlock_t *lock, unsigned l= ong flags) } =20 static inline void __raw_read_unlock_irq(rwlock_t *lock) + __releases_shared(lock) { rwlock_release(&lock->dep_map, _RET_IP_); do_raw_read_unlock(lock); @@ -251,6 +264,7 @@ static inline void __raw_read_unlock_irq(rwlock_t *lock) } =20 static inline void __raw_read_unlock_bh(rwlock_t *lock) + __releases_shared(lock) { rwlock_release(&lock->dep_map, _RET_IP_); do_raw_read_unlock(lock); @@ -259,6 +273,7 @@ static inline void __raw_read_unlock_bh(rwlock_t *lock) =20 static inline void __raw_write_unlock_irqrestore(rwlock_t *lock, unsigned long flags) + __releases(lock) { rwlock_release(&lock->dep_map, _RET_IP_); do_raw_write_unlock(lock); @@ -267,6 +282,7 @@ static inline void __raw_write_unlock_irqrestore(rwlock= _t *lock, } =20 static inline void __raw_write_unlock_irq(rwlock_t *lock) + __releases(lock) { rwlock_release(&lock->dep_map, _RET_IP_); do_raw_write_unlock(lock); @@ -275,6 +291,7 @@ static inline void __raw_write_unlock_irq(rwlock_t *loc= k) } =20 static inline void __raw_write_unlock_bh(rwlock_t *lock) + __releases(lock) { rwlock_release(&lock->dep_map, _RET_IP_); do_raw_write_unlock(lock); diff --git a/include/linux/rwlock_rt.h b/include/linux/rwlock_rt.h index 7d81fc6918ee..742172a06702 100644 --- a/include/linux/rwlock_rt.h +++ b/include/linux/rwlock_rt.h @@ -22,28 +22,32 @@ do { \ \ init_rwbase_rt(&(rwl)->rwbase); \ __rt_rwlock_init(rwl, #rwl, &__key); \ + __assert_cap(rwl); \ } while (0) =20 -extern void rt_read_lock(rwlock_t *rwlock) __acquires(rwlock); +extern void rt_read_lock(rwlock_t *rwlock) __acquires_shared(rwlock); extern int rt_read_trylock(rwlock_t *rwlock); -extern void rt_read_unlock(rwlock_t *rwlock) __releases(rwlock); +extern void rt_read_unlock(rwlock_t *rwlock) __releases_shared(rwlock); extern void rt_write_lock(rwlock_t *rwlock) __acquires(rwlock); extern void rt_write_lock_nested(rwlock_t *rwlock, int subclass) __acquire= s(rwlock); extern int rt_write_trylock(rwlock_t *rwlock); extern void rt_write_unlock(rwlock_t *rwlock) __releases(rwlock); =20 static __always_inline void read_lock(rwlock_t *rwlock) + __acquires_shared(rwlock) { rt_read_lock(rwlock); } =20 static __always_inline void read_lock_bh(rwlock_t *rwlock) + __acquires_shared(rwlock) { local_bh_disable(); rt_read_lock(rwlock); } =20 static __always_inline void read_lock_irq(rwlock_t *rwlock) + __acquires_shared(rwlock) { rt_read_lock(rwlock); } @@ -55,37 +59,43 @@ static __always_inline void read_lock_irq(rwlock_t *rwl= ock) flags =3D 0; \ } while (0) =20 -#define read_trylock(lock) __cond_lock(lock, rt_read_trylock(lock)) +#define read_trylock(lock) __cond_lock_shared(lock, rt_read_trylock(lock)) =20 static __always_inline void read_unlock(rwlock_t *rwlock) + __releases_shared(rwlock) { rt_read_unlock(rwlock); } =20 static __always_inline void read_unlock_bh(rwlock_t *rwlock) + __releases_shared(rwlock) { rt_read_unlock(rwlock); local_bh_enable(); } =20 static __always_inline void read_unlock_irq(rwlock_t *rwlock) + __releases_shared(rwlock) { rt_read_unlock(rwlock); } =20 static __always_inline void read_unlock_irqrestore(rwlock_t *rwlock, unsigned long flags) + __releases_shared(rwlock) { rt_read_unlock(rwlock); } =20 static __always_inline void write_lock(rwlock_t *rwlock) + __acquires(rwlock) { rt_write_lock(rwlock); } =20 #ifdef CONFIG_DEBUG_LOCK_ALLOC static __always_inline void write_lock_nested(rwlock_t *rwlock, int subcla= ss) + __acquires(rwlock) { rt_write_lock_nested(rwlock, subclass); } @@ -94,12 +104,14 @@ static __always_inline void write_lock_nested(rwlock_t= *rwlock, int subclass) #endif =20 static __always_inline void write_lock_bh(rwlock_t *rwlock) + __acquires(rwlock) { local_bh_disable(); rt_write_lock(rwlock); } =20 static __always_inline void write_lock_irq(rwlock_t *rwlock) + __acquires(rwlock) { rt_write_lock(rwlock); } @@ -114,33 +126,34 @@ static __always_inline void write_lock_irq(rwlock_t *= rwlock) #define write_trylock(lock) __cond_lock(lock, rt_write_trylock(lock)) =20 #define write_trylock_irqsave(lock, flags) \ -({ \ - int __locked; \ - \ - typecheck(unsigned long, flags); \ - flags =3D 0; \ - __locked =3D write_trylock(lock); \ - __locked; \ -}) + __cond_lock(lock, ({ \ + typecheck(unsigned long, flags); \ + flags =3D 0; \ + rt_write_trylock(lock); \ + })) =20 static __always_inline void write_unlock(rwlock_t *rwlock) + __releases(rwlock) { rt_write_unlock(rwlock); } =20 static __always_inline void write_unlock_bh(rwlock_t *rwlock) + __releases(rwlock) { rt_write_unlock(rwlock); local_bh_enable(); } =20 static __always_inline void write_unlock_irq(rwlock_t *rwlock) + __releases(rwlock) { rt_write_unlock(rwlock); } =20 static __always_inline void write_unlock_irqrestore(rwlock_t *rwlock, unsigned long flags) + __releases(rwlock) { rt_write_unlock(rwlock); } diff --git a/include/linux/rwlock_types.h b/include/linux/rwlock_types.h index 1948442e7750..231489cc30f2 100644 --- a/include/linux/rwlock_types.h +++ b/include/linux/rwlock_types.h @@ -22,7 +22,7 @@ * portions Copyright 2005, Red Hat, Inc., Ingo Molnar * Released under the General Public License (GPL). */ -typedef struct { +struct_with_capability(rwlock) { arch_rwlock_t raw_lock; #ifdef CONFIG_DEBUG_SPINLOCK unsigned int magic, owner_cpu; @@ -31,7 +31,8 @@ typedef struct { #ifdef CONFIG_DEBUG_LOCK_ALLOC struct lockdep_map dep_map; #endif -} rwlock_t; +}; +typedef struct rwlock rwlock_t; =20 #define RWLOCK_MAGIC 0xdeaf1eed =20 @@ -54,13 +55,14 @@ typedef struct { =20 #include =20 -typedef struct { +struct_with_capability(rwlock) { struct rwbase_rt rwbase; atomic_t readers; #ifdef CONFIG_DEBUG_LOCK_ALLOC struct lockdep_map dep_map; #endif -} rwlock_t; +}; +typedef struct rwlock rwlock_t; =20 #define __RWLOCK_RT_INITIALIZER(name) \ { \ diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h index 63dd8cf3c3c2..09124713b115 100644 --- a/include/linux/spinlock.h +++ b/include/linux/spinlock.h @@ -106,11 +106,12 @@ do { \ static struct lock_class_key __key; \ \ __raw_spin_lock_init((lock), #lock, &__key, LD_WAIT_SPIN); \ + __assert_cap(lock); \ } while (0) =20 #else # define raw_spin_lock_init(lock) \ - do { *(lock) =3D __RAW_SPIN_LOCK_UNLOCKED(lock); } while (0) + do { *(lock) =3D __RAW_SPIN_LOCK_UNLOCKED(lock); __assert_cap(lock); } wh= ile (0) #endif =20 #define raw_spin_is_locked(lock) arch_spin_is_locked(&(lock)->raw_lock) @@ -286,19 +287,19 @@ static inline void do_raw_spin_unlock(raw_spinlock_t = *lock) __releases(lock) #define raw_spin_trylock_bh(lock) \ __cond_lock(lock, _raw_spin_trylock_bh(lock)) =20 -#define raw_spin_trylock_irq(lock) \ -({ \ - local_irq_disable(); \ - raw_spin_trylock(lock) ? \ - 1 : ({ local_irq_enable(); 0; }); \ -}) +#define raw_spin_trylock_irq(lock) \ + __cond_lock(lock, ({ \ + local_irq_disable(); \ + _raw_spin_trylock(lock) ? \ + 1 : ({ local_irq_enable(); 0; }); \ + })) =20 -#define raw_spin_trylock_irqsave(lock, flags) \ -({ \ - local_irq_save(flags); \ - raw_spin_trylock(lock) ? \ - 1 : ({ local_irq_restore(flags); 0; }); \ -}) +#define raw_spin_trylock_irqsave(lock, flags) \ + __cond_lock(lock, ({ \ + local_irq_save(flags); \ + _raw_spin_trylock(lock) ? \ + 1 : ({ local_irq_restore(flags); 0; }); \ + })) =20 #ifndef CONFIG_PREEMPT_RT /* Include rwlock functions for !RT */ @@ -334,6 +335,7 @@ do { \ \ __raw_spin_lock_init(spinlock_check(lock), \ #lock, &__key, LD_WAIT_CONFIG); \ + __assert_cap(lock); \ } while (0) =20 #else @@ -342,21 +344,25 @@ do { \ do { \ spinlock_check(_lock); \ *(_lock) =3D __SPIN_LOCK_UNLOCKED(_lock); \ + __assert_cap(_lock); \ } while (0) =20 #endif =20 static __always_inline void spin_lock(spinlock_t *lock) + __acquires(lock) __no_capability_analysis { raw_spin_lock(&lock->rlock); } =20 static __always_inline void spin_lock_bh(spinlock_t *lock) + __acquires(lock) __no_capability_analysis { raw_spin_lock_bh(&lock->rlock); } =20 static __always_inline int spin_trylock(spinlock_t *lock) + __cond_acquires(lock) __no_capability_analysis { return raw_spin_trylock(&lock->rlock); } @@ -372,6 +378,7 @@ do { \ } while (0) =20 static __always_inline void spin_lock_irq(spinlock_t *lock) + __acquires(lock) __no_capability_analysis { raw_spin_lock_irq(&lock->rlock); } @@ -379,47 +386,53 @@ static __always_inline void spin_lock_irq(spinlock_t = *lock) #define spin_lock_irqsave(lock, flags) \ do { \ raw_spin_lock_irqsave(spinlock_check(lock), flags); \ + __release(spinlock_check(lock)); __acquire(lock); \ } while (0) =20 #define spin_lock_irqsave_nested(lock, flags, subclass) \ do { \ raw_spin_lock_irqsave_nested(spinlock_check(lock), flags, subclass); \ + __release(spinlock_check(lock)); __acquire(lock); \ } while (0) =20 static __always_inline void spin_unlock(spinlock_t *lock) + __releases(lock) __no_capability_analysis { raw_spin_unlock(&lock->rlock); } =20 static __always_inline void spin_unlock_bh(spinlock_t *lock) + __releases(lock) __no_capability_analysis { raw_spin_unlock_bh(&lock->rlock); } =20 static __always_inline void spin_unlock_irq(spinlock_t *lock) + __releases(lock) __no_capability_analysis { raw_spin_unlock_irq(&lock->rlock); } =20 static __always_inline void spin_unlock_irqrestore(spinlock_t *lock, unsig= ned long flags) + __releases(lock) __no_capability_analysis { raw_spin_unlock_irqrestore(&lock->rlock, flags); } =20 static __always_inline int spin_trylock_bh(spinlock_t *lock) + __cond_acquires(lock) __no_capability_analysis { return raw_spin_trylock_bh(&lock->rlock); } =20 static __always_inline int spin_trylock_irq(spinlock_t *lock) + __cond_acquires(lock) __no_capability_analysis { return raw_spin_trylock_irq(&lock->rlock); } =20 #define spin_trylock_irqsave(lock, flags) \ -({ \ - raw_spin_trylock_irqsave(spinlock_check(lock), flags); \ -}) + __cond_lock(lock, raw_spin_trylock_irqsave(spinlock_check(lock), flags)) =20 /** * spin_is_locked() - Check whether a spinlock is locked. diff --git a/include/linux/spinlock_api_smp.h b/include/linux/spinlock_api_= smp.h index 9ecb0ab504e3..fab02d8bf0c9 100644 --- a/include/linux/spinlock_api_smp.h +++ b/include/linux/spinlock_api_smp.h @@ -34,8 +34,8 @@ unsigned long __lockfunc _raw_spin_lock_irqsave(raw_spinl= ock_t *lock) unsigned long __lockfunc _raw_spin_lock_irqsave_nested(raw_spinlock_t *lock, int subclass) __acquires(lock); -int __lockfunc _raw_spin_trylock(raw_spinlock_t *lock); -int __lockfunc _raw_spin_trylock_bh(raw_spinlock_t *lock); +int __lockfunc _raw_spin_trylock(raw_spinlock_t *lock) __cond_acquires(lo= ck); +int __lockfunc _raw_spin_trylock_bh(raw_spinlock_t *lock) __cond_acquires(= lock); void __lockfunc _raw_spin_unlock(raw_spinlock_t *lock) __releases(lock); void __lockfunc _raw_spin_unlock_bh(raw_spinlock_t *lock) __releases(lock); void __lockfunc _raw_spin_unlock_irq(raw_spinlock_t *lock) __releases(lock= ); @@ -84,6 +84,7 @@ _raw_spin_unlock_irqrestore(raw_spinlock_t *lock, unsigne= d long flags) #endif =20 static inline int __raw_spin_trylock(raw_spinlock_t *lock) + __cond_acquires(lock) { preempt_disable(); if (do_raw_spin_trylock(lock)) { @@ -102,6 +103,7 @@ static inline int __raw_spin_trylock(raw_spinlock_t *lo= ck) #if !defined(CONFIG_GENERIC_LOCKBREAK) || defined(CONFIG_DEBUG_LOCK_ALLOC) =20 static inline unsigned long __raw_spin_lock_irqsave(raw_spinlock_t *lock) + __acquires(lock) __no_capability_analysis { unsigned long flags; =20 @@ -113,6 +115,7 @@ static inline unsigned long __raw_spin_lock_irqsave(raw= _spinlock_t *lock) } =20 static inline void __raw_spin_lock_irq(raw_spinlock_t *lock) + __acquires(lock) __no_capability_analysis { local_irq_disable(); preempt_disable(); @@ -121,6 +124,7 @@ static inline void __raw_spin_lock_irq(raw_spinlock_t *= lock) } =20 static inline void __raw_spin_lock_bh(raw_spinlock_t *lock) + __acquires(lock) __no_capability_analysis { __local_bh_disable_ip(_RET_IP_, SOFTIRQ_LOCK_OFFSET); spin_acquire(&lock->dep_map, 0, 0, _RET_IP_); @@ -128,6 +132,7 @@ static inline void __raw_spin_lock_bh(raw_spinlock_t *l= ock) } =20 static inline void __raw_spin_lock(raw_spinlock_t *lock) + __acquires(lock) __no_capability_analysis { preempt_disable(); spin_acquire(&lock->dep_map, 0, 0, _RET_IP_); @@ -137,6 +142,7 @@ static inline void __raw_spin_lock(raw_spinlock_t *lock) #endif /* !CONFIG_GENERIC_LOCKBREAK || CONFIG_DEBUG_LOCK_ALLOC */ =20 static inline void __raw_spin_unlock(raw_spinlock_t *lock) + __releases(lock) { spin_release(&lock->dep_map, _RET_IP_); do_raw_spin_unlock(lock); @@ -145,6 +151,7 @@ static inline void __raw_spin_unlock(raw_spinlock_t *lo= ck) =20 static inline void __raw_spin_unlock_irqrestore(raw_spinlock_t *lock, unsigned long flags) + __releases(lock) { spin_release(&lock->dep_map, _RET_IP_); do_raw_spin_unlock(lock); @@ -153,6 +160,7 @@ static inline void __raw_spin_unlock_irqrestore(raw_spi= nlock_t *lock, } =20 static inline void __raw_spin_unlock_irq(raw_spinlock_t *lock) + __releases(lock) { spin_release(&lock->dep_map, _RET_IP_); do_raw_spin_unlock(lock); @@ -161,6 +169,7 @@ static inline void __raw_spin_unlock_irq(raw_spinlock_t= *lock) } =20 static inline void __raw_spin_unlock_bh(raw_spinlock_t *lock) + __releases(lock) { spin_release(&lock->dep_map, _RET_IP_); do_raw_spin_unlock(lock); @@ -168,6 +177,7 @@ static inline void __raw_spin_unlock_bh(raw_spinlock_t = *lock) } =20 static inline int __raw_spin_trylock_bh(raw_spinlock_t *lock) + __cond_acquires(lock) { __local_bh_disable_ip(_RET_IP_, SOFTIRQ_LOCK_OFFSET); if (do_raw_spin_trylock(lock)) { diff --git a/include/linux/spinlock_api_up.h b/include/linux/spinlock_api_u= p.h index 819aeba1c87e..018f5aabc1be 100644 --- a/include/linux/spinlock_api_up.h +++ b/include/linux/spinlock_api_up.h @@ -24,68 +24,77 @@ * flags straight, to suppress compiler warnings of unused lock * variables, and to add the proper checker annotations: */ -#define ___LOCK(lock) \ - do { __acquire(lock); (void)(lock); } while (0) +#define ___LOCK_void(lock) \ + do { (void)(lock); } while (0) =20 -#define __LOCK(lock) \ - do { preempt_disable(); ___LOCK(lock); } while (0) +#define ___LOCK_(lock) \ + do { __acquire(lock); ___LOCK_void(lock); } while (0) =20 -#define __LOCK_BH(lock) \ - do { __local_bh_disable_ip(_THIS_IP_, SOFTIRQ_LOCK_OFFSET); ___LOCK(lock= ); } while (0) +#define ___LOCK_shared(lock) \ + do { __acquire_shared(lock); ___LOCK_void(lock); } while (0) =20 -#define __LOCK_IRQ(lock) \ - do { local_irq_disable(); __LOCK(lock); } while (0) +#define __LOCK(lock, ...) \ + do { preempt_disable(); ___LOCK_##__VA_ARGS__(lock); } while (0) =20 -#define __LOCK_IRQSAVE(lock, flags) \ - do { local_irq_save(flags); __LOCK(lock); } while (0) +#define __LOCK_BH(lock, ...) \ + do { __local_bh_disable_ip(_THIS_IP_, SOFTIRQ_LOCK_OFFSET); ___LOCK_##__= VA_ARGS__(lock); } while (0) =20 -#define ___UNLOCK(lock) \ +#define __LOCK_IRQ(lock, ...) \ + do { local_irq_disable(); __LOCK(lock, ##__VA_ARGS__); } while (0) + +#define __LOCK_IRQSAVE(lock, flags, ...) \ + do { local_irq_save(flags); __LOCK(lock, ##__VA_ARGS__); } while (0) + +#define ___UNLOCK_(lock) \ do { __release(lock); (void)(lock); } while (0) =20 -#define __UNLOCK(lock) \ - do { preempt_enable(); ___UNLOCK(lock); } while (0) +#define ___UNLOCK_shared(lock) \ + do { __release_shared(lock); (void)(lock); } while (0) =20 -#define __UNLOCK_BH(lock) \ +#define __UNLOCK(lock, ...) \ + do { preempt_enable(); ___UNLOCK_##__VA_ARGS__(lock); } while (0) + +#define __UNLOCK_BH(lock, ...) \ do { __local_bh_enable_ip(_THIS_IP_, SOFTIRQ_LOCK_OFFSET); \ - ___UNLOCK(lock); } while (0) + ___UNLOCK_##__VA_ARGS__(lock); } while (0) =20 -#define __UNLOCK_IRQ(lock) \ - do { local_irq_enable(); __UNLOCK(lock); } while (0) +#define __UNLOCK_IRQ(lock, ...) \ + do { local_irq_enable(); __UNLOCK(lock, ##__VA_ARGS__); } while (0) =20 -#define __UNLOCK_IRQRESTORE(lock, flags) \ - do { local_irq_restore(flags); __UNLOCK(lock); } while (0) +#define __UNLOCK_IRQRESTORE(lock, flags, ...) \ + do { local_irq_restore(flags); __UNLOCK(lock, ##__VA_ARGS__); } while (0) =20 #define _raw_spin_lock(lock) __LOCK(lock) #define _raw_spin_lock_nested(lock, subclass) __LOCK(lock) -#define _raw_read_lock(lock) __LOCK(lock) +#define _raw_read_lock(lock) __LOCK(lock, shared) #define _raw_write_lock(lock) __LOCK(lock) #define _raw_write_lock_nested(lock, subclass) __LOCK(lock) #define _raw_spin_lock_bh(lock) __LOCK_BH(lock) -#define _raw_read_lock_bh(lock) __LOCK_BH(lock) +#define _raw_read_lock_bh(lock) __LOCK_BH(lock, shared) #define _raw_write_lock_bh(lock) __LOCK_BH(lock) #define _raw_spin_lock_irq(lock) __LOCK_IRQ(lock) -#define _raw_read_lock_irq(lock) __LOCK_IRQ(lock) +#define _raw_read_lock_irq(lock) __LOCK_IRQ(lock, shared) #define _raw_write_lock_irq(lock) __LOCK_IRQ(lock) #define _raw_spin_lock_irqsave(lock, flags) __LOCK_IRQSAVE(lock, flags) -#define _raw_read_lock_irqsave(lock, flags) __LOCK_IRQSAVE(lock, flags) +#define _raw_read_lock_irqsave(lock, flags) __LOCK_IRQSAVE(lock, flags, sh= ared) #define _raw_write_lock_irqsave(lock, flags) __LOCK_IRQSAVE(lock, flags) -#define _raw_spin_trylock(lock) ({ __LOCK(lock); 1; }) -#define _raw_read_trylock(lock) ({ __LOCK(lock); 1; }) -#define _raw_write_trylock(lock) ({ __LOCK(lock); 1; }) -#define _raw_spin_trylock_bh(lock) ({ __LOCK_BH(lock); 1; }) +#define _raw_spin_trylock(lock) ({ __LOCK(lock, void); 1; }) +#define _raw_read_trylock(lock) ({ __LOCK(lock, void); 1; }) +#define _raw_write_trylock(lock) ({ __LOCK(lock, void); 1; }) +#define _raw_spin_trylock_bh(lock) ({ __LOCK_BH(lock, void); 1; }) #define _raw_spin_unlock(lock) __UNLOCK(lock) -#define _raw_read_unlock(lock) __UNLOCK(lock) +#define _raw_read_unlock(lock) __UNLOCK(lock, shared) #define _raw_write_unlock(lock) __UNLOCK(lock) #define _raw_spin_unlock_bh(lock) __UNLOCK_BH(lock) #define _raw_write_unlock_bh(lock) __UNLOCK_BH(lock) -#define _raw_read_unlock_bh(lock) __UNLOCK_BH(lock) +#define _raw_read_unlock_bh(lock) __UNLOCK_BH(lock, shared) #define _raw_spin_unlock_irq(lock) __UNLOCK_IRQ(lock) -#define _raw_read_unlock_irq(lock) __UNLOCK_IRQ(lock) +#define _raw_read_unlock_irq(lock) __UNLOCK_IRQ(lock, shared) #define _raw_write_unlock_irq(lock) __UNLOCK_IRQ(lock) #define _raw_spin_unlock_irqrestore(lock, flags) \ __UNLOCK_IRQRESTORE(lock, flags) #define _raw_read_unlock_irqrestore(lock, flags) \ - __UNLOCK_IRQRESTORE(lock, flags) + __UNLOCK_IRQRESTORE(lock, flags, shared) #define _raw_write_unlock_irqrestore(lock, flags) \ __UNLOCK_IRQRESTORE(lock, flags) =20 diff --git a/include/linux/spinlock_rt.h b/include/linux/spinlock_rt.h index f6499c37157d..1f55601e1321 100644 --- a/include/linux/spinlock_rt.h +++ b/include/linux/spinlock_rt.h @@ -20,6 +20,7 @@ static inline void __rt_spin_lock_init(spinlock_t *lock, = const char *name, do { \ rt_mutex_base_init(&(slock)->lock); \ __rt_spin_lock_init(slock, name, key, percpu); \ + __assert_cap(slock); \ } while (0) =20 #define _spin_lock_init(slock, percpu) \ @@ -40,6 +41,7 @@ extern int rt_spin_trylock_bh(spinlock_t *lock); extern int rt_spin_trylock(spinlock_t *lock); =20 static __always_inline void spin_lock(spinlock_t *lock) + __acquires(lock) { rt_spin_lock(lock); } @@ -82,6 +84,7 @@ static __always_inline void spin_lock(spinlock_t *lock) __spin_lock_irqsave_nested(lock, flags, subclass) =20 static __always_inline void spin_lock_bh(spinlock_t *lock) + __acquires(lock) { /* Investigate: Drop bh when blocking ? */ local_bh_disable(); @@ -89,6 +92,7 @@ static __always_inline void spin_lock_bh(spinlock_t *lock) } =20 static __always_inline void spin_lock_irq(spinlock_t *lock) + __acquires(lock) { rt_spin_lock(lock); } @@ -101,23 +105,27 @@ static __always_inline void spin_lock_irq(spinlock_t = *lock) } while (0) =20 static __always_inline void spin_unlock(spinlock_t *lock) + __releases(lock) { rt_spin_unlock(lock); } =20 static __always_inline void spin_unlock_bh(spinlock_t *lock) + __releases(lock) { rt_spin_unlock(lock); local_bh_enable(); } =20 static __always_inline void spin_unlock_irq(spinlock_t *lock) + __releases(lock) { rt_spin_unlock(lock); } =20 static __always_inline void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags) + __releases(lock) { rt_spin_unlock(lock); } @@ -132,14 +140,11 @@ static __always_inline void spin_unlock_irqrestore(sp= inlock_t *lock, __cond_lock(lock, rt_spin_trylock(lock)) =20 #define spin_trylock_irqsave(lock, flags) \ -({ \ - int __locked; \ - \ - typecheck(unsigned long, flags); \ - flags =3D 0; \ - __locked =3D spin_trylock(lock); \ - __locked; \ -}) + __cond_lock(lock, ({ \ + typecheck(unsigned long, flags); \ + flags =3D 0; \ + rt_spin_trylock(lock); \ + })) =20 #define spin_is_contended(lock) (((void)(lock), 0)) =20 diff --git a/include/linux/spinlock_types.h b/include/linux/spinlock_types.h index 2dfa35ffec76..2c5db5b5b990 100644 --- a/include/linux/spinlock_types.h +++ b/include/linux/spinlock_types.h @@ -14,7 +14,7 @@ #ifndef CONFIG_PREEMPT_RT =20 /* Non PREEMPT_RT kernels map spinlock to raw_spinlock */ -typedef struct spinlock { +struct_with_capability(spinlock) { union { struct raw_spinlock rlock; =20 @@ -26,7 +26,8 @@ typedef struct spinlock { }; #endif }; -} spinlock_t; +}; +typedef struct spinlock spinlock_t; =20 #define ___SPIN_LOCK_INITIALIZER(lockname) \ { \ @@ -47,12 +48,13 @@ typedef struct spinlock { /* PREEMPT_RT kernels map spinlock to rt_mutex */ #include =20 -typedef struct spinlock { +struct_with_capability(spinlock) { struct rt_mutex_base lock; #ifdef CONFIG_DEBUG_LOCK_ALLOC struct lockdep_map dep_map; #endif -} spinlock_t; +}; +typedef struct spinlock spinlock_t; =20 #define __SPIN_LOCK_UNLOCKED(name) \ { \ diff --git a/include/linux/spinlock_types_raw.h b/include/linux/spinlock_ty= pes_raw.h index 91cb36b65a17..07792ff2c2b5 100644 --- a/include/linux/spinlock_types_raw.h +++ b/include/linux/spinlock_types_raw.h @@ -11,7 +11,7 @@ =20 #include =20 -typedef struct raw_spinlock { +struct_with_capability(raw_spinlock) { arch_spinlock_t raw_lock; #ifdef CONFIG_DEBUG_SPINLOCK unsigned int magic, owner_cpu; @@ -20,7 +20,8 @@ typedef struct raw_spinlock { #ifdef CONFIG_DEBUG_LOCK_ALLOC struct lockdep_map dep_map; #endif -} raw_spinlock_t; +}; +typedef struct raw_spinlock raw_spinlock_t; =20 #define SPINLOCK_MAGIC 0xdead4ead =20 diff --git a/lib/test_capability-analysis.c b/lib/test_capability-analysis.c index a0adacce30ff..84060bace61d 100644 --- a/lib/test_capability-analysis.c +++ b/lib/test_capability-analysis.c @@ -5,6 +5,7 @@ */ =20 #include +#include =20 /* * Test that helper macros work as expected. @@ -16,3 +17,130 @@ static void __used test_common_helpers(void) BUILD_BUG_ON(capability_unsafe((void)2, 3) !=3D 3); /* does not swallow c= ommas */ capability_unsafe(do { } while (0)); /* works with void statements */ } + +#define TEST_SPINLOCK_COMMON(class, type, type_init, type_lock, type_unloc= k, type_trylock, op) \ + struct test_##class##_data { \ + type lock; \ + int counter __guarded_by(&lock); \ + int *pointer __pt_guarded_by(&lock); \ + }; \ + static void __used test_##class##_init(struct test_##class##_data *d) \ + { \ + type_init(&d->lock); \ + d->counter =3D 0; \ + } \ + static void __used test_##class(struct test_##class##_data *d) \ + { \ + unsigned long flags; \ + d->pointer++; \ + type_lock(&d->lock); \ + op(d->counter); \ + op(*d->pointer); \ + type_unlock(&d->lock); \ + type_lock##_irq(&d->lock); \ + op(d->counter); \ + op(*d->pointer); \ + type_unlock##_irq(&d->lock); \ + type_lock##_bh(&d->lock); \ + op(d->counter); \ + op(*d->pointer); \ + type_unlock##_bh(&d->lock); \ + type_lock##_irqsave(&d->lock, flags); \ + op(d->counter); \ + op(*d->pointer); \ + type_unlock##_irqrestore(&d->lock, flags); \ + } \ + static void __used test_##class##_trylock(struct test_##class##_data *d) = \ + { \ + if (type_trylock(&d->lock)) { \ + op(d->counter); \ + type_unlock(&d->lock); \ + } \ + } \ + static void __used test_##class##_assert(struct test_##class##_data *d) = \ + { \ + lockdep_assert_held(&d->lock); \ + op(d->counter); \ + } \ + static void __used test_##class##_guard(struct test_##class##_data *d) \ + { \ + { guard(class)(&d->lock); op(d->counter); } \ + { guard(class##_irq)(&d->lock); op(d->counter); } \ + { guard(class##_irqsave)(&d->lock); op(d->counter); } \ + } + +#define TEST_OP_RW(x) (x)++ +#define TEST_OP_RO(x) ((void)(x)) + +TEST_SPINLOCK_COMMON(raw_spinlock, + raw_spinlock_t, + raw_spin_lock_init, + raw_spin_lock, + raw_spin_unlock, + raw_spin_trylock, + TEST_OP_RW); +static void __used test_raw_spinlock_trylock_extra(struct test_raw_spinloc= k_data *d) +{ + unsigned long flags; + + if (raw_spin_trylock_irq(&d->lock)) { + d->counter++; + raw_spin_unlock_irq(&d->lock); + } + if (raw_spin_trylock_irqsave(&d->lock, flags)) { + d->counter++; + raw_spin_unlock_irqrestore(&d->lock, flags); + } + scoped_cond_guard(raw_spinlock_try, return, &d->lock) { + d->counter++; + } +} + +TEST_SPINLOCK_COMMON(spinlock, + spinlock_t, + spin_lock_init, + spin_lock, + spin_unlock, + spin_trylock, + TEST_OP_RW); +static void __used test_spinlock_trylock_extra(struct test_spinlock_data *= d) +{ + unsigned long flags; + + if (spin_trylock_irq(&d->lock)) { + d->counter++; + spin_unlock_irq(&d->lock); + } + if (spin_trylock_irqsave(&d->lock, flags)) { + d->counter++; + spin_unlock_irqrestore(&d->lock, flags); + } + scoped_cond_guard(spinlock_try, return, &d->lock) { + d->counter++; + } +} + +TEST_SPINLOCK_COMMON(write_lock, + rwlock_t, + rwlock_init, + write_lock, + write_unlock, + write_trylock, + TEST_OP_RW); +static void __used test_write_trylock_extra(struct test_write_lock_data *d) +{ + unsigned long flags; + + if (write_trylock_irqsave(&d->lock, flags)) { + d->counter++; + write_unlock_irqrestore(&d->lock, flags); + } +} + +TEST_SPINLOCK_COMMON(read_lock, + rwlock_t, + rwlock_init, + read_lock, + read_unlock, + read_trylock, + TEST_OP_RO); --=20 2.48.1.711.g2feabab25a-goog From nobody Thu May 7 18:25:53 2026 Received: from mail-ed1-f74.google.com (mail-ed1-f74.google.com [209.85.208.74]) (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 BED4F1FFC4D for ; Tue, 4 Mar 2025 09:25:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080336; cv=none; b=fYcY+lajeWNBe38bQYIRbED+hPfwHY+wq+dKaerwiEToxuO81kdQhkxLvYjhCP+S4OhmANgUnRP8+BiWC00a2Seq5uUPwxfFKU78rus9oE4bBGhm6geGDY8hvaV3iu9KMHtWoH3TJa2z5wBJ/7AZuyaKarQ/FBf4CNHTAce+VXo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080336; c=relaxed/simple; bh=TLyEQUYL7r6oDXGxc1hiNLMwzZ9LFVmZKfS7DKxQEFY=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=dNltBD4LiZY9u1gIa0065Zvbg6DJr5hQApJ0nVp8dRzi7tYQPyOGI+95zm4KWql/NLNODfqAEbLRxB0JOtXxFEC3EGxatm7lp4zT/+CuZGP5CTNyKGJiOvl8tYzR4gbtZbTh2WgOv7BHTJzLEOen4esMnc4bVgK8J2nvZjcld/A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--elver.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=SHMk7EWS; arc=none smtp.client-ip=209.85.208.74 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--elver.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="SHMk7EWS" Received: by mail-ed1-f74.google.com with SMTP id 4fb4d7f45d1cf-5e4b6eba254so6168940a12.3 for ; Tue, 04 Mar 2025 01:25:34 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1741080333; x=1741685133; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=3N8S7JUPE1q89goF9WrUxLudC8JOfTuJ5GayTplf0i0=; b=SHMk7EWSuWukqRqMG8iYYRQiPbClEgA6m01WDa3uJvnK9TaTbWOhbeqwvd7TvEyXud b+PcBsu4NuG0t8xqKC9GEmUdt6fRvFYDoypC3kTJTTZYWGpm0hvSMicCMhk120S4QasX Y2+J5bdQFuJz6d5Bl5eVoKX5C++MBYrHD1Xaq6/SzbnF2l6MuDx2WeikcrAUTKdUyGNg LVOAXdfCwezYkmETkYRoftOx9m0mtVFPrWloz+9KKlhFVXsxzwOTkbzm7Actf3VcJ4n2 lPwwu//qOmaIIa/kpQS0Nv19v6KfuKAIqGAg6+YecZCbKDiPoQsL79Pv59Dmx1Ku6cMp suQw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741080333; x=1741685133; h=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; bh=3N8S7JUPE1q89goF9WrUxLudC8JOfTuJ5GayTplf0i0=; b=Lo4JfXLHgQ3rBLzD8jB4RX7F4vbnA3W5D0zA1ET+4YKw9MRvbPcmr6p+6O9VkWvguA mzoSVP+qQfx/TVO6h1XvCbRnHaSR7B5Dut9A8CoFqnnBfAqcsa1KmKA6CJBS4755YHgm LafJQixr032CnDNHHJNDtm5Kd68SJSUeHSPxofUDIJ2NRcVIuv+RUzsQp+UWdnR1Bnb9 sb2KPoug5VToTgKN/5b2A3eIC9SjZ2I42uVhKBDPjJWdMA5fdPa3u58w4KEcngIA6PtZ Ya3dHO3ZIUcm8NH9SNTY4hc7KyjkGXrT1/lGDtrRr3GreDAMNkk89MXlCyf7RAdgBecw 6iNQ== X-Forwarded-Encrypted: i=1; AJvYcCWHsCQNg3D0doiyVMPDpCoMqqxu5eGiPZtNhXo8ymZKCRSFKp8o9cAFNExCPRQ8g6Bd2lumFyHkVQcIjjg=@vger.kernel.org X-Gm-Message-State: AOJu0YzdjKaa8W6H0vfQB2TeLJuT4hh+6+ngdARXALGbYVXsOSp9z6+6 54W36luqtn2iK0hE71ig1b4uVrgd+qkAu43ZoTolQysTN1UQ7I0vd/Du9HRLXNjbhc+Mf7nEeA= = X-Google-Smtp-Source: AGHT+IG3w3Av+LCgyTZprIzkeKZapwa6ti8rnRN5LRNN20fd/po8CjvPaQjDhiyO2RBifz8hQtZRzFukLg== X-Received: from edc18.prod.google.com ([2002:a05:6402:4612:b0:5e5:29f3:27af]) (user=elver job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6402:4603:b0:5e5:4807:5441 with SMTP id 4fb4d7f45d1cf-5e5480755bfmr7319106a12.30.1741080333339; Tue, 04 Mar 2025 01:25:33 -0800 (PST) Date: Tue, 4 Mar 2025 10:21:08 +0100 In-Reply-To: <20250304092417.2873893-1-elver@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250304092417.2873893-1-elver@google.com> X-Mailer: git-send-email 2.48.1.711.g2feabab25a-goog Message-ID: <20250304092417.2873893-10-elver@google.com> Subject: [PATCH v2 09/34] compiler-capability-analysis: Change __cond_acquires to take return value From: Marco Elver To: elver@google.com Cc: "David S. Miller" , Luc Van Oostenryck , "Paul E. McKenney" , Alexander Potapenko , Arnd Bergmann , Bart Van Assche , Bill Wendling , Boqun Feng , Dmitry Vyukov , Eric Dumazet , Frederic Weisbecker , Greg Kroah-Hartman , Herbert Xu , Ingo Molnar , Jann Horn , Jiri Slaby , Joel Fernandes , Jonathan Corbet , Josh Triplett , Justin Stitt , Kees Cook , Kentaro Takeda , Mark Rutland , Mathieu Desnoyers , Miguel Ojeda , Nathan Chancellor , Neeraj Upadhyay , Peter Zijlstra , Steven Rostedt , Tetsuo Handa , Thomas Gleixner , Uladzislau Rezki , Waiman Long , Will Deacon , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org, llvm@lists.linux.dev, rcu@vger.kernel.org, linux-crypto@vger.kernel.org, linux-serial@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" While Sparse is oblivious to the return value of conditional acquire functions, Clang's capability analysis needs to know the return value which indicates successful acquisition. Add the additional argument, and convert existing uses. Notably, Clang's interpretation of the value merely relates to the use in a later conditional branch, i.e. 1 =3D=3D> capability acquired in branch taken if condition non-zero, and 0 =3D=3D> capability acquired in branch taken if condition is zero. Given the precise value does not matter, introduce symbolic variants to use instead of either 0 or 1, which should be more intuitive. No functional change intended. Signed-off-by: Marco Elver --- v2: * Use symbolic values for __cond_acquires() and __cond_acquires_shared() (suggested by Bart). --- fs/dlm/lock.c | 2 +- include/linux/compiler-capability-analysis.h | 31 ++++++++++++++++---- include/linux/refcount.h | 6 ++-- include/linux/spinlock.h | 6 ++-- include/linux/spinlock_api_smp.h | 8 ++--- net/ipv4/tcp_sigpool.c | 2 +- 6 files changed, 38 insertions(+), 17 deletions(-) diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c index c8ff88f1cdcf..6799cb0c8f50 100644 --- a/fs/dlm/lock.c +++ b/fs/dlm/lock.c @@ -343,7 +343,7 @@ void dlm_hold_rsb(struct dlm_rsb *r) /* TODO move this to lib/refcount.c */ static __must_check bool dlm_refcount_dec_and_write_lock_bh(refcount_t *r, rwlock_t *lock) -__cond_acquires(lock) + __cond_acquires(true, lock) { if (refcount_dec_not_one(r)) return false; diff --git a/include/linux/compiler-capability-analysis.h b/include/linux/c= ompiler-capability-analysis.h index c47d9ed18303..832727fea140 100644 --- a/include/linux/compiler-capability-analysis.h +++ b/include/linux/compiler-capability-analysis.h @@ -240,7 +240,7 @@ # define __must_hold(x) __attribute__((context(x,1,1))) # define __must_not_hold(x) # define __acquires(x) __attribute__((context(x,0,1))) -# define __cond_acquires(x) __attribute__((context(x,0,-1))) +# define __cond_acquires(ret, x) __attribute__((context(x,0,-1))) # define __releases(x) __attribute__((context(x,1,0))) # define __acquire(x) __context__(x,1) # define __release(x) __context__(x,-1) @@ -283,15 +283,32 @@ */ # define __acquires(x) __acquires_cap(x) =20 +/* + * 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__#= #_cap(1, x) +#define __cond_acquires_impl_false(x, ...) __try_acquires##__VA_ARGS__#= #_cap(0, x) +#define __cond_acquires_impl_nonzero(x, ...) __try_acquires##__VA_ARGS__#= #_cap(1, x) +#define __cond_acquires_impl_0(x, ...) __try_acquires##__VA_ARGS__#= #_cap(0, x) +#define __cond_acquires_impl_nonnull(x, ...) __try_acquires##__VA_ARGS__#= #_cap(1, x) +#define __cond_acquires_impl_NULL(x, ...) __try_acquires##__VA_ARGS__#= #_cap(0, x) + /** * __cond_acquires() - function attribute, function conditionally * acquires a capability exclusively + * @ret: abstract value returned by function if capability acquired * @x: capability instance pointer * * Function attribute declaring that the function conditionally acquires t= he - * given capability instance @x exclusively, but does not release it. + * given capability instance @x exclusively, but does not release it. The + * function return value @ret denotes when the capability is acquired. + * + * @ret may be one of: true, false, nonzero, 0, nonnull, NULL. */ -# define __cond_acquires(x) __try_acquires_cap(1, x) +# define __cond_acquires(ret, x) __cond_acquires_impl_##ret(x) =20 /** * __releases() - function attribute, function releases a capability exclu= sively @@ -358,12 +375,16 @@ /** * __cond_acquires_shared() - function attribute, function conditionally * acquires a capability shared + * @ret: abstract value returned by function if capability acquired * @x: capability instance pointer * * Function attribute declaring that the function conditionally acquires t= he - * given capability instance @x with shared access, but does not release i= t. + * given capability instance @x with shared access, but does not release i= t. The + * function return value @ret denotes when the capability is acquired. + * + * @ret may be one of: true, false, nonzero, 0, nonnull, NULL. */ -# define __cond_acquires_shared(x) __try_acquires_shared_cap(1, x) +# define __cond_acquires_shared(ret, x) __cond_acquires_impl_##ret(x, _sha= red) =20 /** * __releases_shared() - function attribute, function releases a diff --git a/include/linux/refcount.h b/include/linux/refcount.h index 35f039ecb272..88a6e292271d 100644 --- a/include/linux/refcount.h +++ b/include/linux/refcount.h @@ -353,9 +353,9 @@ static inline void refcount_dec(refcount_t *r) =20 extern __must_check bool refcount_dec_if_one(refcount_t *r); extern __must_check bool refcount_dec_not_one(refcount_t *r); -extern __must_check bool refcount_dec_and_mutex_lock(refcount_t *r, struct= mutex *lock) __cond_acquires(lock); -extern __must_check bool refcount_dec_and_lock(refcount_t *r, spinlock_t *= lock) __cond_acquires(lock); +extern __must_check bool refcount_dec_and_mutex_lock(refcount_t *r, struct= mutex *lock) __cond_acquires(true, lock); +extern __must_check bool refcount_dec_and_lock(refcount_t *r, spinlock_t *= lock) __cond_acquires(true, lock); extern __must_check bool refcount_dec_and_lock_irqsave(refcount_t *r, spinlock_t *lock, - unsigned long *flags) __cond_acquires(lock); + unsigned long *flags) __cond_acquires(true, lock); #endif /* _LINUX_REFCOUNT_H */ diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h index 09124713b115..12369fa9e3bb 100644 --- a/include/linux/spinlock.h +++ b/include/linux/spinlock.h @@ -362,7 +362,7 @@ static __always_inline void spin_lock_bh(spinlock_t *lo= ck) } =20 static __always_inline int spin_trylock(spinlock_t *lock) - __cond_acquires(lock) __no_capability_analysis + __cond_acquires(true, lock) __no_capability_analysis { return raw_spin_trylock(&lock->rlock); } @@ -420,13 +420,13 @@ static __always_inline void spin_unlock_irqrestore(sp= inlock_t *lock, unsigned lo } =20 static __always_inline int spin_trylock_bh(spinlock_t *lock) - __cond_acquires(lock) __no_capability_analysis + __cond_acquires(true, lock) __no_capability_analysis { return raw_spin_trylock_bh(&lock->rlock); } =20 static __always_inline int spin_trylock_irq(spinlock_t *lock) - __cond_acquires(lock) __no_capability_analysis + __cond_acquires(true, lock) __no_capability_analysis { return raw_spin_trylock_irq(&lock->rlock); } diff --git a/include/linux/spinlock_api_smp.h b/include/linux/spinlock_api_= smp.h index fab02d8bf0c9..a77b76003ebb 100644 --- a/include/linux/spinlock_api_smp.h +++ b/include/linux/spinlock_api_smp.h @@ -34,8 +34,8 @@ unsigned long __lockfunc _raw_spin_lock_irqsave(raw_spinl= ock_t *lock) unsigned long __lockfunc _raw_spin_lock_irqsave_nested(raw_spinlock_t *lock, int subclass) __acquires(lock); -int __lockfunc _raw_spin_trylock(raw_spinlock_t *lock) __cond_acquires(lo= ck); -int __lockfunc _raw_spin_trylock_bh(raw_spinlock_t *lock) __cond_acquires(= lock); +int __lockfunc _raw_spin_trylock(raw_spinlock_t *lock) __cond_acquires(tr= ue, lock); +int __lockfunc _raw_spin_trylock_bh(raw_spinlock_t *lock) __cond_acquires(= true, lock); void __lockfunc _raw_spin_unlock(raw_spinlock_t *lock) __releases(lock); void __lockfunc _raw_spin_unlock_bh(raw_spinlock_t *lock) __releases(lock); void __lockfunc _raw_spin_unlock_irq(raw_spinlock_t *lock) __releases(lock= ); @@ -84,7 +84,7 @@ _raw_spin_unlock_irqrestore(raw_spinlock_t *lock, unsigne= d long flags) #endif =20 static inline int __raw_spin_trylock(raw_spinlock_t *lock) - __cond_acquires(lock) + __cond_acquires(true, lock) { preempt_disable(); if (do_raw_spin_trylock(lock)) { @@ -177,7 +177,7 @@ static inline void __raw_spin_unlock_bh(raw_spinlock_t = *lock) } =20 static inline int __raw_spin_trylock_bh(raw_spinlock_t *lock) - __cond_acquires(lock) + __cond_acquires(true, lock) { __local_bh_disable_ip(_RET_IP_, SOFTIRQ_LOCK_OFFSET); if (do_raw_spin_trylock(lock)) { diff --git a/net/ipv4/tcp_sigpool.c b/net/ipv4/tcp_sigpool.c index d8a4f192873a..10b2e5970c40 100644 --- a/net/ipv4/tcp_sigpool.c +++ b/net/ipv4/tcp_sigpool.c @@ -257,7 +257,7 @@ void tcp_sigpool_get(unsigned int id) } EXPORT_SYMBOL_GPL(tcp_sigpool_get); =20 -int tcp_sigpool_start(unsigned int id, struct tcp_sigpool *c) __cond_acqui= res(RCU_BH) +int tcp_sigpool_start(unsigned int id, struct tcp_sigpool *c) __cond_acqui= res(0, RCU_BH) { struct crypto_ahash *hash; =20 --=20 2.48.1.711.g2feabab25a-goog From nobody Thu May 7 18:25:53 2026 Received: from mail-wr1-f73.google.com (mail-wr1-f73.google.com [209.85.221.73]) (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 A28DF1FFC67 for ; Tue, 4 Mar 2025 09:25:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080339; cv=none; b=j5hMPil/ztPzX4TN5nbWYOWsoAIC4aMSkTiFkVnTgG04I5yvmVlzP70w64lQlQerCVXlphIdi5UTiAObZpsaTQK+OPDH1tcPtZgFoSflQWmxDuUiGU1eqo1/FPpejP61uN628AD9BNGWrjKmyVMVlIsl5Uphd6/BxWZLUw/duoU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080339; c=relaxed/simple; bh=R7NfOr2i/sd1rk+XA1fxYV0VoUux4hyfMe10hs/GFIo=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=CH0SdxDH120RB3Js+vXZhdbE/PZxR9EVRoMM8PlcNSzYmTmhlbX9uPfQySQINNOi3YMdFjbE8LWCA0crJaEoXSqtmBg3Z4CIPmlt/dsVz+WAVodczUIx1GgxMtySE5LTh3aoMuZMUXwuID3VPWNjRPQoEOU4u39I6LF9hQ98pZ4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--elver.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=rlAmr1h4; arc=none smtp.client-ip=209.85.221.73 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--elver.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="rlAmr1h4" Received: by mail-wr1-f73.google.com with SMTP id ffacd0b85a97d-390f365274dso1583601f8f.0 for ; Tue, 04 Mar 2025 01:25:37 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1741080336; x=1741685136; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=istr0KCQ5s77c/egqf7KkvIi9CTO4kygD0ofOymfkU8=; b=rlAmr1h4tb0e7DR1b6Ty81Ysj52/sL90kwETBPR26PUOsIjJGG87QE9O3gItwv00Vs Z8DpPOcb65brK6KQIsGXxPMUtUjSTNOqY0d/GM2moRjBU4Uo8PMo4ov0WEkgnfnt6bKI GIZPjajsGg+HjL0fBOqC5XLFbI2kzBJplRdg3IBg4DGkNZMJqBQ752PRWW4ooCyx5MFR gz5sRV2QiT7pGJF18uh2zLFiGzF5nLVF4UlojBRP5Cziciad/zCwFhsHD1piNfFrhpY/ A4N7N4cgX1wttIl0C0IwgKfHx6NaEqrRlTDgEL3ycBjmhW2BZp2kaHB6zJPOS3jVkfx6 EJFA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741080336; x=1741685136; h=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; bh=istr0KCQ5s77c/egqf7KkvIi9CTO4kygD0ofOymfkU8=; b=VNARkP67oeehHBLdKW84P5k+1q0pmB95s1n95vg2mX/BK5yL/9iIb4rYulcoPjpmUm 6bw8SPBrXJJLuN53xDHmYKB43yEsV0nGlBXBK7OxN6ZEeMmj68LNKZf0v8aSc5QS5dKo MRUvO7yj7NL1HNsxjYcatztRdWbaDB0snjghAw0jHJ5ydrnLcrvZFAs+1bvXLQyzSgWx V2kiENoqcXW7FmK/wX6M4fI3eZwpiQlIdSP7OTn9GfEhaIW1H2Tc4O7dG4e9XXKjv11h usklVmKf53zfKqNIZJJ/mNwaqHLHkhgRJ5UM5v0vs3lQZID4boW368BhV3bunWm9hTMT RM2Q== X-Forwarded-Encrypted: i=1; AJvYcCXNSeqD6zI2nG0QLbm0/wTlGADOLHYk6w4TOwe72KZhPBSz/c1iiNa0aH+4DpKh0QQUl/9E98JE41RtF7s=@vger.kernel.org X-Gm-Message-State: AOJu0YwfoONS+usokBCGohyGt4xhHmbhwPUy4PYO7wW58IivqwfZe7Ii tpUuAGESlFsHupcUUJxWhCfG6VF2Kv8uhMQksl/EcID9kXk3XRqxqXl+lsiYwdafBhBvfmpF1Q= = X-Google-Smtp-Source: AGHT+IEWpumMq7w2Do+3aHW1xJk7ZnkmrsU/t6znrys5DihZ08Xs8NOd+ecssoGGAfkjsqWUcHoulWJrMg== X-Received: from wrbei4.prod.google.com ([2002:a05:6000:4184:b0:390:f69f:8c34]) (user=elver job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6000:1fa4:b0:390:f9e0:f0d0 with SMTP id ffacd0b85a97d-391155feb2emr1821321f8f.6.1741080335989; Tue, 04 Mar 2025 01:25:35 -0800 (PST) Date: Tue, 4 Mar 2025 10:21:09 +0100 In-Reply-To: <20250304092417.2873893-1-elver@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250304092417.2873893-1-elver@google.com> X-Mailer: git-send-email 2.48.1.711.g2feabab25a-goog Message-ID: <20250304092417.2873893-11-elver@google.com> Subject: [PATCH v2 10/34] locking/mutex: Support Clang's capability analysis From: Marco Elver To: elver@google.com Cc: "David S. Miller" , Luc Van Oostenryck , "Paul E. McKenney" , Alexander Potapenko , Arnd Bergmann , Bart Van Assche , Bill Wendling , Boqun Feng , Dmitry Vyukov , Eric Dumazet , Frederic Weisbecker , Greg Kroah-Hartman , Herbert Xu , Ingo Molnar , Jann Horn , Jiri Slaby , Joel Fernandes , Jonathan Corbet , Josh Triplett , Justin Stitt , Kees Cook , Kentaro Takeda , Mark Rutland , Mathieu Desnoyers , Miguel Ojeda , Nathan Chancellor , Neeraj Upadhyay , Peter Zijlstra , Steven Rostedt , Tetsuo Handa , Thomas Gleixner , Uladzislau Rezki , Waiman Long , Will Deacon , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org, llvm@lists.linux.dev, rcu@vger.kernel.org, linux-crypto@vger.kernel.org, linux-serial@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add support for Clang's capability analysis for mutex. Signed-off-by: Marco Elver --- .../dev-tools/capability-analysis.rst | 2 +- include/linux/mutex.h | 29 +++++---- include/linux/mutex_types.h | 4 +- lib/test_capability-analysis.c | 64 +++++++++++++++++++ 4 files changed, 82 insertions(+), 17 deletions(-) diff --git a/Documentation/dev-tools/capability-analysis.rst b/Documentatio= n/dev-tools/capability-analysis.rst index ddda3dc0d8d3..0000214056c2 100644 --- a/Documentation/dev-tools/capability-analysis.rst +++ b/Documentation/dev-tools/capability-analysis.rst @@ -79,7 +79,7 @@ Supported Kernel Primitives ~~~~~~~~~~~~~~~~~~~~~~~~~~~ =20 Currently the following synchronization primitives are supported: -`raw_spinlock_t`, `spinlock_t`, `rwlock_t`. +`raw_spinlock_t`, `spinlock_t`, `rwlock_t`, `mutex`. =20 For capabilities with an initialization function (e.g., `spin_lock_init()`= ), calling this function on the capability instance before initializing any diff --git a/include/linux/mutex.h b/include/linux/mutex.h index 2bf91b57591b..f71ad9ec96d0 100644 --- a/include/linux/mutex.h +++ b/include/linux/mutex.h @@ -62,6 +62,7 @@ do { \ static struct lock_class_key __key; \ \ __mutex_init((mutex), #mutex, &__key); \ + __assert_cap(mutex); \ } while (0) =20 /** @@ -154,14 +155,14 @@ static inline int __devm_mutex_init(struct device *de= v, struct mutex *lock) * Also see Documentation/locking/mutex-design.rst. */ #ifdef CONFIG_DEBUG_LOCK_ALLOC -extern void mutex_lock_nested(struct mutex *lock, unsigned int subclass); +extern void mutex_lock_nested(struct mutex *lock, unsigned int subclass) _= _acquires(lock); extern void _mutex_lock_nest_lock(struct mutex *lock, struct lockdep_map *= nest_lock); =20 extern int __must_check mutex_lock_interruptible_nested(struct mutex *lock, - unsigned int subclass); + unsigned int subclass) __cond_acquires(0, lock); extern int __must_check mutex_lock_killable_nested(struct mutex *lock, - unsigned int subclass); -extern void mutex_lock_io_nested(struct mutex *lock, unsigned int subclass= ); + unsigned int subclass) __cond_acquires(0, lock); +extern void mutex_lock_io_nested(struct mutex *lock, unsigned int subclass= ) __acquires(lock); =20 #define mutex_lock(lock) mutex_lock_nested(lock, 0) #define mutex_lock_interruptible(lock) mutex_lock_interruptible_nested(loc= k, 0) @@ -175,10 +176,10 @@ do { \ } while (0) =20 #else -extern void mutex_lock(struct mutex *lock); -extern int __must_check mutex_lock_interruptible(struct mutex *lock); -extern int __must_check mutex_lock_killable(struct mutex *lock); -extern void mutex_lock_io(struct mutex *lock); +extern void mutex_lock(struct mutex *lock) __acquires(lock); +extern int __must_check mutex_lock_interruptible(struct mutex *lock) __con= d_acquires(0, lock); +extern int __must_check mutex_lock_killable(struct mutex *lock) __cond_acq= uires(0, lock); +extern void mutex_lock_io(struct mutex *lock) __acquires(lock); =20 # define mutex_lock_nested(lock, subclass) mutex_lock(lock) # define mutex_lock_interruptible_nested(lock, subclass) mutex_lock_interr= uptible(lock) @@ -193,13 +194,13 @@ extern void mutex_lock_io(struct mutex *lock); * * Returns 1 if the mutex has been acquired successfully, and 0 on content= ion. */ -extern int mutex_trylock(struct mutex *lock); -extern void mutex_unlock(struct mutex *lock); +extern int mutex_trylock(struct mutex *lock) __cond_acquires(true, lock); +extern void mutex_unlock(struct mutex *lock) __releases(lock); =20 -extern int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *lock); +extern int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *lock) __= cond_acquires(true, lock); =20 -DEFINE_GUARD(mutex, struct mutex *, mutex_lock(_T), mutex_unlock(_T)) -DEFINE_GUARD_COND(mutex, _try, mutex_trylock(_T)) -DEFINE_GUARD_COND(mutex, _intr, mutex_lock_interruptible(_T) =3D=3D 0) +DEFINE_LOCK_GUARD_1(mutex, struct mutex, mutex_lock(_T->lock), mutex_unloc= k(_T->lock)) +DEFINE_LOCK_GUARD_1_COND(mutex, _try, mutex_trylock(_T->lock)) +DEFINE_LOCK_GUARD_1_COND(mutex, _intr, mutex_lock_interruptible(_T->lock) = =3D=3D 0) =20 #endif /* __LINUX_MUTEX_H */ diff --git a/include/linux/mutex_types.h b/include/linux/mutex_types.h index fdf7f515fde8..e1a5ea12d53c 100644 --- a/include/linux/mutex_types.h +++ b/include/linux/mutex_types.h @@ -38,7 +38,7 @@ * - detects multi-task circular deadlocks and prints out all affected * locks and tasks (and only those tasks) */ -struct mutex { +struct_with_capability(mutex) { atomic_long_t owner; raw_spinlock_t wait_lock; #ifdef CONFIG_MUTEX_SPIN_ON_OWNER @@ -59,7 +59,7 @@ struct mutex { */ #include =20 -struct mutex { +struct_with_capability(mutex) { struct rt_mutex_base rtmutex; #ifdef CONFIG_DEBUG_LOCK_ALLOC struct lockdep_map dep_map; diff --git a/lib/test_capability-analysis.c b/lib/test_capability-analysis.c index 84060bace61d..286723b47328 100644 --- a/lib/test_capability-analysis.c +++ b/lib/test_capability-analysis.c @@ -5,6 +5,7 @@ */ =20 #include +#include #include =20 /* @@ -144,3 +145,66 @@ TEST_SPINLOCK_COMMON(read_lock, read_unlock, read_trylock, TEST_OP_RO); + +struct test_mutex_data { + struct mutex mtx; + int counter __guarded_by(&mtx); +}; + +static void __used test_mutex_init(struct test_mutex_data *d) +{ + mutex_init(&d->mtx); + d->counter =3D 0; +} + +static void __used test_mutex_lock(struct test_mutex_data *d) +{ + mutex_lock(&d->mtx); + d->counter++; + mutex_unlock(&d->mtx); + mutex_lock_io(&d->mtx); + d->counter++; + mutex_unlock(&d->mtx); +} + +static void __used test_mutex_trylock(struct test_mutex_data *d, atomic_t = *a) +{ + if (!mutex_lock_interruptible(&d->mtx)) { + d->counter++; + mutex_unlock(&d->mtx); + } + if (!mutex_lock_killable(&d->mtx)) { + d->counter++; + mutex_unlock(&d->mtx); + } + if (mutex_trylock(&d->mtx)) { + d->counter++; + mutex_unlock(&d->mtx); + } + if (atomic_dec_and_mutex_lock(a, &d->mtx)) { + d->counter++; + mutex_unlock(&d->mtx); + } +} + +static void __used test_mutex_assert(struct test_mutex_data *d) +{ + lockdep_assert_held(&d->mtx); + d->counter++; +} + +static void __used test_mutex_guard(struct test_mutex_data *d) +{ + guard(mutex)(&d->mtx); + d->counter++; +} + +static void __used test_mutex_cond_guard(struct test_mutex_data *d) +{ + scoped_cond_guard(mutex_try, return, &d->mtx) { + d->counter++; + } + scoped_cond_guard(mutex_intr, return, &d->mtx) { + d->counter++; + } +} --=20 2.48.1.711.g2feabab25a-goog From nobody Thu May 7 18:25:53 2026 Received: from mail-ej1-f73.google.com (mail-ej1-f73.google.com [209.85.218.73]) (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 B6D50200116 for ; Tue, 4 Mar 2025 09:25:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080342; cv=none; b=BDdGSGlOahBNAWnbMmLiX+6RJ2wfa+Frhc/aPv7RNqGpjbnXpwoMKJON+ANUlPJ0aM5x0jHun6xLkRJyfPTpwR7k3mPyE4uNvZa7oMg0E/0fnXkFp7tPPEdof8Ex4IAx/xElV4Zu0Z58zyJNho8j2CB+TvQ34T61wxPkx2rMx84= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080342; c=relaxed/simple; bh=+hOyGV6sT5S0OduN60qT6geEoWJUIWkI8FTuectbotA=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=iC98B78wdx7dTQ0kOBWzEc0KOUgA9UpPf18jrsznWr7MhiuM4XX4og0qul9aJbYubM9fzFnNd6cW2FqTyNDOS7MBvQGTcgHwNwL0GtjckK9fYri+z0VIwTm3B3gMmEFDaQNSxm0ijtqqPW68fhw9R91X4pK2fHyR7hNr1X6NYUA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--elver.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=zkYmsCtv; arc=none smtp.client-ip=209.85.218.73 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--elver.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="zkYmsCtv" Received: by mail-ej1-f73.google.com with SMTP id a640c23a62f3a-abf48e1e70eso288315166b.2 for ; Tue, 04 Mar 2025 01:25:40 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1741080339; x=1741685139; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=8z4fgpkLlPzvclrtbcw45VHrfGlnBGLpcfc2M8hQ/8Q=; b=zkYmsCtv88quGei6n+pBRfr5opHmmF/wDl0tPF4VCgDtbMTwiAN1S2/LfZ1/QbpdLK Jnuiwl0rNtXx6yiFVOVjP+zlwE89R5yJtTSONOtqw7IZJyOaADJT5H4JZl9bIe9cevl3 uKxzWsjcPO1N/5pcBOfQZ94z5a67jW9LUNI/CZwWFGV6/sMwWBL9d3jU/sQ1pUz7hE/p K5WZFjBMpKaUoe/l1c2JP9er1TW3Hg5WEDh+fTX1Xjj4bLH0u52sKhe+4RWbC/03N9/w 7IKyux6sZnoD5s/P3pZc70W4m0x6J3CN2TuVtJCuBGVvwAae+5iiqitDDjZw+IXmf0qH jL/Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741080339; x=1741685139; h=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; bh=8z4fgpkLlPzvclrtbcw45VHrfGlnBGLpcfc2M8hQ/8Q=; b=Mphv0uLXkEAo00ZOc3gxjTRIxc5kKBe9YXM866pEVgeT7rAPu+bRyC+uVSGzv8ZQGI G+2ugFUI8VO53aNwKMbB4AsEqnLRbDuGrHEaIL+NoWn8vjYkkI2oM4xVuPT//wzCCXg7 OuGZxuACyeTwXtQPtNgYtmaANF8djF4whcImlHLnqkfJzY82pO/r93TVrEfTt1rPspZr EiYwkNQHucxAlFnjYMHNHRSrYZouebd6KJFNRelEKNGP4RhPOKER9gVzK1h5AH8o02Lw zX3yMicaRcgPqOnczr5VeVaOjfAkS+pEeefqMGHdle6vfeonlceyaDomxv5tv57exwyM zWlQ== X-Forwarded-Encrypted: i=1; AJvYcCUV+x6mps5hIMcEaaP/H8cso6AdmSyS/fPCyL18ijjJWKaRia7/2MQMnQFH4VZEVXXN/frrCTxSVH9+P3c=@vger.kernel.org X-Gm-Message-State: AOJu0YxHHjrxFZ3knRLjI468WM+8g5xbjngvfbVVlKI4iVxAcqSI428M NmxZl34d1qWhA//elGNxP9iFqtVul/utW0m6PQi1m3Y/wnDe+Ze3UDf3Os0r3uFg2d8sIUpJVw= = X-Google-Smtp-Source: AGHT+IH6OTcNSqBkbTu8GVa+WWd3kjf6MqiHYa0XeNWcxZmh/34swAJ3H0QTXtrQX7tePWUnJOEFAomSjA== X-Received: from ejcvg12.prod.google.com ([2002:a17:907:d30c:b0:abf:7710:3f5]) (user=elver job=prod-delivery.src-stubby-dispatcher) by 2002:a17:907:3fa6:b0:abf:65c8:70e5 with SMTP id a640c23a62f3a-abf65c8922cmr1078595566b.25.1741080338878; Tue, 04 Mar 2025 01:25:38 -0800 (PST) Date: Tue, 4 Mar 2025 10:21:10 +0100 In-Reply-To: <20250304092417.2873893-1-elver@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250304092417.2873893-1-elver@google.com> X-Mailer: git-send-email 2.48.1.711.g2feabab25a-goog Message-ID: <20250304092417.2873893-12-elver@google.com> Subject: [PATCH v2 11/34] locking/seqlock: Support Clang's capability analysis From: Marco Elver To: elver@google.com Cc: "David S. Miller" , Luc Van Oostenryck , "Paul E. McKenney" , Alexander Potapenko , Arnd Bergmann , Bart Van Assche , Bill Wendling , Boqun Feng , Dmitry Vyukov , Eric Dumazet , Frederic Weisbecker , Greg Kroah-Hartman , Herbert Xu , Ingo Molnar , Jann Horn , Jiri Slaby , Joel Fernandes , Jonathan Corbet , Josh Triplett , Justin Stitt , Kees Cook , Kentaro Takeda , Mark Rutland , Mathieu Desnoyers , Miguel Ojeda , Nathan Chancellor , Neeraj Upadhyay , Peter Zijlstra , Steven Rostedt , Tetsuo Handa , Thomas Gleixner , Uladzislau Rezki , Waiman Long , Will Deacon , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org, llvm@lists.linux.dev, rcu@vger.kernel.org, linux-crypto@vger.kernel.org, linux-serial@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add support for Clang's capability analysis for seqlock_t. Signed-off-by: Marco Elver --- .../dev-tools/capability-analysis.rst | 2 +- include/linux/seqlock.h | 24 +++++++++++ include/linux/seqlock_types.h | 5 ++- lib/test_capability-analysis.c | 43 +++++++++++++++++++ 4 files changed, 71 insertions(+), 3 deletions(-) diff --git a/Documentation/dev-tools/capability-analysis.rst b/Documentatio= n/dev-tools/capability-analysis.rst index 0000214056c2..e4b333fffb4d 100644 --- a/Documentation/dev-tools/capability-analysis.rst +++ b/Documentation/dev-tools/capability-analysis.rst @@ -79,7 +79,7 @@ Supported Kernel Primitives ~~~~~~~~~~~~~~~~~~~~~~~~~~~ =20 Currently the following synchronization primitives are supported: -`raw_spinlock_t`, `spinlock_t`, `rwlock_t`, `mutex`. +`raw_spinlock_t`, `spinlock_t`, `rwlock_t`, `mutex`, `seqlock_t`. =20 For capabilities with an initialization function (e.g., `spin_lock_init()`= ), calling this function on the capability instance before initializing any diff --git a/include/linux/seqlock.h b/include/linux/seqlock.h index 5ce48eab7a2a..c914eb9714e9 100644 --- a/include/linux/seqlock.h +++ b/include/linux/seqlock.h @@ -816,6 +816,7 @@ static __always_inline void write_seqcount_latch_end(se= qcount_latch_t *s) do { \ spin_lock_init(&(sl)->lock); \ seqcount_spinlock_init(&(sl)->seqcount, &(sl)->lock); \ + __assert_cap(sl); \ } while (0) =20 /** @@ -832,6 +833,7 @@ static __always_inline void write_seqcount_latch_end(se= qcount_latch_t *s) * Return: count, to be passed to read_seqretry() */ static inline unsigned read_seqbegin(const seqlock_t *sl) + __acquires_shared(sl) __no_capability_analysis { return read_seqcount_begin(&sl->seqcount); } @@ -848,6 +850,7 @@ static inline unsigned read_seqbegin(const seqlock_t *s= l) * Return: true if a read section retry is required, else false */ static inline unsigned read_seqretry(const seqlock_t *sl, unsigned start) + __releases_shared(sl) __no_capability_analysis { return read_seqcount_retry(&sl->seqcount, start); } @@ -872,6 +875,7 @@ static inline unsigned read_seqretry(const seqlock_t *s= l, unsigned start) * _irqsave or _bh variants of this function instead. */ static inline void write_seqlock(seqlock_t *sl) + __acquires(sl) __no_capability_analysis { spin_lock(&sl->lock); do_write_seqcount_begin(&sl->seqcount.seqcount); @@ -885,6 +889,7 @@ static inline void write_seqlock(seqlock_t *sl) * critical section of given seqlock_t. */ static inline void write_sequnlock(seqlock_t *sl) + __releases(sl) __no_capability_analysis { do_write_seqcount_end(&sl->seqcount.seqcount); spin_unlock(&sl->lock); @@ -898,6 +903,7 @@ static inline void write_sequnlock(seqlock_t *sl) * other write side sections, can be invoked from softirq contexts. */ static inline void write_seqlock_bh(seqlock_t *sl) + __acquires(sl) __no_capability_analysis { spin_lock_bh(&sl->lock); do_write_seqcount_begin(&sl->seqcount.seqcount); @@ -912,6 +918,7 @@ static inline void write_seqlock_bh(seqlock_t *sl) * write_seqlock_bh(). */ static inline void write_sequnlock_bh(seqlock_t *sl) + __releases(sl) __no_capability_analysis { do_write_seqcount_end(&sl->seqcount.seqcount); spin_unlock_bh(&sl->lock); @@ -925,6 +932,7 @@ static inline void write_sequnlock_bh(seqlock_t *sl) * other write sections, can be invoked from hardirq contexts. */ static inline void write_seqlock_irq(seqlock_t *sl) + __acquires(sl) __no_capability_analysis { spin_lock_irq(&sl->lock); do_write_seqcount_begin(&sl->seqcount.seqcount); @@ -938,12 +946,14 @@ static inline void write_seqlock_irq(seqlock_t *sl) * seqlock_t write side section opened with write_seqlock_irq(). */ static inline void write_sequnlock_irq(seqlock_t *sl) + __releases(sl) __no_capability_analysis { do_write_seqcount_end(&sl->seqcount.seqcount); spin_unlock_irq(&sl->lock); } =20 static inline unsigned long __write_seqlock_irqsave(seqlock_t *sl) + __acquires(sl) __no_capability_analysis { unsigned long flags; =20 @@ -976,6 +986,7 @@ static inline unsigned long __write_seqlock_irqsave(seq= lock_t *sl) */ static inline void write_sequnlock_irqrestore(seqlock_t *sl, unsigned long flags) + __releases(sl) __no_capability_analysis { do_write_seqcount_end(&sl->seqcount.seqcount); spin_unlock_irqrestore(&sl->lock, flags); @@ -998,6 +1009,7 @@ write_sequnlock_irqrestore(seqlock_t *sl, unsigned lon= g flags) * The opened read section must be closed with read_sequnlock_excl(). */ static inline void read_seqlock_excl(seqlock_t *sl) + __acquires_shared(sl) __no_capability_analysis { spin_lock(&sl->lock); } @@ -1007,6 +1019,7 @@ static inline void read_seqlock_excl(seqlock_t *sl) * @sl: Pointer to seqlock_t */ static inline void read_sequnlock_excl(seqlock_t *sl) + __releases_shared(sl) __no_capability_analysis { spin_unlock(&sl->lock); } @@ -1021,6 +1034,7 @@ static inline void read_sequnlock_excl(seqlock_t *sl) * from softirq contexts. */ static inline void read_seqlock_excl_bh(seqlock_t *sl) + __acquires_shared(sl) __no_capability_analysis { spin_lock_bh(&sl->lock); } @@ -1031,6 +1045,7 @@ static inline void read_seqlock_excl_bh(seqlock_t *sl) * @sl: Pointer to seqlock_t */ static inline void read_sequnlock_excl_bh(seqlock_t *sl) + __releases_shared(sl) __no_capability_analysis { spin_unlock_bh(&sl->lock); } @@ -1045,6 +1060,7 @@ static inline void read_sequnlock_excl_bh(seqlock_t *= sl) * hardirq context. */ static inline void read_seqlock_excl_irq(seqlock_t *sl) + __acquires_shared(sl) __no_capability_analysis { spin_lock_irq(&sl->lock); } @@ -1055,11 +1071,13 @@ static inline void read_seqlock_excl_irq(seqlock_t = *sl) * @sl: Pointer to seqlock_t */ static inline void read_sequnlock_excl_irq(seqlock_t *sl) + __releases_shared(sl) __no_capability_analysis { spin_unlock_irq(&sl->lock); } =20 static inline unsigned long __read_seqlock_excl_irqsave(seqlock_t *sl) + __acquires_shared(sl) __no_capability_analysis { unsigned long flags; =20 @@ -1089,6 +1107,7 @@ static inline unsigned long __read_seqlock_excl_irqsa= ve(seqlock_t *sl) */ static inline void read_sequnlock_excl_irqrestore(seqlock_t *sl, unsigned long flags) + __releases_shared(sl) __no_capability_analysis { spin_unlock_irqrestore(&sl->lock, flags); } @@ -1125,6 +1144,7 @@ read_sequnlock_excl_irqrestore(seqlock_t *sl, unsigne= d long flags) * parameter of the next read_seqbegin_or_lock() iteration. */ static inline void read_seqbegin_or_lock(seqlock_t *lock, int *seq) + __acquires_shared(lock) __no_capability_analysis { if (!(*seq & 1)) /* Even */ *seq =3D read_seqbegin(lock); @@ -1140,6 +1160,7 @@ static inline void read_seqbegin_or_lock(seqlock_t *l= ock, int *seq) * Return: true if a read section retry is required, false otherwise */ static inline int need_seqretry(seqlock_t *lock, int seq) + __releases_shared(lock) __no_capability_analysis { return !(seq & 1) && read_seqretry(lock, seq); } @@ -1153,6 +1174,7 @@ static inline int need_seqretry(seqlock_t *lock, int = seq) * with read_seqbegin_or_lock() and validated by need_seqretry(). */ static inline void done_seqretry(seqlock_t *lock, int seq) + __no_capability_analysis { if (seq & 1) read_sequnlock_excl(lock); @@ -1180,6 +1202,7 @@ static inline void done_seqretry(seqlock_t *lock, int= seq) */ static inline unsigned long read_seqbegin_or_lock_irqsave(seqlock_t *lock, int *seq) + __acquires_shared(lock) __no_capability_analysis { unsigned long flags =3D 0; =20 @@ -1205,6 +1228,7 @@ read_seqbegin_or_lock_irqsave(seqlock_t *lock, int *s= eq) */ static inline void done_seqretry_irqrestore(seqlock_t *lock, int seq, unsigned long flags) + __no_capability_analysis { if (seq & 1) read_sequnlock_excl_irqrestore(lock, flags); diff --git a/include/linux/seqlock_types.h b/include/linux/seqlock_types.h index dfdf43e3fa3d..9775d6f1a234 100644 --- a/include/linux/seqlock_types.h +++ b/include/linux/seqlock_types.h @@ -81,13 +81,14 @@ SEQCOUNT_LOCKNAME(mutex, struct mutex, true, = mutex) * - Comments on top of seqcount_t * - Documentation/locking/seqlock.rst */ -typedef struct { +struct_with_capability(seqlock) { /* * Make sure that readers don't starve writers on PREEMPT_RT: use * seqcount_spinlock_t instead of seqcount_t. Check __SEQ_LOCK(). */ seqcount_spinlock_t seqcount; spinlock_t lock; -} seqlock_t; +}; +typedef struct seqlock seqlock_t; =20 #endif /* __LINUX_SEQLOCK_TYPES_H */ diff --git a/lib/test_capability-analysis.c b/lib/test_capability-analysis.c index 286723b47328..74d287740bb8 100644 --- a/lib/test_capability-analysis.c +++ b/lib/test_capability-analysis.c @@ -6,6 +6,7 @@ =20 #include #include +#include #include =20 /* @@ -208,3 +209,45 @@ static void __used test_mutex_cond_guard(struct test_m= utex_data *d) d->counter++; } } + +struct test_seqlock_data { + seqlock_t sl; + int counter __guarded_by(&sl); +}; + +static void __used test_seqlock_init(struct test_seqlock_data *d) +{ + seqlock_init(&d->sl); + d->counter =3D 0; +} + +static void __used test_seqlock_reader(struct test_seqlock_data *d) +{ + unsigned int seq; + + do { + seq =3D read_seqbegin(&d->sl); + (void)d->counter; + } while (read_seqretry(&d->sl, seq)); +} + +static void __used test_seqlock_writer(struct test_seqlock_data *d) +{ + unsigned long flags; + + write_seqlock(&d->sl); + d->counter++; + write_sequnlock(&d->sl); + + write_seqlock_irq(&d->sl); + d->counter++; + write_sequnlock_irq(&d->sl); + + write_seqlock_bh(&d->sl); + d->counter++; + write_sequnlock_bh(&d->sl); + + write_seqlock_irqsave(&d->sl, flags); + d->counter++; + write_sequnlock_irqrestore(&d->sl, flags); +} --=20 2.48.1.711.g2feabab25a-goog From nobody Thu May 7 18:25:53 2026 Received: from mail-ed1-f73.google.com (mail-ed1-f73.google.com [209.85.208.73]) (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 2597B200BA1 for ; Tue, 4 Mar 2025 09:25:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080345; cv=none; b=AFO2RfSjtRC1JloIpLbbg5m2W+wCq+e3uI5TL6Uy+BYtv8I9aXV8JlX98wrV/U/gPqjBX8X50AiSeNYf2iwOZNr6vmuMkF9XMvROu9GKygoD1uAOr1cA0Hg2UtJbtiVkV8gkwt3SBiGfyNerogzRCIjI1Fkm6J/R7V7LdUk7Sas= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080345; c=relaxed/simple; bh=A7gPHEZIEQYCG49NjQ38GqM0IYCU29sZ4kgbaVoDh5Y=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=KxnQW6BXQsvODzgknsKKs8KpPlqpadnNBFjOEO5KcbfjG92O08tFotN4IoySubB7im8KSp32kEq36IXhAcr0I7RXLzZz1Kq8TqGPSVgMnrh17HO/QY2BdXCIZ85oVvoAsQ8znMd+I3expc9JUIxUvivUkLOqCYTotMlYN91CGtE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--elver.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=qW8kpVch; arc=none smtp.client-ip=209.85.208.73 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--elver.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="qW8kpVch" Received: by mail-ed1-f73.google.com with SMTP id 4fb4d7f45d1cf-5e54bade36dso2167823a12.2 for ; Tue, 04 Mar 2025 01:25:42 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1741080341; x=1741685141; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=4NsOo3OXCYTu9WQHyv5ORZtwu1IzgjlVv8TtoKqxnnY=; b=qW8kpVch/2lef4718yfMZbrKvq8oqvrMJ1Zs8wJZ3cysiWvrEDmP2vqWHjc0bO3sEf IqbhcoBfsyEN9LnXVnKlu2nf89pRJmfEvIbKLV14FhpeqBu/R4TWhXY9jTyqasrhiI8A OcMvg+rE/VYrVYqgDnK0cDqO3tbiyHDA5y2FMzHTuaA73KEoNBYqD9zZqVaZNS8up7D7 kNcAbm0h3mTS5eIbs6nb/v2cela2VnQXqwYlr08LEfsgz+FeSbuNmJ4p/U9PazsM6+xd o0m21zGV8/LL7CB4DlomPWCcjBxU6mQhI8QY9PQTR8M6FIF08dZVjgwyikEtSicg0MO1 XNuQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741080341; x=1741685141; h=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; bh=4NsOo3OXCYTu9WQHyv5ORZtwu1IzgjlVv8TtoKqxnnY=; b=Gs6XsXbE8czCTmZ+mqHqbTwgjws0WvfOzPVaAVQC2fXu/0E47hxZrYSgAGUh7DuMQH gGhebtaxUp51A57HtJPXucGarbw75+dQ1b8kEerjb0FYcwNmNHb3+v98HAGOe7JFqpv/ jkv1Zsr5sh1WD1sQpt+3wC9g2wqsoxfD/35twGqQnBf/NXG7tJ4PreSTfM3CL4vG9pMm 66Oe3ARTDBZlXdja6tr077aQ5x1b5UXXVjsUFupdGKimZe6ErwHtPzYcmmKRn5lxvQSc OHXVJNr19By5eWG3eJrN8PgFx4cKV9RUNEYO2M6YoW4xNmSTqFOoZIRpQFltgPJI5mwt zr+Q== X-Forwarded-Encrypted: i=1; AJvYcCUFqWmLHfsS/4ZCXUIDJ1lcSLNillVMu2KGhFySpJe1JalO7JRSpYiAt/nxbAzTE/fnwwLn3uNTWm1s5G4=@vger.kernel.org X-Gm-Message-State: AOJu0YxYHi59BA+43gIg4zdGz5cdM1v4Lq+oRUJ+oNwgWreHNI7/8gM/ /NckZ8miSGTwqaWVZQfq4yOelLWqYuDOTuXXGsyCLAOjJqhV6KXtyb8DXU/hmYTMRgduGqhJWw= = X-Google-Smtp-Source: AGHT+IGvHnVCTmDxfH/8wK0cbMQMdd2+QC7Cg7+dh1AXOrq291KoSLxad8RL5shMmiF0TMtX3LbCMTR8+g== X-Received: from ejctb11.prod.google.com ([2002:a17:907:8b8b:b0:abf:60e8:559]) (user=elver job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6402:43c6:b0:5e0:7ff3:20c with SMTP id 4fb4d7f45d1cf-5e4d6b0cb67mr18149547a12.17.1741080341679; Tue, 04 Mar 2025 01:25:41 -0800 (PST) Date: Tue, 4 Mar 2025 10:21:11 +0100 In-Reply-To: <20250304092417.2873893-1-elver@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250304092417.2873893-1-elver@google.com> X-Mailer: git-send-email 2.48.1.711.g2feabab25a-goog Message-ID: <20250304092417.2873893-13-elver@google.com> Subject: [PATCH v2 12/34] bit_spinlock: Include missing From: Marco Elver To: elver@google.com Cc: "David S. Miller" , Luc Van Oostenryck , "Paul E. McKenney" , Alexander Potapenko , Arnd Bergmann , Bart Van Assche , Bill Wendling , Boqun Feng , Dmitry Vyukov , Eric Dumazet , Frederic Weisbecker , Greg Kroah-Hartman , Herbert Xu , Ingo Molnar , Jann Horn , Jiri Slaby , Joel Fernandes , Jonathan Corbet , Josh Triplett , Justin Stitt , Kees Cook , Kentaro Takeda , Mark Rutland , Mathieu Desnoyers , Miguel Ojeda , Nathan Chancellor , Neeraj Upadhyay , Peter Zijlstra , Steven Rostedt , Tetsuo Handa , Thomas Gleixner , Uladzislau Rezki , Waiman Long , Will Deacon , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org, llvm@lists.linux.dev, rcu@vger.kernel.org, linux-crypto@vger.kernel.org, linux-serial@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Including into an empty TU will result in the compiler complaining: ./include/linux/bit_spinlock.h:34:4: error: call to undeclared function 'cp= u_relax'; <...> 34 | cpu_relax(); | ^ 1 error generated. Include to allow including bit_spinlock.h where is not otherwise included. Signed-off-by: Marco Elver --- include/linux/bit_spinlock.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/bit_spinlock.h b/include/linux/bit_spinlock.h index bbc4730a6505..f1174a2fcc4d 100644 --- a/include/linux/bit_spinlock.h +++ b/include/linux/bit_spinlock.h @@ -7,6 +7,8 @@ #include #include =20 +#include /* for cpu_relax() */ + /* * bit-based spin_lock() * --=20 2.48.1.711.g2feabab25a-goog From nobody Thu May 7 18:25:53 2026 Received: from mail-ed1-f74.google.com (mail-ed1-f74.google.com [209.85.208.74]) (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 C477A201019 for ; Tue, 4 Mar 2025 09:25:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080349; cv=none; b=RPFkNONOzLZ6ziAqAF7e8taXsUBnQHV9iAql8+U1qRh+Xoi6DkcBwL9YfrylGwvXMihouhZHA82avtjyKiGT08kKtRV1Xy/4UcIZLdrgQRCyxtQWiH1rAFwtF7hhrUlcvFJPJR4/IFcNOGFaXjp92SCd9s5TZFolRwdqIaeBn34= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080349; c=relaxed/simple; bh=akMiNQ+gN0RmTpAtCrvDOtnUbNbNNTRmSfn6a9iTJQ0=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=gvvZbomDsi/zl2grvxtV+KqDi+H9+2Hvn1Ikx3zu8A86JnbFFmFFt22ZCw/i1Z9Eycxzv8cQCgsiqRMwI5c8s1Ny/ApfZHnibARCvRzMXg1fpfZ0lXBF6zAuTWb3ECZse6KGlPeGREpmaioOC1OYXqReI1Y1/JX7hpY6pUcq0d0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--elver.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=CQmQGMJ7; arc=none smtp.client-ip=209.85.208.74 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--elver.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="CQmQGMJ7" Received: by mail-ed1-f74.google.com with SMTP id 4fb4d7f45d1cf-5e4cc705909so1863134a12.3 for ; Tue, 04 Mar 2025 01:25:45 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1741080344; x=1741685144; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=7aDkMzmRnQvghHkOpkqZKF4mFOekC+EgfFoIEWs+/yg=; b=CQmQGMJ7xxU/gG597V/dmkvtMl9PBp2toUgb5bzZiNu6X0lSAGQLOCPllHUVug6FBx /cV7FvPxSzB3SO+T5PxZNyLxWmMeYIDZUu0+mTi9VatMUeZXEGUh2dESidJH4bGTZuF+ EXhnUMjYJDg5Yn3cAqw2JklVxvdh1bT4mt18KE35YcPz1uDodCeZ+K2eveOXEj0FEmoh iBbvojWtXwnZ+nZJ7yaWrQLL864iDRqO29up2tjlaJRv+VOtitN4gnOi1naRbUaqPrwE FhC8miShpLF0utQg+ClQlyYXJEd+B4uzBUZPdgK8muFAof0Ow52NT69Avigb/dJVGh6/ 7Ofg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741080344; x=1741685144; h=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; bh=7aDkMzmRnQvghHkOpkqZKF4mFOekC+EgfFoIEWs+/yg=; b=FEmqvIZtZ26ikHSAfC/U91kPEfh/6Fv6xgQ/uM+VilU4whubvXm+00vCsJPg3eNpLf SIGzEakKFuGjQNuBZhRNzlHhwBl8ZRB6FzTqb+wjz8t5FaDDm9cVNmslxroAOjLVY8+r izj7GyRNnrIqdCH58aCRW60/jZ8OYn+ToQi+8xs8uXN1+qGksyXF1iV0dNV3OTbaRV+g PVi6vZgHlNlEdDubRZVNTyCvwzJWVtfzWWUNwLI1Trl3m9fWPl9T70C5FmgBU9671GS0 YfkP0cufsFs7nLsGrR1kMspSTxKW+iLRtLhlWIoKTuoDx/gQNKNboMOuDDm0I1PVxaon lSGA== X-Forwarded-Encrypted: i=1; AJvYcCWy7QS3GUdp2TPGNtneP5oXWOTj2QTRZ1JggJzelTGPpWjrf30h74UNTZR8dVLnWClXiP/OIq30zo1wykM=@vger.kernel.org X-Gm-Message-State: AOJu0Yzq9ijrM8DvfIgDn5Q4LmLFHe4FKhJCZnARNEr71quKYJRhwoUo 9ino2vbCWOQSC6TQCDVOa9PlY+JNzy4+Rvua8qKmgWZCoeCjEIsH4aPTfd+aVBXHrfE6FT+Qzw= = X-Google-Smtp-Source: AGHT+IFrsVxvAlUP16luel5mw8ahTZegvdR1b3AXtwaYU+pzk0iRfg2g0KplRjxoVDdXqAY6iJf5PuATRQ== X-Received: from edbin4.prod.google.com ([2002:a05:6402:2084:b0:5e5:2b03:2ee1]) (user=elver job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6402:348f:b0:5dc:94ce:42a6 with SMTP id 4fb4d7f45d1cf-5e4d6b4b980mr18647852a12.22.1741080344386; Tue, 04 Mar 2025 01:25:44 -0800 (PST) Date: Tue, 4 Mar 2025 10:21:12 +0100 In-Reply-To: <20250304092417.2873893-1-elver@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250304092417.2873893-1-elver@google.com> X-Mailer: git-send-email 2.48.1.711.g2feabab25a-goog Message-ID: <20250304092417.2873893-14-elver@google.com> Subject: [PATCH v2 13/34] bit_spinlock: Support Clang's capability analysis From: Marco Elver To: elver@google.com Cc: "David S. Miller" , Luc Van Oostenryck , "Paul E. McKenney" , Alexander Potapenko , Arnd Bergmann , Bart Van Assche , Bill Wendling , Boqun Feng , Dmitry Vyukov , Eric Dumazet , Frederic Weisbecker , Greg Kroah-Hartman , Herbert Xu , Ingo Molnar , Jann Horn , Jiri Slaby , Joel Fernandes , Jonathan Corbet , Josh Triplett , Justin Stitt , Kees Cook , Kentaro Takeda , Mark Rutland , Mathieu Desnoyers , Miguel Ojeda , Nathan Chancellor , Neeraj Upadhyay , Peter Zijlstra , Steven Rostedt , Tetsuo Handa , Thomas Gleixner , Uladzislau Rezki , Waiman Long , Will Deacon , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org, llvm@lists.linux.dev, rcu@vger.kernel.org, linux-crypto@vger.kernel.org, linux-serial@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The annotations for bit_spinlock.h have simply been using "bitlock" as the token. For Sparse, that was likely sufficient in most cases. But Clang's capability analysis is more precise, and we need to ensure we can distinguish different bitlocks. To do so, add a token capability, and a macro __bitlock(bitnum, addr) that is used to construct unique per-bitlock tokens. Add the appropriate test. is implicitly included through other includes, and requires 2 annotations to indicate that acquisition (without release) and release (without prior acquisition) of its bitlock is intended. Signed-off-by: Marco Elver --- .../dev-tools/capability-analysis.rst | 3 ++- include/linux/bit_spinlock.h | 22 +++++++++++++--- include/linux/list_bl.h | 2 ++ lib/test_capability-analysis.c | 26 +++++++++++++++++++ 4 files changed, 48 insertions(+), 5 deletions(-) diff --git a/Documentation/dev-tools/capability-analysis.rst b/Documentatio= n/dev-tools/capability-analysis.rst index e4b333fffb4d..65972d1e9570 100644 --- a/Documentation/dev-tools/capability-analysis.rst +++ b/Documentation/dev-tools/capability-analysis.rst @@ -79,7 +79,8 @@ Supported Kernel Primitives ~~~~~~~~~~~~~~~~~~~~~~~~~~~ =20 Currently the following synchronization primitives are supported: -`raw_spinlock_t`, `spinlock_t`, `rwlock_t`, `mutex`, `seqlock_t`. +`raw_spinlock_t`, `spinlock_t`, `rwlock_t`, `mutex`, `seqlock_t`, +`bit_spinlock`. =20 For capabilities with an initialization function (e.g., `spin_lock_init()`= ), calling this function on the capability instance before initializing any diff --git a/include/linux/bit_spinlock.h b/include/linux/bit_spinlock.h index f1174a2fcc4d..22ab3c143407 100644 --- a/include/linux/bit_spinlock.h +++ b/include/linux/bit_spinlock.h @@ -9,6 +9,16 @@ =20 #include /* for cpu_relax() */ =20 +/* + * For static capability analysis, we need a unique token for each possibl= e bit + * that can be used as a bit_spinlock. The easiest way to do that is to cr= eate a + * fake capability that we can cast to with the __bitlock(bitnum, addr) ma= cro + * below, which will give us unique instances for each (bit, addr) pair th= at the + * static analysis can use. + */ +struct_with_capability(__capability_bitlock) { }; +#define __bitlock(bitnum, addr) (struct __capability_bitlock *)(bitnum + (= addr)) + /* * bit-based spin_lock() * @@ -16,6 +26,7 @@ * are significantly faster. */ static inline void bit_spin_lock(int bitnum, unsigned long *addr) + __acquires(__bitlock(bitnum, addr)) { /* * Assuming the lock is uncontended, this never enters @@ -34,13 +45,14 @@ static inline void bit_spin_lock(int bitnum, unsigned l= ong *addr) preempt_disable(); } #endif - __acquire(bitlock); + __acquire(__bitlock(bitnum, addr)); } =20 /* * Return true if it was acquired */ static inline int bit_spin_trylock(int bitnum, unsigned long *addr) + __cond_acquires(true, __bitlock(bitnum, addr)) { preempt_disable(); #if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) @@ -49,7 +61,7 @@ static inline int bit_spin_trylock(int bitnum, unsigned l= ong *addr) return 0; } #endif - __acquire(bitlock); + __acquire(__bitlock(bitnum, addr)); return 1; } =20 @@ -57,6 +69,7 @@ static inline int bit_spin_trylock(int bitnum, unsigned l= ong *addr) * bit-based spin_unlock() */ static inline void bit_spin_unlock(int bitnum, unsigned long *addr) + __releases(__bitlock(bitnum, addr)) { #ifdef CONFIG_DEBUG_SPINLOCK BUG_ON(!test_bit(bitnum, addr)); @@ -65,7 +78,7 @@ static inline void bit_spin_unlock(int bitnum, unsigned l= ong *addr) clear_bit_unlock(bitnum, addr); #endif preempt_enable(); - __release(bitlock); + __release(__bitlock(bitnum, addr)); } =20 /* @@ -74,6 +87,7 @@ static inline void bit_spin_unlock(int bitnum, unsigned l= ong *addr) * protecting the rest of the flags in the word. */ static inline void __bit_spin_unlock(int bitnum, unsigned long *addr) + __releases(__bitlock(bitnum, addr)) { #ifdef CONFIG_DEBUG_SPINLOCK BUG_ON(!test_bit(bitnum, addr)); @@ -82,7 +96,7 @@ static inline void __bit_spin_unlock(int bitnum, unsigned= long *addr) __clear_bit_unlock(bitnum, addr); #endif preempt_enable(); - __release(bitlock); + __release(__bitlock(bitnum, addr)); } =20 /* diff --git a/include/linux/list_bl.h b/include/linux/list_bl.h index ae1b541446c9..df9eebe6afca 100644 --- a/include/linux/list_bl.h +++ b/include/linux/list_bl.h @@ -144,11 +144,13 @@ static inline void hlist_bl_del_init(struct hlist_bl_= node *n) } =20 static inline void hlist_bl_lock(struct hlist_bl_head *b) + __acquires(__bitlock(0, b)) { bit_spin_lock(0, (unsigned long *)b); } =20 static inline void hlist_bl_unlock(struct hlist_bl_head *b) + __releases(__bitlock(0, b)) { __bit_spin_unlock(0, (unsigned long *)b); } diff --git a/lib/test_capability-analysis.c b/lib/test_capability-analysis.c index 74d287740bb8..ad362d5a7916 100644 --- a/lib/test_capability-analysis.c +++ b/lib/test_capability-analysis.c @@ -4,6 +4,7 @@ * positive errors when compiled with Clang's capability analysis. */ =20 +#include #include #include #include @@ -251,3 +252,28 @@ static void __used test_seqlock_writer(struct test_seq= lock_data *d) d->counter++; write_sequnlock_irqrestore(&d->sl, flags); } + +struct test_bit_spinlock_data { + unsigned long bits; + int counter __guarded_by(__bitlock(3, &bits)); +}; + +static void __used test_bit_spin_lock(struct test_bit_spinlock_data *d) +{ + /* + * Note, the analysis seems to have false negatives, because it won't + * precisely recognize the bit of the fake __bitlock() token. + */ + bit_spin_lock(3, &d->bits); + d->counter++; + bit_spin_unlock(3, &d->bits); + + bit_spin_lock(3, &d->bits); + d->counter++; + __bit_spin_unlock(3, &d->bits); + + if (bit_spin_trylock(3, &d->bits)) { + d->counter++; + bit_spin_unlock(3, &d->bits); + } +} --=20 2.48.1.711.g2feabab25a-goog From nobody Thu May 7 18:25:53 2026 Received: from mail-ed1-f74.google.com (mail-ed1-f74.google.com [209.85.208.74]) (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 BBA7520110F for ; Tue, 4 Mar 2025 09:25:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080351; cv=none; b=qHa0c5Ag9WnIVk/vqmAOZ35HR46Ei2weL9n8XErL2OCq+4f2UGQRIDLzaf7F/wRUyQ0eWW33zTpy6ExeBipT7RmPxjQP8qRfstqebV1Qavoetas3G7k1heUSl3r6CEinIItPXwguiy9T/OR1G4KSbpsLh4Zdd7dJ6NYC3TJqqoI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080351; c=relaxed/simple; bh=Wqdc+WFhEaZMvjgCHc/zhoRNy3tiy2ObiXWVRytweCo=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=ArkLqCOAKcZto4dipjDCceX3pLcLZKJFr352otVR7VUBZA/dRI5YEcZMnRUgEChEytDeg7TzR2GQ1eZP2xBERyEV7R0ZU8l0tyEC+kqAXA5LRFDiwkLAsUXKqEtY2kBJnQVznIwQf3YLwJmUGNEOz8MtSGrKWPI4xLoRIEpEvqw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--elver.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=ErdcgKfJ; arc=none smtp.client-ip=209.85.208.74 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--elver.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="ErdcgKfJ" Received: by mail-ed1-f74.google.com with SMTP id 4fb4d7f45d1cf-5e4a1a85bf8so7153256a12.0 for ; Tue, 04 Mar 2025 01:25:48 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1741080347; x=1741685147; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=dGU1wvi0i2cL/7Vdis45pwSeF2hTx85fMwlXO1/FTUA=; b=ErdcgKfJndrKyJ17O00049zGXAsomluh0E8s1GNAkQBqpvPc5Lr3Yid7XLM048Iid5 t+oD+wj4vhYvQFoIll3O7Vhstlg0qlbBRq2pJjBgMaY9ZOTeJiXOwCWrgvzY9PGAqBk9 V9TC3UOEWT2aIEcADYHu+Mker6FYYFs0AMP7YdyMT3lrg2cVovQDTKD8Hb/kubY1Ufrq goQvJ0+H6iSv9WvQYXHI2VNwldL1KLzFTBBWesMyHvuwhKbyC05jCHilSvxzIhfeqi8p FKrnQNOcmVkJ1/vJPfkPb/7PRwVfjHRLDZXSpIcR6foIFhwl8U25+iBSy1a2pUrRp36B Nprw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741080347; x=1741685147; h=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; bh=dGU1wvi0i2cL/7Vdis45pwSeF2hTx85fMwlXO1/FTUA=; b=HXjUO3/aNIlNCuZJjMw1eN9SvgrUVqmm48uMrwZNLv2OTBcYOgtmgazIbuizXVj3sd 960/C9nnz7l9wWGEX8c4tF/LPWWy/zuVrnF1cRG5B2+seDZMcZ8759znx9yW1oKmKLWj 74eHjCRFHIqfNXZ3cqd2ORSvRL4ByOgXI1LR1mPnLYZipneiHrywMqvEiYgi7xhOZ8os vsRRVwNCqweUVUUYmEnmxLXFR3MEXwSN0XM/hpq4Yfz1RkqX+cq+OmMCyl4uTVZUnBo6 Mj+aii4VJnD8UyEiZA6CC+DtpQ3jgG/aLrTI1zJJ8+RiQXjdL4q1Xz83Tq/qUP42rcnd EwVw== X-Forwarded-Encrypted: i=1; AJvYcCVECu7Rc2wf46TVcfv7WYUNIVqivfcTNFyim5IVbkR896m8Pms72Cy/RGXdLZfSV++QfhjVwCoYSyonP18=@vger.kernel.org X-Gm-Message-State: AOJu0YwhNmNVB25diIbArhPlsyD555FbD83l4AOgmTuU/IAreYUuMfYz 8YqnUjQKhV7cFdQrk07KAkcdk8f8NEwFYDD0rMO8QZ9hDInGbQJLQIujxCsI8wwwha89RcPCxQ= = X-Google-Smtp-Source: AGHT+IEzpwBNdOV6S2p5H0ctMRiwI9pS2G54haANPvgkRgxFQlowUFQGknXrYikTwfs7UGOz8UW7jP5rjg== X-Received: from edbek14.prod.google.com ([2002:a05:6402:370e:b0:5e5:2f33:208a]) (user=elver job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6402:2546:b0:5e0:8a34:3b5c with SMTP id 4fb4d7f45d1cf-5e584d16ff6mr2399224a12.0.1741080347066; Tue, 04 Mar 2025 01:25:47 -0800 (PST) Date: Tue, 4 Mar 2025 10:21:13 +0100 In-Reply-To: <20250304092417.2873893-1-elver@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250304092417.2873893-1-elver@google.com> X-Mailer: git-send-email 2.48.1.711.g2feabab25a-goog Message-ID: <20250304092417.2873893-15-elver@google.com> Subject: [PATCH v2 14/34] rcu: Support Clang's capability analysis From: Marco Elver To: elver@google.com Cc: "David S. Miller" , Luc Van Oostenryck , "Paul E. McKenney" , Alexander Potapenko , Arnd Bergmann , Bart Van Assche , Bill Wendling , Boqun Feng , Dmitry Vyukov , Eric Dumazet , Frederic Weisbecker , Greg Kroah-Hartman , Herbert Xu , Ingo Molnar , Jann Horn , Jiri Slaby , Joel Fernandes , Jonathan Corbet , Josh Triplett , Justin Stitt , Kees Cook , Kentaro Takeda , Mark Rutland , Mathieu Desnoyers , Miguel Ojeda , Nathan Chancellor , Neeraj Upadhyay , Peter Zijlstra , Steven Rostedt , Tetsuo Handa , Thomas Gleixner , Uladzislau Rezki , Waiman Long , Will Deacon , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org, llvm@lists.linux.dev, rcu@vger.kernel.org, linux-crypto@vger.kernel.org, linux-serial@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Improve the existing annotations to properly support Clang's capability analysis. The old annotations distinguished between RCU, RCU_BH, and RCU_SCHED; however, to more easily be able to express that "hold the RCU read lock" without caring if the normal, _bh(), or _sched() variant was used we'd have to remove the distinction of the latter variants: change the _bh() and _sched() variants to also acquire "RCU". When (and if) we introduce capabilities to denote more generally that "IRQ", "BH", "PREEMPT" are disabled, it would make sense to acquire these capabilities instead of RCU_BH and RCU_SCHED respectively. The above change also simplified introducing __guarded_by support, where only the "RCU" capability needs to be held: introduce __rcu_guarded, where Clang's capability analysis warns if a pointer is dereferenced without any of the RCU locks held, or updated without the appropriate helpers. | Note: A limitation of the compiler's analysis is re-entrancy; a pattern | such as the below will result in a warning: | | rcu_read_lock(); // acquires RCU | .. | rcu_read_lock_bh(); // error: acquiring __capability_RCU 'RCU' that= is already held | .. | rcu_read_unlock_bh(); // releases RCU | .. | rcu_read_unlock(); // error: releasing __capability_RCU 'RCU' that= was not held | | Such patterns should generally be uncommon, and initial usage in enabled | subsystems did not result in any false positives due to re-entrancy. | Until the compiler supports re-entrancy, keeping the analysis disabled | for code relying on re-entrancy is the only option. The primitives rcu_assign_pointer() and friends are wrapped with capability_unsafe(), which enforces using them to update RCU-protected pointers marked with __rcu_guarded. Signed-off-by: Marco Elver --- v2: * Reword commit message and point out re-entrancy caveat. --- .../dev-tools/capability-analysis.rst | 2 +- include/linux/cleanup.h | 4 + include/linux/rcupdate.h | 73 +++++++++++++------ lib/test_capability-analysis.c | 68 +++++++++++++++++ 4 files changed, 123 insertions(+), 24 deletions(-) diff --git a/Documentation/dev-tools/capability-analysis.rst b/Documentatio= n/dev-tools/capability-analysis.rst index 65972d1e9570..a14d796bcd0e 100644 --- a/Documentation/dev-tools/capability-analysis.rst +++ b/Documentation/dev-tools/capability-analysis.rst @@ -80,7 +80,7 @@ Supported Kernel Primitives =20 Currently the following synchronization primitives are supported: `raw_spinlock_t`, `spinlock_t`, `rwlock_t`, `mutex`, `seqlock_t`, -`bit_spinlock`. +`bit_spinlock`, RCU. =20 For capabilities with an initialization function (e.g., `spin_lock_init()`= ), calling this function on the capability instance before initializing any diff --git a/include/linux/cleanup.h b/include/linux/cleanup.h index 93a166549add..7d70d308357a 100644 --- a/include/linux/cleanup.h +++ b/include/linux/cleanup.h @@ -404,6 +404,10 @@ static inline class_##_name##_t class_##_name##_constr= uctor(void) \ return _t; \ } =20 +#define DECLARE_LOCK_GUARD_0_ATTRS(_name, _lock, _unlock) \ +static inline class_##_name##_t class_##_name##_constructor(void) _lock;\ +static inline void class_##_name##_destructor(class_##_name##_t *_T) _unlo= ck + #define DEFINE_LOCK_GUARD_1(_name, _type, _lock, _unlock, ...) \ __DEFINE_CLASS_IS_CONDITIONAL(_name, false); \ __DEFINE_UNLOCK_GUARD(_name, _type, _unlock, __VA_ARGS__) \ diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 48e5c03df1dd..ef8875c4e621 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -31,6 +31,16 @@ #include #include =20 +token_capability(RCU); +token_capability_instance(RCU, RCU_SCHED); +token_capability_instance(RCU, RCU_BH); + +/* + * A convenience macro that can be used for RCU-protected globals or struct + * members; adds type qualifier __rcu, and also enforces __guarded_by(RCU). + */ +#define __rcu_guarded __rcu __guarded_by(RCU) + #define ULONG_CMP_GE(a, b) (ULONG_MAX / 2 >=3D (a) - (b)) #define ULONG_CMP_LT(a, b) (ULONG_MAX / 2 < (a) - (b)) =20 @@ -431,7 +441,8 @@ static inline void rcu_preempt_sleep_check(void) { } =20 // See RCU_LOCKDEP_WARN() for an explanation of the double call to // debug_lockdep_rcu_enabled(). -static inline bool lockdep_assert_rcu_helper(bool c) +static inline bool lockdep_assert_rcu_helper(bool c, const struct __capabi= lity_RCU *cap) + __asserts_shared_cap(RCU) __asserts_shared_cap(cap) { return debug_lockdep_rcu_enabled() && (c || !rcu_is_watching() || !rcu_lockdep_current_cpu_online()) && @@ -444,7 +455,7 @@ static inline bool lockdep_assert_rcu_helper(bool c) * Splats if lockdep is enabled and there is no rcu_read_lock() in effect. */ #define lockdep_assert_in_rcu_read_lock() \ - WARN_ON_ONCE(lockdep_assert_rcu_helper(!lock_is_held(&rcu_lock_map))) + WARN_ON_ONCE(lockdep_assert_rcu_helper(!lock_is_held(&rcu_lock_map), RCU)) =20 /** * lockdep_assert_in_rcu_read_lock_bh - WARN if not protected by rcu_read_= lock_bh() @@ -454,7 +465,7 @@ static inline bool lockdep_assert_rcu_helper(bool c) * actual rcu_read_lock_bh() is required. */ #define lockdep_assert_in_rcu_read_lock_bh() \ - WARN_ON_ONCE(lockdep_assert_rcu_helper(!lock_is_held(&rcu_bh_lock_map))) + WARN_ON_ONCE(lockdep_assert_rcu_helper(!lock_is_held(&rcu_bh_lock_map), R= CU_BH)) =20 /** * lockdep_assert_in_rcu_read_lock_sched - WARN if not protected by rcu_re= ad_lock_sched() @@ -464,7 +475,7 @@ static inline bool lockdep_assert_rcu_helper(bool c) * instead an actual rcu_read_lock_sched() is required. */ #define lockdep_assert_in_rcu_read_lock_sched() \ - WARN_ON_ONCE(lockdep_assert_rcu_helper(!lock_is_held(&rcu_sched_lock_map)= )) + WARN_ON_ONCE(lockdep_assert_rcu_helper(!lock_is_held(&rcu_sched_lock_map)= , RCU_SCHED)) =20 /** * lockdep_assert_in_rcu_reader - WARN if not within some type of RCU read= er @@ -482,17 +493,17 @@ static inline bool lockdep_assert_rcu_helper(bool c) WARN_ON_ONCE(lockdep_assert_rcu_helper(!lock_is_held(&rcu_lock_map) && \ !lock_is_held(&rcu_bh_lock_map) && \ !lock_is_held(&rcu_sched_lock_map) && \ - preemptible())) + preemptible(), RCU)) =20 #else /* #ifdef CONFIG_PROVE_RCU */ =20 #define RCU_LOCKDEP_WARN(c, s) do { } while (0 && (c)) #define rcu_sleep_check() do { } while (0) =20 -#define lockdep_assert_in_rcu_read_lock() do { } while (0) -#define lockdep_assert_in_rcu_read_lock_bh() do { } while (0) -#define lockdep_assert_in_rcu_read_lock_sched() do { } while (0) -#define lockdep_assert_in_rcu_reader() do { } while (0) +#define lockdep_assert_in_rcu_read_lock() __assert_shared_cap(RCU) +#define lockdep_assert_in_rcu_read_lock_bh() __assert_shared_cap(RCU_BH) +#define lockdep_assert_in_rcu_read_lock_sched() __assert_shared_cap(RCU_SC= HED) +#define lockdep_assert_in_rcu_reader() __assert_shared_cap(RCU) =20 #endif /* #else #ifdef CONFIG_PROVE_RCU */ =20 @@ -512,11 +523,11 @@ static inline bool lockdep_assert_rcu_helper(bool c) #endif /* #else #ifdef __CHECKER__ */ =20 #define __unrcu_pointer(p, local) \ -({ \ +capability_unsafe( \ typeof(*p) *local =3D (typeof(*p) *__force)(p); \ rcu_check_sparse(p, __rcu); \ ((typeof(*p) __force __kernel *)(local)); \ -}) +) /** * unrcu_pointer - mark a pointer as not being RCU protected * @p: pointer needing to lose its __rcu property @@ -592,7 +603,7 @@ static inline bool lockdep_assert_rcu_helper(bool c) * other macros that it invokes. */ #define rcu_assign_pointer(p, v) \ -do { \ +capability_unsafe( \ uintptr_t _r_a_p__v =3D (uintptr_t)(v); \ rcu_check_sparse(p, __rcu); \ \ @@ -600,7 +611,7 @@ do { \ WRITE_ONCE((p), (typeof(p))(_r_a_p__v)); \ else \ smp_store_release(&p, RCU_INITIALIZER((typeof(p))_r_a_p__v)); \ -} while (0) +) =20 /** * rcu_replace_pointer() - replace an RCU pointer, returning its old value @@ -843,9 +854,10 @@ do { \ * only when acquiring spinlocks that are subject to priority inheritance. */ static __always_inline void rcu_read_lock(void) + __acquires_shared(RCU) { __rcu_read_lock(); - __acquire(RCU); + __acquire_shared(RCU); rcu_lock_acquire(&rcu_lock_map); RCU_LOCKDEP_WARN(!rcu_is_watching(), "rcu_read_lock() used illegally while idle"); @@ -874,11 +886,12 @@ static __always_inline void rcu_read_lock(void) * See rcu_read_lock() for more information. */ static inline void rcu_read_unlock(void) + __releases_shared(RCU) { RCU_LOCKDEP_WARN(!rcu_is_watching(), "rcu_read_unlock() used illegally while idle"); rcu_lock_release(&rcu_lock_map); /* Keep acq info for rls diags. */ - __release(RCU); + __release_shared(RCU); __rcu_read_unlock(); } =20 @@ -897,9 +910,11 @@ static inline void rcu_read_unlock(void) * was invoked from some other task. */ static inline void rcu_read_lock_bh(void) + __acquires_shared(RCU) __acquires_shared(RCU_BH) { local_bh_disable(); - __acquire(RCU_BH); + __acquire_shared(RCU); + __acquire_shared(RCU_BH); rcu_lock_acquire(&rcu_bh_lock_map); RCU_LOCKDEP_WARN(!rcu_is_watching(), "rcu_read_lock_bh() used illegally while idle"); @@ -911,11 +926,13 @@ static inline void rcu_read_lock_bh(void) * See rcu_read_lock_bh() for more information. */ static inline void rcu_read_unlock_bh(void) + __releases_shared(RCU) __releases_shared(RCU_BH) { RCU_LOCKDEP_WARN(!rcu_is_watching(), "rcu_read_unlock_bh() used illegally while idle"); rcu_lock_release(&rcu_bh_lock_map); - __release(RCU_BH); + __release_shared(RCU_BH); + __release_shared(RCU); local_bh_enable(); } =20 @@ -935,9 +952,11 @@ static inline void rcu_read_unlock_bh(void) * rcu_read_lock_sched() was invoked from an NMI handler. */ static inline void rcu_read_lock_sched(void) + __acquires_shared(RCU) __acquires_shared(RCU_SCHED) { preempt_disable(); - __acquire(RCU_SCHED); + __acquire_shared(RCU); + __acquire_shared(RCU_SCHED); rcu_lock_acquire(&rcu_sched_lock_map); RCU_LOCKDEP_WARN(!rcu_is_watching(), "rcu_read_lock_sched() used illegally while idle"); @@ -945,9 +964,11 @@ static inline void rcu_read_lock_sched(void) =20 /* Used by lockdep and tracing: cannot be traced, cannot call lockdep. */ static inline notrace void rcu_read_lock_sched_notrace(void) + __acquires_shared(RCU) __acquires_shared(RCU_SCHED) { preempt_disable_notrace(); - __acquire(RCU_SCHED); + __acquire_shared(RCU); + __acquire_shared(RCU_SCHED); } =20 /** @@ -956,18 +977,22 @@ static inline notrace void rcu_read_lock_sched_notrac= e(void) * See rcu_read_lock_sched() for more information. */ static inline void rcu_read_unlock_sched(void) + __releases_shared(RCU) __releases_shared(RCU_SCHED) { RCU_LOCKDEP_WARN(!rcu_is_watching(), "rcu_read_unlock_sched() used illegally while idle"); rcu_lock_release(&rcu_sched_lock_map); - __release(RCU_SCHED); + __release_shared(RCU_SCHED); + __release_shared(RCU); preempt_enable(); } =20 /* Used by lockdep and tracing: cannot be traced, cannot call lockdep. */ static inline notrace void rcu_read_unlock_sched_notrace(void) + __releases_shared(RCU) __releases_shared(RCU_SCHED) { - __release(RCU_SCHED); + __release_shared(RCU_SCHED); + __release_shared(RCU); preempt_enable_notrace(); } =20 @@ -1010,10 +1035,10 @@ static inline notrace void rcu_read_unlock_sched_no= trace(void) * ordering guarantees for either the CPU or the compiler. */ #define RCU_INIT_POINTER(p, v) \ - do { \ + capability_unsafe( \ rcu_check_sparse(p, __rcu); \ WRITE_ONCE(p, RCU_INITIALIZER(v)); \ - } while (0) + ) =20 /** * RCU_POINTER_INITIALIZER() - statically initialize an RCU protected poin= ter @@ -1172,4 +1197,6 @@ DEFINE_LOCK_GUARD_0(rcu, } while (0), rcu_read_unlock()) =20 +DECLARE_LOCK_GUARD_0_ATTRS(rcu, __acquires_shared(RCU), __releases_shared(= RCU)); + #endif /* __LINUX_RCUPDATE_H */ diff --git a/lib/test_capability-analysis.c b/lib/test_capability-analysis.c index ad362d5a7916..050fa7c9fcba 100644 --- a/lib/test_capability-analysis.c +++ b/lib/test_capability-analysis.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include =20 @@ -277,3 +278,70 @@ static void __used test_bit_spin_lock(struct test_bit_= spinlock_data *d) bit_spin_unlock(3, &d->bits); } } + +/* + * Test that we can mark a variable guarded by RCU, and we can dereference= and + * write to the pointer with RCU's primitives. + */ +struct test_rcu_data { + long __rcu_guarded *data; +}; + +static void __used test_rcu_guarded_reader(struct test_rcu_data *d) +{ + rcu_read_lock(); + (void)rcu_dereference(d->data); + rcu_read_unlock(); + + rcu_read_lock_bh(); + (void)rcu_dereference(d->data); + rcu_read_unlock_bh(); + + rcu_read_lock_sched(); + (void)rcu_dereference(d->data); + rcu_read_unlock_sched(); +} + +static void __used test_rcu_guard(struct test_rcu_data *d) +{ + guard(rcu)(); + (void)rcu_dereference(d->data); +} + +static void __used test_rcu_guarded_updater(struct test_rcu_data *d) +{ + rcu_assign_pointer(d->data, NULL); + RCU_INIT_POINTER(d->data, NULL); + (void)unrcu_pointer(d->data); +} + +static void wants_rcu_held(void) __must_hold_shared(RCU) { } +static void wants_rcu_held_bh(void) __must_hold_shared(RCU_BH) { } +static void wants_rcu_held_sched(void) __must_hold_shared(RCU_SCHED) { } + +static void __used test_rcu_lock_variants(void) +{ + rcu_read_lock(); + wants_rcu_held(); + rcu_read_unlock(); + + rcu_read_lock_bh(); + wants_rcu_held_bh(); + rcu_read_unlock_bh(); + + rcu_read_lock_sched(); + wants_rcu_held_sched(); + rcu_read_unlock_sched(); +} + +static void __used test_rcu_assert_variants(void) +{ + lockdep_assert_in_rcu_read_lock(); + wants_rcu_held(); + + lockdep_assert_in_rcu_read_lock_bh(); + wants_rcu_held_bh(); + + lockdep_assert_in_rcu_read_lock_sched(); + wants_rcu_held_sched(); +} --=20 2.48.1.711.g2feabab25a-goog From nobody Thu May 7 18:25:53 2026 Received: from mail-wm1-f74.google.com (mail-wm1-f74.google.com [209.85.128.74]) (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 347B21FCFD2 for ; Tue, 4 Mar 2025 09:25:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080353; cv=none; b=rQ3MvfsoEknwxNNkv1VteZl3R/Mdx3M0cGznvjF5QqUhhHbGWegauI2/KNoWi4N3ylFAY/0FpvQgQY00gIxbuvhh0Yn8rBz7z8hRy+tmSonQ48EjPj4OThm0xLrVe8ZBwLwC4YhiCuNuU/fmvV5Pq6sGAYbwSW+elhBoxOpT2EQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080353; c=relaxed/simple; bh=+dINVo1oJ9VhsO5ynOzD5Y4e9AFKu3wP28ZuDYXPff0=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=AdrCnoAE0mILp4x4+te1GeVJx1b32iVC0j7u8JTMcR/Aaww6Ohwky2X0rcu6XMKRcgijxZsnHIb10s6iTvy5PmNDemq9f3C3Ji0kmbTfKcmJ4rpQfA+UTy2o+mRJMOXtu5p7yzTWX4iuAyNW7g3NnHb5+0ersf1kGvQhTpFl2dQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--elver.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=tR/1HHRk; arc=none smtp.client-ip=209.85.128.74 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--elver.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="tR/1HHRk" Received: by mail-wm1-f74.google.com with SMTP id 5b1f17b1804b1-43bc97e6360so5941535e9.3 for ; Tue, 04 Mar 2025 01:25:51 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1741080349; x=1741685149; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=IjZvxS6CXb9r/jfHcsWB9NCl/hhxYyJhywIjI+5O6TY=; b=tR/1HHRkDANpTXSvuUTUiRr9w8AgP6XqHvtRHjBj8zzsPG9UnCHLc1wBi8frgXutGH FGk4+dNEtfkHHPkfTkS/21qWILINhAgMBZ8zTW40pHW01lC+gR6iuE9839N0bJERnzM6 Fag9N0tWa8j3AyVmm20THdtI81A+feNVfW4E4GZc3ZwCAZG0m6A8D0cx61TLX49vsHok JR4DuhkKpBNDt8khZ23mN3nqLZBC367oeXpXO0/3rfbB15p/hs92a7GSRZu7SzVS/Yz/ eobAUtuYMs8ALhbX4LbYLLL2TKyKu9HaczPfyHVNRbzTvCkkAz+TKC1lxwIzwK4gLFSD 0ZuQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741080349; x=1741685149; h=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; bh=IjZvxS6CXb9r/jfHcsWB9NCl/hhxYyJhywIjI+5O6TY=; b=TQA4fIQEPYPjOynrBkI8Av10zSJGBeToefShh+5UnB00R9VwebePMWUDP+ZVaqLKoT v6T4fHjOgJ3Ie6AM6c8wK6n7p2SSz8pBkP97WDsyGc+egPLVnljocjEhqP5IQwhmrCkT tdMglRa1sJef6L3wr8w8qr/AoRw22M6fa/tOH4Lz5nRuK8RMW9oCv+jPHxxguDPLwYiY 1Y1iiO5FFPpaBCXIkdh24ekS/yuFVsnX0nptJ6ZsoDFGjWdX97nC15leX89fAr0wbl0n kRAa39LyAXdIxJqpIEaRJK0if2UjSQipKuzbSk2VpWhiPaIviRX2skpPDHKJgMO9ms0u jjaQ== X-Forwarded-Encrypted: i=1; AJvYcCX4bTxM7TXDwjwm2AiQ3OGhI+HJ2CjIWwrhAtTjLUp8VbzZIFbWoSLY8x48d0F2K4RzeHsj+FhG3isLPj0=@vger.kernel.org X-Gm-Message-State: AOJu0YybwtB+hf2YtVMkxRi4WAe6ORcK2d0QBjIEWikoXuZMkk6TWLDi t+PMMVTbcgxGEs3PA3f1L+RODMOG6djAGKOmOeWLvUE+dhLaLqGmBrkjZ6WEz9+Mr6ohHzyrKw= = X-Google-Smtp-Source: AGHT+IFiYcMhAel+FfswKkfKCtzdpYKZ8TP8BDehixv81OEAKQOJ8MSR/SDR6vYPbtqm7/NxYsQVJMCTAg== X-Received: from wmbg14.prod.google.com ([2002:a05:600c:a40e:b0:43b:cebe:8011]) (user=elver job=prod-delivery.src-stubby-dispatcher) by 2002:a05:600c:3c9c:b0:439:89e9:4eff with SMTP id 5b1f17b1804b1-43ba66e6b5dmr142151345e9.10.1741080349701; Tue, 04 Mar 2025 01:25:49 -0800 (PST) Date: Tue, 4 Mar 2025 10:21:14 +0100 In-Reply-To: <20250304092417.2873893-1-elver@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250304092417.2873893-1-elver@google.com> X-Mailer: git-send-email 2.48.1.711.g2feabab25a-goog Message-ID: <20250304092417.2873893-16-elver@google.com> Subject: [PATCH v2 15/34] srcu: Support Clang's capability analysis From: Marco Elver To: elver@google.com Cc: "David S. Miller" , Luc Van Oostenryck , "Paul E. McKenney" , Alexander Potapenko , Arnd Bergmann , Bart Van Assche , Bill Wendling , Boqun Feng , Dmitry Vyukov , Eric Dumazet , Frederic Weisbecker , Greg Kroah-Hartman , Herbert Xu , Ingo Molnar , Jann Horn , Jiri Slaby , Joel Fernandes , Jonathan Corbet , Josh Triplett , Justin Stitt , Kees Cook , Kentaro Takeda , Mark Rutland , Mathieu Desnoyers , Miguel Ojeda , Nathan Chancellor , Neeraj Upadhyay , Peter Zijlstra , Steven Rostedt , Tetsuo Handa , Thomas Gleixner , Uladzislau Rezki , Waiman Long , Will Deacon , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org, llvm@lists.linux.dev, rcu@vger.kernel.org, linux-crypto@vger.kernel.org, linux-serial@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add support for Clang's capability analysis for SRCU. Signed-off-by: Marco Elver --- .../dev-tools/capability-analysis.rst | 2 +- include/linux/srcu.h | 61 +++++++++++++------ lib/test_capability-analysis.c | 24 ++++++++ 3 files changed, 66 insertions(+), 21 deletions(-) diff --git a/Documentation/dev-tools/capability-analysis.rst b/Documentatio= n/dev-tools/capability-analysis.rst index a14d796bcd0e..918e35d110df 100644 --- a/Documentation/dev-tools/capability-analysis.rst +++ b/Documentation/dev-tools/capability-analysis.rst @@ -80,7 +80,7 @@ Supported Kernel Primitives =20 Currently the following synchronization primitives are supported: `raw_spinlock_t`, `spinlock_t`, `rwlock_t`, `mutex`, `seqlock_t`, -`bit_spinlock`, RCU. +`bit_spinlock`, RCU, SRCU (`srcu_struct`). =20 For capabilities with an initialization function (e.g., `spin_lock_init()`= ), calling this function on the capability instance before initializing any diff --git a/include/linux/srcu.h b/include/linux/srcu.h index d7ba46e74f58..fde8bba191a5 100644 --- a/include/linux/srcu.h +++ b/include/linux/srcu.h @@ -21,7 +21,7 @@ #include #include =20 -struct srcu_struct; +struct_with_capability(srcu_struct); =20 #ifdef CONFIG_DEBUG_LOCK_ALLOC =20 @@ -60,14 +60,14 @@ int init_srcu_struct(struct srcu_struct *ssp); void call_srcu(struct srcu_struct *ssp, struct rcu_head *head, void (*func)(struct rcu_head *head)); void cleanup_srcu_struct(struct srcu_struct *ssp); -int __srcu_read_lock(struct srcu_struct *ssp) __acquires(ssp); -void __srcu_read_unlock(struct srcu_struct *ssp, int idx) __releases(ssp); +int __srcu_read_lock(struct srcu_struct *ssp) __acquires_shared(ssp); +void __srcu_read_unlock(struct srcu_struct *ssp, int idx) __releases_share= d(ssp); #ifdef CONFIG_TINY_SRCU #define __srcu_read_lock_lite __srcu_read_lock #define __srcu_read_unlock_lite __srcu_read_unlock #else // #ifdef CONFIG_TINY_SRCU -int __srcu_read_lock_lite(struct srcu_struct *ssp) __acquires(ssp); -void __srcu_read_unlock_lite(struct srcu_struct *ssp, int idx) __releases(= ssp); +int __srcu_read_lock_lite(struct srcu_struct *ssp) __acquires_shared(ssp); +void __srcu_read_unlock_lite(struct srcu_struct *ssp, int idx) __releases_= shared(ssp); #endif // #else // #ifdef CONFIG_TINY_SRCU void synchronize_srcu(struct srcu_struct *ssp); =20 @@ -110,14 +110,16 @@ static inline bool same_state_synchronize_srcu(unsign= ed long oldstate1, unsigned } =20 #ifdef CONFIG_NEED_SRCU_NMI_SAFE -int __srcu_read_lock_nmisafe(struct srcu_struct *ssp) __acquires(ssp); -void __srcu_read_unlock_nmisafe(struct srcu_struct *ssp, int idx) __releas= es(ssp); +int __srcu_read_lock_nmisafe(struct srcu_struct *ssp) __acquires_shared(ss= p); +void __srcu_read_unlock_nmisafe(struct srcu_struct *ssp, int idx) __releas= es_shared(ssp); #else static inline int __srcu_read_lock_nmisafe(struct srcu_struct *ssp) + __acquires_shared(ssp) { return __srcu_read_lock(ssp); } static inline void __srcu_read_unlock_nmisafe(struct srcu_struct *ssp, int= idx) + __releases_shared(ssp) { __srcu_read_unlock(ssp, idx); } @@ -189,6 +191,14 @@ static inline int srcu_read_lock_held(const struct src= u_struct *ssp) =20 #endif /* #else #ifdef CONFIG_DEBUG_LOCK_ALLOC */ =20 +/* + * No-op helper to denote that ssp must be held. Because SRCU-protected po= inters + * should still be marked with __rcu_guarded, and we do not want to mark t= hem + * with __guarded_by(ssp) as it would complicate annotations for writers, = we + * choose the following strategy: srcu_dereference_check() calls this help= er + * that checks that the passed ssp is held, and then fake-acquires 'RCU'. + */ +static inline void __srcu_read_lock_must_hold(const struct srcu_struct *ss= p) __must_hold_shared(ssp) { } =20 /** * srcu_dereference_check - fetch SRCU-protected pointer for later derefer= encing @@ -202,9 +212,15 @@ static inline int srcu_read_lock_held(const struct src= u_struct *ssp) * to 1. The @c argument will normally be a logical expression containing * lockdep_is_held() calls. */ -#define srcu_dereference_check(p, ssp, c) \ - __rcu_dereference_check((p), __UNIQUE_ID(rcu), \ - (c) || srcu_read_lock_held(ssp), __rcu) +#define srcu_dereference_check(p, ssp, c) \ +({ \ + __srcu_read_lock_must_hold(ssp); \ + __acquire_shared_cap(RCU); \ + __auto_type __v =3D __rcu_dereference_check((p), __UNIQUE_ID(rcu), \ + (c) || srcu_read_lock_held(ssp), __rcu); \ + __release_shared_cap(RCU); \ + __v; \ +}) =20 /** * srcu_dereference - fetch SRCU-protected pointer for later dereferencing @@ -247,7 +263,8 @@ static inline int srcu_read_lock_held(const struct srcu= _struct *ssp) * invoke srcu_read_unlock() from one task and the matching srcu_read_lock= () * from another. */ -static inline int srcu_read_lock(struct srcu_struct *ssp) __acquires(ssp) +static inline int srcu_read_lock(struct srcu_struct *ssp) + __acquires_shared(ssp) { int retval; =20 @@ -274,7 +291,8 @@ static inline int srcu_read_lock(struct srcu_struct *ss= p) __acquires(ssp) * where RCU is watching, that is, from contexts where it would be legal * to invoke rcu_read_lock(). Otherwise, lockdep will complain. */ -static inline int srcu_read_lock_lite(struct srcu_struct *ssp) __acquires(= ssp) +static inline int srcu_read_lock_lite(struct srcu_struct *ssp) + __acquires_shared(ssp) { int retval; =20 @@ -295,7 +313,8 @@ static inline int srcu_read_lock_lite(struct srcu_struc= t *ssp) __acquires(ssp) * then none of the other flavors may be used, whether before, during, * or after. */ -static inline int srcu_read_lock_nmisafe(struct srcu_struct *ssp) __acquir= es(ssp) +static inline int srcu_read_lock_nmisafe(struct srcu_struct *ssp) + __acquires_shared(ssp) { int retval; =20 @@ -307,7 +326,8 @@ static inline int srcu_read_lock_nmisafe(struct srcu_st= ruct *ssp) __acquires(ssp =20 /* Used by tracing, cannot be traced and cannot invoke lockdep. */ static inline notrace int -srcu_read_lock_notrace(struct srcu_struct *ssp) __acquires(ssp) +srcu_read_lock_notrace(struct srcu_struct *ssp) + __acquires_shared(ssp) { int retval; =20 @@ -337,7 +357,8 @@ srcu_read_lock_notrace(struct srcu_struct *ssp) __acqui= res(ssp) * Calls to srcu_down_read() may be nested, similar to the manner in * which calls to down_read() may be nested. */ -static inline int srcu_down_read(struct srcu_struct *ssp) __acquires(ssp) +static inline int srcu_down_read(struct srcu_struct *ssp) + __acquires_shared(ssp) { WARN_ON_ONCE(in_nmi()); srcu_check_read_flavor(ssp, SRCU_READ_FLAVOR_NORMAL); @@ -352,7 +373,7 @@ static inline int srcu_down_read(struct srcu_struct *ss= p) __acquires(ssp) * Exit an SRCU read-side critical section. */ static inline void srcu_read_unlock(struct srcu_struct *ssp, int idx) - __releases(ssp) + __releases_shared(ssp) { WARN_ON_ONCE(idx & ~0x1); srcu_check_read_flavor(ssp, SRCU_READ_FLAVOR_NORMAL); @@ -368,7 +389,7 @@ static inline void srcu_read_unlock(struct srcu_struct = *ssp, int idx) * Exit a light-weight SRCU read-side critical section. */ static inline void srcu_read_unlock_lite(struct srcu_struct *ssp, int idx) - __releases(ssp) + __releases_shared(ssp) { WARN_ON_ONCE(idx & ~0x1); srcu_check_read_flavor(ssp, SRCU_READ_FLAVOR_LITE); @@ -384,7 +405,7 @@ static inline void srcu_read_unlock_lite(struct srcu_st= ruct *ssp, int idx) * Exit an SRCU read-side critical section, but in an NMI-safe manner. */ static inline void srcu_read_unlock_nmisafe(struct srcu_struct *ssp, int i= dx) - __releases(ssp) + __releases_shared(ssp) { WARN_ON_ONCE(idx & ~0x1); srcu_check_read_flavor(ssp, SRCU_READ_FLAVOR_NMI); @@ -394,7 +415,7 @@ static inline void srcu_read_unlock_nmisafe(struct srcu= _struct *ssp, int idx) =20 /* Used by tracing, cannot be traced and cannot call lockdep. */ static inline notrace void -srcu_read_unlock_notrace(struct srcu_struct *ssp, int idx) __releases(ssp) +srcu_read_unlock_notrace(struct srcu_struct *ssp, int idx) __releases_shar= ed(ssp) { srcu_check_read_flavor(ssp, SRCU_READ_FLAVOR_NORMAL); __srcu_read_unlock(ssp, idx); @@ -409,7 +430,7 @@ srcu_read_unlock_notrace(struct srcu_struct *ssp, int i= dx) __releases(ssp) * the same context as the maching srcu_down_read(). */ static inline void srcu_up_read(struct srcu_struct *ssp, int idx) - __releases(ssp) + __releases_shared(ssp) { WARN_ON_ONCE(idx & ~0x1); WARN_ON_ONCE(in_nmi()); diff --git a/lib/test_capability-analysis.c b/lib/test_capability-analysis.c index 050fa7c9fcba..63d81ad1562f 100644 --- a/lib/test_capability-analysis.c +++ b/lib/test_capability-analysis.c @@ -10,6 +10,7 @@ #include #include #include +#include =20 /* * Test that helper macros work as expected. @@ -345,3 +346,26 @@ static void __used test_rcu_assert_variants(void) lockdep_assert_in_rcu_read_lock_sched(); wants_rcu_held_sched(); } + +struct test_srcu_data { + struct srcu_struct srcu; + long __rcu_guarded *data; +}; + +static void __used test_srcu(struct test_srcu_data *d) +{ + init_srcu_struct(&d->srcu); + + int idx =3D srcu_read_lock(&d->srcu); + long *data =3D srcu_dereference(d->data, &d->srcu); + (void)data; + srcu_read_unlock(&d->srcu, idx); + + rcu_assign_pointer(d->data, NULL); +} + +static void __used test_srcu_guard(struct test_srcu_data *d) +{ + guard(srcu)(&d->srcu); + (void)srcu_dereference(d->data, &d->srcu); +} --=20 2.48.1.711.g2feabab25a-goog From nobody Thu May 7 18:25:53 2026 Received: from mail-wm1-f74.google.com (mail-wm1-f74.google.com [209.85.128.74]) (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 CD250202985 for ; Tue, 4 Mar 2025 09:25:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080356; cv=none; b=lxw5K/pkKgSG1YU9kOPJhgahjEBNQUjyiJ3MTJzffN1q90mdd6pFbDWpittuKtDRH6tVRQKEZnZXea2NGG+6bL5onUCQ8xeZAcXHPepsdP9gHIKEAqlJf5Q4EUkShGWsNU0DMHX7+8Nmed7XWOuQMkAz75j0sMII4BPtf0YZa9c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080356; c=relaxed/simple; bh=PiALtBw0DYxsKuBO8J1H1AaY1cU3EmQ3QqFWUaJ2ULI=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=IGJwcARGGhRLc6AH6B2crKzxC7rb4L6AwvaLI1PHWG9KPMmOT7Hh0uW3HKkJaLelWA6iwKvm+QrnBt8tmtKWIoxEGjroik9SY/grPOhgXeHVWJ0dCOOiqGGv3+4jTz/UR0I7nRUTjf8pglSR1jNF5MXa9HyFTsWnFXcds9Ipgn8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--elver.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=xseS9zns; arc=none smtp.client-ip=209.85.128.74 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--elver.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="xseS9zns" Received: by mail-wm1-f74.google.com with SMTP id 5b1f17b1804b1-43947979ce8so21212065e9.0 for ; Tue, 04 Mar 2025 01:25:53 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1741080352; x=1741685152; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=cDlOE/N8Ae1M5H+4yLEwuBDz/LRLExYZEp/cosJZ8Bg=; b=xseS9znsQ87t34sYX/gUp0g2hQZ/UNonxdPqn5B7LJMZ2/n7mRqN7ey1N4I8/VvGVt wcqf61xpLrOaUgfB5G5XrT8rOSZRNnLb2FSitfzM+H6koewUYHd0S6p6SgDDtZFjjw2v ga4SWEVQifSr2qCCjU0KUdxhurb8xDPE+OxbN7/QDf4dVDhNGp6o7JXxe8nDqH0SGobz lNlVgFk5sBuAoTqrKl1j8X+4hLptwTCAuGatsEJ28qbXzZ9wbk1D4H56dU0F19rDETHD 8tyMll8rxrEUkc51aH24J2tE+Ah6qHHSVyCVRdLZXRhZsxTzKw3L2W5RpkrxNf8Tprgs WjJg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741080352; x=1741685152; h=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; bh=cDlOE/N8Ae1M5H+4yLEwuBDz/LRLExYZEp/cosJZ8Bg=; b=l5E+IXPbIy/6QGX9eGuYZj7SI1h7IQAwwQ/tflBPCOkRsCHIw+tFZp1K+cv4h3iHWr 0xHbBF+/x+XKPJWL0qHZ7GQxfcnfju/Oaxjgw9BwFB/IvtlmidBK6i97F/ryJcWJocxI ZzJFmPb7H+t95j8Lfg9fEWHsrVhzGzRtilYMj6woKfj9mAdb1yO6QKz2wkMxN3eN1nZm tdMbw6lWO/rLqUp3MJvTaM30Bz6F7KI6JW8RY+hpMjePY4OGXisNISbpWZo3OTHtGLJN zbTXlSS5KhTlP/nO3xIsaNx4d8nhB0UJaul0+CFR5T3Qn9lBH16JRQVmHXY9bPMIrvlh Fkeg== X-Forwarded-Encrypted: i=1; AJvYcCUSZvhKZpXmKz7HBJm/yjYMmOH3XIdE1Zbgal1WSpPLyMLXP4vXbaHfJPCuDd5dKGilggohNOee8yrHhN4=@vger.kernel.org X-Gm-Message-State: AOJu0YywRFk6Rnm11/1WQz991PY5flE87mn/AiDDJAd/OVVKrg4f0teF qkFkglh/Gj601pCN3CqUg3KVX4jwFyJydGDAvhjoX+mnM1KsjynMpuckF1K6VND/hGvV4tpvnQ= = X-Google-Smtp-Source: AGHT+IHedqiVSmrcvr28lGY8V3DB1o4f03/YwjOgy/3VYsVwJNq1WARMZql7ViymW31VHT1lz95raXYaUw== X-Received: from wmqa13.prod.google.com ([2002:a05:600c:348d:b0:439:64f9:d801]) (user=elver job=prod-delivery.src-stubby-dispatcher) by 2002:a05:600c:190a:b0:434:a4b3:5ebe with SMTP id 5b1f17b1804b1-43ba675830emr110121215e9.24.1741080352374; Tue, 04 Mar 2025 01:25:52 -0800 (PST) Date: Tue, 4 Mar 2025 10:21:15 +0100 In-Reply-To: <20250304092417.2873893-1-elver@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250304092417.2873893-1-elver@google.com> X-Mailer: git-send-email 2.48.1.711.g2feabab25a-goog Message-ID: <20250304092417.2873893-17-elver@google.com> Subject: [PATCH v2 16/34] kref: Add capability-analysis annotations From: Marco Elver To: elver@google.com Cc: "David S. Miller" , Luc Van Oostenryck , "Paul E. McKenney" , Alexander Potapenko , Arnd Bergmann , Bart Van Assche , Bill Wendling , Boqun Feng , Dmitry Vyukov , Eric Dumazet , Frederic Weisbecker , Greg Kroah-Hartman , Herbert Xu , Ingo Molnar , Jann Horn , Jiri Slaby , Joel Fernandes , Jonathan Corbet , Josh Triplett , Justin Stitt , Kees Cook , Kentaro Takeda , Mark Rutland , Mathieu Desnoyers , Miguel Ojeda , Nathan Chancellor , Neeraj Upadhyay , Peter Zijlstra , Steven Rostedt , Tetsuo Handa , Thomas Gleixner , Uladzislau Rezki , Waiman Long , Will Deacon , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org, llvm@lists.linux.dev, rcu@vger.kernel.org, linux-crypto@vger.kernel.org, linux-serial@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Mark functions that conditionally acquire the passed lock. Signed-off-by: Marco Elver --- include/linux/kref.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/kref.h b/include/linux/kref.h index 88e82ab1367c..9bc6abe57572 100644 --- a/include/linux/kref.h +++ b/include/linux/kref.h @@ -81,6 +81,7 @@ static inline int kref_put(struct kref *kref, void (*rele= ase)(struct kref *kref) static inline int kref_put_mutex(struct kref *kref, void (*release)(struct kref *kref), struct mutex *mutex) + __cond_acquires(true, mutex) { if (refcount_dec_and_mutex_lock(&kref->refcount, mutex)) { release(kref); @@ -102,6 +103,7 @@ static inline int kref_put_mutex(struct kref *kref, static inline int kref_put_lock(struct kref *kref, void (*release)(struct kref *kref), spinlock_t *lock) + __cond_acquires(true, lock) { if (refcount_dec_and_lock(&kref->refcount, lock)) { release(kref); --=20 2.48.1.711.g2feabab25a-goog From nobody Thu May 7 18:25:53 2026 Received: from mail-ed1-f74.google.com (mail-ed1-f74.google.com [209.85.208.74]) (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 E0AEF202F71 for ; Tue, 4 Mar 2025 09:25:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080359; cv=none; b=DkYfdMS0ezeKGupKd2tWK8OTsROViTOgFAUAe54iAaBFyWoLr/aeNXzZ775+3DQyZZLlD3fpbzCZPikUrK7r8JzskquwhKpvFFbvCTQDhyQITdlf0QS/LIijFfCXVjBrN7UVHx3K8ZQiFNyp/Nu3JVslZcpWV6YSwO2kwuZ2FGI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080359; c=relaxed/simple; bh=1SmN40z6kKbC+O8dvQdGpD27kvcZTiGHvP/DQN+09H4=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=PxM+S3vAsVxf6PIn1M9aKjGZLZvsY8s+Fh0aBpV9+dQzC6nqIiiCSJ/K81B/JRS6gzlD3ETP881f5zLQClmdAPOd9QJTGDUFbFgzHL3tbZS/hKk7T68hJ50W6R2wnszu/eZnxp0aFC0BhjYgWHbU2+n1qnEb8GB6LRqYhu2AzZQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--elver.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=3SFaGK9L; arc=none smtp.client-ip=209.85.208.74 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--elver.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="3SFaGK9L" Received: by mail-ed1-f74.google.com with SMTP id 4fb4d7f45d1cf-5e54335bf7fso2866832a12.1 for ; Tue, 04 Mar 2025 01:25:56 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1741080355; x=1741685155; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=ezb4DcU7J/tAnP2VeDlPIfb7+eFzdx1whQ0121O6/zI=; b=3SFaGK9LRLwlNLFT/c5cma8UqSuYLMvKhYHr9F4JA14UKIr7ukbOg6thlv9DroPV4b kCFR42USngDGrBKefSB0doNHTpcZWpJwIxKbYyLpxGFTPzL0bq4EnjSO8HgWN70auswC Y6r1RgBIvY11RlkSqnX5eSjm/YvpOqdoAHoQiZvZFZyd4au9f92HN/rWUARgrc7+juO5 sPaVUapc9oqrLBkxLQzXjOpEHrAx5pdCwxxuZJkZg/9OaNR7McT4/YBQn7o7yvNdfB6G G4cputwhg2yHS2h9ybV+6Z31TNlyVwtGCKTFaoO1FLuH2yiFN6bkojarOzzGU/HysUp+ yRPg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741080355; x=1741685155; h=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; bh=ezb4DcU7J/tAnP2VeDlPIfb7+eFzdx1whQ0121O6/zI=; b=hbFnUV8zZfhrtW+Hc1GXsCChAHojp6cGJ327N3Rlo3u5qCKrdBETm5Puaop7wSVrpL t2K2/DXSgF0Iwgh5mFqIjw9cF3BAfngVxbFjYCLqogbeI6/nqdWAua643YVjxQdidsJx w34UCEAV8ePYVE+XYoJSUQqRgx7Bdds7BFWeNoZXxCNLhEDo54mfIyAvOgP2ldn3LLxf My8Bs37VDyy2Tkana5xj19/FegfmWkezeGJVEVEJ0Rkd8hnj+6bMCPZ0+sZPC1km4Efi h39EtKF3aqx/bRRXiJpJU1vH25806W6QpSin9oSfsqVerQweklcpT2RgphBVfacPo/y3 WhSw== X-Forwarded-Encrypted: i=1; AJvYcCWCkKZsvAYwOrSuAa8WV+AaIEjxUrm0eAO8XPDlj912pc9lxGWUWwMHGOSUGVsuk3a0Y+iRcimUqNiZjb8=@vger.kernel.org X-Gm-Message-State: AOJu0Ywzzko5fMTUmpjY2qyQWm/PQU1bsiaCsH75pl/QQB1jZUU4H6U+ ljZ3sEXZ5cVWg5P2yrqA2aB15TCZPJ8AgD4fzhD9O3xjg1//+q6xGmhHnSq07LquKs46+xCB2g= = X-Google-Smtp-Source: AGHT+IEQwbZjdZjN5RppHp55Zz74kJe74FUqiEdr52hms6eJRF3kZ/G4XeCunAHNo+i6Y4TgK/rotcyvNA== X-Received: from edbfd14.prod.google.com ([2002:a05:6402:388e:b0:5e4:c2fd:b4ac]) (user=elver job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6402:2711:b0:5e0:49e4:2180 with SMTP id 4fb4d7f45d1cf-5e4d6b4bc0dmr43845190a12.25.1741080355166; Tue, 04 Mar 2025 01:25:55 -0800 (PST) Date: Tue, 4 Mar 2025 10:21:16 +0100 In-Reply-To: <20250304092417.2873893-1-elver@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250304092417.2873893-1-elver@google.com> X-Mailer: git-send-email 2.48.1.711.g2feabab25a-goog Message-ID: <20250304092417.2873893-18-elver@google.com> Subject: [PATCH v2 17/34] locking/rwsem: Support Clang's capability analysis From: Marco Elver To: elver@google.com Cc: "David S. Miller" , Luc Van Oostenryck , "Paul E. McKenney" , Alexander Potapenko , Arnd Bergmann , Bart Van Assche , Bill Wendling , Boqun Feng , Dmitry Vyukov , Eric Dumazet , Frederic Weisbecker , Greg Kroah-Hartman , Herbert Xu , Ingo Molnar , Jann Horn , Jiri Slaby , Joel Fernandes , Jonathan Corbet , Josh Triplett , Justin Stitt , Kees Cook , Kentaro Takeda , Mark Rutland , Mathieu Desnoyers , Miguel Ojeda , Nathan Chancellor , Neeraj Upadhyay , Peter Zijlstra , Steven Rostedt , Tetsuo Handa , Thomas Gleixner , Uladzislau Rezki , Waiman Long , Will Deacon , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org, llvm@lists.linux.dev, rcu@vger.kernel.org, linux-crypto@vger.kernel.org, linux-serial@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add support for Clang's capability analysis for rw_semaphore. Signed-off-by: Marco Elver --- .../dev-tools/capability-analysis.rst | 2 +- include/linux/rwsem.h | 56 +++++++++------- lib/test_capability-analysis.c | 64 +++++++++++++++++++ 3 files changed, 97 insertions(+), 25 deletions(-) diff --git a/Documentation/dev-tools/capability-analysis.rst b/Documentatio= n/dev-tools/capability-analysis.rst index 918e35d110df..7e4d94d65043 100644 --- a/Documentation/dev-tools/capability-analysis.rst +++ b/Documentation/dev-tools/capability-analysis.rst @@ -80,7 +80,7 @@ Supported Kernel Primitives =20 Currently the following synchronization primitives are supported: `raw_spinlock_t`, `spinlock_t`, `rwlock_t`, `mutex`, `seqlock_t`, -`bit_spinlock`, RCU, SRCU (`srcu_struct`). +`bit_spinlock`, RCU, SRCU (`srcu_struct`), `rw_semaphore`. =20 For capabilities with an initialization function (e.g., `spin_lock_init()`= ), calling this function on the capability instance before initializing any diff --git a/include/linux/rwsem.h b/include/linux/rwsem.h index c8b543d428b0..98aa623ad9bf 100644 --- a/include/linux/rwsem.h +++ b/include/linux/rwsem.h @@ -45,7 +45,7 @@ * reduce the chance that they will share the same cacheline causing * cacheline bouncing problem. */ -struct rw_semaphore { +struct_with_capability(rw_semaphore) { atomic_long_t count; /* * Write owner or one of the read owners as well flags regarding @@ -76,11 +76,13 @@ static inline int rwsem_is_locked(struct rw_semaphore *= sem) } =20 static inline void rwsem_assert_held_nolockdep(const struct rw_semaphore *= sem) + __asserts_cap(sem) { WARN_ON(atomic_long_read(&sem->count) =3D=3D RWSEM_UNLOCKED_VALUE); } =20 static inline void rwsem_assert_held_write_nolockdep(const struct rw_semap= hore *sem) + __asserts_cap(sem) { WARN_ON(!(atomic_long_read(&sem->count) & RWSEM_WRITER_LOCKED)); } @@ -119,6 +121,7 @@ do { \ static struct lock_class_key __key; \ \ __init_rwsem((sem), #sem, &__key); \ + __assert_cap(sem); \ } while (0) =20 /* @@ -136,7 +139,7 @@ static inline int rwsem_is_contended(struct rw_semaphor= e *sem) =20 #include =20 -struct rw_semaphore { +struct_with_capability(rw_semaphore) { struct rwbase_rt rwbase; #ifdef CONFIG_DEBUG_LOCK_ALLOC struct lockdep_map dep_map; @@ -160,6 +163,7 @@ do { \ static struct lock_class_key __key; \ \ __init_rwsem((sem), #sem, &__key); \ + __assert_cap(sem); \ } while (0) =20 static __always_inline int rwsem_is_locked(const struct rw_semaphore *sem) @@ -168,11 +172,13 @@ static __always_inline int rwsem_is_locked(const stru= ct rw_semaphore *sem) } =20 static __always_inline void rwsem_assert_held_nolockdep(const struct rw_se= maphore *sem) + __asserts_cap(sem) { WARN_ON(!rwsem_is_locked(sem)); } =20 static __always_inline void rwsem_assert_held_write_nolockdep(const struct= rw_semaphore *sem) + __asserts_cap(sem) { WARN_ON(!rw_base_is_write_locked(&sem->rwbase)); } @@ -190,6 +196,7 @@ static __always_inline int rwsem_is_contended(struct rw= _semaphore *sem) */ =20 static inline void rwsem_assert_held(const struct rw_semaphore *sem) + __asserts_cap(sem) { if (IS_ENABLED(CONFIG_LOCKDEP)) lockdep_assert_held(sem); @@ -198,6 +205,7 @@ static inline void rwsem_assert_held(const struct rw_se= maphore *sem) } =20 static inline void rwsem_assert_held_write(const struct rw_semaphore *sem) + __asserts_cap(sem) { if (IS_ENABLED(CONFIG_LOCKDEP)) lockdep_assert_held_write(sem); @@ -208,47 +216,47 @@ static inline void rwsem_assert_held_write(const stru= ct rw_semaphore *sem) /* * lock for reading */ -extern void down_read(struct rw_semaphore *sem); -extern int __must_check down_read_interruptible(struct rw_semaphore *sem); -extern int __must_check down_read_killable(struct rw_semaphore *sem); +extern void down_read(struct rw_semaphore *sem) __acquires_shared(sem); +extern int __must_check down_read_interruptible(struct rw_semaphore *sem) = __cond_acquires_shared(0, sem); +extern int __must_check down_read_killable(struct rw_semaphore *sem) __con= d_acquires_shared(0, sem); =20 /* * trylock for reading -- returns 1 if successful, 0 if contention */ -extern int down_read_trylock(struct rw_semaphore *sem); +extern int down_read_trylock(struct rw_semaphore *sem) __cond_acquires_sha= red(true, sem); =20 /* * lock for writing */ -extern void down_write(struct rw_semaphore *sem); -extern int __must_check down_write_killable(struct rw_semaphore *sem); +extern void down_write(struct rw_semaphore *sem) __acquires(sem); +extern int __must_check down_write_killable(struct rw_semaphore *sem) __co= nd_acquires(0, sem); =20 /* * trylock for writing -- returns 1 if successful, 0 if contention */ -extern int down_write_trylock(struct rw_semaphore *sem); +extern int down_write_trylock(struct rw_semaphore *sem) __cond_acquires(tr= ue, sem); =20 /* * release a read lock */ -extern void up_read(struct rw_semaphore *sem); +extern void up_read(struct rw_semaphore *sem) __releases_shared(sem); =20 /* * release a write lock */ -extern void up_write(struct rw_semaphore *sem); +extern void up_write(struct rw_semaphore *sem) __releases(sem); =20 -DEFINE_GUARD(rwsem_read, struct rw_semaphore *, down_read(_T), up_read(_T)) -DEFINE_GUARD_COND(rwsem_read, _try, down_read_trylock(_T)) -DEFINE_GUARD_COND(rwsem_read, _intr, down_read_interruptible(_T) =3D=3D 0) +DEFINE_LOCK_GUARD_1(rwsem_read, struct rw_semaphore, down_read(_T->lock), = up_read(_T->lock)) +DEFINE_LOCK_GUARD_1_COND(rwsem_read, _try, down_read_trylock(_T->lock)) +DEFINE_LOCK_GUARD_1_COND(rwsem_read, _intr, down_read_interruptible(_T->lo= ck) =3D=3D 0) =20 -DEFINE_GUARD(rwsem_write, struct rw_semaphore *, down_write(_T), up_write(= _T)) -DEFINE_GUARD_COND(rwsem_write, _try, down_write_trylock(_T)) +DEFINE_LOCK_GUARD_1(rwsem_write, struct rw_semaphore, down_write(_T->lock)= , up_write(_T->lock)) +DEFINE_LOCK_GUARD_1_COND(rwsem_write, _try, down_write_trylock(_T->lock)) =20 /* * downgrade write lock to read lock */ -extern void downgrade_write(struct rw_semaphore *sem); +extern void downgrade_write(struct rw_semaphore *sem) __releases(sem) __ac= quires_shared(sem); =20 #ifdef CONFIG_DEBUG_LOCK_ALLOC /* @@ -264,11 +272,11 @@ extern void downgrade_write(struct rw_semaphore *sem); * lockdep_set_class() at lock initialization time. * See Documentation/locking/lockdep-design.rst for more details.) */ -extern void down_read_nested(struct rw_semaphore *sem, int subclass); -extern int __must_check down_read_killable_nested(struct rw_semaphore *sem= , int subclass); -extern void down_write_nested(struct rw_semaphore *sem, int subclass); -extern int down_write_killable_nested(struct rw_semaphore *sem, int subcla= ss); -extern void _down_write_nest_lock(struct rw_semaphore *sem, struct lockdep= _map *nest_lock); +extern void down_read_nested(struct rw_semaphore *sem, int subclass) __acq= uires_shared(sem); +extern int __must_check down_read_killable_nested(struct rw_semaphore *sem= , int subclass) __cond_acquires_shared(0, sem); +extern void down_write_nested(struct rw_semaphore *sem, int subclass) __ac= quires(sem); +extern int down_write_killable_nested(struct rw_semaphore *sem, int subcla= ss) __cond_acquires(0, sem); +extern void _down_write_nest_lock(struct rw_semaphore *sem, struct lockdep= _map *nest_lock) __acquires(sem); =20 # define down_write_nest_lock(sem, nest_lock) \ do { \ @@ -282,8 +290,8 @@ do { \ * [ This API should be avoided as much as possible - the * proper abstraction for this case is completions. ] */ -extern void down_read_non_owner(struct rw_semaphore *sem); -extern void up_read_non_owner(struct rw_semaphore *sem); +extern void down_read_non_owner(struct rw_semaphore *sem) __acquires_share= d(sem); +extern void up_read_non_owner(struct rw_semaphore *sem) __releases_shared(= sem); #else # define down_read_nested(sem, subclass) down_read(sem) # define down_read_killable_nested(sem, subclass) down_read_killable(sem) diff --git a/lib/test_capability-analysis.c b/lib/test_capability-analysis.c index 63d81ad1562f..7ccb163ab5b1 100644 --- a/lib/test_capability-analysis.c +++ b/lib/test_capability-analysis.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -255,6 +256,69 @@ static void __used test_seqlock_writer(struct test_seq= lock_data *d) write_sequnlock_irqrestore(&d->sl, flags); } =20 +struct test_rwsem_data { + struct rw_semaphore sem; + int counter __guarded_by(&sem); +}; + +static void __used test_rwsem_init(struct test_rwsem_data *d) +{ + init_rwsem(&d->sem); + d->counter =3D 0; +} + +static void __used test_rwsem_reader(struct test_rwsem_data *d) +{ + down_read(&d->sem); + (void)d->counter; + up_read(&d->sem); + + if (down_read_trylock(&d->sem)) { + (void)d->counter; + up_read(&d->sem); + } +} + +static void __used test_rwsem_writer(struct test_rwsem_data *d) +{ + down_write(&d->sem); + d->counter++; + up_write(&d->sem); + + down_write(&d->sem); + d->counter++; + downgrade_write(&d->sem); + (void)d->counter; + up_read(&d->sem); + + if (down_write_trylock(&d->sem)) { + d->counter++; + up_write(&d->sem); + } +} + +static void __used test_rwsem_assert(struct test_rwsem_data *d) +{ + rwsem_assert_held_nolockdep(&d->sem); + d->counter++; +} + +static void __used test_rwsem_guard(struct test_rwsem_data *d) +{ + { guard(rwsem_read)(&d->sem); (void)d->counter; } + { guard(rwsem_write)(&d->sem); d->counter++; } +} + +static void __used test_rwsem_cond_guard(struct test_rwsem_data *d) +{ + scoped_cond_guard(rwsem_read_try, return, &d->sem) { + (void)d->counter; + } + scoped_cond_guard(rwsem_write_try, return, &d->sem) { + d->counter++; + } +} + struct test_bit_spinlock_data { unsigned long bits; int counter __guarded_by(__bitlock(3, &bits)); --=20 2.48.1.711.g2feabab25a-goog From nobody Thu May 7 18:25:53 2026 Received: from mail-wr1-f74.google.com (mail-wr1-f74.google.com [209.85.221.74]) (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 A76A7203712 for ; Tue, 4 Mar 2025 09:25:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080361; cv=none; b=Br32PfyR+h4zwWKZ+WzyanZEc6sQIN/AplSa2nOjmAk36Odt/Q6isELkMO1d8ADvf+agl7K7pIA9+4aUiESb+55wEUaNF8nUvryiS8gPF6YG5JdV+fgcZDdi/rqvJD2k9J9ZaP79xaX3wII+vNCUkxa9a7ZHfu2SwX/yFzMd7wY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080361; c=relaxed/simple; bh=lUYIYSgoA2ccoaBS4kBmkDa5sN11OxStd6T3cwMJmGw=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=XY5eYbcXGM2JSSPe24MWCQ3OeOK6xl/7v2NCdGJDaLdd6I6BXG55os+Le7tDneJoZs1gLDJUMiP53b3RVMfrcXldkB8di3ZEhOEs9DiZw6ZkHW4oU+XfneBqDBY7ZOV8acK5XM9v8MLmgmJzNjkqWczdwqCykgt8kM4KVz472vw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--elver.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=U4Brh2ju; arc=none smtp.client-ip=209.85.221.74 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--elver.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="U4Brh2ju" Received: by mail-wr1-f74.google.com with SMTP id ffacd0b85a97d-390f000e962so1444077f8f.2 for ; Tue, 04 Mar 2025 01:25:59 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1741080358; x=1741685158; darn=vger.kernel.org; h=content-transfer-encoding:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:from:to:cc:subject:date:message-id :reply-to; bh=PNf/nM4zXVueSeYIgASkm7nQo4wF4e7ceuZttNxifgI=; b=U4Brh2ju0/JzGeQkFzpz6Pa5S+ndwwj+YO/0zui4JgZqTpWkrRXeiobNwYy6GF5uJw 7W7dW3ze6w+baD98PiqhEmYABT651n/BMYhi5kyDXUr8n+mB43S3wFq3bLPwzLi1rNuc GUNv+3c5pe391eo3hgyqolcIMFXVwlUXgmiSDjLl+P3i8BZdx+rD1wAlu204S5jZpItF uqFIuARpFw0X1hMGQNZ5khmk6NGwzFV2Te71IM0xGw0PlQ22M8UbEPCmwLPMJ+IcTLtz n8YlclBp81Ru2voBb/uop3JcdVVkq23FpIY3I04ZFkNjjaB7n31JsfzC8olIiXwaVZjC 5TRg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741080358; x=1741685158; h=content-transfer-encoding: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; bh=PNf/nM4zXVueSeYIgASkm7nQo4wF4e7ceuZttNxifgI=; b=O6O1OAIyhljXKpVpAtLamiAfA9KLb3xdk+rMm3bPrK5PqLt9V+kdPVvH06GlWTkmq4 Iz2+EQsuEkNVYZv2C8hB5T1MoaLU8MneOI8muHQhSsV52947qO6KjacCUVRp98p2alOD TUTranLf/s5s2/kM77NTsAKjhvLLs5KxYVwKy7Ln8BbXchI49tq4JI+iD8wInurFZLMG K7suoUp9NpW8jbRzmgEQ77++sR9bR89SqlrCxGqeJNasr6RSsjX8WVY/gqeNYqLjSFOz 5J0WJYhMLRldiOKyAnfFNd0lvZlTZ1nF4MHb8eH1/WiI27RRbOn4HB5wlOfCi2bfP5qU Zrgg== X-Forwarded-Encrypted: i=1; AJvYcCWid5RHB7RSSJGFNSWtW0OQ5SqyEmX4h6pzAJ2dm8aoNqQIu3Qmdc07S38tR6BIhJLQ+0/Ly94IY8EfMJY=@vger.kernel.org X-Gm-Message-State: AOJu0YxeiHByP99H4VlYw0HpGKOREIaJf9CZKn7SQFCpAAC85y6p7rWV vEONZlFJLY5GNVNXCEWU7cWH3Bty4ZwM0YVopM0Zy/IEP9l1z84RVd0N2DQqo/u0RBNII2aJrg= = X-Google-Smtp-Source: AGHT+IHNV2rVLk7DI7p2vN5TAoqWsmdPeX6tGGapgde3jO/7IaOi1K3xi+RVcuZ51YKSvmN00fSkAHnG5g== X-Received: from wmbbi24.prod.google.com ([2002:a05:600c:3d98:b0:439:8c33:5ed6]) (user=elver job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6000:4022:b0:390:ffd0:4138 with SMTP id ffacd0b85a97d-390ffd04350mr7740206f8f.24.1741080358018; Tue, 04 Mar 2025 01:25:58 -0800 (PST) Date: Tue, 4 Mar 2025 10:21:17 +0100 In-Reply-To: <20250304092417.2873893-1-elver@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250304092417.2873893-1-elver@google.com> X-Mailer: git-send-email 2.48.1.711.g2feabab25a-goog Message-ID: <20250304092417.2873893-19-elver@google.com> Subject: [PATCH v2 18/34] locking/local_lock: Include missing headers From: Marco Elver To: elver@google.com Cc: "David S. Miller" , Luc Van Oostenryck , "Paul E. McKenney" , Alexander Potapenko , Arnd Bergmann , Bart Van Assche , Bill Wendling , Boqun Feng , Dmitry Vyukov , Eric Dumazet , Frederic Weisbecker , Greg Kroah-Hartman , Herbert Xu , Ingo Molnar , Jann Horn , Jiri Slaby , Joel Fernandes , Jonathan Corbet , Josh Triplett , Justin Stitt , Kees Cook , Kentaro Takeda , Mark Rutland , Mathieu Desnoyers , Miguel Ojeda , Nathan Chancellor , Neeraj Upadhyay , Peter Zijlstra , Steven Rostedt , Tetsuo Handa , Thomas Gleixner , Uladzislau Rezki , Waiman Long , Will Deacon , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org, llvm@lists.linux.dev, rcu@vger.kernel.org, linux-crypto@vger.kernel.org, linux-serial@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Including into an empty TU will result in the compiler complaining: ./include/linux/local_lock.h: In function =E2=80=98class_local_lock_irqsave= _constructor=E2=80=99: ./include/linux/local_lock_internal.h:95:17: error: implicit declaration of= function =E2=80=98local_irq_save=E2=80=99; <...> 95 | local_irq_save(flags); \ | ^~~~~~~~~~~~~~ As well as (some architectures only, such as 'sh'): ./include/linux/local_lock_internal.h: In function =E2=80=98local_lock_acqu= ire=E2=80=99: ./include/linux/local_lock_internal.h:33:20: error: =E2=80=98current=E2=80= =99 undeclared (first use in this function) 33 | l->owner =3D current; Include missing headers to allow including local_lock.h where the required headers are not otherwise included. Signed-off-by: Marco Elver --- include/linux/local_lock_internal.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/local_lock_internal.h b/include/linux/local_lock= _internal.h index 8dd71fbbb6d2..420866c1c70b 100644 --- a/include/linux/local_lock_internal.h +++ b/include/linux/local_lock_internal.h @@ -4,7 +4,9 @@ #endif =20 #include +#include #include +#include =20 #ifndef CONFIG_PREEMPT_RT =20 --=20 2.48.1.711.g2feabab25a-goog From nobody Thu May 7 18:25:53 2026 Received: from mail-ed1-f73.google.com (mail-ed1-f73.google.com [209.85.208.73]) (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 0377820409B for ; Tue, 4 Mar 2025 09:26:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080364; cv=none; b=FLOMqFROEABr2zivn2WvtstMIKV5lfPXbNkKtEzYPCobOhg/WjtVUVGQn7y816/roxtSGmI/vB3GBwL19HtRZwyRtNkg2L+tCyz12X7Hg9ym96niZvefU/Z+zWC2gBpf5xGqnFzWdL0ZOy/8X6Sapz2MTrJayX9o9YwIfeQhLzQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080364; c=relaxed/simple; bh=5Pp0cWVWeR/iKG+6F+FtpYqvROINCcN+zxDEvkyjIk0=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=D+vHvv6MNhzfKNCg1NOIVDJS954dFAp1F/DxRQWeHd7KJCLbdol8OWbxLiefWEZAw0RSy4wG1hlhfPmtKfHfETQR+tW31W1X1jPH6TL3ROpErRQsHlGK9e7xOlMlilkSg0MpMvxRIGm1ri61XEfJft02xxmVaiihcIksNl8GLbQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--elver.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=GarN8Gsq; arc=none smtp.client-ip=209.85.208.73 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--elver.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="GarN8Gsq" Received: by mail-ed1-f73.google.com with SMTP id 4fb4d7f45d1cf-5e4c2618332so2147151a12.2 for ; Tue, 04 Mar 2025 01:26:01 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1741080360; x=1741685160; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=fevqVsEsX3/oCaV46XhekBmDNUcdyGVL5LKZ5XmlZNY=; b=GarN8GsqltPtkbPEKbezvzKXhgWxRjqr5fKz0wVsD7XdxGTdl1udQPlSiSwoQ8OTGy mjI2JokbrHDHdhXaPQXm9CJseJdaCioIeJwwO5FY7yeQNrNZgLS3evVf4MuwRnHIJ/lZ xNalbF+e1eutHezymEE1cqV8yJbmJ6U5ueVuCZVZhHzdydyYI0QZNiWxfADU7NTLxFbs gGWK9L8QLW5conEOhVhCUvVhBGKMmqR94LTlAymQsvX9fWxDO6/jERnzTIqtuPpCrE3t yZ8UIBhS7j9b97YZfNYk4g7mGlzJBEARUsZBOjCNcXe1OhyukBXXBowXRh2iDG/PreH6 nIJQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741080360; x=1741685160; h=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; bh=fevqVsEsX3/oCaV46XhekBmDNUcdyGVL5LKZ5XmlZNY=; b=YAKgWzcTlH1CE9Qgs7VWUFlKnVMJ0Ps4vaGA1hN6TLhMqXn8IMhZ85wyJI/8jTx1Nl OS/fgI7CU2y9yEwecPWGHHQbKXkjvK6aXBxAJzmfYdFR9zmnDaoua/3eu/kvClAMiBtv wng45rCj8DpeZ9vVRE888dAS4L8nN/GYoYID2EzJKstfIH61dz2F5p9Ffbn0algaOTll 6b1Uy7msohsEzjUEd291qasYZUXPMVUhiMLyRDSEWW8oR7cDdEUA1Y6icYbcfWTEry0q o0CaHU/U1bLqc9zMKw1/3uNABK1KWQgthebq0w4wEj6uC94XdeJ+p0BicR2ZdLa8V2LO vJsw== X-Forwarded-Encrypted: i=1; AJvYcCXI10QDqjkF+gmwPHs5G2xlOn9ZwuikHaCoLbe885gevN14Ehxw2Mao36DZqvILEv+Sf7dayzGH1xf+9kc=@vger.kernel.org X-Gm-Message-State: AOJu0Yx+W3FeOFWhWEamdZMTVtEADdBSWGujx//lE8Xev8b9WJV76SK6 NuEbvgpQ4k4epjiaELcFEBWgg7UoAm8ikD1ks5Lq5+0wvOaviJ5c/QHb+ubzTmrOcqpo3G/khA= = X-Google-Smtp-Source: AGHT+IFl5s6Iny66DH2m/TkuwyT+wpjNT0HF7LAin4sZpCAQX9J/MzXeXyXsNOCBtJkLhAkMTTKBYFaHlQ== X-Received: from edbfe12.prod.google.com ([2002:a05:6402:390c:b0:5e0:963d:6041]) (user=elver job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6402:3904:b0:5e5:335:dad2 with SMTP id 4fb4d7f45d1cf-5e50335de72mr16333101a12.26.1741080360656; Tue, 04 Mar 2025 01:26:00 -0800 (PST) Date: Tue, 4 Mar 2025 10:21:18 +0100 In-Reply-To: <20250304092417.2873893-1-elver@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250304092417.2873893-1-elver@google.com> X-Mailer: git-send-email 2.48.1.711.g2feabab25a-goog Message-ID: <20250304092417.2873893-20-elver@google.com> Subject: [PATCH v2 19/34] locking/local_lock: Support Clang's capability analysis From: Marco Elver To: elver@google.com Cc: "David S. Miller" , Luc Van Oostenryck , "Paul E. McKenney" , Alexander Potapenko , Arnd Bergmann , Bart Van Assche , Bill Wendling , Boqun Feng , Dmitry Vyukov , Eric Dumazet , Frederic Weisbecker , Greg Kroah-Hartman , Herbert Xu , Ingo Molnar , Jann Horn , Jiri Slaby , Joel Fernandes , Jonathan Corbet , Josh Triplett , Justin Stitt , Kees Cook , Kentaro Takeda , Mark Rutland , Mathieu Desnoyers , Miguel Ojeda , Nathan Chancellor , Neeraj Upadhyay , Peter Zijlstra , Steven Rostedt , Tetsuo Handa , Thomas Gleixner , Uladzislau Rezki , Waiman Long , Will Deacon , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org, llvm@lists.linux.dev, rcu@vger.kernel.org, linux-crypto@vger.kernel.org, linux-serial@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add support for Clang's capability analysis for local_lock_t. Signed-off-by: Marco Elver --- .../dev-tools/capability-analysis.rst | 2 +- include/linux/local_lock.h | 18 ++++---- include/linux/local_lock_internal.h | 41 ++++++++++++++--- lib/test_capability-analysis.c | 46 +++++++++++++++++++ 4 files changed, 90 insertions(+), 17 deletions(-) diff --git a/Documentation/dev-tools/capability-analysis.rst b/Documentatio= n/dev-tools/capability-analysis.rst index 7e4d94d65043..e892a5292841 100644 --- a/Documentation/dev-tools/capability-analysis.rst +++ b/Documentation/dev-tools/capability-analysis.rst @@ -80,7 +80,7 @@ Supported Kernel Primitives =20 Currently the following synchronization primitives are supported: `raw_spinlock_t`, `spinlock_t`, `rwlock_t`, `mutex`, `seqlock_t`, -`bit_spinlock`, RCU, SRCU (`srcu_struct`), `rw_semaphore`. +`bit_spinlock`, RCU, SRCU (`srcu_struct`), `rw_semaphore`, `local_lock_t`. =20 For capabilities with an initialization function (e.g., `spin_lock_init()`= ), calling this function on the capability instance before initializing any diff --git a/include/linux/local_lock.h b/include/linux/local_lock.h index 091dc0b6bdfb..63fadcf66216 100644 --- a/include/linux/local_lock.h +++ b/include/linux/local_lock.h @@ -51,12 +51,12 @@ #define local_unlock_irqrestore(lock, flags) \ __local_unlock_irqrestore(lock, flags) =20 -DEFINE_GUARD(local_lock, local_lock_t __percpu*, - local_lock(_T), - local_unlock(_T)) -DEFINE_GUARD(local_lock_irq, local_lock_t __percpu*, - local_lock_irq(_T), - local_unlock_irq(_T)) +DEFINE_LOCK_GUARD_1(local_lock, local_lock_t __percpu, + local_lock(_T->lock), + local_unlock(_T->lock)) +DEFINE_LOCK_GUARD_1(local_lock_irq, local_lock_t __percpu, + local_lock_irq(_T->lock), + local_unlock_irq(_T->lock)) DEFINE_LOCK_GUARD_1(local_lock_irqsave, local_lock_t __percpu, local_lock_irqsave(_T->lock, _T->flags), local_unlock_irqrestore(_T->lock, _T->flags), @@ -68,8 +68,8 @@ DEFINE_LOCK_GUARD_1(local_lock_irqsave, local_lock_t __pe= rcpu, #define local_unlock_nested_bh(_lock) \ __local_unlock_nested_bh(_lock) =20 -DEFINE_GUARD(local_lock_nested_bh, local_lock_t __percpu*, - local_lock_nested_bh(_T), - local_unlock_nested_bh(_T)) +DEFINE_LOCK_GUARD_1(local_lock_nested_bh, local_lock_t __percpu, + local_lock_nested_bh(_T->lock), + local_unlock_nested_bh(_T->lock)) =20 #endif diff --git a/include/linux/local_lock_internal.h b/include/linux/local_lock= _internal.h index 420866c1c70b..01830f75d9a3 100644 --- a/include/linux/local_lock_internal.h +++ b/include/linux/local_lock_internal.h @@ -10,12 +10,13 @@ =20 #ifndef CONFIG_PREEMPT_RT =20 -typedef struct { +struct_with_capability(local_lock) { #ifdef CONFIG_DEBUG_LOCK_ALLOC struct lockdep_map dep_map; struct task_struct *owner; #endif -} local_lock_t; +}; +typedef struct local_lock local_lock_t; =20 #ifdef CONFIG_DEBUG_LOCK_ALLOC # define LOCAL_LOCK_DEBUG_INIT(lockname) \ @@ -62,6 +63,7 @@ do { \ 0, LD_WAIT_CONFIG, LD_WAIT_INV, \ LD_LOCK_PERCPU); \ local_lock_debug_init(lock); \ + __assert_cap(lock); \ } while (0) =20 #define __spinlock_nested_bh_init(lock) \ @@ -73,40 +75,47 @@ do { \ 0, LD_WAIT_CONFIG, LD_WAIT_INV, \ LD_LOCK_NORMAL); \ local_lock_debug_init(lock); \ + __assert_cap(lock); \ } while (0) =20 #define __local_lock(lock) \ do { \ preempt_disable(); \ local_lock_acquire(this_cpu_ptr(lock)); \ + __acquire(lock); \ } while (0) =20 #define __local_lock_irq(lock) \ do { \ local_irq_disable(); \ local_lock_acquire(this_cpu_ptr(lock)); \ + __acquire(lock); \ } while (0) =20 #define __local_lock_irqsave(lock, flags) \ do { \ local_irq_save(flags); \ local_lock_acquire(this_cpu_ptr(lock)); \ + __acquire(lock); \ } while (0) =20 #define __local_unlock(lock) \ do { \ + __release(lock); \ local_lock_release(this_cpu_ptr(lock)); \ preempt_enable(); \ } while (0) =20 #define __local_unlock_irq(lock) \ do { \ + __release(lock); \ local_lock_release(this_cpu_ptr(lock)); \ local_irq_enable(); \ } while (0) =20 #define __local_unlock_irqrestore(lock, flags) \ do { \ + __release(lock); \ local_lock_release(this_cpu_ptr(lock)); \ local_irq_restore(flags); \ } while (0) @@ -115,19 +124,37 @@ do { \ do { \ lockdep_assert_in_softirq(); \ local_lock_acquire(this_cpu_ptr(lock)); \ + __acquire(lock); \ } while (0) =20 #define __local_unlock_nested_bh(lock) \ - local_lock_release(this_cpu_ptr(lock)) + do { \ + __release(lock); \ + local_lock_release(this_cpu_ptr(lock)); \ + } while (0) =20 #else /* !CONFIG_PREEMPT_RT */ =20 +#include + /* * On PREEMPT_RT local_lock maps to a per CPU spinlock, which protects the * critical section while staying preemptible. */ typedef spinlock_t local_lock_t; =20 +/* + * Because the compiler only knows about the base per-CPU variable, use th= is + * helper function to make the compiler think we lock/unlock the @base var= iable, + * and hide the fact we actually pass the per-CPU instance @pcpu to lock/u= nlock + * functions. + */ +static inline local_lock_t *__local_lock_alias(local_lock_t __percpu *base= , local_lock_t *pcpu) + __returns_cap(base) +{ + return pcpu; +} + #define INIT_LOCAL_LOCK(lockname) __LOCAL_SPIN_LOCK_UNLOCKED((lockname)) =20 #define __local_lock_init(l) \ @@ -138,7 +165,7 @@ typedef spinlock_t local_lock_t; #define __local_lock(__lock) \ do { \ migrate_disable(); \ - spin_lock(this_cpu_ptr((__lock))); \ + spin_lock(__local_lock_alias(__lock, this_cpu_ptr((__lock)))); \ } while (0) =20 #define __local_lock_irq(lock) __local_lock(lock) @@ -152,7 +179,7 @@ typedef spinlock_t local_lock_t; =20 #define __local_unlock(__lock) \ do { \ - spin_unlock(this_cpu_ptr((__lock))); \ + spin_unlock(__local_lock_alias(__lock, this_cpu_ptr((__lock)))); \ migrate_enable(); \ } while (0) =20 @@ -163,12 +190,12 @@ typedef spinlock_t local_lock_t; #define __local_lock_nested_bh(lock) \ do { \ lockdep_assert_in_softirq_func(); \ - spin_lock(this_cpu_ptr(lock)); \ + spin_lock(__local_lock_alias(lock, this_cpu_ptr(lock))); \ } while (0) =20 #define __local_unlock_nested_bh(lock) \ do { \ - spin_unlock(this_cpu_ptr((lock))); \ + spin_unlock(__local_lock_alias(lock, this_cpu_ptr((lock)))); \ } while (0) =20 #endif /* CONFIG_PREEMPT_RT */ diff --git a/lib/test_capability-analysis.c b/lib/test_capability-analysis.c index 7ccb163ab5b1..81c8e74548a9 100644 --- a/lib/test_capability-analysis.c +++ b/lib/test_capability-analysis.c @@ -6,7 +6,9 @@ =20 #include #include +#include #include +#include #include #include #include @@ -433,3 +435,47 @@ static void __used test_srcu_guard(struct test_srcu_da= ta *d) guard(srcu)(&d->srcu); (void)srcu_dereference(d->data, &d->srcu); } + +struct test_local_lock_data { + local_lock_t lock; + int counter __guarded_by(&lock); +}; + +static DEFINE_PER_CPU(struct test_local_lock_data, test_local_lock_data) = =3D { + .lock =3D INIT_LOCAL_LOCK(lock), +}; + +static void __used test_local_lock_init(struct test_local_lock_data *d) +{ + local_lock_init(&d->lock); + d->counter =3D 0; +} + +static void __used test_local_lock(void) +{ + unsigned long flags; + + local_lock(&test_local_lock_data.lock); + this_cpu_add(test_local_lock_data.counter, 1); + local_unlock(&test_local_lock_data.lock); + + local_lock_irq(&test_local_lock_data.lock); + this_cpu_add(test_local_lock_data.counter, 1); + local_unlock_irq(&test_local_lock_data.lock); + + local_lock_irqsave(&test_local_lock_data.lock, flags); + this_cpu_add(test_local_lock_data.counter, 1); + local_unlock_irqrestore(&test_local_lock_data.lock, flags); + + local_lock_nested_bh(&test_local_lock_data.lock); + this_cpu_add(test_local_lock_data.counter, 1); + local_unlock_nested_bh(&test_local_lock_data.lock); +} + +static void __used test_local_lock_guard(void) +{ + { guard(local_lock)(&test_local_lock_data.lock); this_cpu_add(test_local_= lock_data.counter, 1); } + { guard(local_lock_irq)(&test_local_lock_data.lock); this_cpu_add(test_lo= cal_lock_data.counter, 1); } + { guard(local_lock_irqsave)(&test_local_lock_data.lock); this_cpu_add(tes= t_local_lock_data.counter, 1); } + { guard(local_lock_nested_bh)(&test_local_lock_data.lock); this_cpu_add(t= est_local_lock_data.counter, 1); } +} --=20 2.48.1.711.g2feabab25a-goog From nobody Thu May 7 18:25:53 2026 Received: from mail-ej1-f73.google.com (mail-ej1-f73.google.com [209.85.218.73]) (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 2B62020459E for ; Tue, 4 Mar 2025 09:26:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080367; cv=none; b=BegUYgHvrIolqxKYbx1ZmgU49fbF6mO3DECXC1xHBaHamW7dyXToWMdtf1Bqu2XKvSI92zDJkeO7HcxVTB0aFuhvzmBS13GmRTyEaphGkajAz8iyFBwDi7UROPMRxUH4zw1GP5qOY3WSKIGu6XVng6uZAirz0kAqaOBObHix+HY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080367; c=relaxed/simple; bh=FzAM8kONcmoqRCoI2LnTHYjYi8+dzOgEjJ0xHcXrIBg=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=eG3733iR3kiOAvMQ6wLMikwKkNTHfI4hm3JS+5/cBKEipqnL+hOMduBaD98TzgCp6kQGDfVfEnCCqUjO4vzUuoWUdaKPk4MRsw33cGYSIWBSF4vSu7mOCFaIl512uff9se0UfbMamvz+nGddtop+ESvykjpU8Hl4+l2UPaZGZHc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--elver.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=pbvIalTH; arc=none smtp.client-ip=209.85.218.73 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--elver.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="pbvIalTH" Received: by mail-ej1-f73.google.com with SMTP id a640c23a62f3a-abf6e9bbef5so251238066b.1 for ; Tue, 04 Mar 2025 01:26:04 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1741080363; x=1741685163; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=8Nr2jdJ0PNmITUGav9EmcnRuPAHdAawXc4SBIYnGZjc=; b=pbvIalTHqFtB6ktPb+QrNlCcjMSeUCtpa2OgmieHIfbyPL2sGYAN0Obuw5CLRbws6b zrAAJ1Pj56NzzBMegI8M9ArUWqn5H15yXyAzxqS/GhUG509kDTbamFA2Egwtkxl15djL g50MhIha17I5/wY0mBTr7QOV7RKa5avt9NAHeyrBQ+IqoBEliqdJQ+1iuaSHE1sBRuBG DT0BI/jnq+ajpqzitEpot1f3NC8JEPYUFmcfaxQw+Q1qgt71CkVkQ53xX5rop/kzpQX/ v7AvvPKVhoXQjgTE0wQynN2szS+dKtcaeClMsJEdymbMm2xuTHuGfQLMpFdsPZ7xpYKn 3/VQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741080363; x=1741685163; h=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; bh=8Nr2jdJ0PNmITUGav9EmcnRuPAHdAawXc4SBIYnGZjc=; b=loY0jAySFOFR8FR/ZzdDfxj+7LVvefueYUeuz98WqCF6FVS2Z2xkcqa3dkI1vHATW8 l7mXFVf3s02KKIxxVJQptph1oTus7Hpt/lHBCSlzmATT3y87J7JyatnY3Mjh0wTXBL2B Ic9nqX3MKiu5yGott2U1REAt/edgDmISujqd9mxxI/hOBLSqDIHptu0ZmctJ/u3UB3Oy zpcBwghSuatZlPCZQAX2s6mhL1SdhhushBSWObRjsfccA9JLOEk/tPk1Ci1UVGzddOMO TZmof3nToDv5hxNM5LPasrYaLRgV/F9fSFbdntamaqVwlYXu+/n3Rp0VXbVzvLnnS0B2 ylKQ== X-Forwarded-Encrypted: i=1; AJvYcCWshaPH7C2XTUx11op+0nuB+j6B/wylTuyVwfw16udU8jCXLtkrIKd1OgvttHt7BRMP5TiFf5b/sjZ5Mcc=@vger.kernel.org X-Gm-Message-State: AOJu0Yz+IEh+k25OI3qfBVWvf7vv1pUfmkXebDUSpFsyLkYuG/rtGT/V 3WuBUnNWIQjGOuYxIKbydTORgbhWFm7nce/MuZvetzLmbpTbgmNz7U1R0AaIku0AP/C+evRcog= = X-Google-Smtp-Source: AGHT+IHUR6sYdD9TRGssa7cwqccEPoCIYdfeCgWX5dDy0wIQx6B6340985LLh8jF353quqMjRUM/OMs67A== X-Received: from ejcso7.prod.google.com ([2002:a17:907:3907:b0:abf:71ba:a144]) (user=elver job=prod-delivery.src-stubby-dispatcher) by 2002:a17:907:2da1:b0:ac1:deb0:5c3e with SMTP id a640c23a62f3a-ac1deb0d856mr500700666b.16.1741080363274; Tue, 04 Mar 2025 01:26:03 -0800 (PST) Date: Tue, 4 Mar 2025 10:21:19 +0100 In-Reply-To: <20250304092417.2873893-1-elver@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250304092417.2873893-1-elver@google.com> X-Mailer: git-send-email 2.48.1.711.g2feabab25a-goog Message-ID: <20250304092417.2873893-21-elver@google.com> Subject: [PATCH v2 20/34] locking/ww_mutex: Support Clang's capability analysis From: Marco Elver To: elver@google.com Cc: "David S. Miller" , Luc Van Oostenryck , "Paul E. McKenney" , Alexander Potapenko , Arnd Bergmann , Bart Van Assche , Bill Wendling , Boqun Feng , Dmitry Vyukov , Eric Dumazet , Frederic Weisbecker , Greg Kroah-Hartman , Herbert Xu , Ingo Molnar , Jann Horn , Jiri Slaby , Joel Fernandes , Jonathan Corbet , Josh Triplett , Justin Stitt , Kees Cook , Kentaro Takeda , Mark Rutland , Mathieu Desnoyers , Miguel Ojeda , Nathan Chancellor , Neeraj Upadhyay , Peter Zijlstra , Steven Rostedt , Tetsuo Handa , Thomas Gleixner , Uladzislau Rezki , Waiman Long , Will Deacon , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org, llvm@lists.linux.dev, rcu@vger.kernel.org, linux-crypto@vger.kernel.org, linux-serial@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add support for Clang's capability analysis for ww_mutex. The programming model for ww_mutex is subtly more complex than other locking primitives when using ww_acquire_ctx. Encoding the respective pre-conditions for ww_mutex lock/unlock based on ww_acquire_ctx state using Clang's capability analysis makes incorrect use of the API harder. Signed-off-by: Marco Elver --- v2: * New patch. --- .../dev-tools/capability-analysis.rst | 3 +- include/linux/ww_mutex.h | 21 ++++-- lib/test_capability-analysis.c | 65 +++++++++++++++++++ 3 files changed, 82 insertions(+), 7 deletions(-) diff --git a/Documentation/dev-tools/capability-analysis.rst b/Documentatio= n/dev-tools/capability-analysis.rst index e892a5292841..51ea94b0f4cc 100644 --- a/Documentation/dev-tools/capability-analysis.rst +++ b/Documentation/dev-tools/capability-analysis.rst @@ -80,7 +80,8 @@ Supported Kernel Primitives =20 Currently the following synchronization primitives are supported: `raw_spinlock_t`, `spinlock_t`, `rwlock_t`, `mutex`, `seqlock_t`, -`bit_spinlock`, RCU, SRCU (`srcu_struct`), `rw_semaphore`, `local_lock_t`. +`bit_spinlock`, RCU, SRCU (`srcu_struct`), `rw_semaphore`, `local_lock_t`, +`ww_mutex`. =20 For capabilities with an initialization function (e.g., `spin_lock_init()`= ), calling this function on the capability instance before initializing any diff --git a/include/linux/ww_mutex.h b/include/linux/ww_mutex.h index 45ff6f7a872b..e1d5455bd075 100644 --- a/include/linux/ww_mutex.h +++ b/include/linux/ww_mutex.h @@ -44,7 +44,7 @@ struct ww_class { unsigned int is_wait_die; }; =20 -struct ww_mutex { +struct_with_capability(ww_mutex) { struct WW_MUTEX_BASE base; struct ww_acquire_ctx *ctx; #ifdef DEBUG_WW_MUTEXES @@ -52,7 +52,7 @@ struct ww_mutex { #endif }; =20 -struct ww_acquire_ctx { +struct_with_capability(ww_acquire_ctx) { struct task_struct *task; unsigned long stamp; unsigned int acquired; @@ -107,6 +107,7 @@ struct ww_acquire_ctx { */ static inline void ww_mutex_init(struct ww_mutex *lock, struct ww_class *ww_class) + __asserts_cap(lock) { ww_mutex_base_init(&lock->base, ww_class->mutex_name, &ww_class->mutex_ke= y); lock->ctx =3D NULL; @@ -141,6 +142,7 @@ static inline void ww_mutex_init(struct ww_mutex *lock, */ static inline void ww_acquire_init(struct ww_acquire_ctx *ctx, struct ww_class *ww_class) + __acquires(ctx) __no_capability_analysis { ctx->task =3D current; ctx->stamp =3D atomic_long_inc_return_relaxed(&ww_class->stamp); @@ -179,6 +181,7 @@ static inline void ww_acquire_init(struct ww_acquire_ct= x *ctx, * data structures. */ static inline void ww_acquire_done(struct ww_acquire_ctx *ctx) + __releases(ctx) __acquires_shared(ctx) __no_capability_analysis { #ifdef DEBUG_WW_MUTEXES lockdep_assert_held(ctx); @@ -196,6 +199,7 @@ static inline void ww_acquire_done(struct ww_acquire_ct= x *ctx) * mutexes have been released with ww_mutex_unlock. */ static inline void ww_acquire_fini(struct ww_acquire_ctx *ctx) + __releases_shared(ctx) __no_capability_analysis { #ifdef CONFIG_DEBUG_LOCK_ALLOC mutex_release(&ctx->first_lock_dep_map, _THIS_IP_); @@ -245,7 +249,8 @@ static inline void ww_acquire_fini(struct ww_acquire_ct= x *ctx) * * A mutex acquired with this function must be released with ww_mutex_unlo= ck. */ -extern int /* __must_check */ ww_mutex_lock(struct ww_mutex *lock, struct = ww_acquire_ctx *ctx); +extern int /* __must_check */ ww_mutex_lock(struct ww_mutex *lock, struct = ww_acquire_ctx *ctx) + __cond_acquires(0, lock) __must_hold(ctx); =20 /** * ww_mutex_lock_interruptible - acquire the w/w mutex, interruptible @@ -278,7 +283,8 @@ extern int /* __must_check */ ww_mutex_lock(struct ww_m= utex *lock, struct ww_acq * A mutex acquired with this function must be released with ww_mutex_unlo= ck. */ extern int __must_check ww_mutex_lock_interruptible(struct ww_mutex *lock, - struct ww_acquire_ctx *ctx); + struct ww_acquire_ctx *ctx) + __cond_acquires(0, lock) __must_hold(ctx); =20 /** * ww_mutex_lock_slow - slowpath acquiring of the w/w mutex @@ -305,6 +311,7 @@ extern int __must_check ww_mutex_lock_interruptible(str= uct ww_mutex *lock, */ static inline void ww_mutex_lock_slow(struct ww_mutex *lock, struct ww_acquire_ctx *ctx) + __acquires(lock) __must_hold(ctx) __no_capability_analysis { int ret; #ifdef DEBUG_WW_MUTEXES @@ -342,6 +349,7 @@ ww_mutex_lock_slow(struct ww_mutex *lock, struct ww_acq= uire_ctx *ctx) static inline int __must_check ww_mutex_lock_slow_interruptible(struct ww_mutex *lock, struct ww_acquire_ctx *ctx) + __cond_acquires(0, lock) __must_hold(ctx) { #ifdef DEBUG_WW_MUTEXES DEBUG_LOCKS_WARN_ON(!ctx->contending_lock); @@ -349,10 +357,11 @@ ww_mutex_lock_slow_interruptible(struct ww_mutex *loc= k, return ww_mutex_lock_interruptible(lock, ctx); } =20 -extern void ww_mutex_unlock(struct ww_mutex *lock); +extern void ww_mutex_unlock(struct ww_mutex *lock) __releases(lock); =20 extern int __must_check ww_mutex_trylock(struct ww_mutex *lock, - struct ww_acquire_ctx *ctx); + struct ww_acquire_ctx *ctx) + __cond_acquires(true, lock) __must_hold(ctx); =20 /*** * ww_mutex_destroy - mark a w/w mutex unusable diff --git a/lib/test_capability-analysis.c b/lib/test_capability-analysis.c index 81c8e74548a9..853fdc53840f 100644 --- a/lib/test_capability-analysis.c +++ b/lib/test_capability-analysis.c @@ -14,6 +14,7 @@ #include #include #include +#include =20 /* * Test that helper macros work as expected. @@ -479,3 +480,67 @@ static void __used test_local_lock_guard(void) { guard(local_lock_irqsave)(&test_local_lock_data.lock); this_cpu_add(tes= t_local_lock_data.counter, 1); } { guard(local_lock_nested_bh)(&test_local_lock_data.lock); this_cpu_add(t= est_local_lock_data.counter, 1); } } + +static DEFINE_WD_CLASS(ww_class); + +struct test_ww_mutex_data { + struct ww_mutex mtx; + int counter __guarded_by(&mtx); +}; + +static void __used test_ww_mutex_init(struct test_ww_mutex_data *d) +{ + ww_mutex_init(&d->mtx, &ww_class); + d->counter =3D 0; +} + +static void __used test_ww_mutex_lock_noctx(struct test_ww_mutex_data *d) +{ + if (!ww_mutex_lock(&d->mtx, NULL)) { + d->counter++; + ww_mutex_unlock(&d->mtx); + } + + if (!ww_mutex_lock_interruptible(&d->mtx, NULL)) { + d->counter++; + ww_mutex_unlock(&d->mtx); + } + + if (ww_mutex_trylock(&d->mtx, NULL)) { + d->counter++; + ww_mutex_unlock(&d->mtx); + } + + ww_mutex_lock_slow(&d->mtx, NULL); + d->counter++; + ww_mutex_unlock(&d->mtx); +} + +static void __used test_ww_mutex_lock_ctx(struct test_ww_mutex_data *d) +{ + struct ww_acquire_ctx ctx; + + ww_acquire_init(&ctx, &ww_class); + + if (!ww_mutex_lock(&d->mtx, &ctx)) { + d->counter++; + ww_mutex_unlock(&d->mtx); + } + + if (!ww_mutex_lock_interruptible(&d->mtx, &ctx)) { + d->counter++; + ww_mutex_unlock(&d->mtx); + } + + if (ww_mutex_trylock(&d->mtx, &ctx)) { + d->counter++; + ww_mutex_unlock(&d->mtx); + } + + ww_mutex_lock_slow(&d->mtx, &ctx); + d->counter++; + ww_mutex_unlock(&d->mtx); + + ww_acquire_done(&ctx); + ww_acquire_fini(&ctx); +} --=20 2.48.1.711.g2feabab25a-goog From nobody Thu May 7 18:25:53 2026 Received: from mail-ed1-f73.google.com (mail-ed1-f73.google.com [209.85.208.73]) (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 94FDF2045BA for ; Tue, 4 Mar 2025 09:26:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080369; cv=none; b=gXhU+vtIw7GSGBCuiEiMlSJVOTtvEi9P0t6umebS9m5qZNvSozZFmYAnS8cOq80kpZgp2S82UHCBtHaskTWpUOMrOeuvkFP0x4eG4x5+fwkx+mGok0GXAajJsqCA1yQkxeLUPJv+EwP8WQ2fpbBdJASBQ+9fs6Y8YdON6J2zNro= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080369; c=relaxed/simple; bh=X1ktC5ZjhhR5WSX79RqJwEmztNg59gjqNnHaZ1eRNbI=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=ZMamePamrp8Ko+cs7pDxQ3QLHHT1P1dv5Fgl1yiMvZkIWXka/88CUGV1O15ugZSxQwWGWXfZVAfDKmqRiaAWdDqoxRS97qnCgeK5M4DhioCaHSTsU54KfktfARX1J3P9ryks9gPIbJYVS2KOkAgLjDBGD9CB0e3JtSGaCc8PQ98= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--elver.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=Xg6WVpOx; arc=none smtp.client-ip=209.85.208.73 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--elver.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="Xg6WVpOx" Received: by mail-ed1-f73.google.com with SMTP id 4fb4d7f45d1cf-5da15447991so6390803a12.3 for ; Tue, 04 Mar 2025 01:26:07 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1741080366; x=1741685166; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=ljSfvhYh8x6xwHsInA1Gu+wF89bLF/D0O2qs3l3oGhs=; b=Xg6WVpOxl4Uw1y9DqvyTg/3197RCryGmiSeYMqKUZTtF6ekER1WDtt4QMiXC1TPcg6 HnOBzDtLMIUNk+pLQAEWYm23m6PNy2Axi/a9mFpCp7arNL23sz7yugjjTL0VVBPQmfB3 rLoYFizmAR8YildAdPPxqlIMei1XwrW9W//4YPDHVd6dlGFtPOIPYs0SyfHSDWoVscUQ Q3zeOgQlAbM9V4q7fahK+x+vvd7CKuq2ESx/uiBT7Lr3XUn3mpCh3w4zYvjgh8D83Kme I+feMdM/bDcLp18cuqHklttRGdhpsf3ipe5zBWljPKEX9UY/59IQ05SWZKiEKS+iGxN/ jq/A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741080366; x=1741685166; h=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; bh=ljSfvhYh8x6xwHsInA1Gu+wF89bLF/D0O2qs3l3oGhs=; b=pB+6EqN5zcGoAe3bGIIfk1xwm3OfjfR9mpkVzBaMIK3xftWOchZJxnwlF+jsdl9vt0 KKuBc3rO40EWHWWX70P/IBd6N1yrx+9od9H3CRBGr82G+WvFeXF4q0LxA4RlcmXiXAsi a/nGoSOQKWgVZko/WPAGRp5qJLBuvAHJttFOLERTyQY3+F9cjyw7BF6EeteP+8aknGxU zl1hob2KMVpmHPPgavqLLllAIoPY7eCyiyn89KecSH/RjFmW8846P+zs2Bfd2K3KaXaf Lt/i0YQrLh7jkqX6NYgHKaTPiDUoItGtiVOyFgGTuG/E5cJ20S9JsSQVlSWnvLs+XeKo SR+A== X-Forwarded-Encrypted: i=1; AJvYcCUMlgHjNikg8wI7tZe1fOIEZZZuNul2zqDrKvmfrmq1C/PjLbyWyAOeD7eI1DruDSIXUpqWTfQ1TQmxiwQ=@vger.kernel.org X-Gm-Message-State: AOJu0YwF8XgbXR+w6tZjjaRVFcjzfZXJh95EgaUWre4CAEvnfKDfor71 hyETtopp2KgxWzxZiIuFfwR0atSrefb8eHu0J5NeH0FI+OveN33u4EDt979aCP5rttvCGPoWcw= = X-Google-Smtp-Source: AGHT+IFrMBW+OhCnT9icBam/s/vk6OKWe4X42OWK7ynSC2VTQQKw5GLkAoEuFIfZ1S6J7yhnX5gf47Hang== X-Received: from edbij24.prod.google.com ([2002:a05:6402:1598:b0:5de:504d:836a]) (user=elver job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6402:234e:b0:5dc:80ba:dda1 with SMTP id 4fb4d7f45d1cf-5e4d6ad7afcmr43438170a12.9.1741080366105; Tue, 04 Mar 2025 01:26:06 -0800 (PST) Date: Tue, 4 Mar 2025 10:21:20 +0100 In-Reply-To: <20250304092417.2873893-1-elver@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250304092417.2873893-1-elver@google.com> X-Mailer: git-send-email 2.48.1.711.g2feabab25a-goog Message-ID: <20250304092417.2873893-22-elver@google.com> Subject: [PATCH v2 21/34] debugfs: Make debugfs_cancellation a capability struct From: Marco Elver To: elver@google.com Cc: "David S. Miller" , Luc Van Oostenryck , "Paul E. McKenney" , Alexander Potapenko , Arnd Bergmann , Bart Van Assche , Bill Wendling , Boqun Feng , Dmitry Vyukov , Eric Dumazet , Frederic Weisbecker , Greg Kroah-Hartman , Herbert Xu , Ingo Molnar , Jann Horn , Jiri Slaby , Joel Fernandes , Jonathan Corbet , Josh Triplett , Justin Stitt , Kees Cook , Kentaro Takeda , Mark Rutland , Mathieu Desnoyers , Miguel Ojeda , Nathan Chancellor , Neeraj Upadhyay , Peter Zijlstra , Steven Rostedt , Tetsuo Handa , Thomas Gleixner , Uladzislau Rezki , Waiman Long , Will Deacon , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org, llvm@lists.linux.dev, rcu@vger.kernel.org, linux-crypto@vger.kernel.org, linux-serial@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" When compiling include/linux/debugfs.h with CAPABILITY_ANALYSIS enabled, we can see this error: ./include/linux/debugfs.h:239:17: error: use of undeclared identifier 'canc= ellation' 239 | void __acquires(cancellation) Move the __acquires(..) attribute after the declaration, so that the compiler can see the cancellation function argument, as well as making struct debugfs_cancellation a real capability to benefit from Clang's capability analysis. Signed-off-by: Marco Elver --- include/linux/debugfs.h | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h index fa2568b4380d..c6a429381887 100644 --- a/include/linux/debugfs.h +++ b/include/linux/debugfs.h @@ -240,18 +240,16 @@ ssize_t debugfs_read_file_str(struct file *file, char= __user *user_buf, * @cancel: callback to call * @cancel_data: extra data for the callback to call */ -struct debugfs_cancellation { +struct_with_capability(debugfs_cancellation) { struct list_head list; void (*cancel)(struct dentry *, void *); void *cancel_data; }; =20 -void __acquires(cancellation) -debugfs_enter_cancellation(struct file *file, - struct debugfs_cancellation *cancellation); -void __releases(cancellation) -debugfs_leave_cancellation(struct file *file, - struct debugfs_cancellation *cancellation); +void debugfs_enter_cancellation(struct file *file, + struct debugfs_cancellation *cancellation) __acquires(cancellation); +void debugfs_leave_cancellation(struct file *file, + struct debugfs_cancellation *cancellation) __releases(cancellation); =20 #else =20 --=20 2.48.1.711.g2feabab25a-goog From nobody Thu May 7 18:25:53 2026 Received: from mail-ed1-f73.google.com (mail-ed1-f73.google.com [209.85.208.73]) (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 6DA442046B5 for ; Tue, 4 Mar 2025 09:26:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080373; cv=none; b=G/yg/sR9ZnnyaNeaiJAlaMVr6lQHMITqrZpLkrCmLsdfjwS3yyhpZuGGc0aSibL2nbNk+vKmkwPLKLACMZweO9SI7jqfaK5laqtWVDrBhQmclA+gBTr7YfbCn6+avfZ7kSnW3oicnDU0jF5Ga14ZE3d1GEr3bOR0wM35unetM/0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080373; c=relaxed/simple; bh=66LwKwEvJHI65yeM4c4uuHM5+PNXrLfUMMtHzKvNEjk=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=f4ZmqeNR1tTVjgIL2wlm9tu3vGt9c7z/fnL8R/T+mJmoSz5YL3TNZ+KwgX0tAQzWH2Pbhka9vGmTZJlYIdj1IZpYFxN49FyEpucHmPtTHQ5kwG0ydMdWMfTFDssRfSRrDlmwldEAKU6OxoELa5W1JT8xg9wVxtOmKr8nQ/07S7c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--elver.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=jrff2QmO; arc=none smtp.client-ip=209.85.208.73 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--elver.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="jrff2QmO" Received: by mail-ed1-f73.google.com with SMTP id 4fb4d7f45d1cf-5e550e71d33so2000753a12.1 for ; Tue, 04 Mar 2025 01:26:10 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1741080369; x=1741685169; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=P1I/GQ+v/3j1AzYCm6S00P34ezPJ7HmSy44l1ZDIovo=; b=jrff2QmOX09Vy9y2pZk0o7LchsLxoJOP9E9rI6e5XzkUWMWKTzpXUuBYk2p2tvTlk9 LUeJaIc3J2KbvZWbl9FVyAvUz8iyJQ3i/WJt0e1LBLe49cjrwGSJod33vW7GKlAK9kY7 w4fpglkHCuFbuvAdc3by5IxmaTrmO9Q2UCPbDbOmfAHUa24PlNyyZD/QhYolzcs8VE+M GsLVhtbVDalUOCHMmlFBTukJfu4bX2SWg2CiddjZi335NlQ8Bc5vj/PqVkeBZkfu49bj ui+NUcid/uMs7f0TrmhroQNdc8cQf+xcmyNH0kbvqEEaVZXpX190bMzw0vwUAhAL+iXv 4nfg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741080369; x=1741685169; h=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; bh=P1I/GQ+v/3j1AzYCm6S00P34ezPJ7HmSy44l1ZDIovo=; b=NVoO1hxy4KtRqCu4/ugMUz2z5lwtz8dEbTomMPK7qSlO21rL/+WWSf0O06XUNzXOkA plbRKRo0hYw++XVFSpV7adMwiAx6SBihnfHWS+fDoNLfVAy8wB5DqlFpJW+lSvr0qYVr Tk2EwA1oVuxsUIJpYi8OEUZwc5veXKP9G2dsbL9NO33kts5f+hsx/9osrmQgYT71kEjr pz0dsSGtDQgjB7y/qUNmV3xDD4Y6qE2byD993DdMW4VkjR2Wb2Ah8lotRZzE3UgY8w+B w4BuiZN1S7lG8RYguh17XVWgBWnJuE67M57eQaB8KpXlC92/pfElD+xNse6dDPxZWY5Q ONGw== X-Forwarded-Encrypted: i=1; AJvYcCWt49UM3Umhid4M+9UnfvRaAj39iljZmQP2zgezDf7EPg72XYm6SgXdjuoo+1k6nCcOyVddOXmdgFkjR4A=@vger.kernel.org X-Gm-Message-State: AOJu0YzVoyvbIlT0zTSfXc7xNilc59LWPj/K6mmIFkiA/tkawEEys365 zzESKzernQKElWhPKN7Vyst8UkNajyZp3ZkD/rf8P4rJvA7OjXCjAOcmsRnk+bYu/iZMW/2Xug= = X-Google-Smtp-Source: AGHT+IFLim8eecum5uVex3hryFlz3FCAz5xVOg59Qt47EZvr2+Y6KQcxBittVbQ9kTNcN1THrZHhGDAhXQ== X-Received: from edbet14.prod.google.com ([2002:a05:6402:378e:b0:5e5:762:2c87]) (user=elver job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6402:4407:b0:5dc:a44d:36a9 with SMTP id 4fb4d7f45d1cf-5e4d6af158dmr16857891a12.14.1741080368800; Tue, 04 Mar 2025 01:26:08 -0800 (PST) Date: Tue, 4 Mar 2025 10:21:21 +0100 In-Reply-To: <20250304092417.2873893-1-elver@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250304092417.2873893-1-elver@google.com> X-Mailer: git-send-email 2.48.1.711.g2feabab25a-goog Message-ID: <20250304092417.2873893-23-elver@google.com> Subject: [PATCH v2 22/34] compiler-capability-analysis: Remove Sparse support From: Marco Elver To: elver@google.com Cc: "David S. Miller" , Luc Van Oostenryck , "Paul E. McKenney" , Alexander Potapenko , Arnd Bergmann , Bart Van Assche , Bill Wendling , Boqun Feng , Dmitry Vyukov , Eric Dumazet , Frederic Weisbecker , Greg Kroah-Hartman , Herbert Xu , Ingo Molnar , Jann Horn , Jiri Slaby , Joel Fernandes , Jonathan Corbet , Josh Triplett , Justin Stitt , Kees Cook , Kentaro Takeda , Mark Rutland , Mathieu Desnoyers , Miguel Ojeda , Nathan Chancellor , Neeraj Upadhyay , Peter Zijlstra , Steven Rostedt , Tetsuo Handa , Thomas Gleixner , Uladzislau Rezki , Waiman Long , Will Deacon , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org, llvm@lists.linux.dev, rcu@vger.kernel.org, linux-crypto@vger.kernel.org, linux-serial@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Remove Sparse support as discussed at [1]. The kernel codebase is still scattered with numerous places that try to appease Sparse's context tracking ("annotation for sparse", "fake out sparse", "work around sparse", etc.). Eventually, as more subsystems enable Clang's capability analysis, these places will show up and need adjustment or removal of the workarounds altogether. Link: https://lore.kernel.org/all/20250207083335.GW7145@noisy.programming.k= icks-ass.net/ [1] Link: https://lore.kernel.org/all/Z6XTKTo_LMj9KmbY@elver.google.com/ [2] Cc: "Luc Van Oostenryck" Cc: Peter Zijlstra Signed-off-by: Marco Elver --- v2: * New patch. --- Documentation/dev-tools/sparse.rst | 19 ------- include/linux/compiler-capability-analysis.h | 56 ++++++-------------- include/linux/rcupdate.h | 15 +----- 3 files changed, 17 insertions(+), 73 deletions(-) diff --git a/Documentation/dev-tools/sparse.rst b/Documentation/dev-tools/s= parse.rst index dc791c8d84d1..37b20170835d 100644 --- a/Documentation/dev-tools/sparse.rst +++ b/Documentation/dev-tools/sparse.rst @@ -53,25 +53,6 @@ sure that bitwise types don't get mixed up (little-endia= n vs big-endian vs cpu-endian vs whatever), and there the constant "0" really _is_ special. =20 -Using sparse for lock checking ------------------------------- - -The following macros are undefined for gcc and defined during a sparse -run to use the "context" tracking feature of sparse, applied to -locking. These annotations tell sparse when a lock is held, with -regard to the annotated function's entry and exit. - -__must_hold - The specified lock is held on function entry and exit. - -__acquires - The specified lock is held on function exit, but not entry. - -__releases - The specified lock is held on function entry, but not exit. - -If the function enters and exits without the lock held, acquiring and -releasing the lock inside the function in a balanced way, no -annotation is needed. The three annotations above are for cases where -sparse would otherwise report a context imbalance. - Getting sparse -------------- =20 diff --git a/include/linux/compiler-capability-analysis.h b/include/linux/c= ompiler-capability-analysis.h index 832727fea140..741f88e1177f 100644 --- a/include/linux/compiler-capability-analysis.h +++ b/include/linux/compiler-capability-analysis.h @@ -231,30 +231,8 @@ extern const struct __capability_##cap *name =20 /* - * Common keywords for static capability analysis. Both Clang's capability - * analysis and Sparse's context tracking are currently supported. + * Common keywords for static capability analysis. */ -#ifdef __CHECKER__ - -/* Sparse context/lock checking support. */ -# define __must_hold(x) __attribute__((context(x,1,1))) -# define __must_not_hold(x) -# define __acquires(x) __attribute__((context(x,0,1))) -# define __cond_acquires(ret, x) __attribute__((context(x,0,-1))) -# define __releases(x) __attribute__((context(x,1,0))) -# define __acquire(x) __context__(x,1) -# define __release(x) __context__(x,-1) -# define __cond_lock(x, c) ((c) ? ({ __acquire(x); 1; }) : 0) -/* For Sparse, there's no distinction between exclusive and shared locks. = */ -# define __must_hold_shared __must_hold -# define __acquires_shared __acquires -# define __cond_acquires_shared __cond_acquires -# define __releases_shared __releases -# define __acquire_shared __acquire -# define __release_shared __release -# define __cond_lock_shared __cond_acquire - -#else /* !__CHECKER__ */ =20 /** * __must_hold() - function attribute, caller must hold exclusive capabili= ty @@ -263,7 +241,7 @@ * Function attribute declaring that the caller must hold the given capabi= lity * instance @x exclusively. */ -# define __must_hold(x) __requires_cap(x) +#define __must_hold(x) __requires_cap(x) =20 /** * __must_not_hold() - function attribute, caller must not hold capability @@ -272,7 +250,7 @@ * Function attribute declaring that the caller must not hold the given * capability instance @x. */ -# define __must_not_hold(x) __excludes_cap(x) +#define __must_not_hold(x) __excludes_cap(x) =20 /** * __acquires() - function attribute, function acquires capability exclusi= vely @@ -281,7 +259,7 @@ * Function attribute declaring that the function acquires the given * capability instance @x exclusively, but does not release it. */ -# define __acquires(x) __acquires_cap(x) +#define __acquires(x) __acquires_cap(x) =20 /* * Clang's analysis does not care precisely about the value, only that it = is @@ -308,7 +286,7 @@ * * @ret may be one of: true, false, nonzero, 0, nonnull, NULL. */ -# define __cond_acquires(ret, x) __cond_acquires_impl_##ret(x) +#define __cond_acquires(ret, x) __cond_acquires_impl_##ret(x) =20 /** * __releases() - function attribute, function releases a capability exclu= sively @@ -317,7 +295,7 @@ * Function attribute declaring that the function releases the given capab= ility * instance @x exclusively. The capability must be held on entry. */ -# define __releases(x) __releases_cap(x) +#define __releases(x) __releases_cap(x) =20 /** * __acquire() - function to acquire capability exclusively @@ -325,7 +303,7 @@ * * No-op function that acquires the given capability instance @x exclusive= ly. */ -# define __acquire(x) __acquire_cap(x) +#define __acquire(x) __acquire_cap(x) =20 /** * __release() - function to release capability exclusively @@ -333,7 +311,7 @@ * * No-op function that releases the given capability instance @x. */ -# define __release(x) __release_cap(x) +#define __release(x) __release_cap(x) =20 /** * __cond_lock() - function that conditionally acquires a capability @@ -352,7 +330,7 @@ * * #define spin_trylock(l) __cond_lock(&lock, _spin_trylock(&lock)) */ -# define __cond_lock(x, c) __try_acquire_cap(x, c) +#define __cond_lock(x, c) __try_acquire_cap(x, c) =20 /** * __must_hold_shared() - function attribute, caller must hold shared capa= bility @@ -361,7 +339,7 @@ * Function attribute declaring that the caller must hold the given capabi= lity * instance @x with shared access. */ -# define __must_hold_shared(x) __requires_shared_cap(x) +#define __must_hold_shared(x) __requires_shared_cap(x) =20 /** * __acquires_shared() - function attribute, function acquires capability = shared @@ -370,7 +348,7 @@ * Function attribute declaring that the function acquires the given * capability instance @x with shared access, but does not release it. */ -# define __acquires_shared(x) __acquires_shared_cap(x) +#define __acquires_shared(x) __acquires_shared_cap(x) =20 /** * __cond_acquires_shared() - function attribute, function conditionally @@ -384,7 +362,7 @@ * * @ret may be one of: true, false, nonzero, 0, nonnull, NULL. */ -# define __cond_acquires_shared(ret, x) __cond_acquires_impl_##ret(x, _sha= red) +#define __cond_acquires_shared(ret, x) __cond_acquires_impl_##ret(x, _shar= ed) =20 /** * __releases_shared() - function attribute, function releases a @@ -394,7 +372,7 @@ * Function attribute declaring that the function releases the given capab= ility * instance @x with shared access. The capability must be held on entry. */ -# define __releases_shared(x) __releases_shared_cap(x) +#define __releases_shared(x) __releases_shared_cap(x) =20 /** * __acquire_shared() - function to acquire capability shared @@ -403,7 +381,7 @@ * No-op function that acquires the given capability instance @x with shar= ed * access. */ -# define __acquire_shared(x) __acquire_shared_cap(x) +#define __acquire_shared(x) __acquire_shared_cap(x) =20 /** * __release_shared() - function to release capability shared @@ -412,7 +390,7 @@ * No-op function that releases the given capability instance @x with shar= ed * access. */ -# define __release_shared(x) __release_shared_cap(x) +#define __release_shared(x) __release_shared_cap(x) =20 /** * __cond_lock_shared() - function that conditionally acquires a capability @@ -426,8 +404,6 @@ * access, if the boolean expression @c is true. The result of @c is the r= eturn * value, to be able to create a capability-enabled interface. */ -# define __cond_lock_shared(x, c) __try_acquire_shared_cap(x, c) - -#endif /* __CHECKER__ */ +#define __cond_lock_shared(x, c) __try_acquire_shared_cap(x, c) =20 #endif /* _LINUX_COMPILER_CAPABILITY_ANALYSIS_H */ diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index ef8875c4e621..75a2e8c30a3f 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -1183,20 +1183,7 @@ rcu_head_after_call_rcu(struct rcu_head *rhp, rcu_ca= llback_t f) extern int rcu_expedited; extern int rcu_normal; =20 -DEFINE_LOCK_GUARD_0(rcu, - do { - rcu_read_lock(); - /* - * sparse doesn't call the cleanup function, - * so just release immediately and don't track - * the context. We don't need to anyway, since - * the whole point of the guard is to not need - * the explicit unlock. - */ - __release(RCU); - } while (0), - rcu_read_unlock()) - +DEFINE_LOCK_GUARD_0(rcu, rcu_read_lock(), rcu_read_unlock()) DECLARE_LOCK_GUARD_0_ATTRS(rcu, __acquires_shared(RCU), __releases_shared(= RCU)); =20 #endif /* __LINUX_RCUPDATE_H */ --=20 2.48.1.711.g2feabab25a-goog From nobody Thu May 7 18:25:53 2026 Received: from mail-ej1-f73.google.com (mail-ej1-f73.google.com [209.85.218.73]) (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 308E9204C11 for ; Tue, 4 Mar 2025 09:26:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080376; cv=none; b=Ywr8qaHdX31QeibYB40U8VhOoVTYuRUQi+BFyQEYEThwM3jSbxuzCiTWQd+3BUgC7Lp5iuD/8Pg6DWXxgNRqx3elVhCwnpPHkxdtj4DZehM3UJBcEO2YaPk2OI6H+KUOAfK3IcQcr3s7l0sUAVkfmoDJpenZc9N47r2AGGXi6iY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080376; c=relaxed/simple; bh=YKRMcCwlVW+JHReTDDNlNbjIiZXrhQG3R+4ieOvF0KY=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=T3NeJY2iCq9/K6Xxqu/VMIel5NtKPxz3BN/sLE7/vjSGk5DM+R8VPYF/1xGFfJtRtdt57qk3vrjW6xO8IrRBphGQvAuG0MFizy/oCQPgWddOPWyXlFkYq0U9eaD3CNCZtmaJN0cFL1j4yfuay7lICG5N8bdcf21hQzFn3c3EFZE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--elver.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=e69+yJMT; arc=none smtp.client-ip=209.85.218.73 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--elver.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="e69+yJMT" Received: by mail-ej1-f73.google.com with SMTP id a640c23a62f3a-ac1e442740cso150087066b.1 for ; Tue, 04 Mar 2025 01:26:12 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1741080371; x=1741685171; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=32n+Ex/JylKzHQ8GbWl/dZFCHmuz4KLt4uCNJiSuT2I=; b=e69+yJMTsBftNyxq5NTkwldT+MukjqNNdZYLD5p1sS6G2sLxxJucl8hXkqZ1BVaYBW UGHV9thnAlU+XstoW0ZPqL5eyQBh+w881qDD8xJ/w/GbZBrNUUllV5nsEwqw9xbpjhqT moeriPQpJACDcjXbEVZ7w3QcEnfg4esQCeEFA4moSBHfdzI5JN5Q/GxtwFI7eaRaL5pW tuWXYHp6Kz5VrkcRq2ZdPhASp9MyZG4zUUgTp7yEmnUmnhjiDbu3DVQ/DnxwFU+8Z+Tx P0EHbDNXcgRHM8gJbH4ecKSn2+yG/JUbR6O4sj8NzURk5ZaMjrAYdrnzxjjlAbirC3fU WvEw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741080371; x=1741685171; h=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; bh=32n+Ex/JylKzHQ8GbWl/dZFCHmuz4KLt4uCNJiSuT2I=; b=PEqeIWj+4c6kyUKOH5l0QuaeS7t22AWNjhD8NctFF9udy5sHaunSzALG/EMrwhsoj4 njaF3Z73EH3m/loY/817gfzJL6xfJKcwoq4vDFTQN0HvnWF6m/P9WXyIsIMe/UMYDCoO frhkxZe8gkeST7soPE4XYdHp35i8HXPHws6OiiPDY4KvClYadPU3yRZveLu0QeB3Zduz MK4TqES+OqPp9oFjZHFaspvDtt2AS8W/rVUi4JLfE/nZTRcFF14Ko23kSzQl7rqCSP9Z 4R1qqxa4gIzajz+Wbbk0EimZUSXOSyWsT+2aPyel181GRiAE6SaGE/Px7H6DRwCYNh9g c3Mw== X-Forwarded-Encrypted: i=1; AJvYcCXQtBpaxepSt1KMpzl1bEE4Nnb7HijsNGpg9iQ3OiDiTPzjcm+RgjeDKZF35e19oB+n6fyuDxBA/jZnjSs=@vger.kernel.org X-Gm-Message-State: AOJu0Yw504eWtts1yUBKRZnudhEYkAiSsneRmGYLYzRd5e+whUZ66ypL +P1iWSbTTujo31/1W0xo2hbuvwXZXurhO8QqJnVmL4jjxONMQtDjHqzMSGxtVB0qbsBQn12WqQ= = X-Google-Smtp-Source: AGHT+IH7ajhBvj+N9zMLWn9yRIZ8xNtCdS5fHbofGVp+Rc2QgwPO+/i7HmH4t/LWU2ohwJ2AE+ttvPmAuA== X-Received: from ejctp7.prod.google.com ([2002:a17:907:c487:b0:ac2:219:94c3]) (user=elver job=prod-delivery.src-stubby-dispatcher) by 2002:a17:906:794e:b0:abf:742e:1fca with SMTP id a640c23a62f3a-abf742e23d7mr756224866b.18.1741080371564; Tue, 04 Mar 2025 01:26:11 -0800 (PST) Date: Tue, 4 Mar 2025 10:21:22 +0100 In-Reply-To: <20250304092417.2873893-1-elver@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250304092417.2873893-1-elver@google.com> X-Mailer: git-send-email 2.48.1.711.g2feabab25a-goog Message-ID: <20250304092417.2873893-24-elver@google.com> Subject: [PATCH v2 23/34] compiler-capability-analysis: Remove __cond_lock() function-like helper From: Marco Elver To: elver@google.com Cc: "David S. Miller" , Luc Van Oostenryck , "Paul E. McKenney" , Alexander Potapenko , Arnd Bergmann , Bart Van Assche , Bill Wendling , Boqun Feng , Dmitry Vyukov , Eric Dumazet , Frederic Weisbecker , Greg Kroah-Hartman , Herbert Xu , Ingo Molnar , Jann Horn , Jiri Slaby , Joel Fernandes , Jonathan Corbet , Josh Triplett , Justin Stitt , Kees Cook , Kentaro Takeda , Mark Rutland , Mathieu Desnoyers , Miguel Ojeda , Nathan Chancellor , Neeraj Upadhyay , Peter Zijlstra , Steven Rostedt , Tetsuo Handa , Thomas Gleixner , Uladzislau Rezki , Waiman Long , Will Deacon , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org, llvm@lists.linux.dev, rcu@vger.kernel.org, linux-crypto@vger.kernel.org, linux-serial@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" As discussed in [1], removing __cond_lock() will improve the readability of trylock code. Now that Sparse context tracking support has been removed, we can also remove __cond_lock(). Change existing APIs to either drop __cond_lock() completely, or make use of the __cond_acquires() function attribute instead. In particular, spinlock and rwlock implementations required switching over to inline helpers rather than statement-expressions for their trylock_* variants. Link: https://lore.kernel.org/all/20250207082832.GU7145@noisy.programming.k= icks-ass.net/ [1] Suggested-by: Peter Zijlstra Signed-off-by: Marco Elver --- v2: * New patch. --- .../dev-tools/capability-analysis.rst | 2 - Documentation/mm/process_addrs.rst | 6 +- .../net/wireless/intel/iwlwifi/iwl-trans.c | 4 +- .../net/wireless/intel/iwlwifi/iwl-trans.h | 6 +- .../wireless/intel/iwlwifi/pcie/internal.h | 5 +- .../net/wireless/intel/iwlwifi/pcie/trans.c | 4 +- include/linux/compiler-capability-analysis.h | 41 ------------- include/linux/mm.h | 33 ++-------- include/linux/rwlock.h | 11 +--- include/linux/rwlock_api_smp.h | 14 ++++- include/linux/rwlock_rt.h | 21 ++++--- include/linux/sched/signal.h | 14 +---- include/linux/spinlock.h | 45 +++++--------- include/linux/spinlock_api_smp.h | 20 ++++++ include/linux/spinlock_api_up.h | 61 ++++++++++++++++--- include/linux/spinlock_rt.h | 26 ++++---- kernel/signal.c | 4 +- kernel/time/posix-timers.c | 10 +-- lib/dec_and_lock.c | 8 +-- mm/memory.c | 4 +- mm/pgtable-generic.c | 19 +++--- tools/include/linux/compiler_types.h | 2 - 22 files changed, 160 insertions(+), 200 deletions(-) diff --git a/Documentation/dev-tools/capability-analysis.rst b/Documentatio= n/dev-tools/capability-analysis.rst index 51ea94b0f4cc..d11e88ab9882 100644 --- a/Documentation/dev-tools/capability-analysis.rst +++ b/Documentation/dev-tools/capability-analysis.rst @@ -113,10 +113,8 @@ Keywords __releases_shared __acquire __release - __cond_lock __acquire_shared __release_shared - __cond_lock_shared capability_unsafe __capability_unsafe disable_capability_analysis enable_capability_analysis diff --git a/Documentation/mm/process_addrs.rst b/Documentation/mm/process_= addrs.rst index 81417fa2ed20..073480ba7585 100644 --- a/Documentation/mm/process_addrs.rst +++ b/Documentation/mm/process_addrs.rst @@ -540,7 +540,7 @@ To access PTE-level page tables, a helper like :c:func:= `!pte_offset_map_lock` or :c:func:`!pte_offset_map` can be used depending on stability requirements. These map the page table into kernel memory if required, take the RCU lock= , and depending on variant, may also look up or acquire the PTE lock. -See the comment on :c:func:`!__pte_offset_map_lock`. +See the comment on :c:func:`!pte_offset_map_lock`. =20 Atomicity ^^^^^^^^^ @@ -624,7 +624,7 @@ must be released via :c:func:`!pte_unmap_unlock`. .. note:: There are some variants on this, such as :c:func:`!pte_offset_map_rw_nolock` when we know we hold the PTE stable= but for brevity we do not explore this. See the comment for - :c:func:`!__pte_offset_map_lock` for more details. + :c:func:`!pte_offset_map_lock` for more details. =20 When modifying data in ranges we typically only wish to allocate higher pa= ge tables as necessary, using these locks to avoid races or overwriting anyth= ing, @@ -643,7 +643,7 @@ At the leaf page table, that is the PTE, we can't entir= ely rely on this pattern as we have separate PMD and PTE locks and a THP collapse for instance migh= t have eliminated the PMD entry as well as the PTE from under us. =20 -This is why :c:func:`!__pte_offset_map_lock` locklessly retrieves the PMD = entry +This is why :c:func:`!pte_offset_map_lock` locklessly retrieves the PMD en= try for the PTE, carefully checking it is as expected, before acquiring the PTE-specific lock, and then *again* checking that the PMD entry is as expe= cted. =20 diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c b/drivers/net/w= ireless/intel/iwlwifi/iwl-trans.c index 49c8507d1a6b..64394f6dc156 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.c +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.c @@ -528,11 +528,11 @@ int iwl_trans_read_config32(struct iwl_trans *trans, = u32 ofs, } IWL_EXPORT_SYMBOL(iwl_trans_read_config32); =20 -bool _iwl_trans_grab_nic_access(struct iwl_trans *trans) +bool iwl_trans_grab_nic_access(struct iwl_trans *trans) { return iwl_trans_pcie_grab_nic_access(trans); } -IWL_EXPORT_SYMBOL(_iwl_trans_grab_nic_access); +IWL_EXPORT_SYMBOL(iwl_trans_grab_nic_access); =20 void __releases(nic_access) iwl_trans_release_nic_access(struct iwl_trans *trans) diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h b/drivers/net/w= ireless/intel/iwlwifi/iwl-trans.h index f6234065dbdd..8b37fd6c5221 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-trans.h @@ -1133,11 +1133,7 @@ int iwl_trans_sw_reset(struct iwl_trans *trans, bool= retake_ownership); void iwl_trans_set_bits_mask(struct iwl_trans *trans, u32 reg, u32 mask, u32 value); =20 -bool _iwl_trans_grab_nic_access(struct iwl_trans *trans); - -#define iwl_trans_grab_nic_access(trans) \ - __cond_lock(nic_access, \ - likely(_iwl_trans_grab_nic_access(trans))) +bool iwl_trans_grab_nic_access(struct iwl_trans *trans); =20 void __releases(nic_access) iwl_trans_release_nic_access(struct iwl_trans *trans); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h b/drivers/n= et/wireless/intel/iwlwifi/pcie/internal.h index 856b7e9f717d..84ce40b2ec5e 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/intel/iwlwifi/pcie/internal.h @@ -558,10 +558,7 @@ void iwl_trans_pcie_free(struct iwl_trans *trans); void iwl_trans_pcie_free_pnvm_dram_regions(struct iwl_dram_regions *dram_r= egions, struct device *dev); =20 -bool __iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans); -#define _iwl_trans_pcie_grab_nic_access(trans) \ - __cond_lock(nic_access_nobh, \ - likely(__iwl_trans_pcie_grab_nic_access(trans))) +bool _iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans); =20 void iwl_trans_pcie_check_product_reset_status(struct pci_dev *pdev); void iwl_trans_pcie_check_product_reset_mode(struct pci_dev *pdev); diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c b/drivers/net/= wireless/intel/iwlwifi/pcie/trans.c index c917ed4c19bc..caed7d7434f3 100644 --- a/drivers/net/wireless/intel/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/intel/iwlwifi/pcie/trans.c @@ -2405,7 +2405,7 @@ EXPORT_SYMBOL(iwl_trans_pcie_reset); * This version doesn't disable BHs but rather assumes they're * already disabled. */ -bool __iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans) +bool _iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans) { int ret; struct iwl_trans_pcie *trans_pcie =3D IWL_TRANS_GET_PCIE_TRANS(trans); @@ -2488,7 +2488,7 @@ bool iwl_trans_pcie_grab_nic_access(struct iwl_trans = *trans) bool ret; =20 local_bh_disable(); - ret =3D __iwl_trans_pcie_grab_nic_access(trans); + ret =3D _iwl_trans_pcie_grab_nic_access(trans); if (ret) { /* keep BHs disabled until iwl_trans_pcie_release_nic_access */ return ret; diff --git a/include/linux/compiler-capability-analysis.h b/include/linux/c= ompiler-capability-analysis.h index 741f88e1177f..c10938d2f102 100644 --- a/include/linux/compiler-capability-analysis.h +++ b/include/linux/compiler-capability-analysis.h @@ -93,12 +93,6 @@ __attribute__((overloadable)) __no_capability_analysis __acquires_cap(va= r) { } \ static __always_inline void __acquire_shared_cap(const struct name *var) = \ __attribute__((overloadable)) __no_capability_analysis __acquires_shared= _cap(var) { } \ - static __always_inline bool __try_acquire_cap(const struct name *var, boo= l ret) \ - __attribute__((overloadable)) __no_capability_analysis __try_acquires_ca= p(1, var) \ - { return ret; } \ - static __always_inline bool __try_acquire_shared_cap(const struct name *v= ar, bool ret) \ - __attribute__((overloadable)) __no_capability_analysis __try_acquires_sh= ared_cap(1, var) \ - { return ret; } \ static __always_inline void __release_cap(const struct name *var) \ __attribute__((overloadable)) __no_capability_analysis __releases_cap(va= r) { } \ static __always_inline void __release_shared_cap(const struct name *var) = \ @@ -156,8 +150,6 @@ # define __requires_shared_cap(var) # define __acquire_cap(var) do { } while (0) # define __acquire_shared_cap(var) do { } while (0) -# define __try_acquire_cap(var, ret) (ret) -# define __try_acquire_shared_cap(var, ret) (ret) # define __release_cap(var) do { } while (0) # define __release_shared_cap(var) do { } while (0) # define __assert_cap(var) do { (void)(var); } while (0) @@ -313,25 +305,6 @@ */ #define __release(x) __release_cap(x) =20 -/** - * __cond_lock() - function that conditionally acquires a capability - * exclusively - * @x: capability instance pinter - * @c: boolean expression - * - * Return: result of @c - * - * No-op function that conditionally acquires capability instance @x - * exclusively, if the boolean expression @c is true. The result of @c is = the - * return value, to be able to create a capability-enabled interface; for - * example: - * - * .. code-block:: c - * - * #define spin_trylock(l) __cond_lock(&lock, _spin_trylock(&lock)) - */ -#define __cond_lock(x, c) __try_acquire_cap(x, c) - /** * __must_hold_shared() - function attribute, caller must hold shared capa= bility * @x: capability instance pointer @@ -392,18 +365,4 @@ */ #define __release_shared(x) __release_shared_cap(x) =20 -/** - * __cond_lock_shared() - function that conditionally acquires a capability - * shared - * @x: capability instance pinter - * @c: boolean expression - * - * Return: result of @c - * - * No-op function that conditionally acquires capability instance @x with = shared - * access, if the boolean expression @c is true. The result of @c is the r= eturn - * value, to be able to create a capability-enabled interface. - */ -#define __cond_lock_shared(x, c) __try_acquire_shared_cap(x, c) - #endif /* _LINUX_COMPILER_CAPABILITY_ANALYSIS_H */ diff --git a/include/linux/mm.h b/include/linux/mm.h index 7b1068ddcbb7..dbf4eb414bd1 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -2732,15 +2732,8 @@ static inline int pte_devmap(pte_t pte) } #endif =20 -extern pte_t *__get_locked_pte(struct mm_struct *mm, unsigned long addr, - spinlock_t **ptl); -static inline pte_t *get_locked_pte(struct mm_struct *mm, unsigned long ad= dr, - spinlock_t **ptl) -{ - pte_t *ptep; - __cond_lock(*ptl, ptep =3D __get_locked_pte(mm, addr, ptl)); - return ptep; -} +extern pte_t *get_locked_pte(struct mm_struct *mm, unsigned long addr, + spinlock_t **ptl); =20 #ifdef __PAGETABLE_P4D_FOLDED static inline int __p4d_alloc(struct mm_struct *mm, pgd_t *pgd, @@ -3023,31 +3016,15 @@ static inline bool pagetable_pte_ctor(struct ptdesc= *ptdesc) return true; } =20 -pte_t *___pte_offset_map(pmd_t *pmd, unsigned long addr, pmd_t *pmdvalp); -static inline pte_t *__pte_offset_map(pmd_t *pmd, unsigned long addr, - pmd_t *pmdvalp) -{ - pte_t *pte; +pte_t *__pte_offset_map(pmd_t *pmd, unsigned long addr, pmd_t *pmdvalp); =20 - __cond_lock(RCU, pte =3D ___pte_offset_map(pmd, addr, pmdvalp)); - return pte; -} static inline pte_t *pte_offset_map(pmd_t *pmd, unsigned long addr) { return __pte_offset_map(pmd, addr, NULL); } =20 -pte_t *__pte_offset_map_lock(struct mm_struct *mm, pmd_t *pmd, - unsigned long addr, spinlock_t **ptlp); -static inline pte_t *pte_offset_map_lock(struct mm_struct *mm, pmd_t *pmd, - unsigned long addr, spinlock_t **ptlp) -{ - pte_t *pte; - - __cond_lock(RCU, __cond_lock(*ptlp, - pte =3D __pte_offset_map_lock(mm, pmd, addr, ptlp))); - return pte; -} +pte_t *pte_offset_map_lock(struct mm_struct *mm, pmd_t *pmd, + unsigned long addr, spinlock_t **ptlp); =20 pte_t *pte_offset_map_ro_nolock(struct mm_struct *mm, pmd_t *pmd, unsigned long addr, spinlock_t **ptlp); diff --git a/include/linux/rwlock.h b/include/linux/rwlock.h index 3c8971201ec7..701de800c36e 100644 --- a/include/linux/rwlock.h +++ b/include/linux/rwlock.h @@ -50,8 +50,8 @@ do { \ * regardless of whether CONFIG_SMP or CONFIG_PREEMPT are set. The various * methods are defined as nops in the case they are not required. */ -#define read_trylock(lock) __cond_lock_shared(lock, _raw_read_trylock(lock= )) -#define write_trylock(lock) __cond_lock(lock, _raw_write_trylock(lock)) +#define read_trylock(lock) _raw_read_trylock(lock) +#define write_trylock(lock) _raw_write_trylock(lock) =20 #define write_lock(lock) _raw_write_lock(lock) #define read_lock(lock) _raw_read_lock(lock) @@ -113,12 +113,7 @@ do { \ } while (0) #define write_unlock_bh(lock) _raw_write_unlock_bh(lock) =20 -#define write_trylock_irqsave(lock, flags) \ - __cond_lock(lock, ({ \ - local_irq_save(flags); \ - _raw_write_trylock(lock) ? \ - 1 : ({ local_irq_restore(flags); 0; }); \ - })) +#define write_trylock_irqsave(lock, flags) _raw_write_trylock_irqsave(lock= , &(flags)) =20 #ifdef arch_rwlock_is_contended #define rwlock_is_contended(lock) \ diff --git a/include/linux/rwlock_api_smp.h b/include/linux/rwlock_api_smp.h index 3e975105a606..b289c3089ab7 100644 --- a/include/linux/rwlock_api_smp.h +++ b/include/linux/rwlock_api_smp.h @@ -26,8 +26,8 @@ unsigned long __lockfunc _raw_read_lock_irqsave(rwlock_t = *lock) __acquires(lock); unsigned long __lockfunc _raw_write_lock_irqsave(rwlock_t *lock) __acquires(lock); -int __lockfunc _raw_read_trylock(rwlock_t *lock); -int __lockfunc _raw_write_trylock(rwlock_t *lock); +int __lockfunc _raw_read_trylock(rwlock_t *lock) __cond_acquires_shared(tr= ue, lock); +int __lockfunc _raw_write_trylock(rwlock_t *lock) __cond_acquires(true, lo= ck); void __lockfunc _raw_read_unlock(rwlock_t *lock) __releases_shared(lock); void __lockfunc _raw_write_unlock(rwlock_t *lock) __releases(lock); void __lockfunc _raw_read_unlock_bh(rwlock_t *lock) __releases_shared(lock= ); @@ -41,6 +41,16 @@ void __lockfunc _raw_write_unlock_irqrestore(rwlock_t *lock, unsigned long flags) __releases(lock); =20 +static inline bool _raw_write_trylock_irqsave(rwlock_t *lock, unsigned lon= g *flags) + __cond_acquires(true, lock) +{ + local_irq_save(*flags); + if (_raw_write_trylock(lock)) + return true; + local_irq_restore(*flags); + return false; +} + #ifdef CONFIG_INLINE_READ_LOCK #define _raw_read_lock(lock) __raw_read_lock(lock) #endif diff --git a/include/linux/rwlock_rt.h b/include/linux/rwlock_rt.h index 742172a06702..dc34b48a6158 100644 --- a/include/linux/rwlock_rt.h +++ b/include/linux/rwlock_rt.h @@ -26,11 +26,11 @@ do { \ } while (0) =20 extern void rt_read_lock(rwlock_t *rwlock) __acquires_shared(rwlock); -extern int rt_read_trylock(rwlock_t *rwlock); +extern int rt_read_trylock(rwlock_t *rwlock) __cond_acquires_shared(true, = rwlock); extern void rt_read_unlock(rwlock_t *rwlock) __releases_shared(rwlock); extern void rt_write_lock(rwlock_t *rwlock) __acquires(rwlock); extern void rt_write_lock_nested(rwlock_t *rwlock, int subclass) __acquire= s(rwlock); -extern int rt_write_trylock(rwlock_t *rwlock); +extern int rt_write_trylock(rwlock_t *rwlock) __cond_acquires(true, rwlock= ); extern void rt_write_unlock(rwlock_t *rwlock) __releases(rwlock); =20 static __always_inline void read_lock(rwlock_t *rwlock) @@ -59,7 +59,7 @@ static __always_inline void read_lock_irq(rwlock_t *rwloc= k) flags =3D 0; \ } while (0) =20 -#define read_trylock(lock) __cond_lock_shared(lock, rt_read_trylock(lock)) +#define read_trylock(lock) rt_read_trylock(lock) =20 static __always_inline void read_unlock(rwlock_t *rwlock) __releases_shared(rwlock) @@ -123,14 +123,15 @@ static __always_inline void write_lock_irq(rwlock_t *= rwlock) flags =3D 0; \ } while (0) =20 -#define write_trylock(lock) __cond_lock(lock, rt_write_trylock(lock)) +#define write_trylock(lock) rt_write_trylock(lock) =20 -#define write_trylock_irqsave(lock, flags) \ - __cond_lock(lock, ({ \ - typecheck(unsigned long, flags); \ - flags =3D 0; \ - rt_write_trylock(lock); \ - })) +static __always_inline bool _write_trylock_irqsave(rwlock_t *rwlock, unsig= ned long *flags) + __cond_acquires(true, rwlock) +{ + *flags =3D 0; + return rt_write_trylock(rwlock); +} +#define write_trylock_irqsave(lock, flags) _write_trylock_irqsave(lock, &(= flags)) =20 static __always_inline void write_unlock(rwlock_t *rwlock) __releases(rwlock) diff --git a/include/linux/sched/signal.h b/include/linux/sched/signal.h index d5d03d919df8..82c486b67e92 100644 --- a/include/linux/sched/signal.h +++ b/include/linux/sched/signal.h @@ -732,18 +732,8 @@ static inline int thread_group_empty(struct task_struc= t *p) #define delay_group_leader(p) \ (thread_group_leader(p) && !thread_group_empty(p)) =20 -extern struct sighand_struct *__lock_task_sighand(struct task_struct *task, - unsigned long *flags); - -static inline struct sighand_struct *lock_task_sighand(struct task_struct = *task, - unsigned long *flags) -{ - struct sighand_struct *ret; - - ret =3D __lock_task_sighand(task, flags); - (void)__cond_lock(&task->sighand->siglock, ret); - return ret; -} +extern struct sighand_struct *lock_task_sighand(struct task_struct *task, + unsigned long *flags); =20 static inline void unlock_task_sighand(struct task_struct *task, unsigned long *flags) diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h index 12369fa9e3bb..3cfd85b25648 100644 --- a/include/linux/spinlock.h +++ b/include/linux/spinlock.h @@ -213,7 +213,7 @@ static inline void do_raw_spin_unlock(raw_spinlock_t *l= ock) __releases(lock) * various methods are defined as nops in the case they are not * required. */ -#define raw_spin_trylock(lock) __cond_lock(lock, _raw_spin_trylock(lock)) +#define raw_spin_trylock(lock) _raw_spin_trylock(lock) =20 #define raw_spin_lock(lock) _raw_spin_lock(lock) =20 @@ -284,22 +284,11 @@ static inline void do_raw_spin_unlock(raw_spinlock_t = *lock) __releases(lock) } while (0) #define raw_spin_unlock_bh(lock) _raw_spin_unlock_bh(lock) =20 -#define raw_spin_trylock_bh(lock) \ - __cond_lock(lock, _raw_spin_trylock_bh(lock)) +#define raw_spin_trylock_bh(lock) _raw_spin_trylock_bh(lock) =20 -#define raw_spin_trylock_irq(lock) \ - __cond_lock(lock, ({ \ - local_irq_disable(); \ - _raw_spin_trylock(lock) ? \ - 1 : ({ local_irq_enable(); 0; }); \ - })) +#define raw_spin_trylock_irq(lock) _raw_spin_trylock_irq(lock) =20 -#define raw_spin_trylock_irqsave(lock, flags) \ - __cond_lock(lock, ({ \ - local_irq_save(flags); \ - _raw_spin_trylock(lock) ? \ - 1 : ({ local_irq_restore(flags); 0; }); \ - })) +#define raw_spin_trylock_irqsave(lock, flags) _raw_spin_trylock_irqsave(lo= ck, &(flags)) =20 #ifndef CONFIG_PREEMPT_RT /* Include rwlock functions for !RT */ @@ -431,8 +420,12 @@ static __always_inline int spin_trylock_irq(spinlock_t= *lock) return raw_spin_trylock_irq(&lock->rlock); } =20 -#define spin_trylock_irqsave(lock, flags) \ - __cond_lock(lock, raw_spin_trylock_irqsave(spinlock_check(lock), flags)) +static __always_inline bool _spin_trylock_irqsave(spinlock_t *lock, unsign= ed long *flags) + __cond_acquires(true, lock) __no_capability_analysis +{ + return raw_spin_trylock_irqsave(spinlock_check(lock), *flags); +} +#define spin_trylock_irqsave(lock, flags) _spin_trylock_irqsave(lock, &(fl= ags)) =20 /** * spin_is_locked() - Check whether a spinlock is locked. @@ -510,23 +503,17 @@ static inline int rwlock_needbreak(rwlock_t *lock) * Decrements @atomic by 1. If the result is 0, returns true and locks * @lock. Returns false for all other cases. */ -extern int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock); -#define atomic_dec_and_lock(atomic, lock) \ - __cond_lock(lock, _atomic_dec_and_lock(atomic, lock)) +extern int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) __cond_= acquires(true, lock); =20 extern int _atomic_dec_and_lock_irqsave(atomic_t *atomic, spinlock_t *lock, - unsigned long *flags); -#define atomic_dec_and_lock_irqsave(atomic, lock, flags) \ - __cond_lock(lock, _atomic_dec_and_lock_irqsave(atomic, lock, &(flags))) + unsigned long *flags) __cond_acquires(true, lock); +#define atomic_dec_and_lock_irqsave(atomic, lock, flags) _atomic_dec_and_l= ock_irqsave(atomic, lock, &(flags)) =20 -extern int _atomic_dec_and_raw_lock(atomic_t *atomic, raw_spinlock_t *lock= ); -#define atomic_dec_and_raw_lock(atomic, lock) \ - __cond_lock(lock, _atomic_dec_and_raw_lock(atomic, lock)) +extern int atomic_dec_and_raw_lock(atomic_t *atomic, raw_spinlock_t *lock)= __cond_acquires(true, lock); =20 extern int _atomic_dec_and_raw_lock_irqsave(atomic_t *atomic, raw_spinlock= _t *lock, - unsigned long *flags); -#define atomic_dec_and_raw_lock_irqsave(atomic, lock, flags) \ - __cond_lock(lock, _atomic_dec_and_raw_lock_irqsave(atomic, lock, &(flags= ))) + unsigned long *flags) __cond_acquires(true, lock); +#define atomic_dec_and_raw_lock_irqsave(atomic, lock, flags) _atomic_dec_a= nd_raw_lock_irqsave(atomic, lock, &(flags)) =20 int __alloc_bucket_spinlocks(spinlock_t **locks, unsigned int *lock_mask, size_t max_size, unsigned int cpu_mult, diff --git a/include/linux/spinlock_api_smp.h b/include/linux/spinlock_api_= smp.h index a77b76003ebb..1b1896595cbc 100644 --- a/include/linux/spinlock_api_smp.h +++ b/include/linux/spinlock_api_smp.h @@ -95,6 +95,26 @@ static inline int __raw_spin_trylock(raw_spinlock_t *loc= k) return 0; } =20 +static __always_inline bool _raw_spin_trylock_irq(raw_spinlock_t *lock) + __cond_acquires(true, lock) +{ + local_irq_disable(); + if (_raw_spin_trylock(lock)) + return true; + local_irq_enable(); + return false; +} + +static __always_inline bool _raw_spin_trylock_irqsave(raw_spinlock_t *lock= , unsigned long *flags) + __cond_acquires(true, lock) +{ + local_irq_save(*flags); + if (_raw_spin_trylock(lock)) + return true; + local_irq_restore(*flags); + return false; +} + /* * If lockdep is enabled then we use the non-preemption spin-ops * even on CONFIG_PREEMPTION, because lockdep assumes that interrupts are diff --git a/include/linux/spinlock_api_up.h b/include/linux/spinlock_api_u= p.h index 018f5aabc1be..a9d5c7c66e03 100644 --- a/include/linux/spinlock_api_up.h +++ b/include/linux/spinlock_api_up.h @@ -24,14 +24,11 @@ * flags straight, to suppress compiler warnings of unused lock * variables, and to add the proper checker annotations: */ -#define ___LOCK_void(lock) \ - do { (void)(lock); } while (0) - #define ___LOCK_(lock) \ - do { __acquire(lock); ___LOCK_void(lock); } while (0) + do { __acquire(lock); (void)(lock); } while (0) =20 #define ___LOCK_shared(lock) \ - do { __acquire_shared(lock); ___LOCK_void(lock); } while (0) + do { __acquire_shared(lock); (void)(lock); } while (0) =20 #define __LOCK(lock, ...) \ do { preempt_disable(); ___LOCK_##__VA_ARGS__(lock); } while (0) @@ -78,10 +75,56 @@ #define _raw_spin_lock_irqsave(lock, flags) __LOCK_IRQSAVE(lock, flags) #define _raw_read_lock_irqsave(lock, flags) __LOCK_IRQSAVE(lock, flags, sh= ared) #define _raw_write_lock_irqsave(lock, flags) __LOCK_IRQSAVE(lock, flags) -#define _raw_spin_trylock(lock) ({ __LOCK(lock, void); 1; }) -#define _raw_read_trylock(lock) ({ __LOCK(lock, void); 1; }) -#define _raw_write_trylock(lock) ({ __LOCK(lock, void); 1; }) -#define _raw_spin_trylock_bh(lock) ({ __LOCK_BH(lock, void); 1; }) + +static __always_inline int _raw_spin_trylock(raw_spinlock_t *lock) + __cond_acquires(true, lock) +{ + __LOCK(lock); + return 1; +} + +static __always_inline int _raw_spin_trylock_bh(raw_spinlock_t *lock) + __cond_acquires(true, lock) +{ + __LOCK_BH(lock); + return 1; +} + +static __always_inline int _raw_spin_trylock_irq(raw_spinlock_t *lock) + __cond_acquires(true, lock) +{ + __LOCK_IRQ(lock); + return 1; +} + +static __always_inline int _raw_spin_trylock_irqsave(raw_spinlock_t *lock,= unsigned long *flags) + __cond_acquires(true, lock) +{ + __LOCK_IRQSAVE(lock, *(flags)); + return 1; +} + +static __always_inline int _raw_read_trylock(rwlock_t *lock) + __cond_acquires_shared(true, lock) +{ + __LOCK(lock, shared); + return 1; +} + +static __always_inline int _raw_write_trylock(rwlock_t *lock) + __cond_acquires(true, lock) +{ + __LOCK(lock); + return 1; +} + +static __always_inline int _raw_write_trylock_irqsave(rwlock_t *lock, unsi= gned long *flags) + __cond_acquires(true, lock) +{ + __LOCK_IRQSAVE(lock, *(flags)); + return 1; +} + #define _raw_spin_unlock(lock) __UNLOCK(lock) #define _raw_read_unlock(lock) __UNLOCK(lock, shared) #define _raw_write_unlock(lock) __UNLOCK(lock) diff --git a/include/linux/spinlock_rt.h b/include/linux/spinlock_rt.h index 1f55601e1321..d11ecb0ed571 100644 --- a/include/linux/spinlock_rt.h +++ b/include/linux/spinlock_rt.h @@ -37,8 +37,8 @@ extern void rt_spin_lock_nested(spinlock_t *lock, int sub= class) __acquires(lock) extern void rt_spin_lock_nest_lock(spinlock_t *lock, struct lockdep_map *n= est_lock) __acquires(lock); extern void rt_spin_unlock(spinlock_t *lock) __releases(lock); extern void rt_spin_lock_unlock(spinlock_t *lock); -extern int rt_spin_trylock_bh(spinlock_t *lock); -extern int rt_spin_trylock(spinlock_t *lock); +extern int rt_spin_trylock_bh(spinlock_t *lock) __cond_acquires(true, lock= ); +extern int rt_spin_trylock(spinlock_t *lock) __cond_acquires(true, lock); =20 static __always_inline void spin_lock(spinlock_t *lock) __acquires(lock) @@ -130,21 +130,19 @@ static __always_inline void spin_unlock_irqrestore(sp= inlock_t *lock, rt_spin_unlock(lock); } =20 -#define spin_trylock(lock) \ - __cond_lock(lock, rt_spin_trylock(lock)) +#define spin_trylock(lock) rt_spin_trylock(lock) =20 -#define spin_trylock_bh(lock) \ - __cond_lock(lock, rt_spin_trylock_bh(lock)) +#define spin_trylock_bh(lock) rt_spin_trylock_bh(lock) =20 -#define spin_trylock_irq(lock) \ - __cond_lock(lock, rt_spin_trylock(lock)) +#define spin_trylock_irq(lock) rt_spin_trylock(lock) =20 -#define spin_trylock_irqsave(lock, flags) \ - __cond_lock(lock, ({ \ - typecheck(unsigned long, flags); \ - flags =3D 0; \ - rt_spin_trylock(lock); \ - })) +static __always_inline bool _spin_trylock_irqsave(spinlock_t *lock, unsign= ed long *flags) + __cond_acquires(true, lock) +{ + *flags =3D 0; + return rt_spin_trylock(lock); +} +#define spin_trylock_irqsave(lock, flags) _spin_trylock_irqsave(lock, &(fl= ags)) =20 #define spin_is_contended(lock) (((void)(lock), 0)) =20 diff --git a/kernel/signal.c b/kernel/signal.c index 875e97f6205a..8ae095eb1b78 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1354,8 +1354,8 @@ int zap_other_threads(struct task_struct *p) return count; } =20 -struct sighand_struct *__lock_task_sighand(struct task_struct *tsk, - unsigned long *flags) +struct sighand_struct *lock_task_sighand(struct task_struct *tsk, + unsigned long *flags) { struct sighand_struct *sighand; =20 diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c index 1b675aee99a9..8d84409fb3e6 100644 --- a/kernel/time/posix-timers.c +++ b/kernel/time/posix-timers.c @@ -59,14 +59,6 @@ static const struct k_clock clock_realtime, clock_monoto= nic; #error "SIGEV_THREAD_ID must not share bit with other SIGEV values!" #endif =20 -static struct k_itimer *__lock_timer(timer_t timer_id, unsigned long *flag= s); - -#define lock_timer(tid, flags) \ -({ struct k_itimer *__timr; \ - __cond_lock(&__timr->it_lock, __timr =3D __lock_timer(tid, flags)); \ - __timr; \ -}) - static int hash(struct signal_struct *sig, unsigned int nr) { return hash_32(hash32_ptr(sig) ^ nr, HASH_BITS(posix_timers_hashtable)); @@ -507,7 +499,7 @@ COMPAT_SYSCALL_DEFINE3(timer_create, clockid_t, which_c= lock, } #endif =20 -static struct k_itimer *__lock_timer(timer_t timer_id, unsigned long *flag= s) +static struct k_itimer *lock_timer(timer_t timer_id, unsigned long *flags) { struct k_itimer *timr; =20 diff --git a/lib/dec_and_lock.c b/lib/dec_and_lock.c index 1dcca8f2e194..8c7c398fd770 100644 --- a/lib/dec_and_lock.c +++ b/lib/dec_and_lock.c @@ -18,7 +18,7 @@ * because the spin-lock and the decrement must be * "atomic". */ -int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) +int atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) { /* Subtract 1 from counter unless that drops it to 0 (ie. it was 1) */ if (atomic_add_unless(atomic, -1, 1)) @@ -32,7 +32,7 @@ int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lo= ck) return 0; } =20 -EXPORT_SYMBOL(_atomic_dec_and_lock); +EXPORT_SYMBOL(atomic_dec_and_lock); =20 int _atomic_dec_and_lock_irqsave(atomic_t *atomic, spinlock_t *lock, unsigned long *flags) @@ -50,7 +50,7 @@ int _atomic_dec_and_lock_irqsave(atomic_t *atomic, spinlo= ck_t *lock, } EXPORT_SYMBOL(_atomic_dec_and_lock_irqsave); =20 -int _atomic_dec_and_raw_lock(atomic_t *atomic, raw_spinlock_t *lock) +int atomic_dec_and_raw_lock(atomic_t *atomic, raw_spinlock_t *lock) { /* Subtract 1 from counter unless that drops it to 0 (ie. it was 1) */ if (atomic_add_unless(atomic, -1, 1)) @@ -63,7 +63,7 @@ int _atomic_dec_and_raw_lock(atomic_t *atomic, raw_spinlo= ck_t *lock) raw_spin_unlock(lock); return 0; } -EXPORT_SYMBOL(_atomic_dec_and_raw_lock); +EXPORT_SYMBOL(atomic_dec_and_raw_lock); =20 int _atomic_dec_and_raw_lock_irqsave(atomic_t *atomic, raw_spinlock_t *loc= k, unsigned long *flags) diff --git a/mm/memory.c b/mm/memory.c index b4d3d4893267..3bbcdb2f3f34 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -2076,8 +2076,8 @@ static pmd_t *walk_to_pmd(struct mm_struct *mm, unsig= ned long addr) return pmd; } =20 -pte_t *__get_locked_pte(struct mm_struct *mm, unsigned long addr, - spinlock_t **ptl) +pte_t *get_locked_pte(struct mm_struct *mm, unsigned long addr, + spinlock_t **ptl) { pmd_t *pmd =3D walk_to_pmd(mm, addr); =20 diff --git a/mm/pgtable-generic.c b/mm/pgtable-generic.c index 5a882f2b10f9..cc202648c8d8 100644 --- a/mm/pgtable-generic.c +++ b/mm/pgtable-generic.c @@ -279,7 +279,7 @@ static unsigned long pmdp_get_lockless_start(void) { re= turn 0; } static void pmdp_get_lockless_end(unsigned long irqflags) { } #endif =20 -pte_t *___pte_offset_map(pmd_t *pmd, unsigned long addr, pmd_t *pmdvalp) +pte_t *__pte_offset_map(pmd_t *pmd, unsigned long addr, pmd_t *pmdvalp) { unsigned long irqflags; pmd_t pmdval; @@ -331,13 +331,12 @@ pte_t *pte_offset_map_rw_nolock(struct mm_struct *mm,= pmd_t *pmd, } =20 /* - * pte_offset_map_lock(mm, pmd, addr, ptlp), and its internal implementati= on - * __pte_offset_map_lock() below, is usually called with the pmd pointer f= or - * addr, reached by walking down the mm's pgd, p4d, pud for addr: either w= hile - * holding mmap_lock or vma lock for read or for write; or in truncate or = rmap - * context, while holding file's i_mmap_lock or anon_vma lock for read (or= for - * write). In a few cases, it may be used with pmd pointing to a pmd_t alr= eady - * copied to or constructed on the stack. + * pte_offset_map_lock(mm, pmd, addr, ptlp) is usually called with the pmd + * pointer for addr, reached by walking down the mm's pgd, p4d, pud for ad= dr: + * either while holding mmap_lock or vma lock for read or for write; or in + * truncate or rmap context, while holding file's i_mmap_lock or anon_vma = lock + * for read (or for write). In a few cases, it may be used with pmd pointi= ng to + * a pmd_t already copied to or constructed on the stack. * * When successful, it returns the pte pointer for addr, with its page tab= le * kmapped if necessary (when CONFIG_HIGHPTE), and locked against concurre= nt @@ -388,8 +387,8 @@ pte_t *pte_offset_map_rw_nolock(struct mm_struct *mm, p= md_t *pmd, * table, and may not use RCU at all: "outsiders" like khugepaged should a= void * pte_offset_map() and co once the vma is detached from mm or mm_users is= zero. */ -pte_t *__pte_offset_map_lock(struct mm_struct *mm, pmd_t *pmd, - unsigned long addr, spinlock_t **ptlp) +pte_t *pte_offset_map_lock(struct mm_struct *mm, pmd_t *pmd, + unsigned long addr, spinlock_t **ptlp) { spinlock_t *ptl; pmd_t pmdval; diff --git a/tools/include/linux/compiler_types.h b/tools/include/linux/com= piler_types.h index d09f9dc172a4..067a5b4e0f7b 100644 --- a/tools/include/linux/compiler_types.h +++ b/tools/include/linux/compiler_types.h @@ -20,7 +20,6 @@ # define __releases(x) __attribute__((context(x,1,0))) # define __acquire(x) __context__(x,1) # define __release(x) __context__(x,-1) -# define __cond_lock(x,c) ((c) ? ({ __acquire(x); 1; }) : 0) #else /* __CHECKER__ */ /* context/locking */ # define __must_hold(x) @@ -28,7 +27,6 @@ # define __releases(x) # define __acquire(x) (void)0 # define __release(x) (void)0 -# define __cond_lock(x,c) (c) #endif /* __CHECKER__ */ =20 /* Compiler specific macros. */ --=20 2.48.1.711.g2feabab25a-goog From nobody Thu May 7 18:25:53 2026 Received: from mail-ej1-f73.google.com (mail-ej1-f73.google.com [209.85.218.73]) (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 E21AB1FE472 for ; Tue, 4 Mar 2025 09:26:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080378; cv=none; b=uveYjW6yfWpLdALutfSRJTWKA9M87dG6KwlGB9aF6oIB/TYJWNwjTzIoSr02hZvkWjph4e4mswDcOT9utr1p0fkjs0EqFDrY+dIJB1grchsUlocm5X1BEQzHkoXHVJoK0URogw7D7EpwNwL/d6TaoVQfSKw9rAY9FpehXoFdEw4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080378; c=relaxed/simple; bh=ErRP0TLkHTSoiO9G/KD7SlUWq7CmBmFj0LpWE3kApQU=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=LuBgMrGv7vUEVKiJjMVGxEr3PSWbOT5JsziCOC7CK7vmSLP4j2kqVviP5wC1T2OX/6+HIeFQfWAl/HsVPX1fF2sRrsiPeM03+KhUWOjmZJ0mtLFPToIh61Uxfh3SvsG23TKsoqH+eYSpTGEcqGP5NZiQPqBrI0zI6swb1+vpleE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--elver.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=GW7XU3T+; arc=none smtp.client-ip=209.85.218.73 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--elver.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="GW7XU3T+" Received: by mail-ej1-f73.google.com with SMTP id a640c23a62f3a-abb8f65af3dso528826166b.1 for ; Tue, 04 Mar 2025 01:26:15 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1741080374; x=1741685174; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=lSVagzG7gv+v/g8zzR4ILNSARzsQANzMJVGDI4EywE8=; b=GW7XU3T+X2Xp7LEgzH1U3qI9ZjywWJ3zpeAmHijuD+TIuQ1bOTIATIC9yOpFKPQLCw wWk4KV0o6pqRuSfL0KsoR5r6gx2Wobw2gH2lu3+pAezhvGJkbAcMn4AS2In1YC1L/0Gg HaZbwLExngOtwLQU90RevUsmACy0LvWIGSn945PxWYLrkOHDt55z9N6rMNuhLu5YIVoO 1IIW38Diggwct0P0VYwIOp+R9GHD7YazBO7iWu2HpeeN60RsoydhDpQdrag9nc4Izuu9 lZjnxriN521TKqw5KB/wAxIrMva8xWjrUdzrMuuMojYRUrb8cooJAvqyWzTH6zNPDvGN Rjsw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741080374; x=1741685174; h=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; bh=lSVagzG7gv+v/g8zzR4ILNSARzsQANzMJVGDI4EywE8=; b=g+ZTv1vk9OZvPra6jRIUmpD8dsJGuM1KyS72Xnwk4lheW2F2s7De7mXApOpVYiNv2F uvLk/xXTuoHlrtD1tL1w/4Onlbxqp7SmA6i+PytBMeTpg4xCd4L83I7Hje1D9lQgyi93 GcGS9lT7Xk7jpXgIIuuX97QMGHFMgOv+ppERiUiBKeN9SXCaZRAJC/w0fGvqsNinK5RD RkoKOamzJt42IV2ajLjsMvbNOjX1tArh5sutJakQr1WB3p9hljZ/FzQuXmVVCZopx6xB t3H8OqioliIgsNuSCkx9L4fmbAwivt6YciCaQRGLd6YgMFT24tRWp8ZMsxjDa+k+Y6qj ec7A== X-Forwarded-Encrypted: i=1; AJvYcCVRqZ2Hd+bz3Zm9rYW+bcjq9bdOs5P+Tt2sRA6fJTR87GE1tmCSTE9aR3jlTpja+MAkq7KaUUaIMJxON2Q=@vger.kernel.org X-Gm-Message-State: AOJu0YwySzXjPE0b4qxN6nfC8qnmsmfYqcMccZ9K53hKbrjNhDWe0XqV EcUYNUBSZfOWx61xxN+NV2x0WobaQziNvc5wfqXXdn4msRcBkyy2bx54+rOyeGCWAxijC2C4dw= = X-Google-Smtp-Source: AGHT+IFJBP4Tcx72apFD1gIfXnldoSVXluGG30wLL1iAY+mX9Im8gCUaP5MoJwpojqCBSSTJQMcMwqY6Fw== X-Received: from ejcvb9.prod.google.com ([2002:a17:907:d049:b0:ac1:f9fe:d27b]) (user=elver job=prod-delivery.src-stubby-dispatcher) by 2002:a17:906:880e:b0:abf:4521:eb2a with SMTP id a640c23a62f3a-abf4521edabmr1374674266b.49.1741080374222; Tue, 04 Mar 2025 01:26:14 -0800 (PST) Date: Tue, 4 Mar 2025 10:21:23 +0100 In-Reply-To: <20250304092417.2873893-1-elver@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250304092417.2873893-1-elver@google.com> X-Mailer: git-send-email 2.48.1.711.g2feabab25a-goog Message-ID: <20250304092417.2873893-25-elver@google.com> Subject: [PATCH v2 24/34] compiler-capability-analysis: Introduce header suppressions From: Marco Elver To: elver@google.com Cc: "David S. Miller" , Luc Van Oostenryck , "Paul E. McKenney" , Alexander Potapenko , Arnd Bergmann , Bart Van Assche , Bill Wendling , Boqun Feng , Dmitry Vyukov , Eric Dumazet , Frederic Weisbecker , Greg Kroah-Hartman , Herbert Xu , Ingo Molnar , Jann Horn , Jiri Slaby , Joel Fernandes , Jonathan Corbet , Josh Triplett , Justin Stitt , Kees Cook , Kentaro Takeda , Mark Rutland , Mathieu Desnoyers , Miguel Ojeda , Nathan Chancellor , Neeraj Upadhyay , Peter Zijlstra , Steven Rostedt , Tetsuo Handa , Thomas Gleixner , Uladzislau Rezki , Waiman Long , Will Deacon , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org, llvm@lists.linux.dev, rcu@vger.kernel.org, linux-crypto@vger.kernel.org, linux-serial@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" While we can opt in individual subsystems which add the required annotations, such subsystems inevitably include headers from other subsystems which may not yet have the right annotations, which then result in false positive warnings. Making compatible by adding annotations across all common headers currently requires an excessive number of __no_capability_analysis annotations, or carefully analyzing non-trivial cases to add the correct annotations. While this is desirable long-term, providing an incremental path causes less churn and headaches for maintainers not yet interested in dealing with such warnings. Rather than clutter headers unnecessary and mandate all subsystem maintainers to keep their headers working with capability analysis, suppress all -Wthread-safety warnings in headers. Explicitly opt in headers with capability-enabled primitives. This bumps the required Clang version to version 20+. With this in place, we can start enabling the analysis on more complex subsystems in subsequent changes. Signed-off-by: Marco Elver --- .../dev-tools/capability-analysis.rst | 2 ++ lib/Kconfig.debug | 4 ++- scripts/Makefile.capability-analysis | 4 +++ scripts/capability-analysis-suppression.txt | 32 +++++++++++++++++++ 4 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 scripts/capability-analysis-suppression.txt diff --git a/Documentation/dev-tools/capability-analysis.rst b/Documentatio= n/dev-tools/capability-analysis.rst index d11e88ab9882..5c87d7659995 100644 --- a/Documentation/dev-tools/capability-analysis.rst +++ b/Documentation/dev-tools/capability-analysis.rst @@ -17,6 +17,8 @@ features. To enable for Clang, configure the kernel with:: =20 CONFIG_WARN_CAPABILITY_ANALYSIS=3Dy =20 +The feature requires Clang 20 or later. + The analysis is *opt-in by default*, and requires declaring which modules = and subsystems should be analyzed in the respective `Makefile`:: =20 diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 8abaf7dab3f8..8b13353517a9 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -605,7 +605,7 @@ config DEBUG_FORCE_WEAK_PER_CPU =20 config WARN_CAPABILITY_ANALYSIS bool "Compiler capability-analysis warnings" - depends on CC_IS_CLANG && $(cc-option,-Wthread-safety -fexperimental-late= -parse-attributes) + depends on CC_IS_CLANG && $(cc-option,-Wthread-safety -fexperimental-late= -parse-attributes --warning-suppression-mappings=3D/dev/null) # Branch profiling re-defines "if", which messes with the compiler's # ability to analyze __cond_acquires(..), resulting in false positives. depends on !TRACE_BRANCH_PROFILING @@ -619,6 +619,8 @@ config WARN_CAPABILITY_ANALYSIS the original name of the feature; it was later expanded to be a generic "Capability Analysis" framework. =20 + Requires Clang 20 or later. + Produces warnings by default. Select CONFIG_WERROR if you wish to turn these warnings into errors. =20 diff --git a/scripts/Makefile.capability-analysis b/scripts/Makefile.capabi= lity-analysis index b7b36cca47f4..2a3e493a9d06 100644 --- a/scripts/Makefile.capability-analysis +++ b/scripts/Makefile.capability-analysis @@ -4,4 +4,8 @@ capability-analysis-cflags :=3D -DWARN_CAPABILITY_ANALYSIS \ -fexperimental-late-parse-attributes -Wthread-safety \ $(call cc-option,-Wthread-safety-pointer) =20 +ifndef CONFIG_WARN_CAPABILITY_ANALYSIS_ALL +capability-analysis-cflags +=3D --warning-suppression-mappings=3D$(srctree= )/scripts/capability-analysis-suppression.txt +endif + export CFLAGS_CAPABILITY_ANALYSIS :=3D $(capability-analysis-cflags) diff --git a/scripts/capability-analysis-suppression.txt b/scripts/capabili= ty-analysis-suppression.txt new file mode 100644 index 000000000000..0a5392fee710 --- /dev/null +++ b/scripts/capability-analysis-suppression.txt @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# The suppressions file should only match common paths such as header file= s. +# For individual subsytems use Makefile directive CAPABILITY_ANALYSIS :=3D= [yn]. +# +# The suppressions are ignored when CONFIG_WARN_CAPABILITY_ANALYSIS_ALL is +# selected. + +[thread-safety] +src:*arch/*/include/* +src:*include/acpi/* +src:*include/asm-generic/* +src:*include/linux/* +src:*include/net/* + +# Opt-in headers: +src:*include/linux/bit_spinlock.h=3Demit +src:*include/linux/cleanup.h=3Demit +src:*include/linux/kref.h=3Demit +src:*include/linux/list*.h=3Demit +src:*include/linux/local_lock*.h=3Demit +src:*include/linux/lockdep.h=3Demit +src:*include/linux/mutex*.h=3Demit +src:*include/linux/rcupdate.h=3Demit +src:*include/linux/refcount.h=3Demit +src:*include/linux/rhashtable.h=3Demit +src:*include/linux/rwlock*.h=3Demit +src:*include/linux/rwsem.h=3Demit +src:*include/linux/seqlock*.h=3Demit +src:*include/linux/spinlock*.h=3Demit +src:*include/linux/srcu.h=3Demit +src:*include/linux/ww_mutex.h=3Demit --=20 2.48.1.711.g2feabab25a-goog From nobody Thu May 7 18:25:53 2026 Received: from mail-ed1-f74.google.com (mail-ed1-f74.google.com [209.85.208.74]) (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 DEA231FE45A for ; Tue, 4 Mar 2025 09:26:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080380; cv=none; b=cmA0qzYb8LXIpIRU53uRMHUxo1MrLOhtCkoFv5aW+oME0czSYzzBj76rN0WAXk9t5JBlnEsBnJIHSJ5TyzSd/eRTash57nzGLPXptjfnB1//MV5ZMvrPfPmTf4o6oqO9Y9QCll1UwpVzQZBUJ8tchx/7JPPFigVbyuasu4PTsH8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080380; c=relaxed/simple; bh=CbP/cw7Z2VthdUDfVeh49Wsig/SnKaWHlLpS8bXMfTo=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=UZIIoXrVPGGZr6KDFqiDHVDAW/cAeLEL4QOtbuwxYGXgadEu2ZelrmXsmfoje6R1WWdSUHMingHHOAFeQE+Y+trPXKaTHIeniRWgMmZS3i72v/z67x2Irtbccc3DMgMDCXADC3A4N0ZXmQYJIzgHd7QUAa3O/7BYXQBt12N9/4A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--elver.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=Zv51J4Ls; arc=none smtp.client-ip=209.85.208.74 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--elver.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="Zv51J4Ls" Received: by mail-ed1-f74.google.com with SMTP id 4fb4d7f45d1cf-5e073b9cf96so5202407a12.0 for ; Tue, 04 Mar 2025 01:26:18 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1741080377; x=1741685177; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=FyNUfkRqmSD94utdQtDIE/VXIceiBYCUysEEfDdchTw=; b=Zv51J4LsdO/UrZRTAqOhUu3Chnv0Xg5cTBfuVhoJ5ndv3cpB9RQE3gUiuOQW42Epb7 HFE+5Wjl6ByldrP5CZxWHEyBAPAUoXBBtwmXQHBH1c98/r5bR4R3+Ax3ROiHtiKZ+AUO Cw5jz7kJfdZxVWHhcprbJg/smUePni1hrp2MU34B/Vb8djrEjhCLu89WFT7IPJt1Ngbh BvKpKE/Hc9srnoFt9NHka7ih1Vm0XPUQNA0zA18hNOBvMW2qMlCx1t+PV47SW3AhU1lZ IjsBCCbXBFUobDOFk5dL2kpZ6wMpl6kSZBFgfn8peBxTpwZTK7lmuu6UGkC5dWcO2brA IOlA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741080377; x=1741685177; h=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; bh=FyNUfkRqmSD94utdQtDIE/VXIceiBYCUysEEfDdchTw=; b=h5LHt8CelkiD9yOMEeApqOB1M70ckanMBluhN4SsUvpR2LHhfE0F8JchncGRM+cW1k EOek0f+myq+qiG16I/GNo4NJDuFk2j8ca39hYuZ3+YVim/kSugqOGgVeQqb6REd7BHeZ RKyKPVSJyaumnH52aB8+O6qfD6L0XGXb9CUlWGikK4jC6r26xePVY33/xU2gCbfZ0XeI zcKHLpdHcOtH9RSEl5JLkfq6FQR06xdlSMZoMtxh2/5CttFKYUW+uLgXPp77JcTNJ4h9 dKTIPL5yQ4HD1sJBLgsSoUTIsl1CnmCTxGvzIe7hjiKv8avWYWUj8GeDGs0pbatZuXM8 dBVw== X-Forwarded-Encrypted: i=1; AJvYcCVK1doLHllcW1UO0+3f/MDde3E1wOBX+1k4ivlpHTTHp3SSvrC2hneKHJvhZHGTX7UN3bdwZVoYpoxmGbo=@vger.kernel.org X-Gm-Message-State: AOJu0YxztY0yavfmMfoldYraj+Ed7u1wEcbVv83vm6W+VGkGqt9Ux48t yqhnJHvigesLfAc8Ywj92dourJgkY/U7t1Lan9usN5s+zSpSseeoRhG0G+ISrogWDijiRKoYwg= = X-Google-Smtp-Source: AGHT+IEAtq0ynXlYVUKm7b+YYT0hATsqTi0dybAMTX9SWVkp0JEzQx1oEJXq2DXO8kDu8FGhuer7181naA== X-Received: from edb11.prod.google.com ([2002:a05:6402:238b:b0:5e5:339d:60ab]) (user=elver job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6402:274a:b0:5e4:c235:de10 with SMTP id 4fb4d7f45d1cf-5e4d6b7b21fmr14799795a12.32.1741080377028; Tue, 04 Mar 2025 01:26:17 -0800 (PST) Date: Tue, 4 Mar 2025 10:21:24 +0100 In-Reply-To: <20250304092417.2873893-1-elver@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250304092417.2873893-1-elver@google.com> X-Mailer: git-send-email 2.48.1.711.g2feabab25a-goog Message-ID: <20250304092417.2873893-26-elver@google.com> Subject: [PATCH v2 25/34] compiler: Let data_race() imply disabled capability analysis From: Marco Elver To: elver@google.com Cc: "David S. Miller" , Luc Van Oostenryck , "Paul E. McKenney" , Alexander Potapenko , Arnd Bergmann , Bart Van Assche , Bill Wendling , Boqun Feng , Dmitry Vyukov , Eric Dumazet , Frederic Weisbecker , Greg Kroah-Hartman , Herbert Xu , Ingo Molnar , Jann Horn , Jiri Slaby , Joel Fernandes , Jonathan Corbet , Josh Triplett , Justin Stitt , Kees Cook , Kentaro Takeda , Mark Rutland , Mathieu Desnoyers , Miguel Ojeda , Nathan Chancellor , Neeraj Upadhyay , Peter Zijlstra , Steven Rostedt , Tetsuo Handa , Thomas Gleixner , Uladzislau Rezki , Waiman Long , Will Deacon , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org, llvm@lists.linux.dev, rcu@vger.kernel.org, linux-crypto@vger.kernel.org, linux-serial@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Many patterns that involve data-racy accesses often deliberately ignore normal synchronization rules to avoid taking a lock. If we have a lock-guarded variable on which we do a lock-less data-racy access, rather than having to write capability_unsafe(data_race(..)), simply make the data_race(..) macro imply capability-unsafety. The data_race() macro already denotes the intent that something subtly unsafe is about to happen, so it should be clear enough as-is. Signed-off-by: Marco Elver --- v2: * New patch. --- include/linux/compiler.h | 2 ++ lib/test_capability-analysis.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 155385754824..c837464369df 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -186,7 +186,9 @@ void ftrace_likely_update(struct ftrace_likely_data *f,= int val, #define data_race(expr) \ ({ \ __kcsan_disable_current(); \ + disable_capability_analysis(); \ __auto_type __v =3D (expr); \ + enable_capability_analysis(); \ __kcsan_enable_current(); \ __v; \ }) diff --git a/lib/test_capability-analysis.c b/lib/test_capability-analysis.c index 853fdc53840f..13e7732c38a2 100644 --- a/lib/test_capability-analysis.c +++ b/lib/test_capability-analysis.c @@ -92,6 +92,8 @@ static void __used test_raw_spinlock_trylock_extra(struct= test_raw_spinlock_data { unsigned long flags; =20 + data_race(d->counter++); /* no warning */ + if (raw_spin_trylock_irq(&d->lock)) { d->counter++; raw_spin_unlock_irq(&d->lock); --=20 2.48.1.711.g2feabab25a-goog From nobody Thu May 7 18:25:53 2026 Received: from mail-ej1-f74.google.com (mail-ej1-f74.google.com [209.85.218.74]) (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 54A04204F86 for ; Tue, 4 Mar 2025 09:26:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080384; cv=none; b=CmOyuufjIGStyAC5oP8O9In+Uh8fNFbBgXd7xvGs0KREROoRWhsfWivh0F/jdI1QeZlNdJWEGCiTQobx9bfFR5fw4wlAimVnoRMm51nbYhduwWBJ1lIVW8AcvTEDoY/7T+equldOI15RfGdx2Xy1fL4ocG/sT2+rI/3xd/67roY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080384; c=relaxed/simple; bh=RHFHyf594SW/59vIAAifexB1oy6CG72gKKADr/HTL+M=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=p8de9r0o2fRYF7t648cEE0DIXC2F/BzMtQpGejPhT8QZ4ik/bybst5T6PDsP4ADx20RAMJbNoQMsNHKaY7zKhMNLlfKWIpfKTHCcKDtDGvYi7cZO+2b6sdFkjPp0lZJI7Ug6+EhACkdpr+CjojyBKtxqQH1tEFENpSpcA8MmQc0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--elver.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=ui23uomT; arc=none smtp.client-ip=209.85.218.74 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--elver.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="ui23uomT" Received: by mail-ej1-f74.google.com with SMTP id a640c23a62f3a-abf597afe1fso324490866b.1 for ; Tue, 04 Mar 2025 01:26:21 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1741080380; x=1741685180; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=3v8nr6j5ymgBv8KDTOp6L+lQpjYSKF+JE+VajMZf96I=; b=ui23uomTQRH5Irn1upMTy28efjrWGu2blSVGPnYwbbAFgaKq37ur+vsb0CDXlRpIEX WmcpsCaN7OdfPttvp8BEErBMOskMVdXS5TC5EmyuDICf9Fpp7GtB+jQdQMu5q4T9PSjV N8zuZusY7PvKkhciQ9CppnCaO13R9ac6YMiuEPyi+9HZCVN1Vqcfa8HcKwBJ6nU/1zrG 7WKxGHPHRAvESx7xFv/YKokGyIIVNxz9i0uz8J9YDQeUal78Y29a+M0heTWo6OSSbsHW FpRuKBND+P8Fm5KkkYazKgmPIUx8ETgEoGeZ8wqX84KNnOUXE4Gu6A4gD7C5migNtEXy eivA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741080380; x=1741685180; h=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; bh=3v8nr6j5ymgBv8KDTOp6L+lQpjYSKF+JE+VajMZf96I=; b=VgkKnyQb7HQXTBGhL+R/YCIcRekLCB4XoyjCS/OMPF5YaRp6icgTZ/jG7Ibr4lcbXD MzbgXvycJhtiZIaX2wzt0i11zacsfGNed2B51abDaFopKgBoNJitRKLb4ud7LxDum9iC +ZJR5APKOxxr9b1PQD9AVu1UKQGw12R/0dfhanIxOCJJma5e1FKAEAagaAPA00ZTJEHe KIK26Ri1yJec3QxvdAcefGup0TwgGPbYKCwZCXwDjZ/inelLDIfSMDFboJMdaCL5QtbQ n0J73CIhA/fopbyv/uOIiWO09HRNJ3gwP2xaDWf7vx8HFpZDXFNddZDiCftoND8owLFA Zsug== X-Forwarded-Encrypted: i=1; AJvYcCWaLmA7WP5bsjWFznkB4vWDj9JOZK99afoHALhKK4GEnhhpdmZjwcb89ERoRkPSDOmihs/cDy2J1opEQj4=@vger.kernel.org X-Gm-Message-State: AOJu0YxI6uNtnLlDivZjUk1WWlHQt34VAS9h6ELl+aBeQIJlakoyKss6 hQ5w+SOy3hJw0Sg/kKog05zLHTpYhDd1b2ri+wOVaEByJjcxlpnYCRIDlwgqH5mZ+ODqDtvBtw= = X-Google-Smtp-Source: AGHT+IEfigeOF/k7z7vk9qyF+DXgOFknckOxzZ17yq3U/m1fakPgh4OhR4E4S4uofnC24B3oKSKzOpTECQ== X-Received: from ejctb24.prod.google.com ([2002:a17:907:8b98:b0:ac1:4149:808d]) (user=elver job=prod-delivery.src-stubby-dispatcher) by 2002:a17:907:1ca2:b0:abf:5d9b:8076 with SMTP id a640c23a62f3a-abf5d9b8a4fmr1339937166b.33.1741080379689; Tue, 04 Mar 2025 01:26:19 -0800 (PST) Date: Tue, 4 Mar 2025 10:21:25 +0100 In-Reply-To: <20250304092417.2873893-1-elver@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250304092417.2873893-1-elver@google.com> X-Mailer: git-send-email 2.48.1.711.g2feabab25a-goog Message-ID: <20250304092417.2873893-27-elver@google.com> Subject: [PATCH v2 26/34] kfence: Enable capability analysis From: Marco Elver To: elver@google.com Cc: "David S. Miller" , Luc Van Oostenryck , "Paul E. McKenney" , Alexander Potapenko , Arnd Bergmann , Bart Van Assche , Bill Wendling , Boqun Feng , Dmitry Vyukov , Eric Dumazet , Frederic Weisbecker , Greg Kroah-Hartman , Herbert Xu , Ingo Molnar , Jann Horn , Jiri Slaby , Joel Fernandes , Jonathan Corbet , Josh Triplett , Justin Stitt , Kees Cook , Kentaro Takeda , Mark Rutland , Mathieu Desnoyers , Miguel Ojeda , Nathan Chancellor , Neeraj Upadhyay , Peter Zijlstra , Steven Rostedt , Tetsuo Handa , Thomas Gleixner , Uladzislau Rezki , Waiman Long , Will Deacon , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org, llvm@lists.linux.dev, rcu@vger.kernel.org, linux-crypto@vger.kernel.org, linux-serial@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Enable capability analysis for the KFENCE subsystem. Notable, kfence_handle_page_fault() required minor restructure, which also fixed a subtle race; arguably that function is more readable now. Signed-off-by: Marco Elver --- v2: * Remove disable/enable_capability_analysis() around headers. * Use __capability_unsafe() instead of __no_capability_analysis. --- mm/kfence/Makefile | 2 ++ mm/kfence/core.c | 20 +++++++++++++------- mm/kfence/kfence.h | 14 ++++++++------ mm/kfence/report.c | 4 ++-- 4 files changed, 25 insertions(+), 15 deletions(-) diff --git a/mm/kfence/Makefile b/mm/kfence/Makefile index 2de2a58d11a1..b3640bdc3c69 100644 --- a/mm/kfence/Makefile +++ b/mm/kfence/Makefile @@ -1,5 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 =20 +CAPABILITY_ANALYSIS :=3D y + obj-y :=3D core.o report.o =20 CFLAGS_kfence_test.o :=3D -fno-omit-frame-pointer -fno-optimize-sibling-ca= lls diff --git a/mm/kfence/core.c b/mm/kfence/core.c index 102048821c22..f75c3c11c0be 100644 --- a/mm/kfence/core.c +++ b/mm/kfence/core.c @@ -132,8 +132,8 @@ struct kfence_metadata *kfence_metadata __read_mostly; static struct kfence_metadata *kfence_metadata_init __read_mostly; =20 /* Freelist with available objects. */ -static struct list_head kfence_freelist =3D LIST_HEAD_INIT(kfence_freelist= ); -static DEFINE_RAW_SPINLOCK(kfence_freelist_lock); /* Lock protecting freel= ist. */ +DEFINE_RAW_SPINLOCK(kfence_freelist_lock); /* Lock protecting freelist. */ +static struct list_head kfence_freelist __guarded_by(&kfence_freelist_lock= ) =3D LIST_HEAD_INIT(kfence_freelist); =20 /* * The static key to set up a KFENCE allocation; or if static keys are not= used @@ -253,6 +253,7 @@ static bool kfence_unprotect(unsigned long addr) } =20 static inline unsigned long metadata_to_pageaddr(const struct kfence_metad= ata *meta) + __must_hold(&meta->lock) { unsigned long offset =3D (meta - kfence_metadata + 1) * PAGE_SIZE * 2; unsigned long pageaddr =3D (unsigned long)&__kfence_pool[offset]; @@ -288,6 +289,7 @@ static inline bool kfence_obj_allocated(const struct kf= ence_metadata *meta) static noinline void metadata_update_state(struct kfence_metadata *meta, enum kfence_object_sta= te next, unsigned long *stack_entries, size_t num_stack_entries) + __must_hold(&meta->lock) { struct kfence_track *track =3D next =3D=3D KFENCE_OBJECT_ALLOCATED ? &meta->alloc_track : &meta->free_t= rack; @@ -485,7 +487,7 @@ static void *kfence_guarded_alloc(struct kmem_cache *ca= che, size_t size, gfp_t g alloc_covered_add(alloc_stack_hash, 1); =20 /* Set required slab fields. */ - slab =3D virt_to_slab((void *)meta->addr); + slab =3D virt_to_slab(addr); slab->slab_cache =3D cache; slab->objects =3D 1; =20 @@ -514,6 +516,7 @@ static void *kfence_guarded_alloc(struct kmem_cache *ca= che, size_t size, gfp_t g static void kfence_guarded_free(void *addr, struct kfence_metadata *meta, = bool zombie) { struct kcsan_scoped_access assert_page_exclusive; + u32 alloc_stack_hash; unsigned long flags; bool init; =20 @@ -546,9 +549,10 @@ static void kfence_guarded_free(void *addr, struct kfe= nce_metadata *meta, bool z /* Mark the object as freed. */ metadata_update_state(meta, KFENCE_OBJECT_FREED, NULL, 0); init =3D slab_want_init_on_free(meta->cache); + alloc_stack_hash =3D meta->alloc_stack_hash; raw_spin_unlock_irqrestore(&meta->lock, flags); =20 - alloc_covered_add(meta->alloc_stack_hash, -1); + alloc_covered_add(alloc_stack_hash, -1); =20 /* Check canary bytes for memory corruption. */ check_canary(meta); @@ -593,6 +597,7 @@ static void rcu_guarded_free(struct rcu_head *h) * which partial initialization succeeded. */ static unsigned long kfence_init_pool(void) + __capability_unsafe(/* constructor */) { unsigned long addr; struct page *pages; @@ -1192,6 +1197,7 @@ bool kfence_handle_page_fault(unsigned long addr, boo= l is_write, struct pt_regs { const int page_index =3D (addr - (unsigned long)__kfence_pool) / PAGE_SIZ= E; struct kfence_metadata *to_report =3D NULL; + unsigned long unprotected_page =3D 0; enum kfence_error_type error_type; unsigned long flags; =20 @@ -1225,9 +1231,8 @@ bool kfence_handle_page_fault(unsigned long addr, boo= l is_write, struct pt_regs if (!to_report) goto out; =20 - raw_spin_lock_irqsave(&to_report->lock, flags); - to_report->unprotected_page =3D addr; error_type =3D KFENCE_ERROR_OOB; + unprotected_page =3D addr; =20 /* * If the object was freed before we took the look we can still @@ -1239,7 +1244,6 @@ bool kfence_handle_page_fault(unsigned long addr, boo= l is_write, struct pt_regs if (!to_report) goto out; =20 - raw_spin_lock_irqsave(&to_report->lock, flags); error_type =3D KFENCE_ERROR_UAF; /* * We may race with __kfence_alloc(), and it is possible that a @@ -1251,6 +1255,8 @@ bool kfence_handle_page_fault(unsigned long addr, boo= l is_write, struct pt_regs =20 out: if (to_report) { + raw_spin_lock_irqsave(&to_report->lock, flags); + to_report->unprotected_page =3D unprotected_page; kfence_report_error(addr, is_write, regs, to_report, error_type); raw_spin_unlock_irqrestore(&to_report->lock, flags); } else { diff --git a/mm/kfence/kfence.h b/mm/kfence/kfence.h index dfba5ea06b01..f9caea007246 100644 --- a/mm/kfence/kfence.h +++ b/mm/kfence/kfence.h @@ -34,6 +34,8 @@ /* Maximum stack depth for reports. */ #define KFENCE_STACK_DEPTH 64 =20 +extern raw_spinlock_t kfence_freelist_lock; + /* KFENCE object states. */ enum kfence_object_state { KFENCE_OBJECT_UNUSED, /* Object is unused. */ @@ -53,7 +55,7 @@ struct kfence_track { =20 /* KFENCE metadata per guarded allocation. */ struct kfence_metadata { - struct list_head list; /* Freelist node; access under kfence_freelist_lo= ck. */ + struct list_head list __guarded_by(&kfence_freelist_lock); /* Freelist no= de. */ struct rcu_head rcu_head; /* For delayed freeing. */ =20 /* @@ -91,13 +93,13 @@ struct kfence_metadata { * In case of an invalid access, the page that was unprotected; we * optimistically only store one address. */ - unsigned long unprotected_page; + unsigned long unprotected_page __guarded_by(&lock); =20 /* Allocation and free stack information. */ - struct kfence_track alloc_track; - struct kfence_track free_track; + struct kfence_track alloc_track __guarded_by(&lock); + struct kfence_track free_track __guarded_by(&lock); /* For updating alloc_covered on frees. */ - u32 alloc_stack_hash; + u32 alloc_stack_hash __guarded_by(&lock); #ifdef CONFIG_MEMCG struct slabobj_ext obj_exts; #endif @@ -141,6 +143,6 @@ enum kfence_error_type { void kfence_report_error(unsigned long address, bool is_write, struct pt_r= egs *regs, const struct kfence_metadata *meta, enum kfence_error_type type); =20 -void kfence_print_object(struct seq_file *seq, const struct kfence_metadat= a *meta); +void kfence_print_object(struct seq_file *seq, const struct kfence_metadat= a *meta) __must_hold(&meta->lock); =20 #endif /* MM_KFENCE_KFENCE_H */ diff --git a/mm/kfence/report.c b/mm/kfence/report.c index 10e6802a2edf..787e87c26926 100644 --- a/mm/kfence/report.c +++ b/mm/kfence/report.c @@ -106,6 +106,7 @@ static int get_stack_skipnr(const unsigned long stack_e= ntries[], int num_entries =20 static void kfence_print_stack(struct seq_file *seq, const struct kfence_m= etadata *meta, bool show_alloc) + __must_hold(&meta->lock) { const struct kfence_track *track =3D show_alloc ? &meta->alloc_track : &m= eta->free_track; u64 ts_sec =3D track->ts_nsec; @@ -207,8 +208,6 @@ void kfence_report_error(unsigned long address, bool is= _write, struct pt_regs *r if (WARN_ON(type !=3D KFENCE_ERROR_INVALID && !meta)) return; =20 - if (meta) - lockdep_assert_held(&meta->lock); /* * Because we may generate reports in printk-unfriendly parts of the * kernel, such as scheduler code, the use of printk() could deadlock. @@ -263,6 +262,7 @@ void kfence_report_error(unsigned long address, bool is= _write, struct pt_regs *r stack_trace_print(stack_entries + skipnr, num_stack_entries - skipnr, 0); =20 if (meta) { + lockdep_assert_held(&meta->lock); pr_err("\n"); kfence_print_object(NULL, meta); } --=20 2.48.1.711.g2feabab25a-goog From nobody Thu May 7 18:25:53 2026 Received: from mail-wr1-f73.google.com (mail-wr1-f73.google.com [209.85.221.73]) (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 D44872054F7 for ; Tue, 4 Mar 2025 09:26:23 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080386; cv=none; b=JsjEncMjDJcJxJ7n+2ciWrRolj87u1bFVcyLEYJehSA5XWsrbxH9LPxaGZT9l/4TP4I2wUu5bq6MyN6uQ/X69dNBnkcZJ5g1PIuVYA2SbHOjiXcDu+ZtInsl0Y+6KKOsJtVDfb/zuqBP8a2DZOChihYVB8tHHqwSVH3WtSMzeiU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080386; c=relaxed/simple; bh=2htcYMjN8BZSszolzHBrHxrGIk3u9M81dc+fK5u3tUQ=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=Jon07OSSNlzji6UeWcScnVh5aF3sORJOXYwZs22ltDIEhLZfzvPQ01FN5l6ohZBPSOKaa5XBM/7ZI6hYXokmZ7Adxvybv7axmqJ5Gpyl7aGM+u8N4hqVQ9lIMh2EE3R4qzsF1w8GB6eVpzNG4N9wi1k3oxcxPlmzAdF/iOyP1YY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--elver.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=YkpOU6rI; arc=none smtp.client-ip=209.85.221.73 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--elver.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="YkpOU6rI" Received: by mail-wr1-f73.google.com with SMTP id ffacd0b85a97d-390de58dc4eso5096080f8f.0 for ; Tue, 04 Mar 2025 01:26:23 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1741080382; x=1741685182; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=HvhGmPYbdkTfK7RRSri3eLNkf3gftCvKGp0dWVvi1U4=; b=YkpOU6rIQRE3T+9pGTQ/wYLR4rkDtgTFzzW/YjF+78WgFpHWaqpB2XUA+7jJAPya/R 7kln2V3uiucGr+JGhp0iVAvkcmqs+eUTZsubbdSLrr0Lw1bIkfPShJW1R2dn9kRTLvat zcs612pSt8kBc/4VAyKAkoMGx1e1jU+NuKg+S7mK8ZJEugRWyjrBeNZ8eleO4J6nCATU MoWKkTRar33kck5NqooyGrqbsLm8meGGcr2AY3z9XtYaFufrmu9P4t3OdLJ/9zS+Z51r Ss/IVH0TIBpDvrRrhnk+x32DYUOo434mae+wGHr3OEc9kgtEv6ly3EYspeKQOY/mzwBE P2/Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741080382; x=1741685182; h=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; bh=HvhGmPYbdkTfK7RRSri3eLNkf3gftCvKGp0dWVvi1U4=; b=Nh13mftoMg3o3TgJCPDCP4uIVKpvN+DyU6hpSQJIlBqciguFK8IsQTCVIvBbzgcXe9 gEt1TSvlXQUr3LV5C5EPPHXgOH2Y7Qxo+PtqRG4w+LEMF7MMe5RCJlkDcoxCFc7EYtcR bK4OZiGE3tgvOy9s2moe2QOtsq0wlmHEcgnkheafU0xm76HLt+E1zqNF7eKvyfrEC4aG ZYM5h70zKJJNcBD1O+knVD9ZWGMshOyDpqF3HBF1cruk7gBgdXcHl6Z5SfXZN3hBweZy vu2BUe1z0gFRIzzfZsytdKqO1/ptvJ8xhx+oZhB/pKvj7FVzSOg1cr841c/A8fwEGOzP geSg== X-Forwarded-Encrypted: i=1; AJvYcCUzuziwiBSEit2YKbcxmuqJ06h7gir8qxNHpBeWT7tRisL5JnEolJHLYr61HM6+9qo/lTurfmQK0PW4mrU=@vger.kernel.org X-Gm-Message-State: AOJu0YxW2YMd/NkjAfCr/RGl9sKOyG9hTN654vKbpGlmlTj4bEHppkcL Q3CUs8rUSQZBYBdZyIE7I0ZInPOzucAnln/YOgQsz9smWo8orRuRbOGzxqdMfGfuP8iZO+jBhQ= = X-Google-Smtp-Source: AGHT+IFd0j0x2Xkpv3SqARh0/vHgS2OMhe4sdLCWdo0+vG9QAhquZGGKS42LkEsCECdA5ZxT20Xn6/E70w== X-Received: from wmbg5.prod.google.com ([2002:a05:600c:a405:b0:43b:bf84:7e47]) (user=elver job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6000:400e:b0:391:1473:2a08 with SMTP id ffacd0b85a97d-39114732a3cmr2623360f8f.7.1741080382297; Tue, 04 Mar 2025 01:26:22 -0800 (PST) Date: Tue, 4 Mar 2025 10:21:26 +0100 In-Reply-To: <20250304092417.2873893-1-elver@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250304092417.2873893-1-elver@google.com> X-Mailer: git-send-email 2.48.1.711.g2feabab25a-goog Message-ID: <20250304092417.2873893-28-elver@google.com> Subject: [PATCH v2 27/34] kcov: Enable capability analysis From: Marco Elver To: elver@google.com Cc: "David S. Miller" , Luc Van Oostenryck , "Paul E. McKenney" , Alexander Potapenko , Arnd Bergmann , Bart Van Assche , Bill Wendling , Boqun Feng , Dmitry Vyukov , Eric Dumazet , Frederic Weisbecker , Greg Kroah-Hartman , Herbert Xu , Ingo Molnar , Jann Horn , Jiri Slaby , Joel Fernandes , Jonathan Corbet , Josh Triplett , Justin Stitt , Kees Cook , Kentaro Takeda , Mark Rutland , Mathieu Desnoyers , Miguel Ojeda , Nathan Chancellor , Neeraj Upadhyay , Peter Zijlstra , Steven Rostedt , Tetsuo Handa , Thomas Gleixner , Uladzislau Rezki , Waiman Long , Will Deacon , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org, llvm@lists.linux.dev, rcu@vger.kernel.org, linux-crypto@vger.kernel.org, linux-serial@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Enable capability analysis for the KCOV subsystem. Signed-off-by: Marco Elver --- v2: * Remove disable/enable_capability_analysis() around headers. --- kernel/Makefile | 2 ++ kernel/kcov.c | 36 +++++++++++++++++++++++++----------- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/kernel/Makefile b/kernel/Makefile index 87866b037fbe..7e399998532d 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -39,6 +39,8 @@ KASAN_SANITIZE_kcov.o :=3D n KCSAN_SANITIZE_kcov.o :=3D n UBSAN_SANITIZE_kcov.o :=3D n KMSAN_SANITIZE_kcov.o :=3D n + +CAPABILITY_ANALYSIS_kcov.o :=3D y CFLAGS_kcov.o :=3D $(call cc-option, -fno-conserve-stack) -fno-stack-prote= ctor =20 obj-y +=3D sched/ diff --git a/kernel/kcov.c b/kernel/kcov.c index 187ba1b80bda..9015f3b1e08a 100644 --- a/kernel/kcov.c +++ b/kernel/kcov.c @@ -55,13 +55,13 @@ struct kcov { refcount_t refcount; /* The lock protects mode, size, area and t. */ spinlock_t lock; - enum kcov_mode mode; + enum kcov_mode mode __guarded_by(&lock); /* Size of arena (in long's). */ - unsigned int size; + unsigned int size __guarded_by(&lock); /* Coverage buffer shared with user space. */ - void *area; + void *area __guarded_by(&lock); /* Task for which we collect coverage, or NULL. */ - struct task_struct *t; + struct task_struct *t __guarded_by(&lock); /* Collecting coverage from remote (background) threads. */ bool remote; /* Size of remote area (in long's). */ @@ -391,6 +391,7 @@ void kcov_task_init(struct task_struct *t) } =20 static void kcov_reset(struct kcov *kcov) + __must_hold(&kcov->lock) { kcov->t =3D NULL; kcov->mode =3D KCOV_MODE_INIT; @@ -400,6 +401,7 @@ static void kcov_reset(struct kcov *kcov) } =20 static void kcov_remote_reset(struct kcov *kcov) + __must_hold(&kcov->lock) { int bkt; struct kcov_remote *remote; @@ -419,6 +421,7 @@ static void kcov_remote_reset(struct kcov *kcov) } =20 static void kcov_disable(struct task_struct *t, struct kcov *kcov) + __must_hold(&kcov->lock) { kcov_task_reset(t); if (kcov->remote) @@ -435,8 +438,11 @@ static void kcov_get(struct kcov *kcov) static void kcov_put(struct kcov *kcov) { if (refcount_dec_and_test(&kcov->refcount)) { - kcov_remote_reset(kcov); - vfree(kcov->area); + /* Capability-safety: no references left, object being destroyed. */ + capability_unsafe( + kcov_remote_reset(kcov); + vfree(kcov->area); + ); kfree(kcov); } } @@ -491,6 +497,7 @@ static int kcov_mmap(struct file *filep, struct vm_area= _struct *vma) unsigned long size, off; struct page *page; unsigned long flags; + unsigned long *area; =20 spin_lock_irqsave(&kcov->lock, flags); size =3D kcov->size * sizeof(unsigned long); @@ -499,10 +506,11 @@ static int kcov_mmap(struct file *filep, struct vm_ar= ea_struct *vma) res =3D -EINVAL; goto exit; } + area =3D kcov->area; spin_unlock_irqrestore(&kcov->lock, flags); vm_flags_set(vma, VM_DONTEXPAND); for (off =3D 0; off < size; off +=3D PAGE_SIZE) { - page =3D vmalloc_to_page(kcov->area + off); + page =3D vmalloc_to_page(area + off); res =3D vm_insert_page(vma, vma->vm_start + off, page); if (res) { pr_warn_once("kcov: vm_insert_page() failed\n"); @@ -522,10 +530,10 @@ static int kcov_open(struct inode *inode, struct file= *filep) kcov =3D kzalloc(sizeof(*kcov), GFP_KERNEL); if (!kcov) return -ENOMEM; + spin_lock_init(&kcov->lock); kcov->mode =3D KCOV_MODE_DISABLED; kcov->sequence =3D 1; refcount_set(&kcov->refcount, 1); - spin_lock_init(&kcov->lock); filep->private_data =3D kcov; return nonseekable_open(inode, filep); } @@ -556,6 +564,7 @@ static int kcov_get_mode(unsigned long arg) * vmalloc fault handling path is instrumented. */ static void kcov_fault_in_area(struct kcov *kcov) + __must_hold(&kcov->lock) { unsigned long stride =3D PAGE_SIZE / sizeof(unsigned long); unsigned long *area =3D kcov->area; @@ -584,6 +593,7 @@ static inline bool kcov_check_handle(u64 handle, bool c= ommon_valid, =20 static int kcov_ioctl_locked(struct kcov *kcov, unsigned int cmd, unsigned long arg) + __must_hold(&kcov->lock) { struct task_struct *t; unsigned long flags, unused; @@ -814,6 +824,7 @@ static inline bool kcov_mode_enabled(unsigned int mode) } =20 static void kcov_remote_softirq_start(struct task_struct *t) + __must_hold(&kcov_percpu_data.lock) { struct kcov_percpu_data *data =3D this_cpu_ptr(&kcov_percpu_data); unsigned int mode; @@ -831,6 +842,7 @@ static void kcov_remote_softirq_start(struct task_struc= t *t) } =20 static void kcov_remote_softirq_stop(struct task_struct *t) + __must_hold(&kcov_percpu_data.lock) { struct kcov_percpu_data *data =3D this_cpu_ptr(&kcov_percpu_data); =20 @@ -896,10 +908,12 @@ void kcov_remote_start(u64 handle) /* Put in kcov_remote_stop(). */ kcov_get(kcov); /* - * Read kcov fields before unlock to prevent races with - * KCOV_DISABLE / kcov_remote_reset(). + * Read kcov fields before unlocking kcov_remote_lock to prevent races + * with KCOV_DISABLE and kcov_remote_reset(); cannot acquire kcov->lock + * here, because it might lead to deadlock given kcov_remote_lock is + * acquired _after_ kcov->lock elsewhere. */ - mode =3D kcov->mode; + mode =3D capability_unsafe(kcov->mode); sequence =3D kcov->sequence; if (in_task()) { size =3D kcov->remote_size; --=20 2.48.1.711.g2feabab25a-goog From nobody Thu May 7 18:25:53 2026 Received: from mail-ej1-f73.google.com (mail-ej1-f73.google.com [209.85.218.73]) (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 69B2020551C for ; Tue, 4 Mar 2025 09:26:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080388; cv=none; b=jyO7YfmN6qh0XA7clowFH38iqg01G00SvRQVnJRoUbVXvANmkcEUO349MnZJyUgy4uUAVVBVq6hjhFIA4LhtuDX8FZiJuGkEtqa2//nwI3b8ra3xdq/d6Lp4zdqWiI5hG0Kfbzc4LrbhhLcnzsyXReayhUOiC/jfOWL0SjS2k6g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080388; c=relaxed/simple; bh=AA8LaiOOwcSbUCgOuJPxceK60VVmqz78yjgxOe6a/xc=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=uJXV9dEc9Qmmo+hyHaQVGEhPYu/VUSIs5vfZGpoYebmtRyEsJpOpVGiFNGr9xhD845hKyAyQDK+GQbdMc+CogBwNobIhcfFEW8rrg8y9wAA57m1X1fwkVD08mTkQXJ00Cmbvz71/YqzwIviZwqgqDljgMej6XTX3LnwAVDHjXfg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--elver.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=pRxEYeg5; arc=none smtp.client-ip=209.85.218.73 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--elver.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="pRxEYeg5" Received: by mail-ej1-f73.google.com with SMTP id a640c23a62f3a-abf553044abso288200866b.3 for ; Tue, 04 Mar 2025 01:26:26 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1741080385; x=1741685185; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=OCbQJguuxExNh/1WWVSwShtOCrr3VVCLOHRvUq00gbI=; b=pRxEYeg5vrHpLCDBpOE0i+wuYu/dn7VBcKXnRbZukPD2yuJLjnJYnWDJ1CLrXXyaf1 hRl11uPydj7ZzkQGtA2h90bC7hhtR50ycdN33xvVZinMqspVPyA5oOmYKBI0frTU1A9x ghqanVRy4DmUnsSOQ/cSEY/7Bpg+l/Ks1vQJbLpOcgiwjYAwGBvkefG0wGP4WpFJn1Cu xwqyQAA3stIpf7VJXPsNHGJlVpK20kZRrqpPUMgLtgR4+b8wTpv7ayyIaPw9bLzGhcAx SxDjEyl+J7oL3ZeOj3I2JmLeb2XtsIOU9V+a1JX8bwhpiZm1qOtIRKvHD5KuTucYggY5 lMCw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741080385; x=1741685185; h=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; bh=OCbQJguuxExNh/1WWVSwShtOCrr3VVCLOHRvUq00gbI=; b=uuWFOrdUKaJHSeEAY6YF2GoRz/e19CWOb3E3Xqxt9/QdlPiQooo/RY2wwbFIZVhed9 ZAixkNsXI+zqKo5AhbACP++Z96XgAXAuCmFfv+xiddvDIQD9ZoCK0Q4Zy9nAEk+eXu28 v4/w3otCz3H8O2UmOSf8ijaP4qRb3PGxRsyzoHYYC4QBTKWdCqGq9Uch8bIZs6GSXtiM DhsNYw/0VUh5utt61eGUqOKK4z4AysXDt7AtoUI+CIN0AZHhNM7d8i9h8JOfVsX4vcqY w+ZOw9i+J1CEz8VJFIyTcFXiGGOqQwxCFTsTBeiMavf3cuD5MrSJbjtlN5aJMtKzHfs/ 2RDA== X-Forwarded-Encrypted: i=1; AJvYcCXR6XPl44x7YrcaLJwoi6EWdOBLnQDpkaWxQf3r0qdcUdKSSwCY6wCu/ldI9oJErZ5qh9RoWCYKZTH1EhI=@vger.kernel.org X-Gm-Message-State: AOJu0Yyqv3Td0CRV0zS5jeDCnoEtu+GcKpopRKL+2zGMar4+l+4QH/Hp q2qrFRIYgfG58JrsKUJweN1coh6Ksvl3VoQqVb6WqYZxUkomrVnmaKAM0MbtM3FUpI3FEWlb7A= = X-Google-Smtp-Source: AGHT+IElsv0b6BPDqEe7C+Jsk5RB6FSq2PE2ahKujenY2V0Uy7jmG9RZfhrNhYmr9XWSjfqUNV8ETxzUug== X-Received: from ejcwb15.prod.google.com ([2002:a17:907:d50f:b0:abf:740d:69f5]) (user=elver job=prod-delivery.src-stubby-dispatcher) by 2002:a17:907:1b26:b0:abb:c647:a4bf with SMTP id a640c23a62f3a-abf25faa163mr1968124666b.23.1741080385011; Tue, 04 Mar 2025 01:26:25 -0800 (PST) Date: Tue, 4 Mar 2025 10:21:27 +0100 In-Reply-To: <20250304092417.2873893-1-elver@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250304092417.2873893-1-elver@google.com> X-Mailer: git-send-email 2.48.1.711.g2feabab25a-goog Message-ID: <20250304092417.2873893-29-elver@google.com> Subject: [PATCH v2 28/34] stackdepot: Enable capability analysis From: Marco Elver To: elver@google.com Cc: "David S. Miller" , Luc Van Oostenryck , "Paul E. McKenney" , Alexander Potapenko , Arnd Bergmann , Bart Van Assche , Bill Wendling , Boqun Feng , Dmitry Vyukov , Eric Dumazet , Frederic Weisbecker , Greg Kroah-Hartman , Herbert Xu , Ingo Molnar , Jann Horn , Jiri Slaby , Joel Fernandes , Jonathan Corbet , Josh Triplett , Justin Stitt , Kees Cook , Kentaro Takeda , Mark Rutland , Mathieu Desnoyers , Miguel Ojeda , Nathan Chancellor , Neeraj Upadhyay , Peter Zijlstra , Steven Rostedt , Tetsuo Handa , Thomas Gleixner , Uladzislau Rezki , Waiman Long , Will Deacon , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org, llvm@lists.linux.dev, rcu@vger.kernel.org, linux-crypto@vger.kernel.org, linux-serial@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Enable capability analysis for stackdepot. Signed-off-by: Marco Elver --- v2: * Remove disable/enable_capability_analysis() around headers. --- lib/Makefile | 1 + lib/stackdepot.c | 20 ++++++++++++++------ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/lib/Makefile b/lib/Makefile index 1dbb59175eb0..f40ba93c9a94 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -270,6 +270,7 @@ obj-$(CONFIG_POLYNOMIAL) +=3D polynomial.o # Prevent the compiler from calling builtins like memcmp() or bcmp() from = this # file. CFLAGS_stackdepot.o +=3D -fno-builtin +CAPABILITY_ANALYSIS_stackdepot.o :=3D y obj-$(CONFIG_STACKDEPOT) +=3D stackdepot.o KASAN_SANITIZE_stackdepot.o :=3D n # In particular, instrumenting stackdepot.c with KMSAN will result in infi= nite diff --git a/lib/stackdepot.c b/lib/stackdepot.c index 245d5b416699..a8b6a49c9058 100644 --- a/lib/stackdepot.c +++ b/lib/stackdepot.c @@ -61,18 +61,18 @@ static unsigned int stack_bucket_number_order; /* Hash mask for indexing the table. */ static unsigned int stack_hash_mask; =20 +/* The lock must be held when performing pool or freelist modifications. */ +static DEFINE_RAW_SPINLOCK(pool_lock); /* Array of memory regions that store stack records. */ -static void *stack_pools[DEPOT_MAX_POOLS]; +static void *stack_pools[DEPOT_MAX_POOLS] __guarded_by(&pool_lock); /* Newly allocated pool that is not yet added to stack_pools. */ static void *new_pool; /* Number of pools in stack_pools. */ static int pools_num; /* Offset to the unused space in the currently used pool. */ -static size_t pool_offset =3D DEPOT_POOL_SIZE; +static size_t pool_offset __guarded_by(&pool_lock) =3D DEPOT_POOL_SIZE; /* Freelist of stack records within stack_pools. */ -static LIST_HEAD(free_stacks); -/* The lock must be held when performing pool or freelist modifications. */ -static DEFINE_RAW_SPINLOCK(pool_lock); +static __guarded_by(&pool_lock) LIST_HEAD(free_stacks); =20 /* Statistics counters for debugfs. */ enum depot_counter_id { @@ -242,6 +242,7 @@ EXPORT_SYMBOL_GPL(stack_depot_init); * Initializes new stack pool, and updates the list of pools. */ static bool depot_init_pool(void **prealloc) + __must_hold(&pool_lock) { lockdep_assert_held(&pool_lock); =20 @@ -289,6 +290,7 @@ static bool depot_init_pool(void **prealloc) =20 /* Keeps the preallocated memory to be used for a new stack depot pool. */ static void depot_keep_new_pool(void **prealloc) + __must_hold(&pool_lock) { lockdep_assert_held(&pool_lock); =20 @@ -308,6 +310,7 @@ static void depot_keep_new_pool(void **prealloc) * the current pre-allocation. */ static struct stack_record *depot_pop_free_pool(void **prealloc, size_t si= ze) + __must_hold(&pool_lock) { struct stack_record *stack; void *current_pool; @@ -342,6 +345,7 @@ static struct stack_record *depot_pop_free_pool(void **= prealloc, size_t size) =20 /* Try to find next free usable entry from the freelist. */ static struct stack_record *depot_pop_free(void) + __must_hold(&pool_lock) { struct stack_record *stack; =20 @@ -379,6 +383,7 @@ static inline size_t depot_stack_record_size(struct sta= ck_record *s, unsigned in /* Allocates a new stack in a stack depot pool. */ static struct stack_record * depot_alloc_stack(unsigned long *entries, unsigned int nr_entries, u32 has= h, depot_flags_t flags, void **prealloc) + __must_hold(&pool_lock) { struct stack_record *stack =3D NULL; size_t record_size; @@ -437,6 +442,7 @@ depot_alloc_stack(unsigned long *entries, unsigned int = nr_entries, u32 hash, dep } =20 static struct stack_record *depot_fetch_stack(depot_stack_handle_t handle) + __must_not_hold(&pool_lock) { const int pools_num_cached =3D READ_ONCE(pools_num); union handle_parts parts =3D { .handle =3D handle }; @@ -453,7 +459,8 @@ static struct stack_record *depot_fetch_stack(depot_sta= ck_handle_t handle) return NULL; } =20 - pool =3D stack_pools[pool_index]; + /* @pool_index either valid, or user passed in corrupted value. */ + pool =3D capability_unsafe(stack_pools[pool_index]); if (WARN_ON(!pool)) return NULL; =20 @@ -466,6 +473,7 @@ static struct stack_record *depot_fetch_stack(depot_sta= ck_handle_t handle) =20 /* Links stack into the freelist. */ static void depot_free_stack(struct stack_record *stack) + __must_not_hold(&pool_lock) { unsigned long flags; =20 --=20 2.48.1.711.g2feabab25a-goog From nobody Thu May 7 18:25:53 2026 Received: from mail-ej1-f74.google.com (mail-ej1-f74.google.com [209.85.218.74]) (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 34541204C11 for ; Tue, 4 Mar 2025 09:26:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080391; cv=none; b=Q4scm5rxwhGHTj/4XPIeMVBPWOZW98HPtyL3i7xgfstdoPCJMIknSUOmJbv7iSi5dHbbElKRT/QGdpPoRfJiqUQETv6xzDq3PTFfS5EmTE+v5pLZUJC8KejIbwf5whJ2GpDP5FM2/Q8Him2BtHBz0VoJm8CHKs63mlK+ado5Bd8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080391; c=relaxed/simple; bh=ny5w6oHqV2txpuQ0MsAltkXYUEne0mzXHdXbqKiPXa8=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=K6nNtF+ULNZYFjxX/r/EKVMtQaczt2akvgPlkj1RdKAC4xpQtPEgKbyAoayPbrqvaZQVKSqGfvb7aO1m9cXjSnQJyHI/QDft0ysXo0w/96M/v4q2DVrDEONO+QeQ+ARN1XnU/4TUR+wmsNtHCUHveLVHcP9MDYbcOVNYiRD8kcQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--elver.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=GzplkB5q; arc=none smtp.client-ip=209.85.218.74 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--elver.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="GzplkB5q" Received: by mail-ej1-f74.google.com with SMTP id a640c23a62f3a-abf59b0b274so242503166b.0 for ; Tue, 04 Mar 2025 01:26:28 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1741080387; x=1741685187; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=6Oslc0Vw7rD1eBm5IrdyoxIc7gTLsk2fVXwffC4VNN0=; b=GzplkB5qAmFjGkOm61CeLejKHxWb6fhAoVnp6Vk4t3OelyEVkbdlnlgnXOU2KzPOuk 3NGdQrknSOpmR/Tmywq+CCn5gqFVv1Tngg2qARQKwPmA5U3VZd1Ihe8vV7FIXxxy907S 8aklq5Oqbob0MpxvYjGrBRfcW3XbFptiPd1RaZrprSMx1gcFS0VNpav7Gfr8YFAGcLCe aCCAYdx+it2pCz0otT4bWO8TQsG9yx+MJ54Gjb5P+YYCeDoBBvKZSXS6iHxV7WQY9wd5 xWnGp21pnfRYBdSbFHrKp1rHDrH0IWSwem+YMGC7/ckiG0J2KQCRWvFeNm7EI5fN3QDd wlWQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741080387; x=1741685187; h=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; bh=6Oslc0Vw7rD1eBm5IrdyoxIc7gTLsk2fVXwffC4VNN0=; b=LVHpjJv1OfSNT1iUNALhEQ83EuGeiPFb5Y1+PaaTArG+CvS6sDUQshgdTpOoh/7UNY Kegu/qIUaSEzhtRpVTIgSbBeS/ZNRFvO5ed6Y+ubTYZFeDfGVw7nvPjAWKGQukGSBiTz DNdbrrR2zwRUHs8XftmHZMdRJhfRsYNH7xhXJwhgne+Rrs0aEe4q/iYwQCwVPq/zH8so NuOpWwhxubG0/R4/a6KnUnLIBFfutzVjzY7fDAD/p1zuA4ViRth6DCUoqwF7cie7XeTR zztRGz5jwOYTlXUwHwTeoEuTewSVkCfPzqsaD4cN3s8o5f65JkHP2TxOm63t0Fz1ucjl LSoQ== X-Forwarded-Encrypted: i=1; AJvYcCXwiMCf6UvjRfbNwSmUMIaB2Gq21Yyk8h9TZQpsLlE0AYHB3kDS9P4cK41VIXSW+G0xLlzKqFAahtqZo/k=@vger.kernel.org X-Gm-Message-State: AOJu0Yz7CbpB2hLPc4Mw6w+hUj8t6KfaUfWK6vQM5Rw6IK47A6gTxeYn kVIjhkbdmqL6j685Mxu7oAec4p2daLEOF8dzUpR5yOVbXYta+qcMwYk2klz53B8ZLxSWX+OUew= = X-Google-Smtp-Source: AGHT+IHtToTtakBuhP4/+sNMLQALzVHMJHtjC5HLCinrcP/6hbX3DMvKPBSJ238d92jV7XTaug7SYLQQPg== X-Received: from ejctb24.prod.google.com ([2002:a17:907:8b98:b0:ac1:4149:808d]) (user=elver job=prod-delivery.src-stubby-dispatcher) by 2002:a17:907:781:b0:abe:f6f5:93fa with SMTP id a640c23a62f3a-abf261d3b82mr1992742166b.33.1741080387611; Tue, 04 Mar 2025 01:26:27 -0800 (PST) Date: Tue, 4 Mar 2025 10:21:28 +0100 In-Reply-To: <20250304092417.2873893-1-elver@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250304092417.2873893-1-elver@google.com> X-Mailer: git-send-email 2.48.1.711.g2feabab25a-goog Message-ID: <20250304092417.2873893-30-elver@google.com> Subject: [PATCH v2 29/34] rhashtable: Enable capability analysis From: Marco Elver To: elver@google.com Cc: "David S. Miller" , Luc Van Oostenryck , "Paul E. McKenney" , Alexander Potapenko , Arnd Bergmann , Bart Van Assche , Bill Wendling , Boqun Feng , Dmitry Vyukov , Eric Dumazet , Frederic Weisbecker , Greg Kroah-Hartman , Herbert Xu , Ingo Molnar , Jann Horn , Jiri Slaby , Joel Fernandes , Jonathan Corbet , Josh Triplett , Justin Stitt , Kees Cook , Kentaro Takeda , Mark Rutland , Mathieu Desnoyers , Miguel Ojeda , Nathan Chancellor , Neeraj Upadhyay , Peter Zijlstra , Steven Rostedt , Tetsuo Handa , Thomas Gleixner , Uladzislau Rezki , Waiman Long , Will Deacon , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org, llvm@lists.linux.dev, rcu@vger.kernel.org, linux-crypto@vger.kernel.org, linux-serial@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Enable capability analysis for rhashtable, which was used as an initial test as it contains a combination of RCU, mutex, and bit_spinlock usage. Users of rhashtable now also benefit from annotations on the API, which will now warn if the RCU read lock is not held where required. Signed-off-by: Marco Elver --- v2: * Remove disable/enable_capability_analysis() around headers. --- include/linux/rhashtable.h | 14 +++++++++++--- lib/Makefile | 2 ++ lib/rhashtable.c | 5 +++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/include/linux/rhashtable.h b/include/linux/rhashtable.h index 8463a128e2f4..c6374691ccc7 100644 --- a/include/linux/rhashtable.h +++ b/include/linux/rhashtable.h @@ -245,16 +245,17 @@ void *rhashtable_insert_slow(struct rhashtable *ht, c= onst void *key, void rhashtable_walk_enter(struct rhashtable *ht, struct rhashtable_iter *iter); void rhashtable_walk_exit(struct rhashtable_iter *iter); -int rhashtable_walk_start_check(struct rhashtable_iter *iter) __acquires(R= CU); +int rhashtable_walk_start_check(struct rhashtable_iter *iter) __acquires_s= hared(RCU); =20 static inline void rhashtable_walk_start(struct rhashtable_iter *iter) + __acquires_shared(RCU) { (void)rhashtable_walk_start_check(iter); } =20 void *rhashtable_walk_next(struct rhashtable_iter *iter); void *rhashtable_walk_peek(struct rhashtable_iter *iter); -void rhashtable_walk_stop(struct rhashtable_iter *iter) __releases(RCU); +void rhashtable_walk_stop(struct rhashtable_iter *iter) __releases_shared(= RCU); =20 void rhashtable_free_and_destroy(struct rhashtable *ht, void (*free_fn)(void *ptr, void *arg), @@ -325,6 +326,7 @@ static inline struct rhash_lock_head __rcu **rht_bucket= _insert( =20 static inline unsigned long rht_lock(struct bucket_table *tbl, struct rhash_lock_head __rcu **bkt) + __acquires(__bitlock(0, bkt)) { unsigned long flags; =20 @@ -337,6 +339,7 @@ static inline unsigned long rht_lock(struct bucket_tabl= e *tbl, static inline unsigned long rht_lock_nested(struct bucket_table *tbl, struct rhash_lock_head __rcu **bucket, unsigned int subclass) + __acquires(__bitlock(0, bucket)) { unsigned long flags; =20 @@ -349,6 +352,7 @@ static inline unsigned long rht_lock_nested(struct buck= et_table *tbl, static inline void rht_unlock(struct bucket_table *tbl, struct rhash_lock_head __rcu **bkt, unsigned long flags) + __releases(__bitlock(0, bkt)) { lock_map_release(&tbl->dep_map); bit_spin_unlock(0, (unsigned long *)bkt); @@ -402,13 +406,14 @@ static inline void rht_assign_unlock(struct bucket_ta= ble *tbl, struct rhash_lock_head __rcu **bkt, struct rhash_head *obj, unsigned long flags) + __releases(__bitlock(0, bkt)) { if (rht_is_a_nulls(obj)) obj =3D NULL; lock_map_release(&tbl->dep_map); rcu_assign_pointer(*bkt, (void *)obj); preempt_enable(); - __release(bitlock); + __release(__bitlock(0, bkt)); local_irq_restore(flags); } =20 @@ -589,6 +594,7 @@ static inline int rhashtable_compare(struct rhashtable_= compare_arg *arg, static inline struct rhash_head *__rhashtable_lookup( struct rhashtable *ht, const void *key, const struct rhashtable_params params) + __must_hold_shared(RCU) { struct rhashtable_compare_arg arg =3D { .ht =3D ht, @@ -642,6 +648,7 @@ static inline struct rhash_head *__rhashtable_lookup( static inline void *rhashtable_lookup( struct rhashtable *ht, const void *key, const struct rhashtable_params params) + __must_hold_shared(RCU) { struct rhash_head *he =3D __rhashtable_lookup(ht, key, params); =20 @@ -692,6 +699,7 @@ static inline void *rhashtable_lookup_fast( static inline struct rhlist_head *rhltable_lookup( struct rhltable *hlt, const void *key, const struct rhashtable_params params) + __must_hold_shared(RCU) { struct rhash_head *he =3D __rhashtable_lookup(&hlt->ht, key, params); =20 diff --git a/lib/Makefile b/lib/Makefile index f40ba93c9a94..c7004270ad5f 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -45,6 +45,8 @@ lib-$(CONFIG_MIN_HEAP) +=3D min_heap.o lib-y +=3D kobject.o klist.o obj-y +=3D lockref.o =20 +CAPABILITY_ANALYSIS_rhashtable.o :=3D y + obj-y +=3D bcd.o sort.o parser.o debug_locks.o random32.o \ bust_spinlocks.o kasprintf.o bitmap.o scatterlist.o \ list_sort.o uuid.o iov_iter.o clz_ctz.o \ diff --git a/lib/rhashtable.c b/lib/rhashtable.c index 3e555d012ed6..fe8dd776837c 100644 --- a/lib/rhashtable.c +++ b/lib/rhashtable.c @@ -358,6 +358,7 @@ static int rhashtable_rehash_table(struct rhashtable *h= t) static int rhashtable_rehash_alloc(struct rhashtable *ht, struct bucket_table *old_tbl, unsigned int size) + __must_hold(&ht->mutex) { struct bucket_table *new_tbl; int err; @@ -392,6 +393,7 @@ static int rhashtable_rehash_alloc(struct rhashtable *h= t, * bucket locks or concurrent RCU protected lookups and traversals. */ static int rhashtable_shrink(struct rhashtable *ht) + __must_hold(&ht->mutex) { struct bucket_table *old_tbl =3D rht_dereference(ht->tbl, ht); unsigned int nelems =3D atomic_read(&ht->nelems); @@ -724,7 +726,7 @@ EXPORT_SYMBOL_GPL(rhashtable_walk_exit); * resize events and always continue. */ int rhashtable_walk_start_check(struct rhashtable_iter *iter) - __acquires(RCU) + __acquires_shared(RCU) { struct rhashtable *ht =3D iter->ht; bool rhlist =3D ht->rhlist; @@ -940,7 +942,6 @@ EXPORT_SYMBOL_GPL(rhashtable_walk_peek); * hash table. */ void rhashtable_walk_stop(struct rhashtable_iter *iter) - __releases(RCU) { struct rhashtable *ht; struct bucket_table *tbl =3D iter->walker.tbl; --=20 2.48.1.711.g2feabab25a-goog From nobody Thu May 7 18:25:53 2026 Received: from mail-ed1-f74.google.com (mail-ed1-f74.google.com [209.85.208.74]) (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 D51CE1FECB8 for ; Tue, 4 Mar 2025 09:26:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080393; cv=none; b=bgunMLghGHnlMPq/ID/m1mxbPa5tYeadw6PSwgnEixkkxgll8WtqVRNNCxja5PMM7ukYCE9rV8gE6r4bJ4pdYrr3u+iZcDyQOGss0wgq4cyYvRDCs0keamzTBEb1XXXi/+TywXz+JjYHmZZgAykBUNMvsNAlAxzBrpLwSZghnDQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080393; c=relaxed/simple; bh=KT6MN7tzMPolkJ3RDT2fCUl9mndACbg8ns1Ks1oaR0I=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=bsYGpGn0ijXrt6B3oVf5PNyui6PUlUEC26ovxeG0NVPW9MdxRy7J2QQABuQc5TagekZHhEnfLSDqI3svyTg7W+/xG8lCRvoTqwDL9IGspIhcCVJ7CuhJ1KwyU+7d8r6nzI60fDujp/M75hkDyZGCKTewzp2SUo8PHIzC1Zoh6FE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--elver.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=Y42Ex3nU; arc=none smtp.client-ip=209.85.208.74 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--elver.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="Y42Ex3nU" Received: by mail-ed1-f74.google.com with SMTP id 4fb4d7f45d1cf-5e55cf1e9b4so2192717a12.2 for ; Tue, 04 Mar 2025 01:26:31 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1741080390; x=1741685190; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=KzDuuuaiZX8v73IeozPshNFzU/FhGyeu9jS8KRsuYgk=; b=Y42Ex3nU0+QIXsSYWbd1ite56QAtrWpegRON8bJ9kK5QOGDKMxzVAUSN2PqjRiIrKD H/LMOxFM1kFUyFir4GtzVHxddqSHzf9y+5OugZrYl1FLXuV4S0QXO1A9qYIaio0m1WtW 1rjU3iNdV8GFme6mirZBxD+4stJrn56sIFNX1HBqmd66jDqI13Tpox2g+UA98wCqqfZx lgXvHzPb9JMKYtv3iNrl6+78E72fgGYvq28Qs5yh2X88rXH/Qd6nPWcDvZLZ9VELnmdw r79SqMeOqpqvdM15QHRw/ug7fzj7VhNset4ChezHaKeGpTQroAHudhsZ6fWc+gp1OA9s rBBw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741080390; x=1741685190; h=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; bh=KzDuuuaiZX8v73IeozPshNFzU/FhGyeu9jS8KRsuYgk=; b=OMFs54h2rW2S6WVjjwj7U9KPK601vKLy1kOKurVeGQ9agZjVe9HmMoD2PyDovc1xBc gSuNwPNetB59EHDiNVJsw7ysbfHHmY5YY6Ef2Sq8NXmSWv2xYQ/sfJSsfzWlyM057Kwu o07Q7hv/TIyBh40RcI8itlWFyc/Jy7LRZPv/sYdpz/BCkwWBUO7c3hwpjW7o7uMfJ7Vn xCg6Ei+McoF3YH+HBJ7zUeRgimdcAPYUEQE1HPYlu74efrVgJIzSakgKuyzlGPuF4qfj QEFfFdzgrXwQ7/tthL17wFj5Qhu3IapjSeP2mdFN13e58kbRlTKhWT/zNKwtsAyUn4gs uV7A== X-Forwarded-Encrypted: i=1; AJvYcCVVgDXYWsfDzJ1oX9ZJyC0n+u2Wr6MQ+flAr5W0GTp8vJbPJWVVvNQpPcoNHzUeEa4FWQmxblhsfBeZVbc=@vger.kernel.org X-Gm-Message-State: AOJu0Yyf3i9J9oViy2+/Fqst2ec+t2GRQW2Meot1ZkPSRCj2Tx1rgtEf pwMfzlfyR9CCLNooNtNsLzk+MlFqcDxEFq1TKHrJXHTBMNcINumtioMp3ipjg7n2/s6I2opYTA= = X-Google-Smtp-Source: AGHT+IH5l4jKYamySNyxcMXL4HKAIJ9GmtnPKrLPWykOQYXwmzxoLHo5g+W6i+hA1eMCWubxfVXujxm01Q== X-Received: from edbev11.prod.google.com ([2002:a05:6402:540b:b0:5e5:cbc:4d2c]) (user=elver job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6402:541b:b0:5de:4b81:d3fd with SMTP id 4fb4d7f45d1cf-5e4d6afa126mr17250877a12.13.1741080390194; Tue, 04 Mar 2025 01:26:30 -0800 (PST) Date: Tue, 4 Mar 2025 10:21:29 +0100 In-Reply-To: <20250304092417.2873893-1-elver@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250304092417.2873893-1-elver@google.com> X-Mailer: git-send-email 2.48.1.711.g2feabab25a-goog Message-ID: <20250304092417.2873893-31-elver@google.com> Subject: [PATCH v2 30/34] printk: Move locking annotation to printk.c From: Marco Elver To: elver@google.com Cc: "David S. Miller" , Luc Van Oostenryck , "Paul E. McKenney" , Alexander Potapenko , Arnd Bergmann , Bart Van Assche , Bill Wendling , Boqun Feng , Dmitry Vyukov , Eric Dumazet , Frederic Weisbecker , Greg Kroah-Hartman , Herbert Xu , Ingo Molnar , Jann Horn , Jiri Slaby , Joel Fernandes , Jonathan Corbet , Josh Triplett , Justin Stitt , Kees Cook , Kentaro Takeda , Mark Rutland , Mathieu Desnoyers , Miguel Ojeda , Nathan Chancellor , Neeraj Upadhyay , Peter Zijlstra , Steven Rostedt , Tetsuo Handa , Thomas Gleixner , Uladzislau Rezki , Waiman Long , Will Deacon , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org, llvm@lists.linux.dev, rcu@vger.kernel.org, linux-crypto@vger.kernel.org, linux-serial@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" With Sparse support gone, Clang is a bit more strict and warns: ./include/linux/console.h:492:50: error: use of undeclared identifier 'cons= ole_mutex' 492 | extern void console_list_unlock(void) __releases(console_mutex); Since it does not make sense to make console_mutex itself global, move the annotation to printk.c. Capability analysis remains disabled for printk.c. This is needed to enable capability analysis for modules that include . Signed-off-by: Marco Elver --- v2: * New patch. --- include/linux/console.h | 4 ++-- kernel/printk/printk.c | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/linux/console.h b/include/linux/console.h index eba367bf605d..51d2be96514a 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -488,8 +488,8 @@ static inline bool console_srcu_read_lock_is_held(void) extern int console_srcu_read_lock(void); extern void console_srcu_read_unlock(int cookie); =20 -extern void console_list_lock(void) __acquires(console_mutex); -extern void console_list_unlock(void) __releases(console_mutex); +extern void console_list_lock(void); +extern void console_list_unlock(void); =20 extern struct hlist_head console_list; =20 diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 07668433644b..377f21fd9bb4 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -244,6 +244,7 @@ int devkmsg_sysctl_set_loglvl(const struct ctl_table *t= able, int write, * For console list or console->flags updates */ void console_list_lock(void) + __acquires(&console_mutex) { /* * In unregister_console() and console_force_preferred_locked(), @@ -268,6 +269,7 @@ EXPORT_SYMBOL(console_list_lock); * Counterpart to console_list_lock() */ void console_list_unlock(void) + __releases(&console_mutex) { mutex_unlock(&console_mutex); } --=20 2.48.1.711.g2feabab25a-goog From nobody Thu May 7 18:25:53 2026 Received: from mail-ej1-f73.google.com (mail-ej1-f73.google.com [209.85.218.73]) (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 8DB43205E3F for ; Tue, 4 Mar 2025 09:26:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080398; cv=none; b=cBOkavwUvjjeitI/h2yi1objGJKN/pm0m9jNkisJWGYUpNIGtKusPymtHuVAdvWXeKmcg3IGgP4rDTK+54QsQDP6hNj2RvLGB+hynYh8hk1qkurqZmEjijnki4qrDXN4vBZ0nNdo6G7IAR7LqNgGm6wlqbCP+apSRY/A0ZYR/As= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080398; c=relaxed/simple; bh=b0CdiKYI8plcUd/5o7nrlhwn2YMDkb9s4S0Fm28UjnM=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=mE2MbuY5TyhAxWmO6Du5e3ErUSFJyyDnBsT9c2jNe0Z04AB5rOvYGnqThDu6Hva3X3VLUNyTbivuv5YKaCU2zUzboWk1mWJ0a0WBtrbYFaj0W8yJG1bOGMQywHbT+sDOCzVmNbuVNZv0hdwDMz/BoHNIpkwaU1lGqwyx9/dGsOE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--elver.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=heQ5cuwt; arc=none smtp.client-ip=209.85.218.73 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--elver.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="heQ5cuwt" Received: by mail-ej1-f73.google.com with SMTP id a640c23a62f3a-abf78df3bbcso209662466b.3 for ; Tue, 04 Mar 2025 01:26:34 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1741080393; x=1741685193; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=iDk2VwqwOTTMZfSkXTf6seWDq1RAdZgqLjXPZ94M0QA=; b=heQ5cuwtqNsaCbDQI3Bp69jGS6Sl55DcabORQxz3IFOlgNbGqROyexhO8EQYA6K11k ByLsbsNm10ys7wRMTWvw8EV3M42znUbPpMAwZB1Jl8dYOlPAeMuQaWTWgCGO+XLMYg+t Oe1KoOF39wGt1B3tX8ZDxuFaTjb35wDIAUtxRmS4e5PPRZJKluZHrjOD3zoWKcVQWTUo u0pMtXLUkww+kGiD3jc0aAMpZ95CkRYZWFpqoeKaLihqEXHKO1XFNXnWUV9bjbLW+Wcq yRf+AiE4MIcps+cPgek24bj3HfOtRbICnBdU9uMy/x8Uss+gz3S+Z4B3ellw6JB9U/Jg ZvMQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741080393; x=1741685193; h=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; bh=iDk2VwqwOTTMZfSkXTf6seWDq1RAdZgqLjXPZ94M0QA=; b=OV52kNJmvVzr2+VC+K9Y4tjj/DNhAOnSwUCrJ0SnQPj6Y9DaGIfmocq+WlAFUNCj2H 30G4JRM0jXbJE7jqcB4OtpVlUVGsGK55KgZptwKAXV8JBs6IzklnGjBuydD9eY/oxm8I tZ6LwFGLWEchLYlR5ObcqFOmDW3yVX1dUnHFRuLE1pf+15rQkaebG/grYCDVC5nNV52g IwPdRiln6FBSJ/DmqYvsu58tpvNvt4PLQbYHuH+JckNxXgLQt+ozEsUD1e2gWCnfHFUg lQiG7HGraIZvEKDqSkXuuClRqK6KM0U15XGh4izUY2CQ4IjiSCd8GifbcF7QCgjLIdII AWag== X-Forwarded-Encrypted: i=1; AJvYcCXQzNGWqxUQeafAUwNnd9/KGBIYEyA5F66Fo5IAS7I3Qchrf2PHkuJWSYm0vOxFY9eB4VIQsZYPYRcmygE=@vger.kernel.org X-Gm-Message-State: AOJu0YwAmBHiOF2Un/Tefd3l1Hn7WFbzxNWOQG4deVgCugXyGBR8SbzY 7xnNdP1Vohqki0DqCodTmTFcwDw6ke4JLkO6IStQtOoEnh3nmQZxC4iPznqEbZnWjwU3BDk/Uw= = X-Google-Smtp-Source: AGHT+IF8v9zLKhdVdDKTCEZYG8DbcGXKqxfAOcuUpH2RTtDLQJOOCxvLbiKCCrE4y5yhtpae3MqEZYbpjQ== X-Received: from ejcsn10.prod.google.com ([2002:a17:906:628a:b0:ac1:fb2a:4a65]) (user=elver job=prod-delivery.src-stubby-dispatcher) by 2002:a17:907:3e0f:b0:abf:718f:ef27 with SMTP id a640c23a62f3a-abf718ff14amr868693766b.1.1741080393090; Tue, 04 Mar 2025 01:26:33 -0800 (PST) Date: Tue, 4 Mar 2025 10:21:30 +0100 In-Reply-To: <20250304092417.2873893-1-elver@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250304092417.2873893-1-elver@google.com> X-Mailer: git-send-email 2.48.1.711.g2feabab25a-goog Message-ID: <20250304092417.2873893-32-elver@google.com> Subject: [PATCH v2 31/34] drivers/tty: Enable capability analysis for core files From: Marco Elver To: elver@google.com Cc: "David S. Miller" , Luc Van Oostenryck , "Paul E. McKenney" , Alexander Potapenko , Arnd Bergmann , Bart Van Assche , Bill Wendling , Boqun Feng , Dmitry Vyukov , Eric Dumazet , Frederic Weisbecker , Greg Kroah-Hartman , Herbert Xu , Ingo Molnar , Jann Horn , Jiri Slaby , Joel Fernandes , Jonathan Corbet , Josh Triplett , Justin Stitt , Kees Cook , Kentaro Takeda , Mark Rutland , Mathieu Desnoyers , Miguel Ojeda , Nathan Chancellor , Neeraj Upadhyay , Peter Zijlstra , Steven Rostedt , Tetsuo Handa , Thomas Gleixner , Uladzislau Rezki , Waiman Long , Will Deacon , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org, llvm@lists.linux.dev, rcu@vger.kernel.org, linux-crypto@vger.kernel.org, linux-serial@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Enable capability analysis for drivers/tty/*. This demonstrates a larger conversion to use Clang's capability analysis. The benefit is additional static checking of locking rules, along with better documentation. Signed-off-by: Marco Elver Cc: Greg Kroah-Hartman Cc: Jiri Slaby --- v2: * New patch. --- drivers/tty/Makefile | 3 +++ drivers/tty/n_tty.c | 16 ++++++++++++++++ drivers/tty/pty.c | 1 + drivers/tty/sysrq.c | 1 + drivers/tty/tty.h | 8 ++++---- drivers/tty/tty_buffer.c | 8 +++----- drivers/tty/tty_io.c | 12 +++++++++--- drivers/tty/tty_ioctl.c | 2 +- drivers/tty/tty_ldisc.c | 35 ++++++++++++++++++++++++++++++++--- drivers/tty/tty_ldsem.c | 2 ++ drivers/tty/tty_mutex.c | 4 ++++ drivers/tty/tty_port.c | 2 ++ include/linux/tty.h | 14 +++++++------- include/linux/tty_flip.h | 4 ++-- include/linux/tty_ldisc.h | 19 ++++++++++--------- 15 files changed, 97 insertions(+), 34 deletions(-) diff --git a/drivers/tty/Makefile b/drivers/tty/Makefile index 07aca5184a55..35e1a62cbe16 100644 --- a/drivers/tty/Makefile +++ b/drivers/tty/Makefile @@ -1,4 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 + +CAPABILITY_ANALYSIS :=3D y + obj-$(CONFIG_TTY) +=3D tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o \ tty_buffer.o tty_port.o tty_mutex.o \ tty_ldsem.o tty_baudrate.o tty_jobctrl.o \ diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 5e9ca4376d68..45925fc5a8fd 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -1088,6 +1088,7 @@ static void __isig(int sig, struct tty_struct *tty) * Locking: %ctrl.lock */ static void isig(int sig, struct tty_struct *tty) + __must_hold_shared(&tty->termios_rwsem) { struct n_tty_data *ldata =3D tty->disc_data; =20 @@ -1135,6 +1136,7 @@ static void isig(int sig, struct tty_struct *tty) * Note: may get exclusive %termios_rwsem if flushing input buffer */ static void n_tty_receive_break(struct tty_struct *tty) + __must_hold_shared(&tty->termios_rwsem) { struct n_tty_data *ldata =3D tty->disc_data; =20 @@ -1204,6 +1206,7 @@ static void n_tty_receive_parity_error(const struct t= ty_struct *tty, =20 static void n_tty_receive_signal_char(struct tty_struct *tty, int signal, u8 c) + __must_hold_shared(&tty->termios_rwsem) { isig(signal, tty); if (I_IXON(tty)) @@ -1353,6 +1356,7 @@ static bool n_tty_receive_char_canon(struct tty_struc= t *tty, u8 c) =20 static void n_tty_receive_char_special(struct tty_struct *tty, u8 c, bool lookahead_done) + __must_hold_shared(&tty->termios_rwsem) { struct n_tty_data *ldata =3D tty->disc_data; =20 @@ -1463,6 +1467,7 @@ static void n_tty_receive_char_closing(struct tty_str= uct *tty, u8 c, =20 static void n_tty_receive_char_flagged(struct tty_struct *tty, u8 c, u8 flag) + __must_hold_shared(&tty->termios_rwsem) { switch (flag) { case TTY_BREAK: @@ -1483,6 +1488,7 @@ n_tty_receive_char_flagged(struct tty_struct *tty, u8= c, u8 flag) =20 static void n_tty_receive_char_lnext(struct tty_struct *tty, u8 c, u8 flag) + __must_hold_shared(&tty->termios_rwsem) { struct n_tty_data *ldata =3D tty->disc_data; =20 @@ -1540,6 +1546,7 @@ n_tty_receive_buf_real_raw(const struct tty_struct *t= ty, const u8 *cp, static void n_tty_receive_buf_raw(struct tty_struct *tty, const u8 *cp, const u8 *fp, size_t count) + __must_hold_shared(&tty->termios_rwsem) { struct n_tty_data *ldata =3D tty->disc_data; u8 flag =3D TTY_NORMAL; @@ -1571,6 +1578,7 @@ n_tty_receive_buf_closing(struct tty_struct *tty, con= st u8 *cp, const u8 *fp, static void n_tty_receive_buf_standard(struct tty_struct *tty, const u8 *c= p, const u8 *fp, size_t count, bool lookahead_done) + __must_hold_shared(&tty->termios_rwsem) { struct n_tty_data *ldata =3D tty->disc_data; u8 flag =3D TTY_NORMAL; @@ -1609,6 +1617,7 @@ static void n_tty_receive_buf_standard(struct tty_str= uct *tty, const u8 *cp, =20 static void __receive_buf(struct tty_struct *tty, const u8 *cp, const u8 *= fp, size_t count) + __must_hold_shared(&tty->termios_rwsem) { struct n_tty_data *ldata =3D tty->disc_data; bool preops =3D I_ISTRIP(tty) || (I_IUCLC(tty) && L_IEXTEN(tty)); @@ -2188,6 +2197,10 @@ static ssize_t n_tty_read(struct tty_struct *tty, st= ruct file *file, u8 *kbuf, return kb - kbuf; } =20 + /* Adopted locks from prior call. */ + __acquire(&ldata->atomic_read_lock); + __acquire_shared(&tty->termios_rwsem); + /* No more data - release locks and stop retries */ n_tty_kick_worker(tty); n_tty_check_unthrottle(tty); @@ -2305,6 +2318,9 @@ static ssize_t n_tty_read(struct tty_struct *tty, str= uct file *file, u8 *kbuf, more_to_be_read: remove_wait_queue(&tty->read_wait, &wait); *cookie =3D cookie; + /* Hand-off locks to retry with cookie set. */ + __release_shared(&tty->termios_rwsem); + __release(&ldata->atomic_read_lock); return kb - kbuf; } } diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 8bb1a01fef2a..8d4eb0f4c84c 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -824,6 +824,7 @@ static int ptmx_open(struct inode *inode, struct file *= filp) tty =3D tty_init_dev(ptm_driver, index); /* The tty returned here is locked so we can safely drop the mutex */ + lockdep_assert_held(&tty->legacy_mutex); mutex_unlock(&tty_mutex); =20 retval =3D PTR_ERR(tty); diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index f85ce02e4725..82dfa964c965 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -149,6 +149,7 @@ static const struct sysrq_key_op sysrq_unraw_op =3D { static void sysrq_handle_crash(u8 key) { /* release the RCU read lock before crashing */ + lockdep_assert_in_rcu_read_lock(); rcu_read_unlock(); =20 panic("sysrq triggered crash\n"); diff --git a/drivers/tty/tty.h b/drivers/tty/tty.h index 93cf5ef1e857..1a3c2f663b28 100644 --- a/drivers/tty/tty.h +++ b/drivers/tty/tty.h @@ -60,15 +60,15 @@ static inline void tty_set_flow_change(struct tty_struc= t *tty, smp_mb(); } =20 -int tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout); -void tty_ldisc_unlock(struct tty_struct *tty); +int tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout) __cond_a= cquires(0, &tty->ldisc_sem); +void tty_ldisc_unlock(struct tty_struct *tty) __releases(&tty->ldisc_sem); =20 int __tty_check_change(struct tty_struct *tty, int sig); int tty_check_change(struct tty_struct *tty); void __stop_tty(struct tty_struct *tty); void __start_tty(struct tty_struct *tty); -void tty_write_unlock(struct tty_struct *tty); -int tty_write_lock(struct tty_struct *tty, bool ndelay); +void tty_write_unlock(struct tty_struct *tty) __releases(&tty->atomic_writ= e_lock); +int tty_write_lock(struct tty_struct *tty, bool ndelay) __cond_acquires(0,= &tty->atomic_write_lock); void tty_vhangup_session(struct tty_struct *tty); void tty_open_proc_set_tty(struct file *filp, struct tty_struct *tty); int tty_signal_session_leader(struct tty_struct *tty, int exit_session); diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 79f0ff94ce00..dcc56537290f 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -52,10 +52,8 @@ */ void tty_buffer_lock_exclusive(struct tty_port *port) { - struct tty_bufhead *buf =3D &port->buf; - - atomic_inc(&buf->priority); - mutex_lock(&buf->lock); + atomic_inc(&port->buf.priority); + mutex_lock(&port->buf.lock); } EXPORT_SYMBOL_GPL(tty_buffer_lock_exclusive); =20 @@ -73,7 +71,7 @@ void tty_buffer_unlock_exclusive(struct tty_port *port) bool restart =3D buf->head->commit !=3D buf->head->read; =20 atomic_dec(&buf->priority); - mutex_unlock(&buf->lock); + mutex_unlock(&port->buf.lock); =20 if (restart) queue_work(system_unbound_wq, &buf->work); diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 449dbd216460..1eb3794fde4b 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -167,6 +167,7 @@ static void release_tty(struct tty_struct *tty, int idx= ); * Locking: none. Must be called after tty is definitely unused */ static void free_tty_struct(struct tty_struct *tty) + __capability_unsafe(/* destructor */) { tty_ldisc_deinit(tty); put_device(tty->dev); @@ -965,7 +966,7 @@ static ssize_t iterate_tty_write(struct tty_ldisc *ld, = struct tty_struct *tty, ssize_t ret, written =3D 0; =20 ret =3D tty_write_lock(tty, file->f_flags & O_NDELAY); - if (ret < 0) + if (ret) return ret; =20 /* @@ -1154,7 +1155,7 @@ int tty_send_xchar(struct tty_struct *tty, u8 ch) return 0; } =20 - if (tty_write_lock(tty, false) < 0) + if (tty_write_lock(tty, false)) return -ERESTARTSYS; =20 down_read(&tty->termios_rwsem); @@ -1391,6 +1392,7 @@ static int tty_reopen(struct tty_struct *tty) * Return: new tty structure */ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx) + __capability_unsafe(/* returns with locked tty */) { struct tty_struct *tty; int retval; @@ -1874,6 +1876,7 @@ int tty_release(struct inode *inode, struct file *fil= p) * will not work then. It expects inodes to be from devpts FS. */ static struct tty_struct *tty_open_current_tty(dev_t device, struct file *= filp) + __capability_unsafe(/* returns with locked tty */) { struct tty_struct *tty; int retval; @@ -2037,6 +2040,7 @@ EXPORT_SYMBOL_GPL(tty_kopen_shared); */ static struct tty_struct *tty_open_by_driver(dev_t device, struct file *filp) + __capability_unsafe(/* returns with locked tty */) { struct tty_struct *tty; struct tty_driver *driver =3D NULL; @@ -2137,6 +2141,8 @@ static int tty_open(struct inode *inode, struct file = *filp) goto retry_open; } =20 + lockdep_assert_held(&tty->legacy_mutex); + tty_add_file(tty, filp); =20 check_tty_count(tty, __func__); @@ -2486,7 +2492,7 @@ static int send_break(struct tty_struct *tty, unsigne= d int duration) return tty->ops->break_ctl(tty, duration); =20 /* Do the work ourselves */ - if (tty_write_lock(tty, false) < 0) + if (tty_write_lock(tty, false)) return -EINTR; =20 retval =3D tty->ops->break_ctl(tty, -1); diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index 85de90eebc7b..a7ae6cbf3450 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c @@ -489,7 +489,7 @@ static int set_termios(struct tty_struct *tty, void __u= ser *arg, int opt) if (retval < 0) return retval; =20 - if (tty_write_lock(tty, false) < 0) + if (tty_write_lock(tty, false)) goto retry_write_wait; =20 /* Racing writer? */ diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index d80e9d4c974b..e07a5980604e 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -237,6 +237,7 @@ const struct seq_operations tty_ldiscs_seq_ops =3D { * to wait for any ldisc lifetime events to finish. */ struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty) + __cond_acquires_shared(nonnull, &tty->ldisc_sem) { struct tty_ldisc *ld; =20 @@ -257,6 +258,7 @@ EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait); * and timer functions. */ struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty) + __cond_acquires_shared(nonnull, &tty->ldisc_sem) { struct tty_ldisc *ld =3D NULL; =20 @@ -277,26 +279,43 @@ EXPORT_SYMBOL_GPL(tty_ldisc_ref); * in IRQ context. */ void tty_ldisc_deref(struct tty_ldisc *ld) + __releases_shared(&ld->tty->ldisc_sem) { ldsem_up_read(&ld->tty->ldisc_sem); } EXPORT_SYMBOL_GPL(tty_ldisc_deref); =20 +/* + * Note: Capability analysis does not like asymmetric interfaces (above ty= pes + * for ref and deref are tty_struct and tty_ldisc respectively -- which are + * dependent, but the compiler cannot figure that out); in this case, work + * around that with this helper which takes an unused @tty argument but te= lls + * the analysis which lock is released. + */ +static inline void __tty_ldisc_deref(struct tty_struct *tty, struct tty_ld= isc *ld) + __releases_shared(&tty->ldisc_sem) + __capability_unsafe(/* matches released with tty_ldisc_ref() */) +{ + tty_ldisc_deref(ld); +} =20 static inline int __tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout) + __cond_acquires(true, &tty->ldisc_sem) { return ldsem_down_write(&tty->ldisc_sem, timeout); } =20 static inline int __tty_ldisc_lock_nested(struct tty_struct *tty, unsigned long timeout) + __cond_acquires(true, &tty->ldisc_sem) { return ldsem_down_write_nested(&tty->ldisc_sem, LDISC_SEM_OTHER, timeout); } =20 static inline void __tty_ldisc_unlock(struct tty_struct *tty) + __releases(&tty->ldisc_sem) { ldsem_up_write(&tty->ldisc_sem); } @@ -328,6 +347,8 @@ void tty_ldisc_unlock(struct tty_struct *tty) static int tty_ldisc_lock_pair_timeout(struct tty_struct *tty, struct tty_struct *tty= 2, unsigned long timeout) + __cond_acquires(0, &tty->ldisc_sem) + __cond_acquires(0, &tty2->ldisc_sem) { int ret; =20 @@ -362,16 +383,23 @@ tty_ldisc_lock_pair_timeout(struct tty_struct *tty, s= truct tty_struct *tty2, } =20 static void tty_ldisc_lock_pair(struct tty_struct *tty, struct tty_struct = *tty2) + __acquires(&tty->ldisc_sem) + __acquires(&tty2->ldisc_sem) + __capability_unsafe(/* MAX_SCHEDULE_TIMEOUT ensures acquisition */) { tty_ldisc_lock_pair_timeout(tty, tty2, MAX_SCHEDULE_TIMEOUT); } =20 static void tty_ldisc_unlock_pair(struct tty_struct *tty, struct tty_struct *tty2) + __releases(&tty->ldisc_sem) + __releases(&tty2->ldisc_sem) { __tty_ldisc_unlock(tty); if (tty2) __tty_ldisc_unlock(tty2); + else + __release(&tty2->ldisc_sem); } =20 /** @@ -387,7 +415,7 @@ void tty_ldisc_flush(struct tty_struct *tty) =20 tty_buffer_flush(tty, ld); if (ld) - tty_ldisc_deref(ld); + __tty_ldisc_deref(tty, ld); } EXPORT_SYMBOL_GPL(tty_ldisc_flush); =20 @@ -694,7 +722,7 @@ void tty_ldisc_hangup(struct tty_struct *tty, bool rein= it) tty_ldisc_debug(tty, "%p: hangup\n", tty->ldisc); =20 ld =3D tty_ldisc_ref(tty); - if (ld !=3D NULL) { + if (ld) { if (ld->ops->flush_buffer) ld->ops->flush_buffer(tty); tty_driver_flush_buffer(tty); @@ -703,7 +731,7 @@ void tty_ldisc_hangup(struct tty_struct *tty, bool rein= it) ld->ops->write_wakeup(tty); if (ld->ops->hangup) ld->ops->hangup(tty); - tty_ldisc_deref(ld); + __tty_ldisc_deref(tty, ld); } =20 wake_up_interruptible_poll(&tty->write_wait, EPOLLOUT); @@ -716,6 +744,7 @@ void tty_ldisc_hangup(struct tty_struct *tty, bool rein= it) * Avoid racing set_ldisc or tty_ldisc_release */ tty_ldisc_lock(tty, MAX_SCHEDULE_TIMEOUT); + lockdep_assert_held_write(&tty->ldisc_sem); =20 if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) tty_reset_termios(tty); diff --git a/drivers/tty/tty_ldsem.c b/drivers/tty/tty_ldsem.c index 3be428c16260..26d924bb5a46 100644 --- a/drivers/tty/tty_ldsem.c +++ b/drivers/tty/tty_ldsem.c @@ -390,6 +390,7 @@ void ldsem_up_read(struct ld_semaphore *sem) { long count; =20 + __release_shared(sem); rwsem_release(&sem->dep_map, _RET_IP_); =20 count =3D atomic_long_add_return(-LDSEM_READ_BIAS, &sem->count); @@ -404,6 +405,7 @@ void ldsem_up_write(struct ld_semaphore *sem) { long count; =20 + __release(sem); rwsem_release(&sem->dep_map, _RET_IP_); =20 count =3D atomic_long_add_return(-LDSEM_WRITE_BIAS, &sem->count); diff --git a/drivers/tty/tty_mutex.c b/drivers/tty/tty_mutex.c index 784e46a0a3b1..e5576fd6f5a4 100644 --- a/drivers/tty/tty_mutex.c +++ b/drivers/tty/tty_mutex.c @@ -41,12 +41,16 @@ void tty_lock_slave(struct tty_struct *tty) { if (tty && tty !=3D tty->link) tty_lock(tty); + else + __acquire(&tty->legacy_mutex); } =20 void tty_unlock_slave(struct tty_struct *tty) { if (tty && tty !=3D tty->link) tty_unlock(tty); + else + __release(&tty->legacy_mutex); } =20 void tty_set_lock_subclass(struct tty_struct *tty) diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index 14cca33d2269..bcb65a26a6bf 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -509,6 +509,7 @@ EXPORT_SYMBOL(tty_port_lower_dtr_rts); */ int tty_port_block_til_ready(struct tty_port *port, struct tty_struct *tty, struct file *filp) + __must_hold(&tty->legacy_mutex) { int do_clocal =3D 0, retval; unsigned long flags; @@ -764,6 +765,7 @@ EXPORT_SYMBOL_GPL(tty_port_install); */ int tty_port_open(struct tty_port *port, struct tty_struct *tty, struct file *filp) + __must_hold(&tty->legacy_mutex) { spin_lock_irq(&port->lock); ++port->count; diff --git a/include/linux/tty.h b/include/linux/tty.h index 2372f9357240..ee1ba62fc398 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -234,8 +234,8 @@ struct tty_struct { void *disc_data; void *driver_data; spinlock_t files_lock; - int write_cnt; - u8 *write_buf; + int write_cnt __guarded_by(&atomic_write_lock); + u8 *write_buf __guarded_by(&atomic_write_lock); =20 struct list_head tty_files; =20 @@ -500,11 +500,11 @@ long vt_compat_ioctl(struct tty_struct *tty, unsigned= int cmd, =20 /* tty_mutex.c */ /* functions for preparation of BKL removal */ -void tty_lock(struct tty_struct *tty); -int tty_lock_interruptible(struct tty_struct *tty); -void tty_unlock(struct tty_struct *tty); -void tty_lock_slave(struct tty_struct *tty); -void tty_unlock_slave(struct tty_struct *tty); +void tty_lock(struct tty_struct *tty) __acquires(&tty->legacy_mutex); +int tty_lock_interruptible(struct tty_struct *tty) __cond_acquires(0, &tt= y->legacy_mutex); +void tty_unlock(struct tty_struct *tty) __releases(&tty->legacy_mutex); +void tty_lock_slave(struct tty_struct *tty) __acquires(&tty->legacy_mutex); +void tty_unlock_slave(struct tty_struct *tty) __releases(&tty->legacy_mute= x); void tty_set_lock_subclass(struct tty_struct *tty); =20 #endif diff --git a/include/linux/tty_flip.h b/include/linux/tty_flip.h index af4fce98f64e..2214714059f8 100644 --- a/include/linux/tty_flip.h +++ b/include/linux/tty_flip.h @@ -86,7 +86,7 @@ static inline size_t tty_insert_flip_string(struct tty_po= rt *port, size_t tty_ldisc_receive_buf(struct tty_ldisc *ld, const u8 *p, const u8 *= f, size_t count); =20 -void tty_buffer_lock_exclusive(struct tty_port *port); -void tty_buffer_unlock_exclusive(struct tty_port *port); +void tty_buffer_lock_exclusive(struct tty_port *port) __acquires(&port->bu= f.lock); +void tty_buffer_unlock_exclusive(struct tty_port *port) __releases(&port->= buf.lock); =20 #endif /* _LINUX_TTY_FLIP_H */ diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h index af01e89074b2..d834cf115d52 100644 --- a/include/linux/tty_ldisc.h +++ b/include/linux/tty_ldisc.h @@ -14,7 +14,7 @@ struct tty_struct; /* * the semaphore definition */ -struct ld_semaphore { +struct_with_capability(ld_semaphore) { atomic_long_t count; raw_spinlock_t wait_lock; unsigned int wait_readers; @@ -33,21 +33,22 @@ do { \ static struct lock_class_key __key; \ \ __init_ldsem((sem), #sem, &__key); \ + __assert_cap(sem); \ } while (0) =20 =20 -int ldsem_down_read(struct ld_semaphore *sem, long timeout); -int ldsem_down_read_trylock(struct ld_semaphore *sem); -int ldsem_down_write(struct ld_semaphore *sem, long timeout); -int ldsem_down_write_trylock(struct ld_semaphore *sem); -void ldsem_up_read(struct ld_semaphore *sem); -void ldsem_up_write(struct ld_semaphore *sem); +int ldsem_down_read(struct ld_semaphore *sem, long timeout) __cond_acquire= s_shared(true, sem); +int ldsem_down_read_trylock(struct ld_semaphore *sem) __cond_acquires_shar= ed(true, sem); +int ldsem_down_write(struct ld_semaphore *sem, long timeout) __cond_acquir= es(true, sem); +int ldsem_down_write_trylock(struct ld_semaphore *sem) __cond_acquires(tru= e, sem); +void ldsem_up_read(struct ld_semaphore *sem) __releases_shared(sem); +void ldsem_up_write(struct ld_semaphore *sem) __releases(sem); =20 #ifdef CONFIG_DEBUG_LOCK_ALLOC int ldsem_down_read_nested(struct ld_semaphore *sem, int subclass, - long timeout); + long timeout) __cond_acquires_shared(true, sem); int ldsem_down_write_nested(struct ld_semaphore *sem, int subclass, - long timeout); + long timeout) __cond_acquires(true, sem); #else # define ldsem_down_read_nested(sem, subclass, timeout) \ ldsem_down_read(sem, timeout) --=20 2.48.1.711.g2feabab25a-goog From nobody Thu May 7 18:25:53 2026 Received: from mail-wr1-f74.google.com (mail-wr1-f74.google.com [209.85.221.74]) (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 101192063E4 for ; Tue, 4 Mar 2025 09:26:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080400; cv=none; b=SffNFjJl65gO3VJUcfaOdbw+nHyWPMP5KJWFObVPkQyOrSFl4Jr5nKKxYY45yheY8+RJVRgxetU2kw+0lN+M48xCxVT6fJHlLvPgVk+uydag93s6ze+7ybfo0y1PALbM6gEDkRDM5f15Iz0ZjgvLPJPt9L9iDUtleMgQCMLVoIE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080400; c=relaxed/simple; bh=InxI4X+TbJ6TgT6LwD9hFJI6Ub0f0tb76jpiM6Xf9dE=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=WrP9hVWyT/N51E3OEBgn4Zyj+ATJf1+ZGxIUFjTXsDqrW7dN4UyFgOKFvnzyLIbWhHaImfnf5P0OeE++0r75JK4rnbqgcwhkCLt4MP32Jmd0owaiu/hQcuvO6rEYJUAdhoaEtEmntgnmkL/HUKF4aZKzrPWlXQT5LFxQlelS9xw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--elver.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=a8LwUNN5; arc=none smtp.client-ip=209.85.221.74 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--elver.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="a8LwUNN5" Received: by mail-wr1-f74.google.com with SMTP id ffacd0b85a97d-390eb06d920so4009505f8f.3 for ; Tue, 04 Mar 2025 01:26:36 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1741080395; x=1741685195; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=0TZMHeiGcug1Z1nRKjwzk3pJ4ZD+AmZ+4WkrJaQv32Y=; b=a8LwUNN5Ij/6kddp6n1Hd2UeOwiDI+C2iAHegxe3tdsoM3Tl/w/m2BSydy1pU5kd+6 mS5loYZeqdea4kUVRO8g2FqtZJMgJyYT3kWsGoNn7f9spmm8SwPMjrzKV7t9W+BxkHzt D337EXYmvpNftVrMRclXjlF217qsm5575J7spj/dH/GUb6hDHqEZxptiEV5Fb2QxLcP0 4DYz5E4BFLPh0ssEphUH6b1nnSX3dMAQzvDMPc8o8seU6/flun0wBcMidMIKzH4A0S4m KIgBLaL7R8SRaFz/Q15V8u+o2Kb0cXT1ZU6MYfpIfAsr1U4k99rgBCSVxp4fx2WgdepT iySw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741080395; x=1741685195; h=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; bh=0TZMHeiGcug1Z1nRKjwzk3pJ4ZD+AmZ+4WkrJaQv32Y=; b=sNQD/a3L5+eObKn4y67uw01Cnheh0fxpv0fqPNjpQuCpb/U6rTSAh+X2gg5HeG6ZHQ 29Og29N3wxBl6eA1mWw0lvJdiWev5un+w+gfyO80riuPRUZYRCHaWV05CZ3XYMlnzfIx wAcHWtNUn9nAHanlLU+AK5lFR0ABc53wJqE7w5G3JPZJloYPoL5e7Yyq+mRkjM0OZwRu NumhTsc5Ze5p5ps7ZKI/MPLUyZ1NPV83H/Vft+OyrtbpHmAXgNITRcBPzFdQ6p1jjbDE ncynZbiDoO46Z3iB6Sw4IyO+PzSGtm9C66qn1ng+CuSW4irbfgk+3yZk/XUyVQTA0kiN 1rKw== X-Forwarded-Encrypted: i=1; AJvYcCVAIB9BwY3MZkHMM9GLGEo2FjjrPofCDtc2EGPuaJwj1ogIK/LrkHQOa6IMEd/ZFuLSK7SCgClp7gB+NiQ=@vger.kernel.org X-Gm-Message-State: AOJu0YyKVDL6BSgpJZni8f1eF7GT4apDZAfAmvyey79KVjSHZrPZ6tEC zvgXkLBLp6nrcsBJ8mlR6NZngNGxnbibEwcDP9QtBv7U/Maqt+rG4aK2PkRBpBd0Abi1eUs70g= = X-Google-Smtp-Source: AGHT+IGtMpYS24OG5fwIbCCodkhDNQhxjLFPVoBKGOc7tlax2NShCCvfAmG2BEGn8vZPGcxdeVWRKH+RPw== X-Received: from wmpz17.prod.google.com ([2002:a05:600c:a11:b0:43b:cc0a:a2c6]) (user=elver job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6000:186b:b0:391:13d6:c9e5 with SMTP id ffacd0b85a97d-39113d6cc59mr3890950f8f.19.1741080395602; Tue, 04 Mar 2025 01:26:35 -0800 (PST) Date: Tue, 4 Mar 2025 10:21:31 +0100 In-Reply-To: <20250304092417.2873893-1-elver@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250304092417.2873893-1-elver@google.com> X-Mailer: git-send-email 2.48.1.711.g2feabab25a-goog Message-ID: <20250304092417.2873893-33-elver@google.com> Subject: [PATCH v2 32/34] security/tomoyo: Enable capability analysis From: Marco Elver To: elver@google.com Cc: "David S. Miller" , Luc Van Oostenryck , "Paul E. McKenney" , Alexander Potapenko , Arnd Bergmann , Bart Van Assche , Bill Wendling , Boqun Feng , Dmitry Vyukov , Eric Dumazet , Frederic Weisbecker , Greg Kroah-Hartman , Herbert Xu , Ingo Molnar , Jann Horn , Jiri Slaby , Joel Fernandes , Jonathan Corbet , Josh Triplett , Justin Stitt , Kees Cook , Kentaro Takeda , Mark Rutland , Mathieu Desnoyers , Miguel Ojeda , Nathan Chancellor , Neeraj Upadhyay , Peter Zijlstra , Steven Rostedt , Tetsuo Handa , Thomas Gleixner , Uladzislau Rezki , Waiman Long , Will Deacon , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org, llvm@lists.linux.dev, rcu@vger.kernel.org, linux-crypto@vger.kernel.org, linux-serial@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Enable capability analysis for security/tomoyo. This demonstrates a larger conversion to use Clang's capability analysis. The benefit is additional static checking of locking rules, along with better documentation. Tomoyo makes use of several synchronization primitives, yet its clear design made it relatively straightforward to enable capability analysis. One notable finding was: security/tomoyo/gc.c:664:20: error: reading variable 'write_buf' requires= holding mutex '&tomoyo_io_buffer::io_sem' 664 | is_write =3D head->write_buf !=3D NULL; For which Tetsuo writes: "Good catch. This should be data_race(), for tomoyo_write_control() might concurrently update head->write_buf from non-NULL to non-NULL with head->io_sem held." Signed-off-by: Marco Elver Cc: Kentaro Takeda Cc: Tetsuo Handa --- v2: * New patch. --- security/tomoyo/Makefile | 2 + security/tomoyo/common.c | 52 ++++++++++++++++++++++++-- security/tomoyo/common.h | 77 ++++++++++++++++++++------------------- security/tomoyo/domain.c | 1 + security/tomoyo/environ.c | 1 + security/tomoyo/file.c | 5 +++ security/tomoyo/gc.c | 28 ++++++++++---- security/tomoyo/mount.c | 2 + security/tomoyo/network.c | 3 ++ 9 files changed, 122 insertions(+), 49 deletions(-) diff --git a/security/tomoyo/Makefile b/security/tomoyo/Makefile index 55c67b9846a9..6b395ca4e3d2 100644 --- a/security/tomoyo/Makefile +++ b/security/tomoyo/Makefile @@ -1,4 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 +CAPABILITY_ANALYSIS :=3D y + obj-y =3D audit.o common.o condition.o domain.o environ.o file.o gc.o grou= p.o load_policy.o memory.o mount.o network.o realpath.o securityfs_if.o tom= oyo.o util.o =20 targets +=3D builtin-policy.h diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 0f78898bce09..fa9fd134c9cc 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c @@ -268,6 +268,7 @@ static void tomoyo_io_printf(struct tomoyo_io_buffer *h= ead, const char *fmt, */ static void tomoyo_io_printf(struct tomoyo_io_buffer *head, const char *fm= t, ...) + __must_hold(&head->io_sem) { va_list args; size_t len; @@ -416,8 +417,9 @@ static void tomoyo_print_name_union_quoted(struct tomoy= o_io_buffer *head, * * Returns nothing. */ -static void tomoyo_print_number_union_nospace -(struct tomoyo_io_buffer *head, const struct tomoyo_number_union *ptr) +static void +tomoyo_print_number_union_nospace(struct tomoyo_io_buffer *head, const str= uct tomoyo_number_union *ptr) + __must_hold(&head->io_sem) { if (ptr->group) { tomoyo_set_string(head, "@"); @@ -466,6 +468,7 @@ static void tomoyo_print_number_union_nospace */ static void tomoyo_print_number_union(struct tomoyo_io_buffer *head, const struct tomoyo_number_union *ptr) + __must_hold(&head->io_sem) { tomoyo_set_space(head); tomoyo_print_number_union_nospace(head, ptr); @@ -664,6 +667,7 @@ static int tomoyo_set_mode(char *name, const char *valu= e, * Returns 0 on success, negative value otherwise. */ static int tomoyo_write_profile(struct tomoyo_io_buffer *head) + __must_hold(&head->io_sem) { char *data =3D head->write_buf; unsigned int i; @@ -719,6 +723,7 @@ static int tomoyo_write_profile(struct tomoyo_io_buffer= *head) * Caller prints functionality's name. */ static void tomoyo_print_config(struct tomoyo_io_buffer *head, const u8 co= nfig) + __must_hold(&head->io_sem) { tomoyo_io_printf(head, "=3D{ mode=3D%s grant_log=3D%s reject_log=3D%s }\n= ", tomoyo_mode[config & 3], @@ -734,6 +739,7 @@ static void tomoyo_print_config(struct tomoyo_io_buffer= *head, const u8 config) * Returns nothing. */ static void tomoyo_read_profile(struct tomoyo_io_buffer *head) + __must_hold(&head->io_sem) { u8 index; struct tomoyo_policy_namespace *ns =3D @@ -852,6 +858,7 @@ static bool tomoyo_same_manager(const struct tomoyo_acl= _head *a, */ static int tomoyo_update_manager_entry(const char *manager, const bool is_delete) + __must_hold_shared(&tomoyo_ss) { struct tomoyo_manager e =3D { }; struct tomoyo_acl_param param =3D { @@ -883,6 +890,8 @@ static int tomoyo_update_manager_entry(const char *mana= ger, * Caller holds tomoyo_read_lock(). */ static int tomoyo_write_manager(struct tomoyo_io_buffer *head) + __must_hold_shared(&tomoyo_ss) + __must_hold(&head->io_sem) { char *data =3D head->write_buf; =20 @@ -901,6 +910,7 @@ static int tomoyo_write_manager(struct tomoyo_io_buffer= *head) * Caller holds tomoyo_read_lock(). */ static void tomoyo_read_manager(struct tomoyo_io_buffer *head) + __must_hold_shared(&tomoyo_ss) { if (head->r.eof) return; @@ -927,6 +937,7 @@ static void tomoyo_read_manager(struct tomoyo_io_buffer= *head) * Caller holds tomoyo_read_lock(). */ static bool tomoyo_manager(void) + __must_hold_shared(&tomoyo_ss) { struct tomoyo_manager *ptr; const char *exe; @@ -981,6 +992,8 @@ static struct tomoyo_domain_info *tomoyo_find_domain_by= _qid */ static bool tomoyo_select_domain(struct tomoyo_io_buffer *head, const char *data) + __must_hold_shared(&tomoyo_ss) + __must_hold(&head->io_sem) { unsigned int pid; struct tomoyo_domain_info *domain =3D NULL; @@ -1051,6 +1064,7 @@ static bool tomoyo_same_task_acl(const struct tomoyo_= acl_info *a, * Caller holds tomoyo_read_lock(). */ static int tomoyo_write_task(struct tomoyo_acl_param *param) + __must_hold_shared(&tomoyo_ss) { int error =3D -EINVAL; =20 @@ -1079,6 +1093,7 @@ static int tomoyo_write_task(struct tomoyo_acl_param = *param) * Caller holds tomoyo_read_lock(). */ static int tomoyo_delete_domain(char *domainname) + __must_hold_shared(&tomoyo_ss) { struct tomoyo_domain_info *domain; struct tomoyo_path_info name; @@ -1118,6 +1133,7 @@ static int tomoyo_delete_domain(char *domainname) static int tomoyo_write_domain2(struct tomoyo_policy_namespace *ns, struct list_head *list, char *data, const bool is_delete) + __must_hold_shared(&tomoyo_ss) { struct tomoyo_acl_param param =3D { .ns =3D ns, @@ -1162,6 +1178,8 @@ const char * const tomoyo_dif[TOMOYO_MAX_DOMAIN_INFO_= FLAGS] =3D { * Caller holds tomoyo_read_lock(). */ static int tomoyo_write_domain(struct tomoyo_io_buffer *head) + __must_hold_shared(&tomoyo_ss) + __must_hold(&head->io_sem) { char *data =3D head->write_buf; struct tomoyo_policy_namespace *ns; @@ -1223,6 +1241,7 @@ static int tomoyo_write_domain(struct tomoyo_io_buffe= r *head) */ static bool tomoyo_print_condition(struct tomoyo_io_buffer *head, const struct tomoyo_condition *cond) + __must_hold(&head->io_sem) { switch (head->r.cond_step) { case 0: @@ -1364,6 +1383,7 @@ static bool tomoyo_print_condition(struct tomoyo_io_b= uffer *head, */ static void tomoyo_set_group(struct tomoyo_io_buffer *head, const char *category) + __must_hold(&head->io_sem) { if (head->type =3D=3D TOMOYO_EXCEPTIONPOLICY) { tomoyo_print_namespace(head); @@ -1383,6 +1403,7 @@ static void tomoyo_set_group(struct tomoyo_io_buffer = *head, */ static bool tomoyo_print_entry(struct tomoyo_io_buffer *head, struct tomoyo_acl_info *acl) + __must_hold(&head->io_sem) { const u8 acl_type =3D acl->type; bool first =3D true; @@ -1588,6 +1609,8 @@ static bool tomoyo_print_entry(struct tomoyo_io_buffe= r *head, */ static bool tomoyo_read_domain2(struct tomoyo_io_buffer *head, struct list_head *list) + __must_hold_shared(&tomoyo_ss) + __must_hold(&head->io_sem) { list_for_each_cookie(head->r.acl, list) { struct tomoyo_acl_info *ptr =3D @@ -1608,6 +1631,8 @@ static bool tomoyo_read_domain2(struct tomoyo_io_buff= er *head, * Caller holds tomoyo_read_lock(). */ static void tomoyo_read_domain(struct tomoyo_io_buffer *head) + __must_hold_shared(&tomoyo_ss) + __must_hold(&head->io_sem) { if (head->r.eof) return; @@ -1686,6 +1711,7 @@ static int tomoyo_write_pid(struct tomoyo_io_buffer *= head) * using read()/write() interface rather than sysctl() interface. */ static void tomoyo_read_pid(struct tomoyo_io_buffer *head) + __must_hold(&head->io_sem) { char *buf =3D head->write_buf; bool global_pid =3D false; @@ -1746,6 +1772,8 @@ static const char *tomoyo_group_name[TOMOYO_MAX_GROUP= ] =3D { * Caller holds tomoyo_read_lock(). */ static int tomoyo_write_exception(struct tomoyo_io_buffer *head) + __must_hold_shared(&tomoyo_ss) + __must_hold(&head->io_sem) { const bool is_delete =3D head->w.is_delete; struct tomoyo_acl_param param =3D { @@ -1787,6 +1815,8 @@ static int tomoyo_write_exception(struct tomoyo_io_bu= ffer *head) * Caller holds tomoyo_read_lock(). */ static bool tomoyo_read_group(struct tomoyo_io_buffer *head, const int idx) + __must_hold_shared(&tomoyo_ss) + __must_hold(&head->io_sem) { struct tomoyo_policy_namespace *ns =3D container_of(head->r.ns, typeof(*ns), namespace_list); @@ -1846,6 +1876,7 @@ static bool tomoyo_read_group(struct tomoyo_io_buffer= *head, const int idx) * Caller holds tomoyo_read_lock(). */ static bool tomoyo_read_policy(struct tomoyo_io_buffer *head, const int id= x) + __must_hold_shared(&tomoyo_ss) { struct tomoyo_policy_namespace *ns =3D container_of(head->r.ns, typeof(*ns), namespace_list); @@ -1906,6 +1937,8 @@ static bool tomoyo_read_policy(struct tomoyo_io_buffe= r *head, const int idx) * Caller holds tomoyo_read_lock(). */ static void tomoyo_read_exception(struct tomoyo_io_buffer *head) + __must_hold_shared(&tomoyo_ss) + __must_hold(&head->io_sem) { struct tomoyo_policy_namespace *ns =3D container_of(head->r.ns, typeof(*ns), namespace_list); @@ -2097,6 +2130,7 @@ static void tomoyo_patternize_path(char *buffer, cons= t int len, char *entry) * Returns nothing. */ static void tomoyo_add_entry(struct tomoyo_domain_info *domain, char *head= er) + __must_hold_shared(&tomoyo_ss) { char *buffer; char *realpath =3D NULL; @@ -2301,6 +2335,7 @@ static __poll_t tomoyo_poll_query(struct file *file, = poll_table *wait) * @head: Pointer to "struct tomoyo_io_buffer". */ static void tomoyo_read_query(struct tomoyo_io_buffer *head) + __must_hold(&head->io_sem) { struct list_head *tmp; unsigned int pos =3D 0; @@ -2362,6 +2397,7 @@ static void tomoyo_read_query(struct tomoyo_io_buffer= *head) * Returns 0 on success, -EINVAL otherwise. */ static int tomoyo_write_answer(struct tomoyo_io_buffer *head) + __must_hold(&head->io_sem) { char *data =3D head->write_buf; struct list_head *tmp; @@ -2401,6 +2437,7 @@ static int tomoyo_write_answer(struct tomoyo_io_buffe= r *head) * Returns version information. */ static void tomoyo_read_version(struct tomoyo_io_buffer *head) + __must_hold(&head->io_sem) { if (!head->r.eof) { tomoyo_io_printf(head, "2.6.0"); @@ -2449,6 +2486,7 @@ void tomoyo_update_stat(const u8 index) * Returns nothing. */ static void tomoyo_read_stat(struct tomoyo_io_buffer *head) + __must_hold(&head->io_sem) { u8 i; unsigned int total =3D 0; @@ -2493,6 +2531,7 @@ static void tomoyo_read_stat(struct tomoyo_io_buffer = *head) * Returns 0. */ static int tomoyo_write_stat(struct tomoyo_io_buffer *head) + __must_hold(&head->io_sem) { char *data =3D head->write_buf; u8 i; @@ -2717,6 +2756,8 @@ ssize_t tomoyo_read_control(struct tomoyo_io_buffer *= head, char __user *buffer, * Caller holds tomoyo_read_lock(). */ static int tomoyo_parse_policy(struct tomoyo_io_buffer *head, char *line) + __must_hold_shared(&tomoyo_ss) + __must_hold(&head->io_sem) { /* Delete request? */ head->w.is_delete =3D !strncmp(line, "delete ", 7); @@ -2969,8 +3010,11 @@ void __init tomoyo_load_builtin_policy(void) break; *end =3D '\0'; tomoyo_normalize_line(start); - head.write_buf =3D start; - tomoyo_parse_policy(&head, start); + /* head is stack-local and not shared. */ + capability_unsafe( + head.write_buf =3D start; + tomoyo_parse_policy(&head, start); + ); start =3D end + 1; } } diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 0e8e2e959aef..2ff05653743c 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h @@ -827,13 +827,13 @@ struct tomoyo_io_buffer { bool is_delete; } w; /* Buffer for reading. */ - char *read_buf; + char *read_buf __guarded_by(&io_sem); /* Size of read buffer. */ - size_t readbuf_size; + size_t readbuf_size __guarded_by(&io_sem); /* Buffer for writing. */ - char *write_buf; + char *write_buf __guarded_by(&io_sem); /* Size of write buffer. */ - size_t writebuf_size; + size_t writebuf_size __guarded_by(&io_sem); /* Type of this interface. */ enum tomoyo_securityfs_interface_index type; /* Users counter protected by tomoyo_io_buffer_list_lock. */ @@ -922,6 +922,35 @@ struct tomoyo_task { struct tomoyo_domain_info *old_domain_info; }; =20 +/********** External variable definitions. **********/ + +extern bool tomoyo_policy_loaded; +extern int tomoyo_enabled; +extern const char * const tomoyo_condition_keyword +[TOMOYO_MAX_CONDITION_KEYWORD]; +extern const char * const tomoyo_dif[TOMOYO_MAX_DOMAIN_INFO_FLAGS]; +extern const char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX + + TOMOYO_MAX_MAC_CATEGORY_INDEX]; +extern const char * const tomoyo_mode[TOMOYO_CONFIG_MAX_MODE]; +extern const char * const tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION]; +extern const char * const tomoyo_proto_keyword[TOMOYO_SOCK_MAX]; +extern const char * const tomoyo_socket_keyword[TOMOYO_MAX_NETWORK_OPERATI= ON]; +extern const u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX]; +extern const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION]; +extern const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION]; +extern const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION]; +extern struct list_head tomoyo_condition_list; +extern struct list_head tomoyo_domain_list; +extern struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; +extern struct list_head tomoyo_namespace_list; +extern struct mutex tomoyo_policy_lock; +extern struct srcu_struct tomoyo_ss; +extern struct tomoyo_domain_info tomoyo_kernel_domain; +extern struct tomoyo_policy_namespace tomoyo_kernel_namespace; +extern unsigned int tomoyo_memory_quota[TOMOYO_MAX_MEMORY_STAT]; +extern unsigned int tomoyo_memory_used[TOMOYO_MAX_MEMORY_STAT]; +extern struct lsm_blob_sizes tomoyo_blob_sizes; + /********** Function prototypes. **********/ =20 bool tomoyo_address_matches_group(const bool is_ipv6, const __be32 *addres= s, @@ -969,10 +998,10 @@ const struct tomoyo_path_info *tomoyo_path_matches_gr= oup int tomoyo_check_open_permission(struct tomoyo_domain_info *domain, const struct path *path, const int flag); void tomoyo_close_control(struct tomoyo_io_buffer *head); -int tomoyo_env_perm(struct tomoyo_request_info *r, const char *env); +int tomoyo_env_perm(struct tomoyo_request_info *r, const char *env) __must= _hold_shared(&tomoyo_ss); int tomoyo_execute_permission(struct tomoyo_request_info *r, - const struct tomoyo_path_info *filename); -int tomoyo_find_next_domain(struct linux_binprm *bprm); + const struct tomoyo_path_info *filename) __must_hold_shared(&tomo= yo_ss); +int tomoyo_find_next_domain(struct linux_binprm *bprm) __must_hold_shared(= &tomoyo_ss); int tomoyo_get_mode(const struct tomoyo_policy_namespace *ns, const u8 pro= file, const u8 index); int tomoyo_init_request_info(struct tomoyo_request_info *r, @@ -1000,6 +1029,7 @@ int tomoyo_socket_listen_permission(struct socket *so= ck); int tomoyo_socket_sendmsg_permission(struct socket *sock, struct msghdr *m= sg, int size); int tomoyo_supervisor(struct tomoyo_request_info *r, const char *fmt, ...) + __must_hold_shared(&tomoyo_ss) __printf(2, 3); int tomoyo_update_domain(struct tomoyo_acl_info *new_entry, const int size, struct tomoyo_acl_param *param, @@ -1059,7 +1089,7 @@ void tomoyo_print_ulong(char *buffer, const int buffe= r_len, const unsigned long value, const u8 type); void tomoyo_put_name_union(struct tomoyo_name_union *ptr); void tomoyo_put_number_union(struct tomoyo_number_union *ptr); -void tomoyo_read_log(struct tomoyo_io_buffer *head); +void tomoyo_read_log(struct tomoyo_io_buffer *head) __must_hold(&head->io_= sem); void tomoyo_update_stat(const u8 index); void tomoyo_warn_oom(const char *function); void tomoyo_write_log(struct tomoyo_request_info *r, const char *fmt, ...) @@ -1067,35 +1097,6 @@ void tomoyo_write_log(struct tomoyo_request_info *r,= const char *fmt, ...) void tomoyo_write_log2(struct tomoyo_request_info *r, int len, const char = *fmt, va_list args) __printf(3, 0); =20 -/********** External variable definitions. **********/ - -extern bool tomoyo_policy_loaded; -extern int tomoyo_enabled; -extern const char * const tomoyo_condition_keyword -[TOMOYO_MAX_CONDITION_KEYWORD]; -extern const char * const tomoyo_dif[TOMOYO_MAX_DOMAIN_INFO_FLAGS]; -extern const char * const tomoyo_mac_keywords[TOMOYO_MAX_MAC_INDEX - + TOMOYO_MAX_MAC_CATEGORY_INDEX]; -extern const char * const tomoyo_mode[TOMOYO_CONFIG_MAX_MODE]; -extern const char * const tomoyo_path_keyword[TOMOYO_MAX_PATH_OPERATION]; -extern const char * const tomoyo_proto_keyword[TOMOYO_SOCK_MAX]; -extern const char * const tomoyo_socket_keyword[TOMOYO_MAX_NETWORK_OPERATI= ON]; -extern const u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX]; -extern const u8 tomoyo_pn2mac[TOMOYO_MAX_PATH_NUMBER_OPERATION]; -extern const u8 tomoyo_pnnn2mac[TOMOYO_MAX_MKDEV_OPERATION]; -extern const u8 tomoyo_pp2mac[TOMOYO_MAX_PATH2_OPERATION]; -extern struct list_head tomoyo_condition_list; -extern struct list_head tomoyo_domain_list; -extern struct list_head tomoyo_name_list[TOMOYO_MAX_HASH]; -extern struct list_head tomoyo_namespace_list; -extern struct mutex tomoyo_policy_lock; -extern struct srcu_struct tomoyo_ss; -extern struct tomoyo_domain_info tomoyo_kernel_domain; -extern struct tomoyo_policy_namespace tomoyo_kernel_namespace; -extern unsigned int tomoyo_memory_quota[TOMOYO_MAX_MEMORY_STAT]; -extern unsigned int tomoyo_memory_used[TOMOYO_MAX_MEMORY_STAT]; -extern struct lsm_blob_sizes tomoyo_blob_sizes; - /********** Inlined functions. **********/ =20 /** @@ -1104,6 +1105,7 @@ extern struct lsm_blob_sizes tomoyo_blob_sizes; * Returns index number for tomoyo_read_unlock(). */ static inline int tomoyo_read_lock(void) + __acquires_shared(&tomoyo_ss) { return srcu_read_lock(&tomoyo_ss); } @@ -1116,6 +1118,7 @@ static inline int tomoyo_read_lock(void) * Returns nothing. */ static inline void tomoyo_read_unlock(int idx) + __releases_shared(&tomoyo_ss) { srcu_read_unlock(&tomoyo_ss, idx); } diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 5f9ccab26e9a..5b7989ad85bf 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c @@ -611,6 +611,7 @@ struct tomoyo_domain_info *tomoyo_assign_domain(const c= har *domainname, * Returns 0 on success, negative value otherwise. */ static int tomoyo_environ(struct tomoyo_execve *ee) + __must_hold_shared(&tomoyo_ss) { struct tomoyo_request_info *r =3D &ee->r; struct linux_binprm *bprm =3D ee->bprm; diff --git a/security/tomoyo/environ.c b/security/tomoyo/environ.c index 7f0a471f19b2..bcb05910facc 100644 --- a/security/tomoyo/environ.c +++ b/security/tomoyo/environ.c @@ -32,6 +32,7 @@ static bool tomoyo_check_env_acl(struct tomoyo_request_in= fo *r, * Returns 0 on success, negative value otherwise. */ static int tomoyo_audit_env_log(struct tomoyo_request_info *r) + __must_hold_shared(&tomoyo_ss) { return tomoyo_supervisor(r, "misc env %s\n", r->param.environ.name->name); diff --git a/security/tomoyo/file.c b/security/tomoyo/file.c index 8f3b90b6e03d..e9b67dbb38e7 100644 --- a/security/tomoyo/file.c +++ b/security/tomoyo/file.c @@ -164,6 +164,7 @@ static bool tomoyo_get_realpath(struct tomoyo_path_info= *buf, const struct path * Returns 0 on success, negative value otherwise. */ static int tomoyo_audit_path_log(struct tomoyo_request_info *r) + __must_hold_shared(&tomoyo_ss) { return tomoyo_supervisor(r, "file %s %s\n", tomoyo_path_keyword [r->param.path.operation], @@ -178,6 +179,7 @@ static int tomoyo_audit_path_log(struct tomoyo_request_= info *r) * Returns 0 on success, negative value otherwise. */ static int tomoyo_audit_path2_log(struct tomoyo_request_info *r) + __must_hold_shared(&tomoyo_ss) { return tomoyo_supervisor(r, "file %s %s %s\n", tomoyo_mac_keywords [tomoyo_pp2mac[r->param.path2.operation]], @@ -193,6 +195,7 @@ static int tomoyo_audit_path2_log(struct tomoyo_request= _info *r) * Returns 0 on success, negative value otherwise. */ static int tomoyo_audit_mkdev_log(struct tomoyo_request_info *r) + __must_hold_shared(&tomoyo_ss) { return tomoyo_supervisor(r, "file %s %s 0%o %u %u\n", tomoyo_mac_keywords @@ -210,6 +213,7 @@ static int tomoyo_audit_mkdev_log(struct tomoyo_request= _info *r) * Returns 0 on success, negative value otherwise. */ static int tomoyo_audit_path_number_log(struct tomoyo_request_info *r) + __must_hold_shared(&tomoyo_ss) { const u8 type =3D r->param.path_number.operation; u8 radix; @@ -572,6 +576,7 @@ static int tomoyo_update_path2_acl(const u8 perm, */ static int tomoyo_path_permission(struct tomoyo_request_info *r, u8 operat= ion, const struct tomoyo_path_info *filename) + __must_hold_shared(&tomoyo_ss) { int error; =20 diff --git a/security/tomoyo/gc.c b/security/tomoyo/gc.c index 026e29ea3796..34912f120854 100644 --- a/security/tomoyo/gc.c +++ b/security/tomoyo/gc.c @@ -23,11 +23,10 @@ static inline void tomoyo_memory_free(void *ptr) tomoyo_memory_used[TOMOYO_MEMORY_POLICY] -=3D ksize(ptr); kfree(ptr); } - -/* The list for "struct tomoyo_io_buffer". */ -static LIST_HEAD(tomoyo_io_buffer_list); /* Lock for protecting tomoyo_io_buffer_list. */ static DEFINE_SPINLOCK(tomoyo_io_buffer_list_lock); +/* The list for "struct tomoyo_io_buffer". */ +static __guarded_by(&tomoyo_io_buffer_list_lock) LIST_HEAD(tomoyo_io_buffe= r_list); =20 /** * tomoyo_struct_used_by_io_buffer - Check whether the list element is use= d by /sys/kernel/security/tomoyo/ users or not. @@ -385,6 +384,7 @@ static inline void tomoyo_del_number_group(struct list_= head *element) */ static void tomoyo_try_to_gc(const enum tomoyo_policy_id type, struct list_head *element) + __must_hold(&tomoyo_policy_lock) { /* * __list_del_entry() guarantees that the list element became no longer @@ -484,6 +484,7 @@ static void tomoyo_try_to_gc(const enum tomoyo_policy_i= d type, */ static void tomoyo_collect_member(const enum tomoyo_policy_id id, struct list_head *member_list) + __must_hold(&tomoyo_policy_lock) { struct tomoyo_acl_head *member; struct tomoyo_acl_head *tmp; @@ -504,6 +505,7 @@ static void tomoyo_collect_member(const enum tomoyo_pol= icy_id id, * Returns nothing. */ static void tomoyo_collect_acl(struct list_head *list) + __must_hold(&tomoyo_policy_lock) { struct tomoyo_acl_info *acl; struct tomoyo_acl_info *tmp; @@ -627,8 +629,11 @@ static int tomoyo_gc_thread(void *unused) if (head->users) continue; list_del(&head->list); - kfree(head->read_buf); - kfree(head->write_buf); + /* Safe destruction because no users are left. */ + capability_unsafe( + kfree(head->read_buf); + kfree(head->write_buf); + ); kfree(head); } spin_unlock(&tomoyo_io_buffer_list_lock); @@ -656,11 +661,18 @@ void tomoyo_notify_gc(struct tomoyo_io_buffer *head, = const bool is_register) head->users =3D 1; list_add(&head->list, &tomoyo_io_buffer_list); } else { - is_write =3D head->write_buf !=3D NULL; + /* + * tomoyo_write_control() can concurrently update write_buf from + * a non-NULL to new non-NULL pointer with io_sem held. + */ + is_write =3D data_race(head->write_buf !=3D NULL); if (!--head->users) { list_del(&head->list); - kfree(head->read_buf); - kfree(head->write_buf); + /* Safe destruction because no users are left. */ + capability_unsafe( + kfree(head->read_buf); + kfree(head->write_buf); + ); kfree(head); } } diff --git a/security/tomoyo/mount.c b/security/tomoyo/mount.c index 2755971f50df..322dfd188ada 100644 --- a/security/tomoyo/mount.c +++ b/security/tomoyo/mount.c @@ -28,6 +28,7 @@ static const char * const tomoyo_mounts[TOMOYO_MAX_SPECIA= L_MOUNT] =3D { * Returns 0 on success, negative value otherwise. */ static int tomoyo_audit_mount_log(struct tomoyo_request_info *r) + __must_hold_shared(&tomoyo_ss) { return tomoyo_supervisor(r, "file mount %s %s %s 0x%lX\n", r->param.mount.dev->name, @@ -78,6 +79,7 @@ static int tomoyo_mount_acl(struct tomoyo_request_info *r, const char *dev_name, const struct path *dir, const char *type, unsigned long flags) + __must_hold_shared(&tomoyo_ss) { struct tomoyo_obj_info obj =3D { }; struct path path; diff --git a/security/tomoyo/network.c b/security/tomoyo/network.c index 8dc61335f65e..cfc2a019de1e 100644 --- a/security/tomoyo/network.c +++ b/security/tomoyo/network.c @@ -363,6 +363,7 @@ int tomoyo_write_unix_network(struct tomoyo_acl_param *= param) static int tomoyo_audit_net_log(struct tomoyo_request_info *r, const char *family, const u8 protocol, const u8 operation, const char *address) + __must_hold_shared(&tomoyo_ss) { return tomoyo_supervisor(r, "network %s %s %s %s\n", family, tomoyo_proto_keyword[protocol], @@ -377,6 +378,7 @@ static int tomoyo_audit_net_log(struct tomoyo_request_i= nfo *r, * Returns 0 on success, negative value otherwise. */ static int tomoyo_audit_inet_log(struct tomoyo_request_info *r) + __must_hold_shared(&tomoyo_ss) { char buf[128]; int len; @@ -402,6 +404,7 @@ static int tomoyo_audit_inet_log(struct tomoyo_request_= info *r) * Returns 0 on success, negative value otherwise. */ static int tomoyo_audit_unix_log(struct tomoyo_request_info *r) + __must_hold_shared(&tomoyo_ss) { return tomoyo_audit_net_log(r, "unix", r->param.unix_network.protocol, r->param.unix_network.operation, --=20 2.48.1.711.g2feabab25a-goog From nobody Thu May 7 18:25:53 2026 Received: from mail-ej1-f73.google.com (mail-ej1-f73.google.com [209.85.218.73]) (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 96F9C20010C for ; Tue, 4 Mar 2025 09:26:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080402; cv=none; b=eEA74KY0XO9tpnB/NeeuMMViAPia/Ql9rwSM4clHTq/kEZ5xaJQ0T35pvRCxcWSsSN93dY94Q3O9eAyRTeZ0zlEY1x+UgqkFBUcuvHT25vobPEhAYPIgAuuOQrz8YVywkzaj5mSghZe2Z/cJBOxvbsipmwUDhVYwN4JJePZSrbQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080402; c=relaxed/simple; bh=Mh+9JdRk90KetkZXttq6SxfLAoOSSno0nfwH9pudmzA=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=u6wZt/SapqWjUqQJAiDExNN1laOePmqIABmV0JcTViPgsE2PnhKgMLlwXjhaYjA/7EkhsNzkyy1o7QYQfaqdgvJpN/7T0uaQvtwvdzt/GSDDl+TmsiLu0G5QYFXa7j1Pdv642WyrhHFtbvlNSaYh/1hervdS9URlBkXs3L3EaiU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--elver.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=dn3EzAlo; arc=none smtp.client-ip=209.85.218.73 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--elver.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="dn3EzAlo" Received: by mail-ej1-f73.google.com with SMTP id a640c23a62f3a-abf4c4294b0so308425466b.0 for ; Tue, 04 Mar 2025 01:26:39 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1741080398; x=1741685198; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=N6cosU/aHEF331Tgbf58Vi03lqVulZKFB2l/GT8tm7Y=; b=dn3EzAlosTzHbBvhgMn3ZvES4EtnSHEKhfOwLRu5lIbUArNhBz7KIywGzdE3pv0s4u ShNskvRe5wx7fVAhiutKXrQUIhgxqumCsHibrqodQuNH0OHx2DeswLUfg8i+dSSqZtrP lYGf3qVd3KGIYBQx/gyRcQT0049KKpUEMdBwGhiPrFerPbUEVBqiszqqf1yMdEXZc5tu tf3vBDcxTaiMOCKVC+dcks+P+d60cCDfJEqxDK59mQ61pekGsmjmaW2inVuxzVYSpvIy tEVJ36XQOonqVLy6Dkd+hKazxt0+LJIOibW/wfBY4gfKqnkZWoO7Uk8XyJMRtG1F5f/a GJsQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741080398; x=1741685198; h=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; bh=N6cosU/aHEF331Tgbf58Vi03lqVulZKFB2l/GT8tm7Y=; b=Mzy6Q1SHJpoYaD2xaaM/U3+WE8vuEDLHcfMpoVrGv0bE6kGkaoYGvmXUjvCJH3DosB S33gep5pX8JtE+QMgySgCTou3xbv9U5m4aiMRlSFah90ci3Rs2vgATjxsvoEI9nQ0kFt 3oLKRWFavQoYlcixcWt3zp+v9sn2ZJMw/YyZPh0gzjCvJI8lXczavGrF3B4+WtXQa2ql jWvi/9Up8mtaE+MAAb5prOW2vpmAJFGN+5cq6XM6HDSoBAR+2vehLvr4AFUc2D8NrGjJ jPFO2LlelJ5AEq/wWBDIqqqm4MiK6S+STWQ4D6dzlB4knw7LPUN6f6IBAMfLuc0YxKIw XRBg== X-Forwarded-Encrypted: i=1; AJvYcCUoBvqLn4Yj2NDP3tWNaD4KkDHeLix6ld/9ziGu1HTdkKEyzZe9ml08MwFooIJo22uhWeO+Qw08R0wuIRY=@vger.kernel.org X-Gm-Message-State: AOJu0YyVsloBwvkImDDa0k4Lw/+HRwG3vaMqs/SGjI7CFo+iKlgX8RrY EDadsjNfmulHO/W6xdDb8NGs40mW5TVtAQGEDTxrJW5iKsv9xm/HzOgHgEgorVvCAhwJi47fwg= = X-Google-Smtp-Source: AGHT+IFpyuhMExDXeCwmdXSX22gTbHPs/JgCeV/PZoB6R3/aCXNcolqtoeQq/ql3Ce1MbHxHrlos3aOHkA== X-Received: from ejcvx9.prod.google.com ([2002:a17:907:a789:b0:ac1:fb2a:4a70]) (user=elver job=prod-delivery.src-stubby-dispatcher) by 2002:a17:907:3da3:b0:ac1:edc5:d73b with SMTP id a640c23a62f3a-ac1f0edc8c7mr225816966b.8.1741080398288; Tue, 04 Mar 2025 01:26:38 -0800 (PST) Date: Tue, 4 Mar 2025 10:21:32 +0100 In-Reply-To: <20250304092417.2873893-1-elver@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250304092417.2873893-1-elver@google.com> X-Mailer: git-send-email 2.48.1.711.g2feabab25a-goog Message-ID: <20250304092417.2873893-34-elver@google.com> Subject: [PATCH v2 33/34] crypto: Enable capability analysis From: Marco Elver To: elver@google.com Cc: "David S. Miller" , Luc Van Oostenryck , "Paul E. McKenney" , Alexander Potapenko , Arnd Bergmann , Bart Van Assche , Bill Wendling , Boqun Feng , Dmitry Vyukov , Eric Dumazet , Frederic Weisbecker , Greg Kroah-Hartman , Herbert Xu , Ingo Molnar , Jann Horn , Jiri Slaby , Joel Fernandes , Jonathan Corbet , Josh Triplett , Justin Stitt , Kees Cook , Kentaro Takeda , Mark Rutland , Mathieu Desnoyers , Miguel Ojeda , Nathan Chancellor , Neeraj Upadhyay , Peter Zijlstra , Steven Rostedt , Tetsuo Handa , Thomas Gleixner , Uladzislau Rezki , Waiman Long , Will Deacon , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org, llvm@lists.linux.dev, rcu@vger.kernel.org, linux-crypto@vger.kernel.org, linux-serial@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Enable capability analysis for crypto subsystem. This demonstrates a larger conversion to use Clang's capability analysis. The benefit is additional static checking of locking rules, along with better documentation. Signed-off-by: Marco Elver Cc: Herbert Xu Cc: "David S. Miller" Cc: linux-crypto@vger.kernel.org --- v2: * New patch. --- crypto/Makefile | 2 ++ crypto/algapi.c | 2 ++ crypto/api.c | 1 + crypto/crypto_engine.c | 2 +- crypto/drbg.c | 5 +++++ crypto/internal.h | 2 +- crypto/proc.c | 3 +++ crypto/scompress.c | 8 +++++--- include/crypto/internal/engine.h | 2 +- 9 files changed, 21 insertions(+), 6 deletions(-) diff --git a/crypto/Makefile b/crypto/Makefile index f67e853c4690..b7fa58ab8783 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -3,6 +3,8 @@ # Cryptographic API # =20 +CAPABILITY_ANALYSIS :=3D y + obj-$(CONFIG_CRYPTO) +=3D crypto.o crypto-y :=3D api.o cipher.o compress.o =20 diff --git a/crypto/algapi.c b/crypto/algapi.c index 5318c214debb..c2bafcde6f64 100644 --- a/crypto/algapi.c +++ b/crypto/algapi.c @@ -230,6 +230,7 @@ EXPORT_SYMBOL_GPL(crypto_remove_spawns); =20 static void crypto_alg_finish_registration(struct crypto_alg *alg, struct list_head *algs_to_put) + __must_hold(&crypto_alg_sem) { struct crypto_alg *q; =20 @@ -286,6 +287,7 @@ static struct crypto_larval *crypto_alloc_test_larval(s= truct crypto_alg *alg) =20 static struct crypto_larval * __crypto_register_alg(struct crypto_alg *alg, struct list_head *algs_to_pu= t) + __must_hold(&crypto_alg_sem) { struct crypto_alg *q; struct crypto_larval *larval; diff --git a/crypto/api.c b/crypto/api.c index bfd177a4313a..def3430ab332 100644 --- a/crypto/api.c +++ b/crypto/api.c @@ -57,6 +57,7 @@ EXPORT_SYMBOL_GPL(crypto_mod_put); =20 static struct crypto_alg *__crypto_alg_lookup(const char *name, u32 type, u32 mask) + __must_hold_shared(&crypto_alg_sem) { struct crypto_alg *q, *alg =3D NULL; int best =3D -2; diff --git a/crypto/crypto_engine.c b/crypto/crypto_engine.c index c7c16da5e649..4ab0bbc4c7ce 100644 --- a/crypto/crypto_engine.c +++ b/crypto/crypto_engine.c @@ -514,8 +514,8 @@ struct crypto_engine *crypto_engine_alloc_init_and_set(= struct device *dev, snprintf(engine->name, sizeof(engine->name), "%s-engine", dev_name(dev)); =20 - crypto_init_queue(&engine->queue, qlen); spin_lock_init(&engine->queue_lock); + crypto_init_queue(&engine->queue, qlen); =20 engine->kworker =3D kthread_run_worker(0, "%s", engine->name); if (IS_ERR(engine->kworker)) { diff --git a/crypto/drbg.c b/crypto/drbg.c index f28dfc2511a2..881579afa160 100644 --- a/crypto/drbg.c +++ b/crypto/drbg.c @@ -231,6 +231,7 @@ static inline unsigned short drbg_sec_strength(drbg_fla= g_t flags) */ static int drbg_fips_continuous_test(struct drbg_state *drbg, const unsigned char *entropy) + __must_hold(&drbg->drbg_mutex) { unsigned short entropylen =3D drbg_sec_strength(drbg->core->flags); int ret =3D 0; @@ -1061,6 +1062,7 @@ static inline int __drbg_seed(struct drbg_state *drbg= , struct list_head *seed, static inline int drbg_get_random_bytes(struct drbg_state *drbg, unsigned char *entropy, unsigned int entropylen) + __must_hold(&drbg->drbg_mutex) { int ret; =20 @@ -1075,6 +1077,7 @@ static inline int drbg_get_random_bytes(struct drbg_s= tate *drbg, } =20 static int drbg_seed_from_random(struct drbg_state *drbg) + __must_hold(&drbg->drbg_mutex) { struct drbg_string data; LIST_HEAD(seedlist); @@ -1132,6 +1135,7 @@ static bool drbg_nopr_reseed_interval_elapsed(struct = drbg_state *drbg) */ static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers, bool reseed) + __must_hold(&drbg->drbg_mutex) { int ret; unsigned char entropy[((32 + 16) * 2)]; @@ -1368,6 +1372,7 @@ static inline int drbg_alloc_state(struct drbg_state = *drbg) static int drbg_generate(struct drbg_state *drbg, unsigned char *buf, unsigned int buflen, struct drbg_string *addtl) + __must_hold(&drbg->drbg_mutex) { int len =3D 0; LIST_HEAD(addtllist); diff --git a/crypto/internal.h b/crypto/internal.h index 46b661be0f90..3ac76faf228b 100644 --- a/crypto/internal.h +++ b/crypto/internal.h @@ -45,8 +45,8 @@ enum { /* Maximum number of (rtattr) parameters for each template. */ #define CRYPTO_MAX_ATTRS 32 =20 -extern struct list_head crypto_alg_list; extern struct rw_semaphore crypto_alg_sem; +extern struct list_head crypto_alg_list __guarded_by(&crypto_alg_sem); extern struct blocking_notifier_head crypto_chain; =20 int alg_test(const char *driver, const char *alg, u32 type, u32 mask); diff --git a/crypto/proc.c b/crypto/proc.c index 522b27d90d29..4679eb6b81c9 100644 --- a/crypto/proc.c +++ b/crypto/proc.c @@ -19,17 +19,20 @@ #include "internal.h" =20 static void *c_start(struct seq_file *m, loff_t *pos) + __acquires_shared(&crypto_alg_sem) { down_read(&crypto_alg_sem); return seq_list_start(&crypto_alg_list, *pos); } =20 static void *c_next(struct seq_file *m, void *p, loff_t *pos) + __must_hold_shared(&crypto_alg_sem) { return seq_list_next(p, &crypto_alg_list, pos); } =20 static void c_stop(struct seq_file *m, void *p) + __releases_shared(&crypto_alg_sem) { up_read(&crypto_alg_sem); } diff --git a/crypto/scompress.c b/crypto/scompress.c index 1cef6bb06a81..0f24c84cc550 100644 --- a/crypto/scompress.c +++ b/crypto/scompress.c @@ -25,8 +25,8 @@ =20 struct scomp_scratch { spinlock_t lock; - void *src; - void *dst; + void *src __guarded_by(&lock); + void *dst __guarded_by(&lock); }; =20 static DEFINE_PER_CPU(struct scomp_scratch, scomp_scratch) =3D { @@ -34,8 +34,8 @@ static DEFINE_PER_CPU(struct scomp_scratch, scomp_scratch= ) =3D { }; =20 static const struct crypto_type crypto_scomp_type; -static int scomp_scratch_users; static DEFINE_MUTEX(scomp_lock); +static int scomp_scratch_users __guarded_by(&scomp_lock); =20 static int __maybe_unused crypto_scomp_report( struct sk_buff *skb, struct crypto_alg *alg) @@ -59,6 +59,7 @@ static void crypto_scomp_show(struct seq_file *m, struct = crypto_alg *alg) } =20 static void crypto_scomp_free_scratches(void) + __capability_unsafe(/* frees @scratch */) { struct scomp_scratch *scratch; int i; @@ -74,6 +75,7 @@ static void crypto_scomp_free_scratches(void) } =20 static int crypto_scomp_alloc_scratches(void) + __capability_unsafe(/* allocates @scratch */) { struct scomp_scratch *scratch; int i; diff --git a/include/crypto/internal/engine.h b/include/crypto/internal/eng= ine.h index fbf4be56cf12..10edbb451f1c 100644 --- a/include/crypto/internal/engine.h +++ b/include/crypto/internal/engine.h @@ -54,7 +54,7 @@ struct crypto_engine { =20 struct list_head list; spinlock_t queue_lock; - struct crypto_queue queue; + struct crypto_queue queue __guarded_by(&queue_lock); struct device *dev; =20 bool rt; --=20 2.48.1.711.g2feabab25a-goog From nobody Thu May 7 18:25:53 2026 Received: from mail-ej1-f74.google.com (mail-ej1-f74.google.com [209.85.218.74]) (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 44EAA2066C8 for ; Tue, 4 Mar 2025 09:26:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.218.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080404; cv=none; b=io+Qr4mgUkXF6S3qydyIBoObapz2Y9je1GtuhCY7eTLwP9Cv2UPl+UFcphko47D7EpRtNEnnjVv+dMkBWRGcyylB6mHfE30wzUXNNJF5kfJL6XdZIxFo1mgmnMlVYzIuNUfKcsRzS27J6nMQDAsio5bAKoAY6m12xr/OIj6xfD4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1741080404; c=relaxed/simple; bh=Pb5v8XeAHlUAdU8teJGT/joxk1D2UYCLbNbcthK7dEs=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=PgVOvvKiGrU/NXD99AUyVy/YuSrIIrDxon0e56YRMmzAr/+xr07QxjcBL7lhHzgTEimR3w128aa2i2WavObHuxeA+bbE4nOEU4gXLBdhYBH7xOMWbhQ1Lr0Aae61aTDZddQ3X6IFLSVvBLOUWmyyvqIV9NatQOBkhsRtgupdZ7s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--elver.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=eqTUwK1o; arc=none smtp.client-ip=209.85.218.74 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--elver.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="eqTUwK1o" Received: by mail-ej1-f74.google.com with SMTP id a640c23a62f3a-ac1fa7a5097so41985466b.0 for ; Tue, 04 Mar 2025 01:26:42 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1741080401; x=1741685201; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=Vumk0HTnchdldWRc8wT0cAdQjFLn1MfJ3/QC5i3Nw5Q=; b=eqTUwK1ozQnv7PEsQryrxWFaC4V9xB/TW/o9zIGwNoOmqD1aqBzj1JC3drB8erfo5p wb9Hcya48YEnC3EHpitzfauyVpJiyDwAjTkW/daucl+eHEuIIjalwWsm1eHbGLG41iBY fgOLwF1PUiBtNADhsW4nt4zwl4L9fZK7mVDl2u6cvVDikqbjK7EUyQ0urMTCNYbdQO/l mqJ3HSFwjdr5aYOsP9rBFQ2aUmj501MaDcxZzEinBfz8cG3OCcxAQ+XprkSAo44oY9iX hKf8OutnsPysfeip7QE/2XGG68KKvnfkU3eHfiHBF4Po/OzNJeU0hNWIO8btMtdG4k+R Li9w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1741080401; x=1741685201; h=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; bh=Vumk0HTnchdldWRc8wT0cAdQjFLn1MfJ3/QC5i3Nw5Q=; b=nDMy0gX7UHrwO/WBoQgzr12TjMjWY0xzXd9D2yu36PlPxKXvrSD5cdZrdOZSGTfqbF qQFnb7f6R6rHNYWH5uvusqE7ogxBfaoUaXKLTXCyCGK515OoWRd+oxhGuBJMsF+n2ivZ bhVsLeSb9tLcXDdyzYGP9t00RccjLy2mLbWpqH3kEiavB89SDxYYxVOh1BBQjRRiKw17 WaTmfMvMEVXEHm1BZgo2mtYVp0TdVOzBuzXgXSJaSAlHlSyzCc+tFFlzOlvn0Z3dDT56 4Lc6xbbsqOqs+SDGQvrjydA0+FI83SNEoXYQKXqYYaRTrMVGr0FYCWQn/tLXUVrAEgFo K6ug== X-Forwarded-Encrypted: i=1; AJvYcCVSLFkJD60V2HQ2hvM73DFKLA6l0BZ5QHW5Y6Wx7rVvFXu2X+JSBxGYs0yFiWDqDKE8DSuHcL6jDj2o6DU=@vger.kernel.org X-Gm-Message-State: AOJu0Yxhr/TaQ1mbBboIM9QC4wjuCJQ2+Z5heYaqvXGH/hijz2enEwnV ZtEMYHbxfdP64px8Pxm99e85z8K+YwP0wMJ++J52PtTluVg/t9zvOeRsuUCMNYIreJ9zNce9uQ= = X-Google-Smtp-Source: AGHT+IHe+2tTUNkWh4sjbCTVRn346FQZX3D8pl7o+PzR8CFWDsL38sKG72bCeLReMhyKEWhXvddJVO8sWw== X-Received: from ejckt25.prod.google.com ([2002:a17:907:9d19:b0:ac1:ed2c:ab54]) (user=elver job=prod-delivery.src-stubby-dispatcher) by 2002:a17:906:7fd6:b0:abf:46cd:5e3f with SMTP id a640c23a62f3a-abf46cd7414mr1245962366b.16.1741080400857; Tue, 04 Mar 2025 01:26:40 -0800 (PST) Date: Tue, 4 Mar 2025 10:21:33 +0100 In-Reply-To: <20250304092417.2873893-1-elver@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250304092417.2873893-1-elver@google.com> X-Mailer: git-send-email 2.48.1.711.g2feabab25a-goog Message-ID: <20250304092417.2873893-35-elver@google.com> Subject: [PATCH v2 34/34] MAINTAINERS: Add entry for Capability Analysis From: Marco Elver To: elver@google.com Cc: "David S. Miller" , Luc Van Oostenryck , "Paul E. McKenney" , Alexander Potapenko , Arnd Bergmann , Bart Van Assche , Bill Wendling , Boqun Feng , Dmitry Vyukov , Eric Dumazet , Frederic Weisbecker , Greg Kroah-Hartman , Herbert Xu , Ingo Molnar , Jann Horn , Jiri Slaby , Joel Fernandes , Jonathan Corbet , Josh Triplett , Justin Stitt , Kees Cook , Kentaro Takeda , Mark Rutland , Mathieu Desnoyers , Miguel Ojeda , Nathan Chancellor , Neeraj Upadhyay , Peter Zijlstra , Steven Rostedt , Tetsuo Handa , Thomas Gleixner , Uladzislau Rezki , Waiman Long , Will Deacon , kasan-dev@googlegroups.com, linux-kernel@vger.kernel.org, llvm@lists.linux.dev, rcu@vger.kernel.org, linux-crypto@vger.kernel.org, linux-serial@vger.kernel.org Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add entry for all new files added for Clang's capability analysis. Signed-off-by: Marco Elver Cc: Bart Van Assche Reviewed-by: Bart Van Assche --- MAINTAINERS | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 8e0736dc2ee0..cf9bf14f99b9 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5638,6 +5638,17 @@ M: Nelson Escobar S: Supported F: drivers/infiniband/hw/usnic/ =20 +CLANG CAPABILITY ANALYSIS +M: Marco Elver +R: Bart Van Assche +L: llvm@lists.linux.dev +S: Maintained +F: Documentation/dev-tools/capability-analysis.rst +F: include/linux/compiler-capability-analysis.h +F: lib/test_capability-analysis.c +F: scripts/Makefile.capability-analysis +F: scripts/capability-analysis-suppression.txt + CLANG CONTROL FLOW INTEGRITY SUPPORT M: Sami Tolvanen M: Kees Cook --=20 2.48.1.711.g2feabab25a-goog