]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
nvmet-fc: free pending reqs on tgtport unregister
authorDaniel Wagner <wagi@kernel.org>
Wed, 7 May 2025 12:23:08 +0000 (14:23 +0200)
committerChristoph Hellwig <hch@lst.de>
Tue, 20 May 2025 03:34:26 +0000 (05:34 +0200)
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>
drivers/nvme/target/fc.c

index a82cff9a80643956921e61c80439afad41639923..b8985559d1f14e6729996e1670c19dbe353e3895 100644 (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;