nvmet-fc: free pending reqs on tgtport unregister

When nvmet_fc_unregister_targetport is called by the LLDD, it's not
possible to communicate with the host, thus all pending request will not
be process. Thus explicitly free them.

Signed-off-by: Daniel Wagner <wagi@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
Daniel Wagner 2025-05-07 14:23:08 +02:00 committed by Christoph Hellwig
parent 84eedced1c
commit bbccbf791e

View File

@ -1583,6 +1583,39 @@ nvmet_fc_delete_ctrl(struct nvmet_ctrl *ctrl)
spin_unlock_irqrestore(&nvmet_fc_tgtlock, flags);
}
static void
nvmet_fc_free_pending_reqs(struct nvmet_fc_tgtport *tgtport)
{
struct nvmet_fc_ls_req_op *lsop;
struct nvmefc_ls_req *lsreq;
struct nvmet_fc_ls_iod *iod;
int i;
iod = tgtport->iod;
for (i = 0; i < NVMET_LS_CTX_COUNT; iod++, i++)
cancel_work(&iod->work);
/*
* After this point the connection is lost and thus any pending
* request can't be processed by the normal completion path. This
* is likely a request from nvmet_fc_send_ls_req_async.
*/
while ((lsop = list_first_entry_or_null(&tgtport->ls_req_list,
struct nvmet_fc_ls_req_op, lsreq_list))) {
list_del(&lsop->lsreq_list);
if (!lsop->req_queued)
continue;
lsreq = &lsop->ls_req;
fc_dma_unmap_single(tgtport->dev, lsreq->rqstdma,
(lsreq->rqstlen + lsreq->rsplen),
DMA_BIDIRECTIONAL);
nvmet_fc_tgtport_put(tgtport);
kfree(lsop);
}
}
/**
* nvmet_fc_unregister_targetport - transport entry point called by an
* LLDD to deregister/remove a previously
@ -1611,13 +1644,7 @@ nvmet_fc_unregister_targetport(struct nvmet_fc_target_port *target_port)
flush_workqueue(nvmet_wq);
/*
* should terminate LS's as well. However, LS's will be generated
* at the tail end of association termination, so they likely don't
* exist yet. And even if they did, it's worthwhile to just let
* them finish and targetport ref counting will clean things up.
*/
nvmet_fc_free_pending_reqs(tgtport);
nvmet_fc_tgtport_put(tgtport);
return 0;