On Fri, 2018-07-27 at 09:57 +0800, jianchao.wang wrote:
> Something like:
> 
>       percpu_ref_switch_to_atomic_sync(&q->q_usage_counter);
>       if (!percpu_ref_is_zero(&q->q_usage_counter)) {
>               ret = -EBUSY;
>               pm_runtime_mark_last_busy(q->dev);
>       } else {
>               blk_set_preempt_only(q);
>               if (!percpu_ref_is_zero(&q->q_usage_counter) {
>                       ret = -EBUSY;
>                       pm_runtime_mark_last_busy(q->dev);
>                       blk_clear_preempt_only(q);
>               } else {
>                       q->rpm_status = RPM_SUSPENDIN;    
>               }
>         }

I think this code is racy. Because there is no memory barrier in
blk_queue_enter() between the percpu_ref_tryget_live() and the
blk_queue_preempt_only() calls, the context that sets the PREEMPT_ONLY flag
has to use synchronize_rcu() or call_rcu() to ensure that blk_queue_enter()
sees the PREEMPT_ONLY flag after it has called percpu_ref_tryget_live().
See also http://lwn.net/Articles/573497/.

Bart.

Reply via email to