Message ID | 20240113011145.10888-2-bpappas@pappasbrent.com |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel+bounces-25153-ouuuleilei=gmail.com@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:693c:2614:b0:101:6a76:bbe3 with SMTP id mm20csp540478dyc; Fri, 12 Jan 2024 17:22:51 -0800 (PST) X-Google-Smtp-Source: AGHT+IGU8WHYIUpoO1JCvZy0UWyO20xgPSkwUpLigXJBKhCssA1cdhKu4VyLT7g4vnzv02GNLUnd X-Received: by 2002:a17:902:ce81:b0:1d4:e0ea:f760 with SMTP id f1-20020a170902ce8100b001d4e0eaf760mr1770201plg.103.1705108971411; Fri, 12 Jan 2024 17:22:51 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1705108971; cv=none; d=google.com; s=arc-20160816; b=P+pPLVbRAJ25SGB+akjliejWWlqIiFgP87PmHnV5R677H3ORD7LS/TJVU89McQy0MZ rQVfjAjcCxRQ0oyCVY9QjMgD8U5Bcgz4su5/6+3KRt9Wo63C04rid3r7V6W3l+RbpDeB sJzs0YmtF2lTfuDUvcNM7UT/Us6OC8wDrnxN4wnfTZNmGlu5UkLZ2y7Hto03GlUQzb3P mR3dE4m0eey0zEJdyUyNke0OAKcewefK0Na0RjqUYLhTypN4ZQPwj37SXVJyjTE8j6dZ 6m0JO2lnxs2TIy1zcAPWrocXd9QmC9ZZ5UWPmMAPzIBWRktP461S3IM/0FjqmMa+6Av7 QQbA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=content-transfer-encoding:mime-version:list-unsubscribe :list-subscribe:list-id:precedence:message-id:date:subject:cc:to :from:dkim-signature; bh=0Ctx+/zmCcVG6P4rZ04GNVj1+tQXzo6XO+o7DACNcLo=; fh=XwLEJ0qdoxBRTcTu3fetdunu0G7wpnFq1jUPX55ozZ4=; b=InoR1ZpOjFpHvwC0TPMbjNyz8D7UgeKCFdQMfegXAIrlaO5CC6nS/4VKTEQtHIok6X BPk6WOUaq69JKWCDEZY4Om4wR/Eo9j2miL3KvDgpYrssoRZuzZ7gFu+/slVMBU6vYU1L PVn2RV8SgBt8LgXV2An+F5RxAwyqgq6jb858wjRaO1YMMSNGz25yvpkPMAMP/DQJ/eUJ dSeQo5qIugfOAumslaUcwyROu/Mrd7y8GjcaKiYn9lK0gKiIzf95KoeFoUvq1aVn4fvF VuFyXV5xYenbgCp/ouLAUiVv/Mk+xFguVhWQ0nDn7ub2+IX2hfJzX0AnEkJOWjAhH0ZZ u3TA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@pappasbrent.com header.s=default header.b="QcbN3/tm"; spf=pass (google.com: domain of linux-kernel+bounces-25153-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:45e3:2400::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-25153-ouuuleilei=gmail.com@vger.kernel.org" Received: from sv.mirrors.kernel.org (sv.mirrors.kernel.org. [2604:1380:45e3:2400::1]) by mx.google.com with ESMTPS id n9-20020a1709026a8900b001d5486faf60si4289543plk.272.2024.01.12.17.22.51 for <ouuuleilei@gmail.com> (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 12 Jan 2024 17:22:51 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel+bounces-25153-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:45e3:2400::1 as permitted sender) client-ip=2604:1380:45e3:2400::1; Authentication-Results: mx.google.com; dkim=pass header.i=@pappasbrent.com header.s=default header.b="QcbN3/tm"; spf=pass (google.com: domain of linux-kernel+bounces-25153-ouuuleilei=gmail.com@vger.kernel.org designates 2604:1380:45e3:2400::1 as permitted sender) smtp.mailfrom="linux-kernel+bounces-25153-ouuuleilei=gmail.com@vger.kernel.org" Received: from smtp.subspace.kernel.org (wormhole.subspace.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by sv.mirrors.kernel.org (Postfix) with ESMTPS id 34AAD286D35 for <ouuuleilei@gmail.com>; Sat, 13 Jan 2024 01:22:51 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 4FB5718EBF; Sat, 13 Jan 2024 01:22:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pappasbrent.com header.i=@pappasbrent.com header.b="QcbN3/tm" Received: from h5.fbrelay.privateemail.com (h5.fbrelay.privateemail.com [162.0.218.228]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 98D41134C2; Sat, 13 Jan 2024 01:22:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pappasbrent.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pappasbrent.com Received: from MTA-10-4.privateemail.com (mta-10.privateemail.com [198.54.118.218]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by h5.fbrelay.privateemail.com (Postfix) with ESMTPSA id B138B60562; Sat, 13 Jan 2024 01:14:49 +0000 (UTC) Received: from mta-10.privateemail.com (localhost [127.0.0.1]) by mta-10.privateemail.com (Postfix) with ESMTP id E443E180020E; Fri, 12 Jan 2024 20:14:40 -0500 (EST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=pappasbrent.com; s=default; t=1705108481; bh=5tLeUjD4Wuj2pnMpbrqMQhIri6Cryus27QrLloXWnoE=; h=From:To:Cc:Subject:Date:From; b=QcbN3/tm2Mzp1wE86PFCzJsLp8ocsCOFrvclQrhYXpGSYMFuMcvh5Hcl7VqAZ7Cc+ aAel++fm523ubqNQ3B13GH33fzD4tydNS3woLkLuvXHjYQZOMyzdhxXuIUKUPncqhV jEz4pHOSNjWR5LYlJOIXMmDTz6bCNOkDdmNXm6L6UoD41wC0BB7xbs4KHFgJDtUXBX BrizwHfnjtfM3m7rD3k+WrsSWsf7q4R62lOGrWaKZfCt/FLidHWkdme37WDtGhhQea QtH7sXMOlNVFfbOCFD/KmB/t9CPXKKF5HkVv3RBlafVAfH9/2Ev3m+LGItkigT2Rv6 tSCasZnAe62EQ== Received: from bpappas-XPS-13-9310.cfl.rr.com (050-088-208-203.res.spectrum.com [50.88.208.203]) by mta-10.privateemail.com (Postfix) with ESMTPA; Fri, 12 Jan 2024 20:14:30 -0500 (EST) From: Brent Pappas <bpappas@pappasbrent.com> To: Johannes Berg <johannes@sipsolutions.net>, "David S. Miller" <davem@davemloft.net>, Eric Dumazet <edumazet@google.com>, Jakub Kicinski <kuba@kernel.org>, Paolo Abeni <pabeni@redhat.com> Cc: Brent Pappas <bpappas@pappasbrent.com>, linux-wireless@vger.kernel.org, netdev@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH] wifi: mac80211: tx: Add __must_hold() annotation Date: Fri, 12 Jan 2024 20:11:45 -0500 Message-ID: <20240113011145.10888-2-bpappas@pappasbrent.com> X-Mailer: git-send-email 2.43.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: <linux-kernel.vger.kernel.org> List-Subscribe: <mailto:linux-kernel+subscribe@vger.kernel.org> List-Unsubscribe: <mailto:linux-kernel+unsubscribe@vger.kernel.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Virus-Scanned: ClamAV using ClamSMTP X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1787936344740512241 X-GMAIL-MSGID: 1787936344740512241 |
Series |
wifi: mac80211: tx: Add __must_hold() annotation
|
|
Commit Message
Brent Pappas
Jan. 13, 2024, 1:11 a.m. UTC
Annotates ieee80211_set_beacon_cntdwn() with a __must_hold() annotation to
make it clear that ieee80211_set_beacon_cntdwn() is only intended to be
called when the caller has a lock on the argument "link."
Signed-off-by: Brent Pappas <bpappas@pappasbrent.com>
---
Currently, ieee80211_set_beacon_cntdwn() calls rcu_dereference(), but
without calling rcu_read_lock() beforehand and rcu_read_unlock()
afterward. At first I thought this was a bug, since (if I understand the
RCU API correctly) rcu_dereference() should only be called in RCU
read-side critical sections. However, upon closer inspection of the code,
I realized that ieee80211_set_beacon_cntdwn() is only ever called inside
critical sections. Therefore it seems appropriate to me to annotate
ieee80211_set_beacon_cntdwn() with a __must_hold() annotation to make this
apparent precondition explicit.
This is my first time submitting an RCU-related patch so please tell me if
I am misunderstanding the RCU API.
net/mac80211/tx.c | 2 ++
1 file changed, 2 insertions(+)
Comments
Brent Pappas <bpappas@pappasbrent.com> writes: > Annotates ieee80211_set_beacon_cntdwn() with a __must_hold() annotation to > make it clear that ieee80211_set_beacon_cntdwn() is only intended to be > called when the caller has a lock on the argument "link." > > Signed-off-by: Brent Pappas <bpappas@pappasbrent.com> > --- > > Currently, ieee80211_set_beacon_cntdwn() calls rcu_dereference(), but > without calling rcu_read_lock() beforehand and rcu_read_unlock() > afterward. At first I thought this was a bug, since (if I understand the > RCU API correctly) rcu_dereference() should only be called in RCU > read-side critical sections. However, upon closer inspection of the code, > I realized that ieee80211_set_beacon_cntdwn() is only ever called inside > critical sections. Therefore it seems appropriate to me to annotate > ieee80211_set_beacon_cntdwn() with a __must_hold() annotation to make this > apparent precondition explicit. > > This is my first time submitting an RCU-related patch so please tell me if > I am misunderstanding the RCU API. > > net/mac80211/tx.c | 2 ++ > 1 file changed, 2 insertions(+) > > diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c > index 314998fdb1a5..7245f2e641ba 100644 > --- a/net/mac80211/tx.c > +++ b/net/mac80211/tx.c > @@ -10,6 +10,7 @@ > * Transmit and frame generation functions. > */ > > +#include "linux/compiler_types.h" > #include <linux/kernel.h> > #include <linux/slab.h> > #include <linux/skbuff.h> > @@ -4974,6 +4975,7 @@ static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, > static void ieee80211_set_beacon_cntdwn(struct ieee80211_sub_if_data *sdata, > struct beacon_data *beacon, > struct ieee80211_link_data *link) > + __must_hold(link) Oh, never seen __must_hold() before and looks very useful. So does this work with RCU, mutexes and spinlocks? In case others are interested, here's the documentation I was able to find: https://docs.kernel.org/dev-tools/sparse.html#using-sparse-for-lock-checking
On Sat, 2024-01-13 at 08:32 +0200, Kalle Valo wrote: > > > static void ieee80211_set_beacon_cntdwn(struct ieee80211_sub_if_data *sdata, > > struct beacon_data *beacon, > > struct ieee80211_link_data *link) > > + __must_hold(link) > > Oh, never seen __must_hold() before and looks very useful. So does this > work with RCU, mutexes and spinlocks? > > In case others are interested, here's the documentation I was able to find: > > https://docs.kernel.org/dev-tools/sparse.html#using-sparse-for-lock-checking > Except it's not actually useful, and looks more useful than it is. IMHO it's actually more harmful than anything else. One might even consider this patch a good example! The function ieee80211_set_beacon_cntdwn() is called from a number of places in this file, some of which acquire RCU critical section, and some of which acquire no locks nor RCU critical section at all. Most of them nest and are called in RCU. However, there's basically no way to get sparse to warn on this. Even inserting a function void test(void); void test(void) { ieee80211_set_beacon_cntdwn(NULL, NULL, NULL); } will not cause sparse to complain, where this *clearly* doesn't hold an locks. Also, as we (should) all know, the argument to __acquires(), __releases() and __must_check() is pretty much ignored. I tried to fix this in sparse many years ago, some code even got merged (and then reverted), and if the experience tells me anything then that it's pretty much not fixable. __acquires() and __releases() at least are useful for tracking that you don't have a mismatch, e.g. a function that __acquires() but then takes a lock in most paths but forgot one, for example. With __must_hold(), this really isn't the case. And then we could argue that at least it has a documentation effect, but .. what does it even mean to "hold 'link'"? There isn't even a lock, mutex or otherwise, in the link. You can't "own" a reference to it, or anything like that. The closest thing in current kernels would be to maybe see if you have the wiphy mutex, but that's likely not the case in these paths and RCU was used to get to the link struct ... IOW, I find this lacking from an implementation/validation point of view, and lacking if not outright confusing from a documentation point of view. Much better to put something lockdep_assert_held() or similar into the right places. As for your comment about RCU in ath11k (which points back to this thread): I don't find RCU_LOCKDEP_WARN(!rcu_read_lock_held()); or WARN_ON_ONCE(!rcu_read_lock_held()); very persuasive, it's much better to have it checked with rcu_dereference_protected(), rcu_dereference_check(), the condition argument to list_for_each_rcu(), or (in the case of wiphy) our wrappers around these like wiphy_dereference(). I cannot think of any case where you'd want to ensure that some code is in an RCU critical section without it actually using RCU - and if it does you have rcu_dereference() and all those things that (a) check anyway, and also (b) serve as their own documentation. Anyway, long story short: I don't see value in this patch and won't be applying it unless somebody here can convince me otherwise, ideally addressing the concerns stated above. johannes
Thanks for the feedback Johannes. As I mentioned in my original email, I'm still learning the RCU API, so I appreciate the insight from someone more knowledgeable. > Much better to put something lockdep_assert_held() or similar into the right > places. I'm not committed to using __must_hold(); would you be willing to accept this patch if I change it to use lockdep_assert_held() instead? > The function ieee80211_set_beacon_cntdwn() is called from a number of places > in this file, some of which acquire RCU critical section, and some of which > acquire no locks nor RCU critical section at all. Grepping through tx.c, I see ieee80211_set_beacon_cntdwn() is invoked in three places: - Line 5285: Inside the definition of ieee80211_beacon_get_ap(), which is only invoked in critical sections (both directly and in another nested call). - Line 5439: Directly inside a critical section. - Line 5471: Directly inside a critical section (same as previous). > I tried to fix this in sparse many years ago, some code even got merged (and > then reverted), and if the experience tells me anything then that it's pretty > much not fixable. I'm sorry to hear that; a solution to this problem sounds very useful. I'm currently working on making my own static analyzer for performing more checks than what sparse currently provides. Since you've worked on this problem and have deeper insight into than I do, what sort of checks would you like to see added to a tool like sparse (besides checking whether specific locks are held)? Thank you, Brent The 01/15/2024 14:13, Johannes Berg wrote: > On Sat, 2024-01-13 at 08:32 +0200, Kalle Valo wrote: > > > > > static void ieee80211_set_beacon_cntdwn(struct ieee80211_sub_if_data *sdata, > > > struct beacon_data *beacon, > > > struct ieee80211_link_data *link) > > > + __must_hold(link) > > > > Oh, never seen __must_hold() before and looks very useful. So does this > > work with RCU, mutexes and spinlocks? > > > > In case others are interested, here's the documentation I was able to find: > > > > https://docs.kernel.org/dev-tools/sparse.html#using-sparse-for-lock-checking > > > > Except it's not actually useful, and looks more useful than it is. IMHO > it's actually more harmful than anything else. > > One might even consider this patch a good example! The function > ieee80211_set_beacon_cntdwn() is called from a number of places in this > file, some of which acquire RCU critical section, and some of which > acquire no locks nor RCU critical section at all. Most of them nest and > are called in RCU. > > However, there's basically no way to get sparse to warn on this. Even > inserting a function > > void test(void); > void test(void) > { > ieee80211_set_beacon_cntdwn(NULL, NULL, NULL); > } > > will not cause sparse to complain, where this *clearly* doesn't hold an > locks. > > > Also, as we (should) all know, the argument to __acquires(), > __releases() and __must_check() is pretty much ignored. I tried to fix > this in sparse many years ago, some code even got merged (and then > reverted), and if the experience tells me anything then that it's pretty > much not fixable. > > __acquires() and __releases() at least are useful for tracking that you > don't have a mismatch, e.g. a function that __acquires() but then takes > a lock in most paths but forgot one, for example. With __must_hold(), > this really isn't the case. > > And then we could argue that at least it has a documentation effect, but > ... what does it even mean to "hold 'link'"? There isn't even a lock, > mutex or otherwise, in the link. You can't "own" a reference to it, or > anything like that. The closest thing in current kernels would be to > maybe see if you have the wiphy mutex, but that's likely not the case in > these paths and RCU was used to get to the link struct ... > > > IOW, I find this lacking from an implementation/validation point of > view, and lacking if not outright confusing from a documentation point > of view. Much better to put something lockdep_assert_held() or similar > into the right places. > > As for your comment about RCU in ath11k (which points back to this > thread): I don't find > > RCU_LOCKDEP_WARN(!rcu_read_lock_held()); > or > WARN_ON_ONCE(!rcu_read_lock_held()); > > very persuasive, it's much better to have it checked with > rcu_dereference_protected(), rcu_dereference_check(), the condition > argument to list_for_each_rcu(), or (in the case of wiphy) our wrappers > around these like wiphy_dereference(). I cannot think of any case where > you'd want to ensure that some code is in an RCU critical section > without it actually using RCU - and if it does you have > rcu_dereference() and all those things that (a) check anyway, and also > (b) serve as their own documentation. > > > Anyway, long story short: I don't see value in this patch and won't be > applying it unless somebody here can convince me otherwise, ideally > addressing the concerns stated above. > > johannes
Hi Brent, On Wed, 2024-01-17 at 15:00 -0500, Brent Pappas wrote: > Thanks for the feedback Johannes. As I mentioned in my original email, I'm still > learning the RCU API, so I appreciate the insight from someone more > knowledgeable. Note this isn't really all that RCU related. > > Much better to put something lockdep_assert_held() or similar into the right > > places. > > I'm not committed to using __must_hold(); would you be willing to accept this > patch if I change it to use lockdep_assert_held() instead? I'm actually not sure what you're trying to check here. The rcu_dereference() inside of it? But that'll already be checked at runtime by lockdep without any further code. So ... right now I don't see that there's any point in adding any further annotations, but I'm also not sure what you're trying to achieve. > > The function ieee80211_set_beacon_cntdwn() is called from a number of places > > in this file, some of which acquire RCU critical section, and some of which > > acquire no locks nor RCU critical section at all. > > Grepping through tx.c, I see ieee80211_set_beacon_cntdwn() is invoked in three > places: > > - Line 5285: Inside the definition of ieee80211_beacon_get_ap(), which is only > invoked in critical sections (both directly and in another nested call). > - Line 5439: Directly inside a critical section. > - Line 5471: Directly inside a critical section (same as previous). Right. > > I tried to fix this in sparse many years ago, some code even got merged (and > > then reverted), and if the experience tells me anything then that it's pretty > > much not fixable. > > I'm sorry to hear that; a solution to this problem sounds very useful. I'm > currently working on making my own static analyzer for performing more checks > than what sparse currently provides. Are you aware of smatch? > Since you've worked on this problem and > have deeper insight into than I do, what sort of checks would you like to see > added to a tool like sparse (besides checking whether specific locks are held)? I haven't really thought about that ... some better taint tracking would be nice but that's _really_ hard ;-) johannes
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 314998fdb1a5..7245f2e641ba 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -10,6 +10,7 @@ * Transmit and frame generation functions. */ +#include "linux/compiler_types.h" #include <linux/kernel.h> #include <linux/slab.h> #include <linux/skbuff.h> @@ -4974,6 +4975,7 @@ static int ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata, static void ieee80211_set_beacon_cntdwn(struct ieee80211_sub_if_data *sdata, struct beacon_data *beacon, struct ieee80211_link_data *link) + __must_hold(link) { u8 *beacon_data, count, max_count = 1; struct probe_resp *resp;