| From: Bart Van Assche <bart.vanassche@wdc.com> |
| Date: Wed, 11 Oct 2017 10:27:26 -0700 |
| Subject: IB/srp: Avoid that a cable pull can trigger a kernel crash |
| |
| commit 8a0d18c62121d3c554a83eb96e2752861d84d937 upstream. |
| |
| This patch fixes the following kernel crash: |
| |
| general protection fault: 0000 [#1] PREEMPT SMP |
| Workqueue: ib_mad2 timeout_sends [ib_core] |
| Call Trace: |
| ib_sa_path_rec_callback+0x1c4/0x1d0 [ib_core] |
| send_handler+0xb2/0xd0 [ib_core] |
| timeout_sends+0x14d/0x220 [ib_core] |
| process_one_work+0x200/0x630 |
| worker_thread+0x4e/0x3b0 |
| kthread+0x113/0x150 |
| |
| Fixes: commit aef9ec39c47f ("IB: Add SCSI RDMA Protocol (SRP) initiator") |
| Signed-off-by: Bart Van Assche <bart.vanassche@wdc.com> |
| Reviewed-by: Sagi Grimberg <sagi@grimberg.me> |
| Signed-off-by: Doug Ledford <dledford@redhat.com> |
| [bwh: Backported to 3.2: adjust context] |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| --- a/drivers/infiniband/ulp/srp/ib_srp.c |
| +++ b/drivers/infiniband/ulp/srp/ib_srp.c |
| @@ -310,10 +310,19 @@ static void srp_path_rec_completion(int |
| |
| static int srp_lookup_path(struct srp_target_port *target) |
| { |
| + int ret = -ENODEV; |
| + |
| target->path.numb_path = 1; |
| |
| init_completion(&target->done); |
| |
| + /* |
| + * Avoid that the SCSI host can be removed by srp_remove_target() |
| + * before srp_path_rec_completion() is called. |
| + */ |
| + if (!scsi_host_get(target->scsi_host)) |
| + goto out; |
| + |
| target->path_query_id = ib_sa_path_rec_get(&srp_sa_client, |
| target->srp_host->srp_dev->dev, |
| target->srp_host->port, |
| @@ -327,16 +336,22 @@ static int srp_lookup_path(struct srp_ta |
| GFP_KERNEL, |
| srp_path_rec_completion, |
| target, &target->path_query); |
| - if (target->path_query_id < 0) |
| - return target->path_query_id; |
| + ret = target->path_query_id; |
| + if (ret < 0) |
| + goto put; |
| |
| wait_for_completion(&target->done); |
| |
| - if (target->status < 0) |
| + ret = target->status; |
| + if (ret < 0) |
| shost_printk(KERN_WARNING, target->scsi_host, |
| PFX "Path record query failed\n"); |
| |
| - return target->status; |
| +put: |
| + scsi_host_put(target->scsi_host); |
| + |
| +out: |
| + return ret; |
| } |
| |
| static int srp_send_req(struct srp_target_port *target) |