From: Bart Van Assche Date: Thu, 18 Oct 2012 12:47:21 +0000 (+0200) Subject: ib_srp: Add post-3.5 upstream patches X-Git-Tag: vofed-3.5-x~27 X-Git-Url: https://openfabrics.org/gitweb/?a=commitdiff_plain;h=6fe832dd49eef7ffb56effce83641d8c762f884f;p=~emulex%2Ffor-vlad%2Fold%2Fcompat-rdma.git ib_srp: Add post-3.5 upstream patches The following three patches have been accepted upstream after kernel 3.5 was released: - IB-srp-Fix-a-race-condition: avoid that late replies can trigger a crash. - IB-srp-Fix-use-after-free-in-srp_reset_req - IB-srp-Avoid-having-aborted-requests-hang Add these patches to OFED 3.5. Signed-off-by: Bart Van Assche --- diff --git a/patches/0026-IB-srp-Fix-a-race-condition.patch b/patches/0026-IB-srp-Fix-a-race-condition.patch new file mode 100644 index 0000000..969a3c1 --- /dev/null +++ b/patches/0026-IB-srp-Fix-a-race-condition.patch @@ -0,0 +1,160 @@ +From 220329916c72ee3d54ae7262b215a050f04a18fc Mon Sep 17 00:00:00 2001 +From: Bart Van Assche +Date: Tue, 14 Aug 2012 13:18:53 +0000 +Subject: [PATCH] IB/srp: Fix a race condition + +Avoid a crash caused by the scmnd->scsi_done(scmnd) call in +srp_process_rsp() being invoked with scsi_done == NULL. This can +happen if a reply is received during or after a command abort. + +Reported-by: Joseph Glanville +Reference: http://marc.info/?l=linux-rdma&m=134314367801595 +Cc: +Acked-by: David Dillow +Signed-off-by: Bart Van Assche +Signed-off-by: Roland Dreier +--- + drivers/infiniband/ulp/srp/ib_srp.c | 87 +++++++++++++++++++++++++---------- + 1 file changed, 63 insertions(+), 24 deletions(-) + +diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c +index bcbf22e..1b5b0c7 100644 +--- a/drivers/infiniband/ulp/srp/ib_srp.c ++++ b/drivers/infiniband/ulp/srp/ib_srp.c +@@ -586,24 +586,62 @@ static void srp_unmap_data(struct scsi_cmnd *scmnd, + scmnd->sc_data_direction); + } + +-static void srp_remove_req(struct srp_target_port *target, +- struct srp_request *req, s32 req_lim_delta) ++/** ++ * srp_claim_req - Take ownership of the scmnd associated with a request. ++ * @target: SRP target port. ++ * @req: SRP request. ++ * @scmnd: If NULL, take ownership of @req->scmnd. If not NULL, only take ++ * ownership of @req->scmnd if it equals @scmnd. ++ * ++ * Return value: ++ * Either NULL or a pointer to the SCSI command the caller became owner of. ++ */ ++static struct scsi_cmnd *srp_claim_req(struct srp_target_port *target, ++ struct srp_request *req, ++ struct scsi_cmnd *scmnd) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&target->lock, flags); ++ if (!scmnd) { ++ scmnd = req->scmnd; ++ req->scmnd = NULL; ++ } else if (req->scmnd == scmnd) { ++ req->scmnd = NULL; ++ } else { ++ scmnd = NULL; ++ } ++ spin_unlock_irqrestore(&target->lock, flags); ++ ++ return scmnd; ++} ++ ++/** ++ * srp_free_req() - Unmap data and add request to the free request list. ++ */ ++static void srp_free_req(struct srp_target_port *target, ++ struct srp_request *req, struct scsi_cmnd *scmnd, ++ s32 req_lim_delta) + { + unsigned long flags; + +- srp_unmap_data(req->scmnd, target, req); ++ srp_unmap_data(scmnd, target, req); ++ + spin_lock_irqsave(&target->lock, flags); + target->req_lim += req_lim_delta; +- req->scmnd = NULL; + list_add_tail(&req->list, &target->free_reqs); + spin_unlock_irqrestore(&target->lock, flags); + } + + static void srp_reset_req(struct srp_target_port *target, struct srp_request *req) + { +- req->scmnd->result = DID_RESET << 16; +- req->scmnd->scsi_done(req->scmnd); +- srp_remove_req(target, req, 0); ++ struct scsi_cmnd *scmnd = srp_claim_req(target, req, NULL); ++ ++ if (scmnd) { ++ scmnd->result = DID_RESET << 16; ++ scmnd->scsi_done(scmnd); ++ srp_free_req(target, req, scmnd, 0); ++ } + } + + static int srp_reconnect_target(struct srp_target_port *target) +@@ -1073,11 +1111,18 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) + complete(&target->tsk_mgmt_done); + } else { + req = &target->req_ring[rsp->tag]; +- scmnd = req->scmnd; +- if (!scmnd) ++ scmnd = srp_claim_req(target, req, NULL); ++ if (!scmnd) { + shost_printk(KERN_ERR, target->scsi_host, + "Null scmnd for RSP w/tag %016llx\n", + (unsigned long long) rsp->tag); ++ ++ spin_lock_irqsave(&target->lock, flags); ++ target->req_lim += be32_to_cpu(rsp->req_lim_delta); ++ spin_unlock_irqrestore(&target->lock, flags); ++ ++ return; ++ } + scmnd->result = rsp->status; + + if (rsp->flags & SRP_RSP_FLAG_SNSVALID) { +@@ -1092,7 +1137,9 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp) + else if (rsp->flags & (SRP_RSP_FLAG_DIOVER | SRP_RSP_FLAG_DIUNDER)) + scsi_set_resid(scmnd, be32_to_cpu(rsp->data_in_res_cnt)); + +- srp_remove_req(target, req, be32_to_cpu(rsp->req_lim_delta)); ++ srp_free_req(target, req, scmnd, ++ be32_to_cpu(rsp->req_lim_delta)); ++ + scmnd->host_scribble = NULL; + scmnd->scsi_done(scmnd); + } +@@ -1631,25 +1678,17 @@ static int srp_abort(struct scsi_cmnd *scmnd) + { + struct srp_target_port *target = host_to_target(scmnd->device->host); + struct srp_request *req = (struct srp_request *) scmnd->host_scribble; +- int ret = SUCCESS; + + shost_printk(KERN_ERR, target->scsi_host, "SRP abort called\n"); + +- if (!req || target->qp_in_error) ++ if (!req || target->qp_in_error || !srp_claim_req(target, req, scmnd)) + return FAILED; +- if (srp_send_tsk_mgmt(target, req->index, scmnd->device->lun, +- SRP_TSK_ABORT_TASK)) +- return FAILED; +- +- if (req->scmnd) { +- if (!target->tsk_mgmt_status) { +- srp_remove_req(target, req, 0); +- scmnd->result = DID_ABORT << 16; +- } else +- ret = FAILED; +- } ++ srp_send_tsk_mgmt(target, req->index, scmnd->device->lun, ++ SRP_TSK_ABORT_TASK); ++ srp_free_req(target, req, scmnd, 0); ++ scmnd->result = DID_ABORT << 16; + +- return ret; ++ return SUCCESS; + } + + static int srp_reset_device(struct scsi_cmnd *scmnd) +-- +1.7.10.4 + diff --git a/patches/0027-IB-srp-Fix-use-after-free-in-srp_reset_req.patch b/patches/0027-IB-srp-Fix-use-after-free-in-srp_reset_req.patch new file mode 100644 index 0000000..f9b3e24 --- /dev/null +++ b/patches/0027-IB-srp-Fix-use-after-free-in-srp_reset_req.patch @@ -0,0 +1,35 @@ +From 9b796d06d5d1b1e85ae2316a283ea11dd739ef96 Mon Sep 17 00:00:00 2001 +From: Bart Van Assche +Date: Fri, 24 Aug 2012 10:27:54 +0000 +Subject: [PATCH] IB/srp: Fix use-after-free in srp_reset_req() + +srp_free_req() uses the scsi_cmnd structure contents to unmap +buffers, so we must invoke srp_free_req() before we release +ownership of that structure. + +Signed-off-by: Bart Van Assche +Acked-by: David Dillow +Cc: +Signed-off-by: Roland Dreier +--- + drivers/infiniband/ulp/srp/ib_srp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c +index 1b5b0c7..ac66e6b 100644 +--- a/drivers/infiniband/ulp/srp/ib_srp.c ++++ b/drivers/infiniband/ulp/srp/ib_srp.c +@@ -638,9 +638,9 @@ static void srp_reset_req(struct srp_target_port *target, struct srp_request *re + struct scsi_cmnd *scmnd = srp_claim_req(target, req, NULL); + + if (scmnd) { ++ srp_free_req(target, req, scmnd, 0); + scmnd->result = DID_RESET << 16; + scmnd->scsi_done(scmnd); +- srp_free_req(target, req, scmnd, 0); + } + } + +-- +1.7.10.4 + diff --git a/patches/0028-IB-srp-Avoid-having-aborted-requests-hang.patch b/patches/0028-IB-srp-Avoid-having-aborted-requests-hang.patch new file mode 100644 index 0000000..586d5b9 --- /dev/null +++ b/patches/0028-IB-srp-Avoid-having-aborted-requests-hang.patch @@ -0,0 +1,30 @@ +From d8536670916a685df116b5c2cb256573fd25e4e3 Mon Sep 17 00:00:00 2001 +From: Bart Van Assche +Date: Fri, 24 Aug 2012 10:29:11 +0000 +Subject: [PATCH] IB/srp: Avoid having aborted requests hang + +We need to call scsi_done() for commands after we abort them. + +Signed-off-by: Bart Van Assche +Acked-by: David Dillow +Cc: +Signed-off-by: Roland Dreier +--- + drivers/infiniband/ulp/srp/ib_srp.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c +index ac66e6b..922d845 100644 +--- a/drivers/infiniband/ulp/srp/ib_srp.c ++++ b/drivers/infiniband/ulp/srp/ib_srp.c +@@ -1687,6 +1687,7 @@ static int srp_abort(struct scsi_cmnd *scmnd) + SRP_TSK_ABORT_TASK); + srp_free_req(target, req, scmnd, 0); + scmnd->result = DID_ABORT << 16; ++ scmnd->scsi_done(scmnd); + + return SUCCESS; + } +-- +1.7.10.4 +