Re: [PATCH v5 10/16] nvme-tcp: Use CCR to recover controller that hits an error
Hannes Reinecke <[email protected]>
| Newsgroups | org.infradead.lists.linux-nvme,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
On 7/12/26 4:23 AM, Mohamed Khalfella wrote: > An alive nvme controller that hits an error now will move to FENCING > state instead of RESETTING state. ctrl->fencing_work attempts CCR to > terminate inflight IOs. Regardless of the success or failure of CCR > operation the controller is transitioned to RESETTING state to continue > error recovery process. > > Signed-off-by: Mohamed Khalfella <[email protected]> > --- > drivers/nvme/host/tcp.c | 30 +++++++++++++++++++++++++++++- > 1 file changed, 29 insertions(+), 1 deletion(-) > > diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c > index ba5c7b3e2a7c..a1711dd1d3c2 100644 > --- a/drivers/nvme/host/tcp.c > +++ b/drivers/nvme/host/tcp.c > @@ -161,6 +161,7 @@ struct nvme_tcp_ctrl { > struct sockaddr_storage src_addr; > struct nvme_ctrl ctrl; > > + struct work_struct fencing_work; > struct work_struct err_work; > struct delayed_work connect_work; > struct nvme_tcp_request async_req; > @@ -605,6 +606,12 @@ static void nvme_tcp_init_recv_ctx(struct nvme_tcp_queue *queue) > > static void nvme_tcp_error_recovery(struct nvme_ctrl *ctrl) > { > + if (nvme_change_ctrl_state(ctrl, NVME_CTRL_FENCING)) { > + dev_warn(ctrl->device, "starting controller fencing\n"); > + queue_work(nvme_wq, &to_tcp_ctrl(ctrl)->fencing_work); > + return; > + } > + > if (!nvme_change_ctrl_state(ctrl, NVME_CTRL_RESETTING)) > return; > > @@ -2494,12 +2501,29 @@ static void nvme_tcp_reconnect_ctrl_work(struct work_struct *work) > nvme_tcp_reconnect_or_remove(ctrl, ret); > } > > +static void nvme_tcp_fencing_work(struct work_struct *work) > +{ > + struct nvme_tcp_ctrl *tcp_ctrl = container_of(work, > + struct nvme_tcp_ctrl, fencing_work); > + struct nvme_ctrl *ctrl = &tcp_ctrl->ctrl; > + unsigned long rem; > + > + rem = nvme_fence_ctrl(ctrl); > + if (rem) > + dev_info(ctrl->device, "CCR failed, starting error recovery\n"); > + > + nvme_change_ctrl_state(ctrl, NVME_CTRL_FENCED); This needs to be before nvme_fence_ctrl(). Otherwise the state is meaningless are we're moving to RESETTING directly afterwards. > + if (nvme_change_ctrl_state(ctrl, NVME_CTRL_RESETTING)) > + queue_work(nvme_reset_wq, &tcp_ctrl->err_work); > +} > + > static void nvme_tcp_error_recovery_work(struct work_struct *work) > { > struct nvme_tcp_ctrl *tcp_ctrl = container_of(work, > struct nvme_tcp_ctrl, err_work); > struct nvme_ctrl *ctrl = &tcp_ctrl->ctrl; > > + flush_work(&to_tcp_ctrl(ctrl)->fencing_work); Not so happy with this one here. _If_ fencing is still running we really should not be entering here. And If fencing is not running we won't need to call it. I'd prefer some sort of WARN_ON() here if fencing is still running. > if (nvme_tcp_key_revoke_needed(ctrl)) > nvme_auth_revoke_tls_key(ctrl); > nvme_stop_keep_alive(ctrl); > @@ -2542,6 +2566,7 @@ static void nvme_reset_ctrl_work(struct work_struct *work) > container_of(work, struct nvme_ctrl, reset_work); > int ret; > > + flush_work(&to_tcp_ctrl(ctrl)->fencing_work); Same here. > if (nvme_tcp_key_revoke_needed(ctrl)) > nvme_auth_revoke_tls_key(ctrl); > nvme_stop_ctrl(ctrl); > @@ -2667,13 +2692,15 @@ static enum blk_eh_timer_return nvme_tcp_timeout(struct request *rq) > struct nvme_tcp_cmd_pdu *pdu = nvme_tcp_req_cmd_pdu(req); > struct nvme_command *cmd = &pdu->cmd; > int qid = nvme_tcp_queue_id(req->queue); > + enum nvme_ctrl_state state; > > dev_warn(ctrl->device, > "I/O tag %d (%04x) type %d opcode %#x (%s) QID %d timeout\n", > rq->tag, nvme_cid(rq), pdu->hdr.type, cmd->common.opcode, > nvme_fabrics_opcode_str(qid, cmd), qid); > > - if (nvme_ctrl_state(ctrl) != NVME_CTRL_LIVE) { > + state = nvme_ctrl_state(ctrl); > + if (state != NVME_CTRL_LIVE && state != NVME_CTRL_FENCING) { > /* > * If we are resetting, connecting or deleting we should > * complete immediately because we may block controller > @@ -2928,6 +2955,7 @@ static struct nvme_tcp_ctrl *nvme_tcp_alloc_ctrl(struct device *dev, > > INIT_DELAYED_WORK(&ctrl->connect_work, > nvme_tcp_reconnect_ctrl_work); > + INIT_WORK(&ctrl->fencing_work, nvme_tcp_fencing_work); > INIT_WORK(&ctrl->err_work, nvme_tcp_error_recovery_work); > INIT_WORK(&ctrl->ctrl.reset_work, nvme_reset_ctrl_work); > Cheers, Hannes -- Dr. Hannes Reinecke Kernel Storage Architect [email protected] +49 911 74053 688 SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich