[PATCH RESEND 1/3] locking: add rwsem_is_write_locked(), update non-lockdep asserts

Lorenzo Stoakes posted 3 patches 3 weeks, 2 days ago
There is a newer version of this series
[PATCH RESEND 1/3] locking: add rwsem_is_write_locked(), update non-lockdep asserts
Posted by Lorenzo Stoakes 3 weeks, 2 days ago
As part of adding some additional lock asserts in mm, we wish to be able to
determine if a read/write semaphore is write-locked, so add
rwsem_is_write_locked() to do the write-lock equivalent of
rwsem_is_locked().

While we're here, update rwsem_assert_[write_]held_nolockdep() to utilise
the rwsem_is_[write_]locked() helpers directly to reduce code duplication,
and also update rwsem_is_locked() to take a const rwsem and return a
boolean.

This patch also updates the CONFIG_PREEMPT_RT helpers to do the same thing
there.

Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
---
 include/linux/rwsem.h | 20 +++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/include/linux/rwsem.h b/include/linux/rwsem.h
index f1aaf676a874..b25b7944ad99 100644
--- a/include/linux/rwsem.h
+++ b/include/linux/rwsem.h
@@ -70,19 +70,24 @@ struct rw_semaphore {
 #define RWSEM_WRITER_LOCKED		(1UL << 0)
 #define __RWSEM_COUNT_INIT(name)	.count = ATOMIC_LONG_INIT(RWSEM_UNLOCKED_VALUE)

-static inline int rwsem_is_locked(struct rw_semaphore *sem)
+static inline bool rwsem_is_locked(const struct rw_semaphore *sem)
 {
 	return atomic_long_read(&sem->count) != RWSEM_UNLOCKED_VALUE;
 }

+static inline bool rwsem_is_write_locked(const struct rw_semaphore *sem)
+{
+	return atomic_long_read(&sem->count) & RWSEM_WRITER_LOCKED;
+}
+
 static inline void rwsem_assert_held_nolockdep(const struct rw_semaphore *sem)
 {
-	WARN_ON(atomic_long_read(&sem->count) == RWSEM_UNLOCKED_VALUE);
+	WARN_ON(!rwsem_is_locked(sem));
 }

 static inline void rwsem_assert_held_write_nolockdep(const struct rw_semaphore *sem)
 {
-	WARN_ON(!(atomic_long_read(&sem->count) & RWSEM_WRITER_LOCKED));
+	WARN_ON(!rwsem_is_write_locked(sem));
 }

 /* Common initializer macros and functions */
@@ -174,11 +179,16 @@ do {								\
 	__init_rwsem((sem), #sem, &__key);			\
 } while (0)

-static __always_inline int rwsem_is_locked(const struct rw_semaphore *sem)
+static __always_inline bool rwsem_is_locked(const struct rw_semaphore *sem)
 {
 	return rw_base_is_locked(&sem->rwbase);
 }

+static __always_inline bool rwsem_is_write_locked(const struct rw_semaphore *sem)
+{
+	return rw_base_is_write_locked(&sem->rwbase);
+}
+
 static __always_inline void rwsem_assert_held_nolockdep(const struct rw_semaphore *sem)
 {
 	WARN_ON(!rwsem_is_locked(sem));
@@ -186,7 +196,7 @@ static __always_inline void rwsem_assert_held_nolockdep(const struct rw_semaphor

 static __always_inline void rwsem_assert_held_write_nolockdep(const struct rw_semaphore *sem)
 {
-	WARN_ON(!rw_base_is_write_locked(&sem->rwbase));
+	WARN_ON(!rwsem_is_write_locked(sem));
 }

 static __always_inline int rwsem_is_contended(struct rw_semaphore *sem)
--
2.52.0
Re: [PATCH RESEND 1/3] locking: add rwsem_is_write_locked(), update non-lockdep asserts
Posted by Zi Yan 3 weeks, 2 days ago
On 16 Jan 2026, at 8:36, Lorenzo Stoakes wrote:

> As part of adding some additional lock asserts in mm, we wish to be able to
> determine if a read/write semaphore is write-locked, so add
> rwsem_is_write_locked() to do the write-lock equivalent of
> rwsem_is_locked().
>
> While we're here, update rwsem_assert_[write_]held_nolockdep() to utilise
> the rwsem_is_[write_]locked() helpers directly to reduce code duplication,
> and also update rwsem_is_locked() to take a const rwsem and return a
> boolean.
>
> This patch also updates the CONFIG_PREEMPT_RT helpers to do the same thing
> there.
>
> Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
> ---
>  include/linux/rwsem.h | 20 +++++++++++++++-----
>  1 file changed, 15 insertions(+), 5 deletions(-)
>
> diff --git a/include/linux/rwsem.h b/include/linux/rwsem.h
> index f1aaf676a874..b25b7944ad99 100644
> --- a/include/linux/rwsem.h
> +++ b/include/linux/rwsem.h
> @@ -70,19 +70,24 @@ struct rw_semaphore {
>  #define RWSEM_WRITER_LOCKED		(1UL << 0)
>  #define __RWSEM_COUNT_INIT(name)	.count = ATOMIC_LONG_INIT(RWSEM_UNLOCKED_VALUE)
>
> -static inline int rwsem_is_locked(struct rw_semaphore *sem)
> +static inline bool rwsem_is_locked(const struct rw_semaphore *sem)
>  {
>  	return atomic_long_read(&sem->count) != RWSEM_UNLOCKED_VALUE;
>  }
>
> +static inline bool rwsem_is_write_locked(const struct rw_semaphore *sem)
> +{
> +	return atomic_long_read(&sem->count) & RWSEM_WRITER_LOCKED;
> +}
> +
>  static inline void rwsem_assert_held_nolockdep(const struct rw_semaphore *sem)
>  {
> -	WARN_ON(atomic_long_read(&sem->count) == RWSEM_UNLOCKED_VALUE);
> +	WARN_ON(!rwsem_is_locked(sem));
>  }
>
>  static inline void rwsem_assert_held_write_nolockdep(const struct rw_semaphore *sem)
>  {
> -	WARN_ON(!(atomic_long_read(&sem->count) & RWSEM_WRITER_LOCKED));
> +	WARN_ON(!rwsem_is_write_locked(sem));
>  }
>
>  /* Common initializer macros and functions */
> @@ -174,11 +179,16 @@ do {								\
>  	__init_rwsem((sem), #sem, &__key);			\
>  } while (0)
>
> -static __always_inline int rwsem_is_locked(const struct rw_semaphore *sem)
> +static __always_inline bool rwsem_is_locked(const struct rw_semaphore *sem)
>  {
>  	return rw_base_is_locked(&sem->rwbase);
>  }
>
> +static __always_inline bool rwsem_is_write_locked(const struct rw_semaphore *sem)
> +{
> +	return rw_base_is_write_locked(&sem->rwbase);
> +}
> +
>  static __always_inline void rwsem_assert_held_nolockdep(const struct rw_semaphore *sem)
>  {
>  	WARN_ON(!rwsem_is_locked(sem));
> @@ -186,7 +196,7 @@ static __always_inline void rwsem_assert_held_nolockdep(const struct rw_semaphor
>
>  static __always_inline void rwsem_assert_held_write_nolockdep(const struct rw_semaphore *sem)
>  {
> -	WARN_ON(!rw_base_is_write_locked(&sem->rwbase));
> +	WARN_ON(!rwsem_is_write_locked(sem));

I thought it was wrong since rwsem_is_write_locked() at the top reads ->count
instead of ->rwbase until I see there is another rwsem_is_write_locked() above.


>  }
>
>  static __always_inline int rwsem_is_contended(struct rw_semaphore *sem)
> --

Reviewed-by: Zi Yan <ziy@nvidia.com>


--
Best Regards,
Yan, Zi
Re: [PATCH RESEND 1/3] locking: add rwsem_is_write_locked(), update non-lockdep asserts
Posted by Lorenzo Stoakes 3 weeks, 2 days ago
On Fri, Jan 16, 2026 at 10:08:00AM -0500, Zi Yan wrote:
> On 16 Jan 2026, at 8:36, Lorenzo Stoakes wrote:
>
> > As part of adding some additional lock asserts in mm, we wish to be able to
> > determine if a read/write semaphore is write-locked, so add
> > rwsem_is_write_locked() to do the write-lock equivalent of
> > rwsem_is_locked().
> >
> > While we're here, update rwsem_assert_[write_]held_nolockdep() to utilise
> > the rwsem_is_[write_]locked() helpers directly to reduce code duplication,
> > and also update rwsem_is_locked() to take a const rwsem and return a
> > boolean.
> >
> > This patch also updates the CONFIG_PREEMPT_RT helpers to do the same thing
> > there.
> >
> > Signed-off-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
> > ---
> >  include/linux/rwsem.h | 20 +++++++++++++++-----
> >  1 file changed, 15 insertions(+), 5 deletions(-)
> >
> > diff --git a/include/linux/rwsem.h b/include/linux/rwsem.h
> > index f1aaf676a874..b25b7944ad99 100644
> > --- a/include/linux/rwsem.h
> > +++ b/include/linux/rwsem.h
> > @@ -70,19 +70,24 @@ struct rw_semaphore {
> >  #define RWSEM_WRITER_LOCKED		(1UL << 0)
> >  #define __RWSEM_COUNT_INIT(name)	.count = ATOMIC_LONG_INIT(RWSEM_UNLOCKED_VALUE)
> >
> > -static inline int rwsem_is_locked(struct rw_semaphore *sem)
> > +static inline bool rwsem_is_locked(const struct rw_semaphore *sem)
> >  {
> >  	return atomic_long_read(&sem->count) != RWSEM_UNLOCKED_VALUE;
> >  }
> >
> > +static inline bool rwsem_is_write_locked(const struct rw_semaphore *sem)
> > +{
> > +	return atomic_long_read(&sem->count) & RWSEM_WRITER_LOCKED;
> > +}
> > +
> >  static inline void rwsem_assert_held_nolockdep(const struct rw_semaphore *sem)
> >  {
> > -	WARN_ON(atomic_long_read(&sem->count) == RWSEM_UNLOCKED_VALUE);
> > +	WARN_ON(!rwsem_is_locked(sem));
> >  }
> >
> >  static inline void rwsem_assert_held_write_nolockdep(const struct rw_semaphore *sem)
> >  {
> > -	WARN_ON(!(atomic_long_read(&sem->count) & RWSEM_WRITER_LOCKED));
> > +	WARN_ON(!rwsem_is_write_locked(sem));
> >  }
> >
> >  /* Common initializer macros and functions */
> > @@ -174,11 +179,16 @@ do {								\
> >  	__init_rwsem((sem), #sem, &__key);			\
> >  } while (0)
> >
> > -static __always_inline int rwsem_is_locked(const struct rw_semaphore *sem)
> > +static __always_inline bool rwsem_is_locked(const struct rw_semaphore *sem)
> >  {
> >  	return rw_base_is_locked(&sem->rwbase);
> >  }
> >
> > +static __always_inline bool rwsem_is_write_locked(const struct rw_semaphore *sem)
> > +{
> > +	return rw_base_is_write_locked(&sem->rwbase);
> > +}
> > +
> >  static __always_inline void rwsem_assert_held_nolockdep(const struct rw_semaphore *sem)
> >  {
> >  	WARN_ON(!rwsem_is_locked(sem));
> > @@ -186,7 +196,7 @@ static __always_inline void rwsem_assert_held_nolockdep(const struct rw_semaphor
> >
> >  static __always_inline void rwsem_assert_held_write_nolockdep(const struct rw_semaphore *sem)
> >  {
> > -	WARN_ON(!rw_base_is_write_locked(&sem->rwbase));
> > +	WARN_ON(!rwsem_is_write_locked(sem));
>
> I thought it was wrong since rwsem_is_write_locked() at the top reads ->count
> instead of ->rwbase until I see there is another rwsem_is_write_locked() above.

:)

>
>
> >  }
> >
> >  static __always_inline int rwsem_is_contended(struct rw_semaphore *sem)
> > --
>
> Reviewed-by: Zi Yan <ziy@nvidia.com>

Thanks!

>
>
> --
> Best Regards,
> Yan, Zi
Re: [PATCH RESEND 1/3] locking: add rwsem_is_write_locked(), update non-lockdep asserts
Posted by Peter Zijlstra 3 weeks, 2 days ago
On Fri, Jan 16, 2026 at 01:36:45PM +0000, Lorenzo Stoakes wrote:
> As part of adding some additional lock asserts in mm, we wish to be able to
> determine if a read/write semaphore is write-locked, so add
> rwsem_is_write_locked() to do the write-lock equivalent of
> rwsem_is_locked().
> 
> While we're here, update rwsem_assert_[write_]held_nolockdep() to utilise
> the rwsem_is_[write_]locked() helpers directly to reduce code duplication,
> and also update rwsem_is_locked() to take a const rwsem and return a
> boolean.

There is a long history of abuse of _is_locked() primitives. I don't
suppose you read the email thread that led to
rwsem_assert_held_*_nolockdep() by any chance?
Re: [PATCH RESEND 1/3] locking: add rwsem_is_write_locked(), update non-lockdep asserts
Posted by Lorenzo Stoakes 3 weeks, 2 days ago
On Fri, Jan 16, 2026 at 04:12:15PM +0100, Peter Zijlstra wrote:
> On Fri, Jan 16, 2026 at 01:36:45PM +0000, Lorenzo Stoakes wrote:
> > As part of adding some additional lock asserts in mm, we wish to be able to
> > determine if a read/write semaphore is write-locked, so add
> > rwsem_is_write_locked() to do the write-lock equivalent of
> > rwsem_is_locked().
> >
> > While we're here, update rwsem_assert_[write_]held_nolockdep() to utilise
> > the rwsem_is_[write_]locked() helpers directly to reduce code duplication,
> > and also update rwsem_is_locked() to take a const rwsem and return a
> > boolean.
>
> There is a long history of abuse of _is_locked() primitives. I don't
> suppose you read the email thread that led to
> rwsem_assert_held_*_nolockdep() by any chance?

No, but we need to be able to assert that one of two locks are held and we
don't want the failure of one being held to cause an assert when the other
isn't.

At any rate we already have rwsem_is_locked() function from 2011+, I don't
think it's overly egregious to add a write equivalent.

We have a specific need for that, as the VMA locking logic asserts the mmap
write lock is held before you can check the VMA write lock is held.

I suppose we could rely on the mmap write lock assert in
__is_vma_write_locked(), because if it's not set we want to assert, but
then we lose all the neat and structured design here...

Would kind of suck for vma_is_read_locked() to not assert but
vma_is_write_locked() to assert.

Really I don't think __is_vma_write_locked() should be asserting like that
anyway, it's a footgun to make a predicate check like that assert
IMO... but that might speak more broadly to the overly complicated
implementation of VMA locks we have now.
Re: [PATCH RESEND 1/3] locking: add rwsem_is_write_locked(), update non-lockdep asserts
Posted by Sebastian Andrzej Siewior 3 weeks, 2 days ago
On 2026-01-16 15:50:24 [+0000], Lorenzo Stoakes wrote:
> No, but we need to be able to assert that one of two locks are held and we
> don't want the failure of one being held to cause an assert when the other
> isn't.

But why don't you use the lockdep based check? That assert only ensures
that it is locked at the time you did the check. This does not mean you
are owner - it could be owned by another task which is unrelated to your
cause.

Sebastian
Re: [PATCH RESEND 1/3] locking: add rwsem_is_write_locked(), update non-lockdep asserts
Posted by Lorenzo Stoakes 3 weeks, 2 days ago
On Fri, Jan 16, 2026 at 04:57:43PM +0100, Sebastian Andrzej Siewior wrote:
> On 2026-01-16 15:50:24 [+0000], Lorenzo Stoakes wrote:
> > No, but we need to be able to assert that one of two locks are held and we
> > don't want the failure of one being held to cause an assert when the other
> > isn't.
>
> But why don't you use the lockdep based check? That assert only ensures

Not sure what you mean, the checks I'm adding don't exist yet.

> that it is locked at the time you did the check. This does not mean you
> are owner - it could be owned by another task which is unrelated to your
> cause.

Yup I'm aware that lockdep tests more than a simple assert.

I wasn't aware this was possible with the lockdep primitives, mea culpa.

Also this came out of a previous discussion where I added a similar
predicate vma_is_detached() and Suren suggested similar for the locks.

Anyway, I went and looked and yes I see there's lockdep_is_held() for
instance.

However, I'd STILL need to do what I'm doing here to account for
CONFIG_DEBUG_VM && !CONFIG_LOCKDEP configurations right?

So I'll respin later with if (IS_ENABLED(CONFIG_LOCKDEP)) ...
And sprinkle with some lockdep_is_held() and see how that works.

I mean rwsem_is_locked() is already specified, so naming is going to be a
thing now but I guess:

static inline bool rwsem_is_locked_nolockdep(const struct rw_semaphore *sem)
{
	return rw_base_is_locked(&sem->rwbase);
}

static inline bool rwsem_is_locked(const struct rw_semaphore *sem)
{
	if (IS_ENABLED(CONFIG_LOCKDEP))
		return lockdep_is_held(sem);

	return rwsem_is_locked_nolockdep(sem);
}

And obviously equivalent for the write case is what's necessary now right?

Or am I misunderstanding you?

>
> Sebastian

Thanks, Lorenzo
Re: [PATCH RESEND 1/3] locking: add rwsem_is_write_locked(), update non-lockdep asserts
Posted by Boqun Feng 3 weeks, 2 days ago
On Fri, Jan 16, 2026 at 04:21:29PM +0000, Lorenzo Stoakes wrote:
> On Fri, Jan 16, 2026 at 04:57:43PM +0100, Sebastian Andrzej Siewior wrote:
> > On 2026-01-16 15:50:24 [+0000], Lorenzo Stoakes wrote:
> > > No, but we need to be able to assert that one of two locks are held and we
> > > don't want the failure of one being held to cause an assert when the other
> > > isn't.
> >
> > But why don't you use the lockdep based check? That assert only ensures
> 
> Not sure what you mean, the checks I'm adding don't exist yet.
> 
> > that it is locked at the time you did the check. This does not mean you
> > are owner - it could be owned by another task which is unrelated to your
> > cause.
> 
> Yup I'm aware that lockdep tests more than a simple assert.
> 
> I wasn't aware this was possible with the lockdep primitives, mea culpa.
> 
> Also this came out of a previous discussion where I added a similar
> predicate vma_is_detached() and Suren suggested similar for the locks.
> 
> Anyway, I went and looked and yes I see there's lockdep_is_held() for
> instance.
> 
> However, I'd STILL need to do what I'm doing here to account for
> CONFIG_DEBUG_VM && !CONFIG_LOCKDEP configurations right?
> 

There is an idea about a light weight lockdep where we only remain
tracking the held locks in a per-task stack and skip the whole
dependency checking, that would provide lock holding
information without the full cost of LOCKDEP, but that requires some
work and I'm not sure whether it fulfills what you need for DEBUG_VM
tests (each task_struct would have some extra space and lock/unlock
would do extra book-keeping).

> So I'll respin later with if (IS_ENABLED(CONFIG_LOCKDEP)) ...
> And sprinkle with some lockdep_is_held() and see how that works.
> 

Yeah, for LOCKDEP=y cases, please do use lockdep_is_held() or
lockdep_is_held_type(), those would provide the accurate information.

> I mean rwsem_is_locked() is already specified, so naming is going to be a
> thing now but I guess:
> 
> static inline bool rwsem_is_locked_nolockdep(const struct rw_semaphore *sem)
> {
> 	return rw_base_is_locked(&sem->rwbase);
> }
> 
> static inline bool rwsem_is_locked(const struct rw_semaphore *sem)
> {
> 	if (IS_ENABLED(CONFIG_LOCKDEP))
> 		return lockdep_is_held(sem);
> 
> 	return rwsem_is_locked_nolockdep(sem);
> }
> 
> And obviously equivalent for the write case is what's necessary now right?
> 

Assuming we want CONFIG_LOCKDEP=n cases to work without extra
book-keeping, I think we could use rwsem_owner() for write cases, and
name the function as rwsem_is_write_held(), which tells you whether
the current thread is the owner of the write lock (we are lucky here
because rwsem is one of those locks remember their owners ;-)). This
would cover the use case of MM without introducing another is_locked()
function. Peter & Sebastian, how do you like (or not hate ;-)) that
idea?

Regards,
Boqun

> Or am I misunderstanding you?
> 
> >
> > Sebastian
> 
> Thanks, Lorenzo
Re: [PATCH RESEND 1/3] locking: add rwsem_is_write_locked(), update non-lockdep asserts
Posted by Sebastian Andrzej Siewior 3 weeks, 2 days ago
On 2026-01-16 16:21:29 [+0000], Lorenzo Stoakes wrote:
> On Fri, Jan 16, 2026 at 04:57:43PM +0100, Sebastian Andrzej Siewior wrote:
> > On 2026-01-16 15:50:24 [+0000], Lorenzo Stoakes wrote:
> > > No, but we need to be able to assert that one of two locks are held and we
> > > don't want the failure of one being held to cause an assert when the other
> > > isn't.
> >
> > But why don't you use the lockdep based check? That assert only ensures
> 
> Not sure what you mean, the checks I'm adding don't exist yet.

The checks you add are not lockdep.

> > that it is locked at the time you did the check. This does not mean you
> > are owner - it could be owned by another task which is unrelated to your
> > cause.
> 
> Yup I'm aware that lockdep tests more than a simple assert.
> 
> I wasn't aware this was possible with the lockdep primitives, mea culpa.
> 
> Also this came out of a previous discussion where I added a similar
> predicate vma_is_detached() and Suren suggested similar for the locks.
> 
> Anyway, I went and looked and yes I see there's lockdep_is_held() for
> instance.
> 
> However, I'd STILL need to do what I'm doing here to account for
> CONFIG_DEBUG_VM && !CONFIG_LOCKDEP configurations right?

Without CONFIG_LOCKDEP the locking view is not really accurate. So maybe
it is not worth doing it. The complains are that lockdep is too slow but
the other checks are just "is it locked by someone? - fine". 

> So I'll respin later with if (IS_ENABLED(CONFIG_LOCKDEP)) ...
> And sprinkle with some lockdep_is_held() and see how that works.
> 
> I mean rwsem_is_locked() is already specified, so naming is going to be a
> thing now but I guess:
> 
> static inline bool rwsem_is_locked_nolockdep(const struct rw_semaphore *sem)
> {
> 	return rw_base_is_locked(&sem->rwbase);
> }
> 
> static inline bool rwsem_is_locked(const struct rw_semaphore *sem)
> {
> 	if (IS_ENABLED(CONFIG_LOCKDEP))
> 		return lockdep_is_held(sem);
> 
> 	return rwsem_is_locked_nolockdep(sem);
> }
> 
> And obviously equivalent for the write case is what's necessary now right?

I would drop the rwsem_is_locked.* and just go with
lockdep_assert_held()/ lockdep_assert_held_write(). Unless you want that
verification in production because it is important and false positives
(as in held by other thread and not caller) are zero.

> Or am I misunderstanding you?

Sebastian
Re: [PATCH RESEND 1/3] locking: add rwsem_is_write_locked(), update non-lockdep asserts
Posted by Lorenzo Stoakes 3 weeks, 2 days ago
On Fri, Jan 16, 2026 at 05:41:39PM +0100, Sebastian Andrzej Siewior wrote:
> On 2026-01-16 16:21:29 [+0000], Lorenzo Stoakes wrote:
> > On Fri, Jan 16, 2026 at 04:57:43PM +0100, Sebastian Andrzej Siewior wrote:
> > > On 2026-01-16 15:50:24 [+0000], Lorenzo Stoakes wrote:
> > > > No, but we need to be able to assert that one of two locks are held and we
> > > > don't want the failure of one being held to cause an assert when the other
> > > > isn't.
> > >
> > > But why don't you use the lockdep based check? That assert only ensures
> >
> > Not sure what you mean, the checks I'm adding don't exist yet.
>
> The checks you add are not lockdep.

I understand that thanks (?)

I'm not sure responding point by point is productive here, so let me
summarise:

We often run code locally without lockdep, testing isn't always ideal
across mm and these asserts are gated by CONFIG_DEBUG_VM anyway so yes I
want a non-lockdep version also.

Note that existing mm lock asserts already work this way, so that's
consistent (though mmap asserts are also at runtime...)

I can't just use existing asserts because I need to test that EITHER one
lock OR the other is held. If there's a way to do that with lockdep in a
way other than what I have suggested, I am more than happy to hear it?

If not I'll respin this with both a lockdep + not-lockdep version.

What you're suggesting, just using the existing lockdep asserts, won't work
unless I'm missing something, because of this _either_ lock requirement.

But if there is an existing solution that you can point me at I'd be more
than happy to use it.

Thanks, Lorenzo