History

blk-mq: drain I/O when all CPUs in a hctx are offline

Most of blk-mq drivers depend on managed IRQ's auto-affinity to setup up queue mapping. Thomas mentioned the following point[1]: "That was the constraint of managed interrupts from the very beginning: The driver/subsystem has to quiesce the interrupt line and the associated queue _before_ it gets shutdown in CPU unplug and not fiddle with it until it's restarted by the core when the CPU is plugged in again." However, current blk-mq implementation doesn't quiesce hw queue before the last CPU in the hctx is shutdown. Even worse, CPUHP_BLK_MQ_DEAD is a cpuhp state handled after the CPU is down, so there isn't any chance to quiesce the hctx before shutting down the CPU. Add new CPUHP_AP_BLK_MQ_ONLINE state to stop allocating from blk-mq hctxs where the last CPU goes away, and wait for completion of in-flight requests. This guarantees that there is no inflight I/O before shutting down the managed IRQ. Add a BLK_MQ_F_STACKING and set it for dm-rq and loop, so we don't need to wait for completion of in-flight requests from these drivers to avoid a potential dead-lock. It is safe to do this for stacking drivers as those do not use interrupts at all and their I/O completions are triggered by underlying devices I/O completion. [1] https://lore.kernel.org/linux-block/alpine.DEB.2.21.1904051331270.1802@nanos.tec.linutronix.de/ [hch: different retry mechanism, merged two patches, minor cleanups]

Ming Lei committed 6 years ago

Commit bf0beec1 parent 602380d7 files · +133 −4Browse files

Showing the changes to include/linux (2 of 7 files). Show all

Unified · Split

2 files
  1. include/linux/blk-mq.h +10 −0
  2. include/linux/cpuhotplug.h +1 −0
include/linux/blk-mq.h+10−0
@@ -140,6 +140,8 @@ struct blk_mq_hw_ctx { · 139 unmodified lines
140 */140 */
141 atomic_t nr_active;141 atomic_t nr_active;
142 142
143 /** @cpuhp_online: List to store request if CPU is going to die */
144 struct hlist_node cpuhp_online;
143 /** @cpuhp_dead: List to store request if some CPU die. */145 /** @cpuhp_dead: List to store request if some CPU die. */
144 struct hlist_node cpuhp_dead;146 struct hlist_node cpuhp_dead;
145 /** @kobj: Kernel object for sysfs. */147 /** @kobj: Kernel object for sysfs. */
@@ -391,6 +393,11 @@ struct blk_mq_ops { · 245 unmodified lines
391enum {393enum {
392 BLK_MQ_F_SHOULD_MERGE = 1 << 0,394 BLK_MQ_F_SHOULD_MERGE = 1 << 0,
393 BLK_MQ_F_TAG_SHARED = 1 << 1,395 BLK_MQ_F_TAG_SHARED = 1 << 1,
396 /*
397 * Set when this device requires underlying blk-mq device for
398 * completing IO:
399 */
400 BLK_MQ_F_STACKING = 1 << 2,
394 BLK_MQ_F_BLOCKING = 1 << 5,401 BLK_MQ_F_BLOCKING = 1 << 5,
395 BLK_MQ_F_NO_SCHED = 1 << 6,402 BLK_MQ_F_NO_SCHED = 1 << 6,
396 BLK_MQ_F_ALLOC_POLICY_START_BIT = 8,403 BLK_MQ_F_ALLOC_POLICY_START_BIT = 8,
@@ -400,6 +407,9 @@ enum { · 3 unmodified lines
400 BLK_MQ_S_TAG_ACTIVE = 1,407 BLK_MQ_S_TAG_ACTIVE = 1,
401 BLK_MQ_S_SCHED_RESTART = 2,408 BLK_MQ_S_SCHED_RESTART = 2,
402 409
410 /* hw queue is inactive after all its CPUs become offline */
411 BLK_MQ_S_INACTIVE = 3,
412
403 BLK_MQ_MAX_DEPTH = 10240,413 BLK_MQ_MAX_DEPTH = 10240,
404 414
405 BLK_MQ_CPU_WORK_BATCH = 8,415 BLK_MQ_CPU_WORK_BATCH = 8,
include/linux/cpuhotplug.h+1−0
@@ -152,6 +152,7 @@ enum cpuhp_state { · 151 unmodified lines
152 CPUHP_AP_SMPBOOT_THREADS,152 CPUHP_AP_SMPBOOT_THREADS,
153 CPUHP_AP_X86_VDSO_VMA_ONLINE,153 CPUHP_AP_X86_VDSO_VMA_ONLINE,
154 CPUHP_AP_IRQ_AFFINITY_ONLINE,154 CPUHP_AP_IRQ_AFFINITY_ONLINE,
155 CPUHP_AP_BLK_MQ_ONLINE,
155 CPUHP_AP_ARM_MVEBU_SYNC_CLOCKS,156 CPUHP_AP_ARM_MVEBU_SYNC_CLOCKS,
156 CPUHP_AP_X86_INTEL_EPB_ONLINE,157 CPUHP_AP_X86_INTEL_EPB_ONLINE,
157 CPUHP_AP_PERF_ONLINE,158 CPUHP_AP_PERF_ONLINE,