aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Smart <jsmart2021@gmail.com>2017-11-29 19:47:30 -0500
committerChristoph Hellwig <hch@lst.de>2018-01-08 05:01:53 -0500
commit278e096063f1914fccfc77a617be9fc8dbb31b0e (patch)
tree8bbb60c518b3ea73bc14e8848acff1e3acd969a9
parent6a1c57acab85e2e7a18827b43710b4e16c11148d (diff)
nvme_fcloop: fix abort race condition
A test case revealed a race condition of an i/o completing on a thread parallel to the delete_association generating the aborts for the outstanding ios on the controller. The i/o completion was freeing the target fcloop context, thus the abort task referenced the just-freed memory. Correct by clearing the target/initiator cross pointers in the io completion and abort tasks before calling the callbacks. On aborts that detect already finished io's, ensure the complete context is called. Signed-off-by: James Smart <james.smart@broadcom.com> Signed-off-by: Christoph Hellwig <hch@lst.de>
-rw-r--r--drivers/nvme/target/fcloop.c12
1 files changed, 7 insertions, 5 deletions
diff --git a/drivers/nvme/target/fcloop.c b/drivers/nvme/target/fcloop.c
index 7b75d9de55ab..3eb2a0733f46 100644
--- a/drivers/nvme/target/fcloop.c
+++ b/drivers/nvme/target/fcloop.c
@@ -370,6 +370,7 @@ fcloop_tgt_fcprqst_done_work(struct work_struct *work)
370 370
371 spin_lock(&tfcp_req->reqlock); 371 spin_lock(&tfcp_req->reqlock);
372 fcpreq = tfcp_req->fcpreq; 372 fcpreq = tfcp_req->fcpreq;
373 tfcp_req->fcpreq = NULL;
373 spin_unlock(&tfcp_req->reqlock); 374 spin_unlock(&tfcp_req->reqlock);
374 375
375 if (tport->remoteport && fcpreq) { 376 if (tport->remoteport && fcpreq) {
@@ -611,11 +612,7 @@ fcloop_fcp_abort(struct nvme_fc_local_port *localport,
611 612
612 if (!tfcp_req) 613 if (!tfcp_req)
613 /* abort has already been called */ 614 /* abort has already been called */
614 return; 615 goto finish;
615
616 if (rport->targetport)
617 nvmet_fc_rcv_fcp_abort(rport->targetport,
618 &tfcp_req->tgt_fcp_req);
619 616
620 /* break initiator/target relationship for io */ 617 /* break initiator/target relationship for io */
621 spin_lock(&tfcp_req->reqlock); 618 spin_lock(&tfcp_req->reqlock);
@@ -623,6 +620,11 @@ fcloop_fcp_abort(struct nvme_fc_local_port *localport,
623 tfcp_req->fcpreq = NULL; 620 tfcp_req->fcpreq = NULL;
624 spin_unlock(&tfcp_req->reqlock); 621 spin_unlock(&tfcp_req->reqlock);
625 622
623 if (rport->targetport)
624 nvmet_fc_rcv_fcp_abort(rport->targetport,
625 &tfcp_req->tgt_fcp_req);
626
627finish:
626 /* post the aborted io completion */ 628 /* post the aborted io completion */
627 fcpreq->status = -ECANCELED; 629 fcpreq->status = -ECANCELED;
628 schedule_work(&inireq->iniwork); 630 schedule_work(&inireq->iniwork);