diff options
author | Scott Bauer <scott.bauer@intel.com> | 2018-06-29 15:03:28 -0400 |
---|---|---|
committer | Christoph Hellwig <hch@lst.de> | 2018-07-17 08:46:19 -0400 |
commit | cf39a6bc342b980f10f344d88035829638a89a48 (patch) | |
tree | b035f19521ca8abe1ed19584dc732e1470b46d8c | |
parent | b6e44b4c74ef75f729f0147d43d189173fe463c9 (diff) |
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: 84fef62d135b6 ("nvme: check admin passthru command effects")
Signed-off-by: Scott Bauer <scott.bauer@intel.com>
Reviewed-by: Keith Busch <keith.busch@linux.intel.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
-rw-r--r-- | drivers/nvme/host/core.c | 50 |
1 files changed, 26 insertions, 24 deletions
diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 46df030b2c3f..e7668c4bb4dd 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c | |||
@@ -100,6 +100,22 @@ static struct class *nvme_subsys_class; | |||
100 | static void nvme_ns_remove(struct nvme_ns *ns); | 100 | static void nvme_ns_remove(struct nvme_ns *ns); |
101 | static int nvme_revalidate_disk(struct gendisk *disk); | 101 | static int nvme_revalidate_disk(struct gendisk *disk); |
102 | static void nvme_put_subsystem(struct nvme_subsystem *subsys); | 102 | 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 | } | ||
103 | 119 | ||
104 | static void nvme_queue_scan(struct nvme_ctrl *ctrl) | 120 | static void nvme_queue_scan(struct nvme_ctrl *ctrl) |
105 | { | 121 | { |
@@ -1151,19 +1167,15 @@ static u32 nvme_passthru_start(struct nvme_ctrl *ctrl, struct nvme_ns *ns, | |||
1151 | 1167 | ||
1152 | static void nvme_update_formats(struct nvme_ctrl *ctrl) | 1168 | static void nvme_update_formats(struct nvme_ctrl *ctrl) |
1153 | { | 1169 | { |
1154 | struct nvme_ns *ns, *next; | 1170 | struct nvme_ns *ns; |
1155 | LIST_HEAD(rm_list); | ||
1156 | 1171 | ||
1157 | down_write(&ctrl->namespaces_rwsem); | 1172 | down_read(&ctrl->namespaces_rwsem); |
1158 | list_for_each_entry(ns, &ctrl->namespaces, list) { | 1173 | list_for_each_entry(ns, &ctrl->namespaces, list) |
1159 | if (ns->disk && nvme_revalidate_disk(ns->disk)) { | 1174 | if (ns->disk && nvme_revalidate_disk(ns->disk)) |
1160 | list_move_tail(&ns->list, &rm_list); | 1175 | nvme_set_queue_dying(ns); |
1161 | } | 1176 | up_read(&ctrl->namespaces_rwsem); |
1162 | } | ||
1163 | up_write(&ctrl->namespaces_rwsem); | ||
1164 | 1177 | ||
1165 | list_for_each_entry_safe(ns, next, &rm_list, list) | 1178 | nvme_remove_invalid_namespaces(ctrl, NVME_NSID_ALL); |
1166 | nvme_ns_remove(ns); | ||
1167 | } | 1179 | } |
1168 | 1180 | ||
1169 | static void nvme_passthru_end(struct nvme_ctrl *ctrl, u32 effects) | 1181 | 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, | |||
3138 | 3150 | ||
3139 | down_write(&ctrl->namespaces_rwsem); | 3151 | down_write(&ctrl->namespaces_rwsem); |
3140 | list_for_each_entry_safe(ns, next, &ctrl->namespaces, list) { | 3152 | 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)) |
3142 | list_move_tail(&ns->list, &rm_list); | 3154 | list_move_tail(&ns->list, &rm_list); |
3143 | } | 3155 | } |
3144 | up_write(&ctrl->namespaces_rwsem); | 3156 | up_write(&ctrl->namespaces_rwsem); |
@@ -3542,19 +3554,9 @@ void nvme_kill_queues(struct nvme_ctrl *ctrl) | |||
3542 | if (ctrl->admin_q) | 3554 | if (ctrl->admin_q) |
3543 | blk_mq_unquiesce_queue(ctrl->admin_q); | 3555 | blk_mq_unquiesce_queue(ctrl->admin_q); |
3544 | 3556 | ||
3545 | list_for_each_entry(ns, &ctrl->namespaces, list) { | 3557 | list_for_each_entry(ns, &ctrl->namespaces, list) |
3546 | /* | 3558 | nvme_set_queue_dying(ns); |
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); | ||
3554 | 3559 | ||
3555 | /* Forcibly unquiesce queues to avoid blocking dispatch */ | ||
3556 | blk_mq_unquiesce_queue(ns->queue); | ||
3557 | } | ||
3558 | up_read(&ctrl->namespaces_rwsem); | 3560 | up_read(&ctrl->namespaces_rwsem); |
3559 | } | 3561 | } |
3560 | EXPORT_SYMBOL_GPL(nvme_kill_queues); | 3562 | EXPORT_SYMBOL_GPL(nvme_kill_queues); |