On Mon, 2017-04-10 at 09:54 -0600, Jens Axboe wrote:
> @@ -1281,27 +1280,39 @@ static void blk_mq_run_work_fn(struct work_struct
> *work)
> struct blk_mq_hw_ctx *hctx;
>
> hctx = container_of(work, struct blk_mq_hw_ctx, run_work.work);
> - __blk_mq_run_hw_queue(hctx);
> -}
>
> -static void blk_mq_delay_work_fn(struct work_struct *work)
> -{
> - struct blk_mq_hw_ctx *hctx;
> + /*
> + * If we are stopped, don't run the queue. The exception is if
> + * BLK_MQ_S_START_ON_RUN is set. For that case, we auto-clear
> + * the STOPPED bit and run it.
> + */
> + if (test_bit(BLK_MQ_S_STOPPED, &hctx->state)) {
> + if (!test_bit(BLK_MQ_S_START_ON_RUN, &hctx->state))
> + return;
>
> - hctx = container_of(work, struct blk_mq_hw_ctx, delay_work.work);
> + clear_bit(BLK_MQ_S_START_ON_RUN, &hctx->state);
> + clear_bit(BLK_MQ_S_STOPPED, &hctx->state);
> + }
>
> - if (test_and_clear_bit(BLK_MQ_S_STOPPED, &hctx->state))
> - __blk_mq_run_hw_queue(hctx);
> + __blk_mq_run_hw_queue(hctx);
> }
>
> +
> void blk_mq_delay_queue(struct blk_mq_hw_ctx *hctx, unsigned long msecs)
> {
> if (unlikely(!blk_mq_hw_queue_mapped(hctx)))
> return;
>
> + /*
> + * Stop the hw queue, then modify currently delayed work.
> + * This should prevent us from running the queue prematurely.
> + * Mark the queue as auto-clearing STOPPED when it runs.
> + */
> blk_mq_stop_hw_queue(hctx);
> - kblockd_schedule_delayed_work_on(blk_mq_hctx_next_cpu(hctx),
> - &hctx->delay_work, msecs_to_jiffies(msecs));
> + set_bit(BLK_MQ_S_START_ON_RUN, &hctx->state);
> + kblockd_mod_delayed_work_on(blk_mq_hctx_next_cpu(hctx),
> + &hctx->run_work,
> + msecs_to_jiffies(msecs));
> }
> EXPORT_SYMBOL(blk_mq_delay_queue);
Hello Jens,
Is it possible for a block driver to call blk_mq_delay_queue() while
blk_mq_delay_work_fn() is running? Can that result in BLK_MQ_S_STOPPED
and BLK_MQ_S_START_ON_RUN being checked by blk_mq_delay_work_fn() after
blk_mq_delay_queue() has set BLK_MQ_S_STOPPED and before it has set
BLK_MQ_S_START_ON_RUN?
Thanks,
Bart.