Skip to content

Commit 4c75f87

Browse files
committed
nvme: Prevent resets during paused controller state
A paused controller is doing critical internal activation work in the background. Prevent subsequent controller resets from occurring during this period by setting the controller state to RESETTING first. A helper function, nvme_try_sched_reset_work(), is introduced for these paths so they may continue with scheduling the reset_work after they've completed their uninterruptible critical section. Tested-by: Edmund Nadolski <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Signed-off-by: Keith Busch <[email protected]>
1 parent 92b98e8 commit 4c75f87

File tree

1 file changed

+25
-4
lines changed

1 file changed

+25
-4
lines changed

drivers/nvme/host/core.c

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,21 @@ static void nvme_queue_scan(struct nvme_ctrl *ctrl)
120120
queue_work(nvme_wq, &ctrl->scan_work);
121121
}
122122

123+
/*
124+
* Use this function to proceed with scheduling reset_work for a controller
125+
* that had previously been set to the resetting state. This is intended for
126+
* code paths that can't be interrupted by other reset attempts. A hot removal
127+
* may prevent this from succeeding.
128+
*/
129+
static int nvme_try_sched_reset(struct nvme_ctrl *ctrl)
130+
{
131+
if (ctrl->state != NVME_CTRL_RESETTING)
132+
return -EBUSY;
133+
if (!queue_work(nvme_reset_wq, &ctrl->reset_work))
134+
return -EBUSY;
135+
return 0;
136+
}
137+
123138
int nvme_reset_ctrl(struct nvme_ctrl *ctrl)
124139
{
125140
if (!nvme_change_ctrl_state(ctrl, NVME_CTRL_RESETTING))
@@ -3828,13 +3843,13 @@ static void nvme_fw_act_work(struct work_struct *work)
38283843
if (time_after(jiffies, fw_act_timeout)) {
38293844
dev_warn(ctrl->device,
38303845
"Fw activation timeout, reset controller\n");
3831-
nvme_reset_ctrl(ctrl);
3832-
break;
3846+
nvme_try_sched_reset(ctrl);
3847+
return;
38333848
}
38343849
msleep(100);
38353850
}
38363851

3837-
if (ctrl->state != NVME_CTRL_LIVE)
3852+
if (!nvme_change_ctrl_state(ctrl, NVME_CTRL_LIVE))
38383853
return;
38393854

38403855
nvme_start_queues(ctrl);
@@ -3854,7 +3869,13 @@ static void nvme_handle_aen_notice(struct nvme_ctrl *ctrl, u32 result)
38543869
nvme_queue_scan(ctrl);
38553870
break;
38563871
case NVME_AER_NOTICE_FW_ACT_STARTING:
3857-
queue_work(nvme_wq, &ctrl->fw_act_work);
3872+
/*
3873+
* We are (ab)using the RESETTING state to prevent subsequent
3874+
* recovery actions from interfering with the controller's
3875+
* firmware activation.
3876+
*/
3877+
if (nvme_change_ctrl_state(ctrl, NVME_CTRL_RESETTING))
3878+
queue_work(nvme_wq, &ctrl->fw_act_work);
38583879
break;
38593880
#ifdef CONFIG_NVME_MULTIPATH
38603881
case NVME_AER_NOTICE_ANA:

0 commit comments

Comments
 (0)