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.

Reply via email to