diff options
author | James Smart <jsmart2021@gmail.com> | 2017-11-29 19:47:30 -0500 |
---|---|---|
committer | Christoph Hellwig <hch@lst.de> | 2018-01-08 05:01:53 -0500 |
commit | 278e096063f1914fccfc77a617be9fc8dbb31b0e (patch) | |
tree | 8bbb60c518b3ea73bc14e8848acff1e3acd969a9 | |
parent | 6a1c57acab85e2e7a18827b43710b4e16c11148d (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.c | 12 |
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 | |||
627 | finish: | ||
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); |