2021-02-27 00:08:12

by Shuah Khan

[permalink] [raw]
Subject: [PATCH v3 0/3] Add lockdep_assert_not_held()

Some kernel functions must not be called holding a specific lock. Doing
so could lead to locking problems. Currently these routines call
lock_is_held() to check for lock hold followed by WARN_ON.

Adding a common lockdep interface will help reduce the duplication of this
logic in the rest of the kernel.

Add lockdep_assert_not_held() to be used in these functions to detect
incorrect calls while holding a lock.

lockdep_assert_not_held() provides the opposite functionality of
lockdep_assert_held() which is used to assert calls that require
holding a specific lock.

The need for lockdep_assert_not_held() came up in a discussion on
ath10k patch. ath10k_drain_tx() and i915_vma_pin_ww() are examples
of functions that can use lockdep_assert_not_held().

Link: https://lore.kernel.org/lkml/[email protected]nuxfoundation.org/
Link: https://lore.kernel.org/linux-wireless/[email protected]/

This patch series adds lockdep_assert_not_held() and uses it in the
second patch in ath10k_drain_tx() function.

Changes since v2:
-- Fixed coding style issues
-- Patch 2 uses new lock states in __lock_is_held() and
lock_is_held_type

Patch 1 incorporates suggestions from Peter Zijlstra on v1 series
to avoid misfires when lockdep_off() is employed.

Patch 2 Johannes Berg's suggestions as it make it easier to read and
maintain the lock states. These are defines and a enum to avoid changes
to lock_is_held_type() and lockdep_is_held() return types.

Patch 2 is a separate patch because it adds defines to lockdep.h and
kernel/locking/lockdep.c now includes lockdep.h - decided make this
a separate patch just in case issues related to header dependencies
pop up. I can combine Patches 1&2 if that is preferred.

Patch 3 uses the new interface in ath10k_drain_tx() function. Added
Kalle Valo's Ack from v1 for this change.

Tested on the mainline from yesterday.

Shuah Khan (3):
lockdep: add lockdep_assert_not_held()
lockdep: add lockdep lock state defines
ath10k: detect conf_mutex held ath10k_drain_tx() calls

drivers/net/wireless/ath/ath10k/mac.c | 2 ++
include/linux/lockdep.h | 18 +++++++++++++++---
kernel/locking/lockdep.c | 15 ++++++++++-----
3 files changed, 27 insertions(+), 8 deletions(-)

--
2.27.0


2021-02-27 00:09:37

by Shuah Khan

[permalink] [raw]
Subject: [PATCH v3 1/3] lockdep: add lockdep_assert_not_held()

Some kernel functions must be called without holding a specific lock.
Add lockdep_assert_not_held() to be used in these functions to detect
incorrect calls while holding a lock.

lockdep_assert_not_held() provides the opposite functionality of
lockdep_assert_held() which is used to assert calls that require
holding a specific lock.

Incorporates suggestions from Peter Zijlstra to avoid misfires when
lockdep_off() is employed.

The need for lockdep_assert_not_held() came up in a discussion on
ath10k patch. ath10k_drain_tx() and i915_vma_pin_ww() are examples
of functions that can use lockdep_assert_not_held().

Link: https://lore.kernel.org/lkml/[email protected]nuxfoundation.org/
Link: https://lore.kernel.org/linux-wireless/[email protected]/
Signed-off-by: Shuah Khan <[email protected]>
---
include/linux/lockdep.h | 11 ++++++++---
kernel/locking/lockdep.c | 6 +++++-
2 files changed, 13 insertions(+), 4 deletions(-)

diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h
index 7b7ebf2e28ec..dbd9ea846b36 100644
--- a/include/linux/lockdep.h
+++ b/include/linux/lockdep.h
@@ -301,8 +301,12 @@ extern void lock_unpin_lock(struct lockdep_map *lock, struct pin_cookie);

#define lockdep_depth(tsk) (debug_locks ? (tsk)->lockdep_depth : 0)

-#define lockdep_assert_held(l) do { \
- WARN_ON(debug_locks && !lockdep_is_held(l)); \
+#define lockdep_assert_held(l) do { \
+ WARN_ON(debug_locks && lockdep_is_held(l) == 0); \
+ } while (0)
+
+#define lockdep_assert_not_held(l) do { \
+ WARN_ON(debug_locks && lockdep_is_held(l) == 1); \
} while (0)

#define lockdep_assert_held_write(l) do { \
@@ -393,7 +397,8 @@ extern int lockdep_is_held(const void *);
#define lockdep_is_held_type(l, r) (1)

#define lockdep_assert_held(l) do { (void)(l); } while (0)
-#define lockdep_assert_held_write(l) do { (void)(l); } while (0)
+#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_once(l) do { (void)(l); } while (0)

diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c
index c6d0c1dc6253..818d0ceed3eb 100644
--- a/kernel/locking/lockdep.c
+++ b/kernel/locking/lockdep.c
@@ -5539,8 +5539,12 @@ noinstr int lock_is_held_type(const struct lockdep_map *lock, int read)
unsigned long flags;
int ret = 0;

+ /*
+ * avoid false negative lockdep_assert_held() and
+ * lockdep_assert_not_held()
+ */
if (unlikely(!lockdep_enabled()))
- return 1; /* avoid false negative lockdep_assert_held() */
+ return -1;

raw_local_irq_save(flags);
check_flags(flags);
--
2.27.0

2021-02-27 00:10:12

by Shuah Khan

[permalink] [raw]
Subject: [PATCH v3 2/3] lockdep: add lockdep lock state defines

Adds defines for lock state returns from lock_is_held_type() based on
Johannes Berg's suggestions as it make it easier to read and maintain
the lock states. These are defines and a enum to avoid changes to
lock_is_held_type() and lockdep_is_held() return types.

Updates to lock_is_held_type() and __lock_is_held() to use the new
defines.

Link: https://lore.kernel.org/lkml/[email protected]nuxfoundation.org/
Link: https://lore.kernel.org/linux-wireless/[email protected]/
Signed-off-by: Shuah Khan <[email protected]>
---
include/linux/lockdep.h | 11 +++++++++--
kernel/locking/lockdep.c | 11 ++++++-----
2 files changed, 15 insertions(+), 7 deletions(-)

diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h
index dbd9ea846b36..17805aac0e85 100644
--- a/include/linux/lockdep.h
+++ b/include/linux/lockdep.h
@@ -268,6 +268,11 @@ extern void lock_acquire(struct lockdep_map *lock, unsigned int subclass,

extern void lock_release(struct lockdep_map *lock, unsigned long ip);

+/* lock_is_held_type() returns */
+#define LOCK_STATE_UNKNOWN -1
+#define LOCK_STATE_NOT_HELD 0
+#define LOCK_STATE_HELD 1
+
/*
* Same "read" as for lock_acquire(), except -1 means any.
*/
@@ -302,11 +307,13 @@ extern void lock_unpin_lock(struct lockdep_map *lock, struct pin_cookie);
#define lockdep_depth(tsk) (debug_locks ? (tsk)->lockdep_depth : 0)

#define lockdep_assert_held(l) do { \
- WARN_ON(debug_locks && lockdep_is_held(l) == 0); \
+ WARN_ON(debug_locks && \
+ lockdep_is_held(l) == LOCK_STATE_NOT_HELD); \
} while (0)

#define lockdep_assert_not_held(l) do { \
- WARN_ON(debug_locks && lockdep_is_held(l) == 1); \
+ WARN_ON(debug_locks && \
+ lockdep_is_held(l) == LOCK_STATE_HELD); \
} while (0)

#define lockdep_assert_held_write(l) do { \
diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c
index 818d0ceed3eb..f5a8200f24f1 100644
--- a/kernel/locking/lockdep.c
+++ b/kernel/locking/lockdep.c
@@ -54,6 +54,7 @@
#include <linux/nmi.h>
#include <linux/rcupdate.h>
#include <linux/kprobes.h>
+#include <linux/lockdep.h>

#include <asm/sections.h>

@@ -5252,13 +5253,13 @@ int __lock_is_held(const struct lockdep_map *lock, int read)

if (match_held_lock(hlock, lock)) {
if (read == -1 || hlock->read == read)
- return 1;
+ return LOCK_STATE_HELD;

- return 0;
+ return LOCK_STATE_NOT_HELD;
}
}

- return 0;
+ return LOCK_STATE_NOT_HELD;
}

