diff --git a/drivers/nvme/target/fc.c b/drivers/nvme/target/fc.c index 1b557775e033..a25f7579049d 100644 --- a/drivers/nvme/target/fc.c +++ b/drivers/nvme/target/fc.c @@ -56,6 +56,7 @@ struct nvmet_fc_ls_req_op { /* for an LS RQST XMT */ bool req_queued; struct work_struct put_work; + struct kref ref; }; @@ -339,6 +340,22 @@ fc_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, dma_unmap_sg(dev, sg, nents, dir); } +static void +nvmet_fc_ls_req_op_release(struct kref *ref) +{ + struct nvmet_fc_ls_req_op *lsop = + container_of(ref, struct nvmet_fc_ls_req_op, ref); + struct nvmet_fc_tgtport *tgtport = lsop->tgtport; + struct nvmefc_ls_req *lsreq = &lsop->ls_req; + + if (lsop->req_queued) + fc_dma_unmap_single(tgtport->dev, lsreq->rqstdma, + (lsreq->rqstlen + lsreq->rsplen), + DMA_BIDIRECTIONAL); + queue_work(nvmet_wq, &lsop->put_work); +} + + /* ********************** FC-NVME LS XMT Handling ************************* */ @@ -347,7 +364,6 @@ static void __nvmet_fc_finish_ls_req(struct nvmet_fc_ls_req_op *lsop) { struct nvmet_fc_tgtport *tgtport = lsop->tgtport; - struct nvmefc_ls_req *lsreq = &lsop->ls_req; unsigned long flags; spin_lock_irqsave(&tgtport->lock, flags); @@ -363,12 +379,8 @@ __nvmet_fc_finish_ls_req(struct nvmet_fc_ls_req_op *lsop) spin_unlock_irqrestore(&tgtport->lock, flags); - fc_dma_unmap_single(tgtport->dev, lsreq->rqstdma, - (lsreq->rqstlen + lsreq->rsplen), - DMA_BIDIRECTIONAL); - out_putwork: - queue_work(nvmet_wq, &lsop->put_work); + kref_put(&lsop->ref, nvmet_fc_ls_req_op_release); } static int @@ -406,12 +418,16 @@ __nvmet_fc_send_ls_req(struct nvmet_fc_tgtport *tgtport, lsop->req_queued = true; + kref_init(&lsop->ref); + kref_get(&lsop->ref); spin_unlock_irqrestore(&tgtport->lock, flags); ret = tgtport->ops->ls_req(&tgtport->fc_target_port, lsop->hosthandle, lsreq); - if (ret) + if (ret) { + kref_put(&lsop->ref, nvmet_fc_ls_req_op_release); goto out_unlink; + } return 0; @@ -1591,7 +1607,6 @@ 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; @@ -1611,12 +1626,7 @@ nvmet_fc_free_pending_reqs(struct nvmet_fc_tgtport *tgtport) 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); + kref_put(&lsop->ref, nvmet_fc_ls_req_op_release); } }