diff mbox series

blk-cgroup: fix rcu lockdep warning in blkg_lookup()

Message ID 20231219012833.2129540-1-ming.lei@redhat.com (mailing list archive)
State New, archived
Headers show
Series blk-cgroup: fix rcu lockdep warning in blkg_lookup() | expand

Commit Message

Ming Lei Dec. 19, 2023, 1:28 a.m. UTC
blkg_lookup() is called with either queue_lock or rcu read lock, so
use rcu_dereference_check(lockdep_is_held(&q->queue_lock)) for
retrieving 'blkg', which way models the check exactly for covering
queue lock or rcu read lock.

Fix lockdep warning of "block/blk-cgroup.h:254 suspicious rcu_dereference_check() usage!"
from blkg_lookup().

Tested-by: Changhui Zhong <czhong@redhat.com>
Signed-off-by: Ming Lei <ming.lei@redhat.com>
---
 block/blk-cgroup.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

Comments

Ming Lei Jan. 2, 2024, 7:38 a.m. UTC | #1
On Tue, Dec 19, 2023 at 9:28 AM Ming Lei <ming.lei@redhat.com> wrote:
>
> blkg_lookup() is called with either queue_lock or rcu read lock, so
> use rcu_dereference_check(lockdep_is_held(&q->queue_lock)) for
> retrieving 'blkg', which way models the check exactly for covering
> queue lock or rcu read lock.
>
> Fix lockdep warning of "block/blk-cgroup.h:254 suspicious rcu_dereference_check() usage!"
> from blkg_lookup().
>
> Tested-by: Changhui Zhong <czhong@redhat.com>
> Signed-off-by: Ming Lei <ming.lei@redhat.com>
> ---
>  block/blk-cgroup.h | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/block/blk-cgroup.h b/block/blk-cgroup.h
> index fd482439afbc..b927a4a0ad03 100644
> --- a/block/blk-cgroup.h
> +++ b/block/blk-cgroup.h
> @@ -252,7 +252,8 @@ static inline struct blkcg_gq *blkg_lookup(struct blkcg *blkcg,
>         if (blkcg == &blkcg_root)
>                 return q->root_blkg;
>
> -       blkg = rcu_dereference(blkcg->blkg_hint);
> +       blkg = rcu_dereference_check(blkcg->blkg_hint,
> +                       lockdep_is_held(&q->queue_lock));
>         if (blkg && blkg->q == q)
>                 return blkg;

Hello,

Ping...

Thanks,
Yu Kuai Jan. 2, 2024, 10:32 a.m. UTC | #2
Hi,

在 2023/12/19 9:28, Ming Lei 写道:
> blkg_lookup() is called with either queue_lock or rcu read lock, so
> use rcu_dereference_check(lockdep_is_held(&q->queue_lock)) for
> retrieving 'blkg', which way models the check exactly for covering
> queue lock or rcu read lock.
> 
> Fix lockdep warning of "block/blk-cgroup.h:254 suspicious rcu_dereference_check() usage!"
> from blkg_lookup().
> 
> Tested-by: Changhui Zhong <czhong@redhat.com>
> Signed-off-by: Ming Lei <ming.lei@redhat.com>
> ---
>   block/blk-cgroup.h | 3 ++-
>   1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/block/blk-cgroup.h b/block/blk-cgroup.h
> index fd482439afbc..b927a4a0ad03 100644
> --- a/block/blk-cgroup.h
> +++ b/block/blk-cgroup.h
> @@ -252,7 +252,8 @@ static inline struct blkcg_gq *blkg_lookup(struct blkcg *blkcg,
>   	if (blkcg == &blkcg_root)
>   		return q->root_blkg;
>   
> -	blkg = rcu_dereference(blkcg->blkg_hint);
> +	blkg = rcu_dereference_check(blkcg->blkg_hint,
> +			lockdep_is_held(&q->queue_lock));

This patch itself is correct, and in fact this is a false positive
warning.

I noticed that commit 83462a6c971c ("blkcg: Drop unnecessary RCU read
[un]locks from blkg_conf_prep/finish()") drop rcu_read_lock/unlock()
because 'queue_lock' is held. This is correct, however you add this back
for tg_conf_updated() later in commit 27b13e209ddc ("blk-throttle: fix
lockdep warning of "cgroup_mutex or RCU read lock required!"") because
rcu_read_lock_held() from blkg_lookup() is triggered. And this patch is
again another use case cased by commit 83462a6c971c.

I just wonder, with the respect of rcu implementation, is it possible to
add preemptible() check directly in rcu_read_lock_held() to bypass all
this kind of false positive warning?

Thanks,
Kuai

>   	if (blkg && blkg->q == q)
>   		return blkg;
>   
>
Ming Lei Jan. 2, 2024, 11:27 a.m. UTC | #3
On Tue, Jan 02, 2024 at 06:32:13PM +0800, Yu Kuai wrote:
> Hi,
> 
> 在 2023/12/19 9:28, Ming Lei 写道:
> > blkg_lookup() is called with either queue_lock or rcu read lock, so
> > use rcu_dereference_check(lockdep_is_held(&q->queue_lock)) for
> > retrieving 'blkg', which way models the check exactly for covering
> > queue lock or rcu read lock.
> > 
> > Fix lockdep warning of "block/blk-cgroup.h:254 suspicious rcu_dereference_check() usage!"
> > from blkg_lookup().
> > 
> > Tested-by: Changhui Zhong <czhong@redhat.com>
> > Signed-off-by: Ming Lei <ming.lei@redhat.com>
> > ---
> >   block/blk-cgroup.h | 3 ++-
> >   1 file changed, 2 insertions(+), 1 deletion(-)
> > 
> > diff --git a/block/blk-cgroup.h b/block/blk-cgroup.h
> > index fd482439afbc..b927a4a0ad03 100644
> > --- a/block/blk-cgroup.h
> > +++ b/block/blk-cgroup.h
> > @@ -252,7 +252,8 @@ static inline struct blkcg_gq *blkg_lookup(struct blkcg *blkcg,
> >   	if (blkcg == &blkcg_root)
> >   		return q->root_blkg;
> > -	blkg = rcu_dereference(blkcg->blkg_hint);
> > +	blkg = rcu_dereference_check(blkcg->blkg_hint,
> > +			lockdep_is_held(&q->queue_lock));
> 
> This patch itself is correct, and in fact this is a false positive
> warning.

Yeah, it is, but we always teach lockdep to not trigger warning,

> 
> I noticed that commit 83462a6c971c ("blkcg: Drop unnecessary RCU read
> [un]locks from blkg_conf_prep/finish()") drop rcu_read_lock/unlock()
> because 'queue_lock' is held. This is correct, however you add this back
> for tg_conf_updated() later in commit 27b13e209ddc ("blk-throttle: fix
> lockdep warning of "cgroup_mutex or RCU read lock required!"") because
> rcu_read_lock_held() from blkg_lookup() is triggered. And this patch is
> again another use case cased by commit 83462a6c971c.

We should add:

Fixes: 83462a6c971c ("blkcg: Drop unnecessary RCU read [un]locks from blkg_conf_prep/finish()")

> 
> I just wonder, with the respect of rcu implementation, is it possible to
> add preemptible() check directly in rcu_read_lock_held() to bypass all
> this kind of false positive warning?

It isn't related with rcu_read_lock_held(), and the check is done in
RCU_LOCKDEP_WARN(). rcu_dereference_check() does cover this situation,
and no need to invent wheel for avoiding the warning.

Thanks,
Ming
Yu Kuai Jan. 3, 2024, 1:05 a.m. UTC | #4
在 2024/01/02 19:27, Ming Lei 写道:
> On Tue, Jan 02, 2024 at 06:32:13PM +0800, Yu Kuai wrote:
>> Hi,
>>
>> 在 2023/12/19 9:28, Ming Lei 写道:
>>> blkg_lookup() is called with either queue_lock or rcu read lock, so
>>> use rcu_dereference_check(lockdep_is_held(&q->queue_lock)) for
>>> retrieving 'blkg', which way models the check exactly for covering
>>> queue lock or rcu read lock.
>>>
>>> Fix lockdep warning of "block/blk-cgroup.h:254 suspicious rcu_dereference_check() usage!"
>>> from blkg_lookup().
>>>
>>> Tested-by: Changhui Zhong <czhong@redhat.com>
>>> Signed-off-by: Ming Lei <ming.lei@redhat.com>
>>> ---
>>>    block/blk-cgroup.h | 3 ++-
>>>    1 file changed, 2 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/block/blk-cgroup.h b/block/blk-cgroup.h
>>> index fd482439afbc..b927a4a0ad03 100644
>>> --- a/block/blk-cgroup.h
>>> +++ b/block/blk-cgroup.h
>>> @@ -252,7 +252,8 @@ static inline struct blkcg_gq *blkg_lookup(struct blkcg *blkcg,
>>>    	if (blkcg == &blkcg_root)
>>>    		return q->root_blkg;
>>> -	blkg = rcu_dereference(blkcg->blkg_hint);
>>> +	blkg = rcu_dereference_check(blkcg->blkg_hint,
>>> +			lockdep_is_held(&q->queue_lock));
>>
>> This patch itself is correct, and in fact this is a false positive
>> warning.
> 
> Yeah, it is, but we always teach lockdep to not trigger warning,
> 
>>
>> I noticed that commit 83462a6c971c ("blkcg: Drop unnecessary RCU read
>> [un]locks from blkg_conf_prep/finish()") drop rcu_read_lock/unlock()
>> because 'queue_lock' is held. This is correct, however you add this back
>> for tg_conf_updated() later in commit 27b13e209ddc ("blk-throttle: fix
>> lockdep warning of "cgroup_mutex or RCU read lock required!"") because
>> rcu_read_lock_held() from blkg_lookup() is triggered. And this patch is
>> again another use case cased by commit 83462a6c971c.
> 
> We should add:
> 
> Fixes: 83462a6c971c ("blkcg: Drop unnecessary RCU read [un]locks from blkg_conf_prep/finish()")

With the above fix tag,

Reviewed-by: Yu Kuai <yukuai3@huawei.com>
> 
>>
>> I just wonder, with the respect of rcu implementation, is it possible to
>> add preemptible() check directly in rcu_read_lock_held() to bypass all
>> this kind of false positive warning?
> 
> It isn't related with rcu_read_lock_held(), and the check is done in
> RCU_LOCKDEP_WARN(). rcu_dereference_check() does cover this situation,
> and no need to invent wheel for avoiding the warning.
> 
> Thanks,
> Ming
> 
> 
> .
>
Tejun Heo Jan. 4, 2024, 10:04 p.m. UTC | #5
On Tue, Jan 02, 2024 at 03:38:10PM +0800, Ming Lei wrote:
> On Tue, Dec 19, 2023 at 9:28 AM Ming Lei <ming.lei@redhat.com> wrote:
> >
> > blkg_lookup() is called with either queue_lock or rcu read lock, so
> > use rcu_dereference_check(lockdep_is_held(&q->queue_lock)) for
> > retrieving 'blkg', which way models the check exactly for covering
> > queue lock or rcu read lock.
> >
> > Fix lockdep warning of "block/blk-cgroup.h:254 suspicious rcu_dereference_check() usage!"
> > from blkg_lookup().
> >
> > Tested-by: Changhui Zhong <czhong@redhat.com>
> > Signed-off-by: Ming Lei <ming.lei@redhat.com>

Acked-by: Tejun Heo <tj@kernel.org>

Thanks.
Jens Axboe Jan. 4, 2024, 11:10 p.m. UTC | #6
On Tue, 19 Dec 2023 09:28:33 +0800, Ming Lei wrote:
> blkg_lookup() is called with either queue_lock or rcu read lock, so
> use rcu_dereference_check(lockdep_is_held(&q->queue_lock)) for
> retrieving 'blkg', which way models the check exactly for covering
> queue lock or rcu read lock.
> 
> Fix lockdep warning of "block/blk-cgroup.h:254 suspicious rcu_dereference_check() usage!"
> from blkg_lookup().
> 
> [...]

Applied, thanks!

[1/1] blk-cgroup: fix rcu lockdep warning in blkg_lookup()
      commit: 393cd8ffd832f23eec3a105553eff622e8198918

Best regards,
diff mbox series

Patch

diff --git a/block/blk-cgroup.h b/block/blk-cgroup.h
index fd482439afbc..b927a4a0ad03 100644
--- a/block/blk-cgroup.h
+++ b/block/blk-cgroup.h
@@ -252,7 +252,8 @@  static inline struct blkcg_gq *blkg_lookup(struct blkcg *blkcg,
 	if (blkcg == &blkcg_root)
 		return q->root_blkg;
 
-	blkg = rcu_dereference(blkcg->blkg_hint);
+	blkg = rcu_dereference_check(blkcg->blkg_hint,
+			lockdep_is_held(&q->queue_lock));
 	if (blkg && blkg->q == q)
 		return blkg;