static struct pin_cookie __lock_pin_lock(struct lockdep_map *lock)
@@ -5537,14 +5538,14 @@ EXPORT_SYMBOL_GPL(lock_release);
noinstr int lock_is_held_type(const struct lockdep_map *lock, int read)
{
unsigned long flags;
- int ret = 0;
+ int ret = LOCK_STATE_NOT_HELD;

/*
* avoid false negative lockdep_assert_held() and
* lockdep_assert_not_held()
*/
if (unlikely(!lockdep_enabled()))
- return -1;
+ return LOCK_STATE_UNKNOWN;

raw_local_irq_save(flags);
check_flags(flags);
--
2.27.0

2021-02-27 00:10:17

by Shuah Khan

[permalink] [raw]
Subject: [PATCH v3 3/3] ath10k: detect conf_mutex held ath10k_drain_tx() calls

ath10k_drain_tx() must not be called with conf_mutex held as workers can
use that also. Add call to lockdep_assert_not_held() on conf_mutex to
detect if conf_mutex is held by the caller.

The idea for this patch stemmed from coming across the comment block
above the ath10k_drain_tx() while reviewing the conf_mutex holds during
to debug the conf_mutex lock assert in ath10k_debug_fw_stats_request().

Adding detection to assert on conf_mutex hold will help detect incorrect
usages that could lead to locking problems when async worker routines try
to call this routine.

Link: https://lore.kernel.org/lkml/[email protected]nuxfoundation.org/
Link: https://lore.kernel.org/linux-wireless/[email protected]/
Acked-by: Kalle Valo <[email protected]>
Signed-off-by: Shuah Khan <[email protected]>
---
drivers/net/wireless/ath/ath10k/mac.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index bb6c5ee43ac0..5ce4f8d038b9 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -4727,6 +4727,8 @@ static void ath10k_mac_op_wake_tx_queue(struct ieee80211_hw *hw,
/* Must not be called with conf_mutex held as workers can use that also. */
void ath10k_drain_tx(struct ath10k *ar)
{
+ lockdep_assert_not_held(&ar->conf_mutex);
+
/* make sure rcu-protected mac80211 tx path itself is drained */
synchronize_net();

--
2.27.0

2021-03-01 08:42:53

by Peter Zijlstra

[permalink] [raw]
Subject: Re: [PATCH v3 0/3] Add lockdep_assert_not_held()

On Fri, Feb 26, 2021 at 05:06:57PM -0700, Shuah Khan wrote:
> Shuah Khan (3):
> lockdep: add lockdep_assert_not_held()
> lockdep: add lockdep lock state defines
> ath10k: detect conf_mutex held ath10k_drain_tx() calls

Thanks!

2021-03-01 08:49:19

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH v3 0/3] Add lockdep_assert_not_held()

Peter Zijlstra <[email protected]> writes:

> On Fri, Feb 26, 2021 at 05:06:57PM -0700, Shuah Khan wrote:
>> Shuah Khan (3):
>> lockdep: add lockdep_assert_not_held()
>> lockdep: add lockdep lock state defines
>> ath10k: detect conf_mutex held ath10k_drain_tx() calls
>
> Thanks!

Via which tree should these go?

--
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

2021-03-01 09:39:12

by Peter Zijlstra

[permalink] [raw]
Subject: Re: [PATCH v3 0/3] Add lockdep_assert_not_held()

On Mon, Mar 01, 2021 at 10:45:32AM +0200, Kalle Valo wrote:
> Peter Zijlstra <[email protected]> writes:
>
> > On Fri, Feb 26, 2021 at 05:06:57PM -0700, Shuah Khan wrote:
> >> Shuah Khan (3):
> >> lockdep: add lockdep_assert_not_held()
> >> lockdep: add lockdep lock state defines
> >> ath10k: detect conf_mutex held ath10k_drain_tx() calls
> >
> > Thanks!
>
> Via which tree should these go?

I've just queued the lot for locking/core, which will show up in tip
when the robots don't hate on it.

Does that work for you?

2021-03-01 11:06:55

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH v3 0/3] Add lockdep_assert_not_held()

Peter Zijlstra <[email protected]> writes:

> On Mon, Mar 01, 2021 at 10:45:32AM +0200, Kalle Valo wrote:
>> Peter Zijlstra <[email protected]> writes:
>>
>> > On Fri, Feb 26, 2021 at 05:06:57PM -0700, Shuah Khan wrote:
>> >> Shuah Khan (3):
>> >> lockdep: add lockdep_assert_not_held()
>> >> lockdep: add lockdep lock state defines
>> >> ath10k: detect conf_mutex held ath10k_drain_tx() calls
>> >
>> > Thanks!
>>
>> Via which tree should these go?
>
> I've just queued the lot for locking/core, which will show up in tip
> when the robots don't hate on it.
>
> Does that work for you?

That's perfect, thanks! Just making sure that the patches don't get
lost.

--
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches

2021-03-01 16:09:15

by Shuah Khan

[permalink] [raw]
Subject: Re: [PATCH v3 0/3] Add lockdep_assert_not_held()

On 3/1/21 4:02 AM, Kalle Valo wrote:
> Peter Zijlstra <[email protected]> writes:
>
>> On Mon, Mar 01, 2021 at 10:45:32AM +0200, Kalle Valo wrote:
>>> Peter Zijlstra <[email protected]> writes:
>>>
>>>> On Fri, Feb 26, 2021 at 05:06:57PM -0700, Shuah Khan wrote:
>>>>> Shuah Khan (3):
>>>>> lockdep: add lockdep_assert_not_held()
>>>>> lockdep: add lockdep lock state defines
>>>>> ath10k: detect conf_mutex held ath10k_drain_tx() calls
>>>>
>>>> Thanks!
>>>
>>> Via which tree should these go?
>>
>> I've just queued the lot for locking/core, which will show up in tip
>> when the robots don't hate on it.
>>
>> Does that work for you?
>
> That's perfect, thanks! Just making sure that the patches don't get
> lost.
>

Awesome. Thank you.

thanks,
-- Shuah