aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Marciniszyn <mike.marciniszyn@intel.com>2017-04-09 13:16:35 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-05-20 08:28:38 -0400
commite3cea38357ea66d63b1c42500c69ca88a3f0c44f (patch)
treeaf3ebc979b7de6be128c985120ff26d29407ada5
parent43c54927f6f4e0dba5714dbcd53fea44114cd7cf (diff)
IB/hfi1: Prevent kernel QP post send hard lockups
commit b6eac931b9bb2bce4db7032c35b41e5e34ec22a5 upstream. The driver progress routines can call cond_resched() when a timeslice is exhausted and irqs are enabled. If the ULP had been holding a spin lock without disabling irqs and the post send directly called the progress routine, the cond_resched() could yield allowing another thread from the same ULP to deadlock on that same lock. Correct by replacing the current hfi1_do_send() calldown with a unique one for post send and adding an argument to hfi1_do_send() to indicate that the send engine is running in a thread. If the routine is not running in a thread, avoid calling cond_resched(). Fixes: Commit 831464ce4b74 ("IB/hfi1: Don't call cond_resched in atomic mode when sending packets") Reviewed-by: Dennis Dalessandro <dennis.dalessandro@intel.com> Signed-off-by: Mike Marciniszyn <mike.marciniszyn@intel.com> Signed-off-by: Dennis Dalessandro <dennis.dalessandro@intel.com> Signed-off-by: Doug Ledford <dledford@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/infiniband/hw/hfi1/ruc.c26
-rw-r--r--drivers/infiniband/hw/hfi1/verbs.c4
-rw-r--r--drivers/infiniband/hw/hfi1/verbs.h6
3 files changed, 22 insertions, 14 deletions
diff --git a/drivers/infiniband/hw/hfi1/ruc.c b/drivers/infiniband/hw/hfi1/ruc.c
index a1576aea4756..9f768b48321f 100644
--- a/drivers/infiniband/hw/hfi1/ruc.c
+++ b/drivers/infiniband/hw/hfi1/ruc.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright(c) 2015, 2016 Intel Corporation. 2 * Copyright(c) 2015 - 2017 Intel Corporation.
3 * 3 *
4 * This file is provided under a dual BSD/GPLv2 license. When using or 4 * This file is provided under a dual BSD/GPLv2 license. When using or
5 * redistributing this file, you may do so under either license. 5 * redistributing this file, you may do so under either license.
@@ -833,23 +833,29 @@ void hfi1_make_ruc_header(struct rvt_qp *qp, struct ib_other_headers *ohdr,
833/* when sending, force a reschedule every one of these periods */ 833/* when sending, force a reschedule every one of these periods */
834#define SEND_RESCHED_TIMEOUT (5 * HZ) /* 5s in jiffies */ 834#define SEND_RESCHED_TIMEOUT (5 * HZ) /* 5s in jiffies */
835 835
836void hfi1_do_send_from_rvt(struct rvt_qp *qp)
837{
838 hfi1_do_send(qp, false);
839}
840
836void _hfi1_do_send(struct work_struct *work) 841void _hfi1_do_send(struct work_struct *work)
837{ 842{
838 struct iowait *wait = container_of(work, struct iowait, iowork); 843 struct iowait *wait = container_of(work, struct iowait, iowork);
839 struct rvt_qp *qp = iowait_to_qp(wait); 844 struct rvt_qp *qp = iowait_to_qp(wait);
840 845
841 hfi1_do_send(qp); 846 hfi1_do_send(qp, true);
842} 847}
843 848
844/** 849/**
845 * hfi1_do_send - perform a send on a QP 850 * hfi1_do_send - perform a send on a QP
846 * @work: contains a pointer to the QP 851 * @work: contains a pointer to the QP
852 * @in_thread: true if in a workqueue thread
847 * 853 *
848 * Process entries in the send work queue until credit or queue is 854 * Process entries in the send work queue until credit or queue is
849 * exhausted. Only allow one CPU to send a packet per QP. 855 * exhausted. Only allow one CPU to send a packet per QP.
850 * Otherwise, two threads could send packets out of order. 856 * Otherwise, two threads could send packets out of order.
851 */ 857 */
852void hfi1_do_send(struct rvt_qp *qp) 858void hfi1_do_send(struct rvt_qp *qp, bool in_thread)
853{ 859{
854 struct hfi1_pkt_state ps; 860 struct hfi1_pkt_state ps;
855 struct hfi1_qp_priv *priv = qp->priv; 861 struct hfi1_qp_priv *priv = qp->priv;
@@ -917,8 +923,10 @@ void hfi1_do_send(struct rvt_qp *qp)
917 qp->s_hdrwords = 0; 923 qp->s_hdrwords = 0;
918 /* allow other tasks to run */ 924 /* allow other tasks to run */
919 if (unlikely(time_after(jiffies, timeout))) { 925 if (unlikely(time_after(jiffies, timeout))) {
920 if (workqueue_congested(cpu, 926 if (!in_thread ||
921 ps.ppd->hfi1_wq)) { 927 workqueue_congested(
928 cpu,
929 ps.ppd->hfi1_wq)) {
922 spin_lock_irqsave( 930 spin_lock_irqsave(
923 &qp->s_lock, 931 &qp->s_lock,
924 ps.flags); 932 ps.flags);
@@ -931,11 +939,9 @@ void hfi1_do_send(struct rvt_qp *qp)
931 *ps.ppd->dd->send_schedule); 939 *ps.ppd->dd->send_schedule);
932 return; 940 return;
933 } 941 }
934 if (!irqs_disabled()) { 942 cond_resched();
935 cond_resched(); 943 this_cpu_inc(
936 this_cpu_inc( 944 *ps.ppd->dd->send_schedule);
937 *ps.ppd->dd->send_schedule);
938 }
939 timeout = jiffies + (timeout_int) / 8; 945 timeout = jiffies + (timeout_int) / 8;
940 } 946 }
941 spin_lock_irqsave(&qp->s_lock, ps.flags); 947 spin_lock_irqsave(&qp->s_lock, ps.flags);
diff --git a/drivers/infiniband/hw/hfi1/verbs.c b/drivers/infiniband/hw/hfi1/verbs.c
index 4b7a16ceb362..01a380efea6b 100644
--- a/drivers/infiniband/hw/hfi1/verbs.c
+++ b/drivers/infiniband/hw/hfi1/verbs.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright(c) 2015, 2016 Intel Corporation. 2 * Copyright(c) 2015 - 2017 Intel Corporation.
3 * 3 *
4 * This file is provided under a dual BSD/GPLv2 license. When using or 4 * This file is provided under a dual BSD/GPLv2 license. When using or
5 * redistributing this file, you may do so under either license. 5 * redistributing this file, you may do so under either license.
@@ -1697,7 +1697,7 @@ int hfi1_register_ib_device(struct hfi1_devdata *dd)
1697 dd->verbs_dev.rdi.driver_f.qp_priv_free = qp_priv_free; 1697 dd->verbs_dev.rdi.driver_f.qp_priv_free = qp_priv_free;
1698 dd->verbs_dev.rdi.driver_f.free_all_qps = free_all_qps; 1698 dd->verbs_dev.rdi.driver_f.free_all_qps = free_all_qps;
1699 dd->verbs_dev.rdi.driver_f.notify_qp_reset = notify_qp_reset; 1699 dd->verbs_dev.rdi.driver_f.notify_qp_reset = notify_qp_reset;
1700 dd->verbs_dev.rdi.driver_f.do_send = hfi1_do_send; 1700 dd->verbs_dev.rdi.driver_f.do_send = hfi1_do_send_from_rvt;
1701 dd->verbs_dev.rdi.driver_f.schedule_send = hfi1_schedule_send; 1701 dd->verbs_dev.rdi.driver_f.schedule_send = hfi1_schedule_send;
1702 dd->verbs_dev.rdi.driver_f.schedule_send_no_lock = _hfi1_schedule_send; 1702 dd->verbs_dev.rdi.driver_f.schedule_send_no_lock = _hfi1_schedule_send;
1703 dd->verbs_dev.rdi.driver_f.get_pmtu_from_attr = get_pmtu_from_attr; 1703 dd->verbs_dev.rdi.driver_f.get_pmtu_from_attr = get_pmtu_from_attr;
diff --git a/drivers/infiniband/hw/hfi1/verbs.h b/drivers/infiniband/hw/hfi1/verbs.h
index 1c3815d89eb7..bac84f820a54 100644
--- a/drivers/infiniband/hw/hfi1/verbs.h
+++ b/drivers/infiniband/hw/hfi1/verbs.h
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright(c) 2015, 2016 Intel Corporation. 2 * Copyright(c) 2015 - 2017 Intel Corporation.
3 * 3 *
4 * This file is provided under a dual BSD/GPLv2 license. When using or 4 * This file is provided under a dual BSD/GPLv2 license. When using or
5 * redistributing this file, you may do so under either license. 5 * redistributing this file, you may do so under either license.
@@ -372,7 +372,9 @@ void hfi1_make_ruc_header(struct rvt_qp *qp, struct ib_other_headers *ohdr,
372 372
373void _hfi1_do_send(struct work_struct *work); 373void _hfi1_do_send(struct work_struct *work);
374 374
375void hfi1_do_send(struct rvt_qp *qp); 375void hfi1_do_send_from_rvt(struct rvt_qp *qp);
376
377void hfi1_do_send(struct rvt_qp *qp, bool in_thread);
376 378
377void hfi1_send_complete(struct rvt_qp *qp, struct rvt_swqe *wqe, 379void hfi1_send_complete(struct rvt_qp *qp, struct rvt_swqe *wqe,
378 enum ib_wc_status status); 380 enum ib_wc_status status);