On 07/27/2018 11:29 PM, Bart Van Assche wrote:
> 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 
> https://urldefense.proofpoint.com/v2/url?u=http-3A__lwn.net_Articles_573497_&d=DwIFgQ&c=RoP1YumCXCgaWHvlZYR8PZh8Bv7qIrMUB65eapI_JnE&r=7WdAxUBeiTUTCy8v-7zXyr4qk7sx26ATvfo6QSTvZyQ&m=mkAOXQtxuVTAej2tBjOvEed2h4TRvX3mE-EPeNEUD5E&s=xTgTB2x1JwvRUQVyOL8m3rhbbk8xhOkZMC_Io9bmpFc&e=.

Yes, a synchrorize_rcu is indeed needed here to ensure a q_usage_counter is
got successfully with increasing one,  or unsuccessfully without increasing one.

Thanks
Jianchao

Reply via email to