Skip to content

Commit cf39a6b

Browse files
Scott BauerChristoph Hellwig
authored andcommitted
nvme: ensure forward progress during Admin passthru
If the controller supports effects and goes down during the passthru admin command we will deadlock during namespace revalidation. [ 363.488275] INFO: task kworker/u16:5:231 blocked for more than 120 seconds. [ 363.488290] Not tainted 4.17.0+ #2 [ 363.488296] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. [ 363.488303] kworker/u16:5 D 0 231 2 0x80000000 [ 363.488331] Workqueue: nvme-reset-wq nvme_reset_work [nvme] [ 363.488338] Call Trace: [ 363.488385] schedule+0x75/0x190 [ 363.488396] rwsem_down_read_failed+0x1c3/0x2f0 [ 363.488481] call_rwsem_down_read_failed+0x14/0x30 [ 363.488504] down_read+0x1d/0x80 [ 363.488523] nvme_stop_queues+0x1e/0xa0 [nvme_core] [ 363.488536] nvme_dev_disable+0xae4/0x1620 [nvme] [ 363.488614] nvme_reset_work+0xd1e/0x49d9 [nvme] [ 363.488911] process_one_work+0x81a/0x1400 [ 363.488934] worker_thread+0x87/0xe80 [ 363.488955] kthread+0x2db/0x390 [ 363.488977] ret_from_fork+0x35/0x40 Fixes: 84fef62 ("nvme: check admin passthru command effects") Signed-off-by: Scott Bauer <[email protected]> Reviewed-by: Keith Busch <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]>
1 parent b6e44b4 commit cf39a6b

File tree

1 file changed

+26
-24
lines changed

1 file changed

+26
-24
lines changed

drivers/nvme/host/core.c

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,22 @@ static struct class *nvme_subsys_class;
100100
static void nvme_ns_remove(struct nvme_ns *ns);
101101
static int nvme_revalidate_disk(struct gendisk *disk);
102102
static void nvme_put_subsystem(struct nvme_subsystem *subsys);
103+
static void nvme_remove_invalid_namespaces(struct nvme_ctrl *ctrl,
104+
unsigned nsid);
105+
106+
static void nvme_set_queue_dying(struct nvme_ns *ns)
107+
{
108+
/*
109+
* Revalidating a dead namespace sets capacity to 0. This will end
110+
* buffered writers dirtying pages that can't be synced.
111+
*/
112+
if (!ns->disk || test_and_set_bit(NVME_NS_DEAD, &ns->flags))
113+
return;
114+
revalidate_disk(ns->disk);
115+
blk_set_queue_dying(ns->queue);
116+
/* Forcibly unquiesce queues to avoid blocking dispatch */
117+
blk_mq_unquiesce_queue(ns->queue);
118+
}
103119

104120
static void nvme_queue_scan(struct nvme_ctrl *ctrl)
105121
{
@@ -1151,19 +1167,15 @@ static u32 nvme_passthru_start(struct nvme_ctrl *ctrl, struct nvme_ns *ns,
11511167

11521168
static void nvme_update_formats(struct nvme_ctrl *ctrl)
11531169
{
1154-
struct nvme_ns *ns, *next;
1155-
LIST_HEAD(rm_list);
1170+
struct nvme_ns *ns;
11561171

1157-
down_write(&ctrl->namespaces_rwsem);
1158-
list_for_each_entry(ns, &ctrl->namespaces, list) {
1159-
if (ns->disk && nvme_revalidate_disk(ns->disk)) {
1160-
list_move_tail(&ns->list, &rm_list);
1161-
}
1162-
}
1163-
up_write(&ctrl->namespaces_rwsem);
1172+
down_read(&ctrl->namespaces_rwsem);
1173+
list_for_each_entry(ns, &ctrl->namespaces, list)
1174+
if (ns->disk && nvme_revalidate_disk(ns->disk))
1175+
nvme_set_queue_dying(ns);
1176+
up_read(&ctrl->namespaces_rwsem);
11641177

1165-
list_for_each_entry_safe(ns, next, &rm_list, list)
1166-
nvme_ns_remove(ns);
1178+
nvme_remove_invalid_namespaces(ctrl, NVME_NSID_ALL);
11671179
}
11681180

11691181
static void nvme_passthru_end(struct nvme_ctrl *ctrl, u32 effects)
@@ -3138,7 +3150,7 @@ static void nvme_remove_invalid_namespaces(struct nvme_ctrl *ctrl,
31383150

31393151
down_write(&ctrl->namespaces_rwsem);
31403152
list_for_each_entry_safe(ns, next, &ctrl->namespaces, list) {
3141-
if (ns->head->ns_id > nsid)
3153+
if (ns->head->ns_id > nsid || test_bit(NVME_NS_DEAD, &ns->flags))
31423154
list_move_tail(&ns->list, &rm_list);
31433155
}
31443156
up_write(&ctrl->namespaces_rwsem);
@@ -3542,19 +3554,9 @@ void nvme_kill_queues(struct nvme_ctrl *ctrl)
35423554
if (ctrl->admin_q)
35433555
blk_mq_unquiesce_queue(ctrl->admin_q);
35443556

3545-
list_for_each_entry(ns, &ctrl->namespaces, list) {
3546-
/*
3547-
* Revalidating a dead namespace sets capacity to 0. This will
3548-
* end buffered writers dirtying pages that can't be synced.
3549-
*/
3550-
if (!ns->disk || test_and_set_bit(NVME_NS_DEAD, &ns->flags))
3551-
continue;
3552-
revalidate_disk(ns->disk);
3553-
blk_set_queue_dying(ns->queue);
3557+
list_for_each_entry(ns, &ctrl->namespaces, list)
3558+
nvme_set_queue_dying(ns);
35543559

3555-
/* Forcibly unquiesce queues to avoid blocking dispatch */
3556-
blk_mq_unquiesce_queue(ns->queue);
3557-
}
35583560
up_read(&ctrl->namespaces_rwsem);
35593561
}
35603562
EXPORT_SYMBOL_GPL(nvme_kill_queues);

0 commit comments

Comments
 (0)