Commit bbccbf79 authored by Daniel Wagner's avatar Daniel Wagner Committed by Christoph Hellwig
Browse files

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: default avatarDaniel Wagner <wagi@kernel.org>
Reviewed-by: default avatarHannes Reinecke <hare@suse.de>
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
parent 84eedced
Loading
Loading
Loading
Loading
+34 −7
Original line number Diff line number Diff line
@@ -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;