Thread (10 messages) 10 messages, 4 authors, 2018-07-19

Re: [PATCH 2/3] block, scsi: Rework runtime power management

From: Ming Lei <hidden>
Date: 2018-07-18 22:45:46

On Wed, Jul 18, 2018 at 03:45:15PM +0000, Bart Van Assche wrote:
On Wed, 2018-07-18 at 20:16 +0800, Ming Lei wrote:
quoted
On Wed, Jul 18, 2018 at 7:49 AM, Bart Van Assche [off-list ref] wrote:
quoted
@@ -3801,8 +3778,11 @@ int blk_pre_runtime_suspend(struct request_queue *q)
        if (!q->dev)
                return ret;

+       blk_set_preempt_only(q);
+       blk_freeze_queue_start(q);
+
        spin_lock_irq(q->queue_lock);
-       if (q->nr_pending) {
+       if (!percpu_ref_is_zero(&q->q_usage_counter)) {
This way can't work reliably because the percpu ref isn't in atomic mode
yet after blk_freeze_queue_start() returns, then percpu_ref_is_zero() won't
see accurate value of the counter, finally the device may be put down before
in-flight requests are completed by hardware.
Hello Ming,

The blk_freeze_queue_start() implementation is as follows:

void blk_freeze_queue_start(struct request_queue *q)
{
	int freeze_depth;

	freeze_depth = atomic_inc_return(&q->mq_freeze_depth);
	if (freeze_depth == 1) {
		percpu_ref_kill(&q->q_usage_counter);
		if (q->mq_ops)
			blk_mq_run_hw_queues(q, false);
	}
}

From the documentation header in include/linux/percpu-refcount.h above
percpu_ref_kill():

 * Switches @ref into atomic mode before gathering up the percpu counters
 * and dropping the initial ref.
IMO, the comment isn't accurate enough. Yes, the counter becomes atomic
mode after percpu_ref_kill() returns, but the counter can't be retrieved
accurately before the rcu confirmation is done.

One extra get is done in __percpu_ref_switch_to_atomic(), and the put pair
is run in percpu_ref_call_confirm_rcu(), which is scheduled via call_rcu_sched().

So once blk_freeze_queue_start() returns, percpu_ref_is_zero() won't
return true only until the rcu confirmation is done. That means this
approach may not put device down.

Thanks,
Ming
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help