aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBart Van Assche <bart.vanassche@sandisk.com>2016-02-11 14:10:09 -0500
committerDoug Ledford <dledford@redhat.com>2016-02-29 17:12:36 -0500
commit387add460dc2f61567fa127bd76dab8ba6833234 (patch)
tree6095535d3363c22c4e71c4119fb0990d0fb0fa4c
parent539b3248d7f5f0341e3797e734ba653bccfaf498 (diff)
IB/srpt: Fix wait list processing
Since the wait list is not protected against concurrent access it must be processed from the context of the completion handler. Replace the wait list processing code in the IB CM RTU callback handler by code that triggers a completion handler. This patch fixes the following rare crash: WARNING: CPU: 2 PID: 78656 at lib/list_debug.c:53 __list_del_entry+0x67/0xd0() list_del corruption, ffff88041ae404b8->next is LIST_POISON1 (dead000000000100) Call Trace: [<ffffffff81251c6b>] dump_stack+0x4f/0x74 [<ffffffff810574ab>] warn_slowpath_common+0x8b/0xd0 [<ffffffff81057591>] warn_slowpath_fmt+0x41/0x70 [<ffffffff8126f007>] __list_del_entry+0x67/0xd0 [<ffffffff8126f081>] list_del+0x11/0x40 [<ffffffffa0265242>] srpt_cm_handler+0x172/0x1a4 [ib_srpt] [<ffffffffa0370370>] cm_process_work+0x20/0xf0 [ib_cm] [<ffffffffa0370dae>] cm_establish_handler+0xbe/0x110 [ib_cm] [<ffffffffa03733e7>] cm_work_handler+0x67/0xd0 [ib_cm] [<ffffffff8107184d>] process_one_work+0x1bd/0x460 [<ffffffff81073148>] worker_thread+0x118/0x420 [<ffffffff81078444>] kthread+0xe4/0x100 [<ffffffff8151caff>] ret_from_fork+0x3f/0x70 Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Alex Estrin <alex.estrin@intel.com> Cc: Sagi Grimberg <sagig@mellanox.com> Signed-off-by: Doug Ledford <dledford@redhat.com>
-rw-r--r--drivers/infiniband/ulp/srpt/ib_srpt.c24
1 files changed, 15 insertions, 9 deletions
diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c
index 289e058012fa..25bdaeef2520 100644
--- a/drivers/infiniband/ulp/srpt/ib_srpt.c
+++ b/drivers/infiniband/ulp/srpt/ib_srpt.c
@@ -96,7 +96,7 @@ static void srpt_free_ch(struct kref *kref);
96static int srpt_queue_status(struct se_cmd *cmd); 96static int srpt_queue_status(struct se_cmd *cmd);
97static void srpt_recv_done(struct ib_cq *cq, struct ib_wc *wc); 97static void srpt_recv_done(struct ib_cq *cq, struct ib_wc *wc);
98static void srpt_send_done(struct ib_cq *cq, struct ib_wc *wc); 98static void srpt_send_done(struct ib_cq *cq, struct ib_wc *wc);
99static void srpt_zerolength_write_done(struct ib_cq *cq, struct ib_wc *wc); 99static void srpt_process_wait_list(struct srpt_rdma_ch *ch);
100 100
101/* 101/*
102 * The only allowed channel state changes are those that change the channel 102 * The only allowed channel state changes are those that change the channel
@@ -833,12 +833,14 @@ static void srpt_zerolength_write_done(struct ib_cq *cq, struct ib_wc *wc)
833{ 833{
834 struct srpt_rdma_ch *ch = cq->cq_context; 834 struct srpt_rdma_ch *ch = cq->cq_context;
835 835
836 WARN(wc->status == IB_WC_SUCCESS, "%s-%d: QP not in error state\n", 836 if (wc->status == IB_WC_SUCCESS) {
837 ch->sess_name, ch->qp->qp_num); 837 srpt_process_wait_list(ch);
838 if (srpt_set_ch_state(ch, CH_DISCONNECTED)) 838 } else {
839 schedule_work(&ch->release_work); 839 if (srpt_set_ch_state(ch, CH_DISCONNECTED))
840 else 840 schedule_work(&ch->release_work);
841 WARN_ONCE("%s-%d\n", ch->sess_name, ch->qp->qp_num); 841 else
842 WARN_ONCE("%s-%d\n", ch->sess_name, ch->qp->qp_num);
843 }
842} 844}
843 845
844/** 846/**
@@ -2324,9 +2326,13 @@ static void srpt_cm_rtu_recv(struct srpt_rdma_ch *ch)
2324 if (srpt_set_ch_state(ch, CH_LIVE)) { 2326 if (srpt_set_ch_state(ch, CH_LIVE)) {
2325 ret = srpt_ch_qp_rts(ch, ch->qp); 2327 ret = srpt_ch_qp_rts(ch, ch->qp);
2326 2328
2327 srpt_process_wait_list(ch); 2329 if (ret == 0) {
2328 if (ret) 2330 /* Trigger wait list processing. */
2331 ret = srpt_zerolength_write(ch);
2332 WARN_ONCE(ret < 0, "%d\n", ret);
2333 } else {
2329 srpt_close_ch(ch); 2334 srpt_close_ch(ch);
2335 }
2330 } 2336 }
2331} 2337}
2332 2338