diff --git a/block/blk-mq.c b/block/blk-mq.c index 7096f23b18da0fd2d10dbb146a15ab4e2b05cf2d..41e92dbff821024460676d2f7415c6490740acc9 100644 --- a/block/blk-mq.c +++ b/block/blk-mq.c @@ -242,6 +242,24 @@ void blk_mq_quiesce_queue(struct request_queue *q) } EXPORT_SYMBOL_GPL(blk_mq_quiesce_queue); +bool blk_mq_quiesce_queue_without_rcu(struct request_queue *q) +{ + struct blk_mq_hw_ctx *hctx; + unsigned int i; + bool rcu = false; + + blk_mq_quiesce_queue_nowait(q); + + queue_for_each_hw_ctx(q, hctx, i) { + if (hctx->flags & BLK_MQ_F_BLOCKING) + synchronize_srcu(hctx->srcu); + else + rcu = true; + } + return rcu; +} +EXPORT_SYMBOL_GPL(blk_mq_quiesce_queue_without_rcu); + /* * blk_mq_unquiesce_queue() - counterpart of blk_mq_quiesce_queue() * @q: request queue. diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 8443c6c5c5afe22266338424fd29d34a9cba9069..c9faa824de26c00b845e57e80eed7b1be2081afe 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -3904,11 +3904,15 @@ EXPORT_SYMBOL_GPL(nvme_start_freeze); void nvme_stop_queues(struct nvme_ctrl *ctrl) { struct nvme_ns *ns; + bool rcu = false; down_read(&ctrl->namespaces_rwsem); list_for_each_entry(ns, &ctrl->namespaces, list) - blk_mq_quiesce_queue(ns->queue); + rcu = (blk_mq_quiesce_queue_without_rcu(ns->queue) || rcu); up_read(&ctrl->namespaces_rwsem); + + if (rcu) + synchronize_rcu(); } EXPORT_SYMBOL_GPL(nvme_stop_queues); diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h index d26edab21d5c52a6dceea8af8a1814daa9c27348..730de600075b5a2ba83ee7a456c65c0a2f02e024 100644 --- a/include/linux/blk-mq.h +++ b/include/linux/blk-mq.h @@ -309,6 +309,7 @@ void blk_mq_start_hw_queues(struct request_queue *q); void blk_mq_start_stopped_hw_queue(struct blk_mq_hw_ctx *hctx, bool async); void blk_mq_start_stopped_hw_queues(struct request_queue *q, bool async); void blk_mq_quiesce_queue(struct request_queue *q); +bool blk_mq_quiesce_queue_without_rcu(struct request_queue *q); void blk_mq_unquiesce_queue(struct request_queue *q); void blk_mq_delay_run_hw_queue(struct blk_mq_hw_ctx *hctx, unsigned long msecs); bool blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx, bool async);