diff options
author | Bart Van Assche <bvanassche@acm.org> | 2014-03-14 08:54:11 -0400 |
---|---|---|
committer | Roland Dreier <roland@purestorage.com> | 2014-03-24 13:05:31 -0400 |
commit | b3fe628da2898cf1387105026dfed551ecc25de5 (patch) | |
tree | 6df463ae165b00ab3ca3f005e98853f8c97e2565 /drivers/infiniband | |
parent | ac72d766a8e44d782bd5480fc953ab6025c82e92 (diff) |
IB/srp: Fix a race condition between failing I/O and I/O completion
Avoid that srp_terminate_io() can access req->scmnd after it has been
cleared by the I/O completion code. Do this by protecting req->scmnd
accesses from srp_terminate_io() via locking
Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Acked-by: Sagi Grimberg <sagig@mellanox.com>
Signed-off-by: Roland Dreier <roland@purestorage.com>
Diffstat (limited to 'drivers/infiniband')
-rw-r--r-- | drivers/infiniband/ulp/srp/ib_srp.c | 33 |
1 files changed, 22 insertions, 11 deletions
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index a64e469db116..66a908bf3fb9 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c | |||
@@ -783,6 +783,7 @@ static void srp_unmap_data(struct scsi_cmnd *scmnd, | |||
783 | * srp_claim_req - Take ownership of the scmnd associated with a request. | 783 | * srp_claim_req - Take ownership of the scmnd associated with a request. |
784 | * @target: SRP target port. | 784 | * @target: SRP target port. |
785 | * @req: SRP request. | 785 | * @req: SRP request. |
786 | * @sdev: If not NULL, only take ownership for this SCSI device. | ||
786 | * @scmnd: If NULL, take ownership of @req->scmnd. If not NULL, only take | 787 | * @scmnd: If NULL, take ownership of @req->scmnd. If not NULL, only take |
787 | * ownership of @req->scmnd if it equals @scmnd. | 788 | * ownership of @req->scmnd if it equals @scmnd. |
788 | * | 789 | * |
@@ -791,16 +792,17 @@ static void srp_unmap_data(struct scsi_cmnd *scmnd, | |||
791 | */ | 792 | */ |
792 | static struct scsi_cmnd *srp_claim_req(struct srp_target_port *target, | 793 | static struct scsi_cmnd *srp_claim_req(struct srp_target_port *target, |
793 | struct srp_request *req, | 794 | struct srp_request *req, |
795 | struct scsi_device *sdev, | ||
794 | struct scsi_cmnd *scmnd) | 796 | struct scsi_cmnd *scmnd) |
795 | { | 797 | { |
796 | unsigned long flags; | 798 | unsigned long flags; |
797 | 799 | ||
798 | spin_lock_irqsave(&target->lock, flags); | 800 | spin_lock_irqsave(&target->lock, flags); |
799 | if (!scmnd) { | 801 | if (req->scmnd && |
802 | (!sdev || req->scmnd->device == sdev) && | ||
803 | (!scmnd || req->scmnd == scmnd)) { | ||
800 | scmnd = req->scmnd; | 804 | scmnd = req->scmnd; |
801 | req->scmnd = NULL; | 805 | req->scmnd = NULL; |
802 | } else if (req->scmnd == scmnd) { | ||
803 | req->scmnd = NULL; | ||
804 | } else { | 806 | } else { |
805 | scmnd = NULL; | 807 | scmnd = NULL; |
806 | } | 808 | } |
@@ -827,9 +829,10 @@ static void srp_free_req(struct srp_target_port *target, | |||
827 | } | 829 | } |
828 | 830 | ||
829 | static void srp_finish_req(struct srp_target_port *target, | 831 | static void srp_finish_req(struct srp_target_port *target, |
830 | struct srp_request *req, int result) | 832 | struct srp_request *req, struct scsi_device *sdev, |
833 | int result) | ||
831 | { | 834 | { |
832 | struct scsi_cmnd *scmnd = srp_claim_req(target, req, NULL); | 835 | struct scsi_cmnd *scmnd = srp_claim_req(target, req, sdev, NULL); |
833 | 836 | ||
834 | if (scmnd) { | 837 | if (scmnd) { |
835 | srp_free_req(target, req, scmnd, 0); | 838 | srp_free_req(target, req, scmnd, 0); |
@@ -841,11 +844,20 @@ static void srp_finish_req(struct srp_target_port *target, | |||
841 | static void srp_terminate_io(struct srp_rport *rport) | 844 | static void srp_terminate_io(struct srp_rport *rport) |
842 | { | 845 | { |
843 | struct srp_target_port *target = rport->lld_data; | 846 | struct srp_target_port *target = rport->lld_data; |
847 | struct Scsi_Host *shost = target->scsi_host; | ||
848 | struct scsi_device *sdev; | ||
844 | int i; | 849 | int i; |
845 | 850 | ||
851 | /* | ||
852 | * Invoking srp_terminate_io() while srp_queuecommand() is running | ||
853 | * is not safe. Hence the warning statement below. | ||
854 | */ | ||
855 | shost_for_each_device(sdev, shost) | ||
856 | WARN_ON_ONCE(sdev->request_queue->request_fn_active); | ||
857 | |||
846 | for (i = 0; i < target->req_ring_size; ++i) { | 858 | for (i = 0; i < target->req_ring_size; ++i) { |
847 | struct srp_request *req = &target->req_ring[i]; | 859 | struct srp_request *req = &target->req_ring[i]; |
848 | srp_finish_req(target, req, DID_TRANSPORT_FAILFAST << 16); | 860 | srp_finish_req(target, req, NULL, DID_TRANSPORT_FAILFAST << 16); |
849 | } | 861 | } |
850 | } | 862 | } |
851 | 863 | ||
@@ -882,7 +894,7 @@ static int srp_rport_reconnect(struct srp_rport *rport) | |||
882 | 894 | ||
883 | for (i = 0; i < target->req_ring_size; ++i) { | 895 | for (i = 0; i < target->req_ring_size; ++i) { |
884 | struct srp_request *req = &target->req_ring[i]; | 896 | struct srp_request *req = &target->req_ring[i]; |
885 | srp_finish_req(target, req, DID_RESET << 16); | 897 | srp_finish_req(target, req, NULL, DID_RESET << 16); |
886 | } | 898 | } |
887 | 899 | ||
888 | INIT_LIST_HEAD(&target->free_tx); | 900 | INIT_LIST_HEAD(&target->free_tx); |
@@ -1290,7 +1302,7 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) | |||
1290 | complete(&target->tsk_mgmt_done); | 1302 | complete(&target->tsk_mgmt_done); |
1291 | } else { | 1303 | } else { |
1292 | req = &target->req_ring[rsp->tag]; | 1304 | req = &target->req_ring[rsp->tag]; |
1293 | scmnd = srp_claim_req(target, req, NULL); | 1305 | scmnd = srp_claim_req(target, req, NULL, NULL); |
1294 | if (!scmnd) { | 1306 | if (!scmnd) { |
1295 | shost_printk(KERN_ERR, target->scsi_host, | 1307 | shost_printk(KERN_ERR, target->scsi_host, |
1296 | "Null scmnd for RSP w/tag %016llx\n", | 1308 | "Null scmnd for RSP w/tag %016llx\n", |
@@ -2008,7 +2020,7 @@ static int srp_abort(struct scsi_cmnd *scmnd) | |||
2008 | 2020 | ||
2009 | shost_printk(KERN_ERR, target->scsi_host, "SRP abort called\n"); | 2021 | shost_printk(KERN_ERR, target->scsi_host, "SRP abort called\n"); |
2010 | 2022 | ||
2011 | if (!req || !srp_claim_req(target, req, scmnd)) | 2023 | if (!req || !srp_claim_req(target, req, NULL, scmnd)) |
2012 | return SUCCESS; | 2024 | return SUCCESS; |
2013 | if (srp_send_tsk_mgmt(target, req->index, scmnd->device->lun, | 2025 | if (srp_send_tsk_mgmt(target, req->index, scmnd->device->lun, |
2014 | SRP_TSK_ABORT_TASK) == 0) | 2026 | SRP_TSK_ABORT_TASK) == 0) |
@@ -2039,8 +2051,7 @@ static int srp_reset_device(struct scsi_cmnd *scmnd) | |||
2039 | 2051 | ||
2040 | for (i = 0; i < target->req_ring_size; ++i) { | 2052 | for (i = 0; i < target->req_ring_size; ++i) { |
2041 | struct srp_request *req = &target->req_ring[i]; | 2053 | struct srp_request *req = &target->req_ring[i]; |
2042 | if (req->scmnd && req->scmnd->device == scmnd->device) | 2054 | srp_finish_req(target, req, scmnd->device, DID_RESET << 16); |
2043 | srp_finish_req(target, req, DID_RESET << 16); | ||
2044 | } | 2055 | } |
2045 | 2056 | ||
2046 | return SUCCESS; | 2057 | return SUCCESS; |