aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMike Marciniszyn <mike.marciniszyn@intel.com>2017-04-09 13:16:35 -0400
committerDoug Ledford <dledford@redhat.com>2017-04-28 13:48:01 -0400
commitb6eac931b9bb2bce4db7032c35b41e5e34ec22a5 (patch)
tree9f6757a5a525248cb8ed496ad39ce8bad60c24da
parent3d591099a0a2b45a50913130f0599ab838002fc3 (diff)
IB/hfi1: Prevent kernel QP post send hard lockups
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(). CC: <stable@vger.kernel.org> # 4.7.x- 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>
-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 879eb9b31954..ccf8d8037355 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.
@@ -784,23 +784,29 @@ void hfi1_make_ruc_header(struct rvt_qp *qp, struct ib_other_headers *ohdr,
784/* when sending, force a reschedule every one of these periods */ 784/* when sending, force a reschedule every one of these periods */
785#define SEND_RESCHED_TIMEOUT (5 * HZ) /* 5s in jiffies */ 785#define SEND_RESCHED_TIMEOUT (5 * HZ) /* 5s in jiffies */
786 786
787void hfi1_do_send_from_rvt(struct rvt_qp *qp)
788{
789 hfi1_do_send(qp, false);
790}
791
787void _hfi1_do_send(struct work_struct *work) 792void _hfi1_do_send(struct work_struct *work)
788{ 793{
789 struct iowait *wait = container_of(work, struct iowait, iowork); 794 struct iowait *wait = container_of(work, struct iowait, iowork);
790 struct rvt_qp *qp = iowait_to_qp(wait); 795 struct rvt_qp *qp = iowait_to_qp(wait);
791 796
792 hfi1_do_send(qp); 797 hfi1_do_send(qp, true);
793} 798}
794 799
795/** 800/**
796 * hfi1_do_send - perform a send on a QP 801 * hfi1_do_send - perform a send on a QP
797 * @work: contains a pointer to the QP 802 * @work: contains a pointer to the QP
803 * @in_thread: true if in a workqueue thread
798 * 804 *
799 * Process entries in the send work queue until credit or queue is 805 * Process entries in the send work queue until credit or queue is
800 * exhausted. Only allow one CPU to send a packet per QP. 806 * exhausted. Only allow one CPU to send a packet per QP.
801 * Otherwise, two threads could send packets out of order. 807 * Otherwise, two threads could send packets out of order.
802 */ 808 */
803void hfi1_do_send(struct rvt_qp *qp) 809void hfi1_do_send(struct rvt_qp *qp, bool in_thread)
804{ 810{
805 struct hfi1_pkt_state ps; 811 struct hfi1_pkt_state ps;
806 struct hfi1_qp_priv *priv = qp->priv; 812 struct hfi1_qp_priv *priv = qp->priv;
@@ -868,8 +874,10 @@ void hfi1_do_send(struct rvt_qp *qp)
868 qp->s_hdrwords = 0; 874 qp->s_hdrwords = 0;
869 /* allow other tasks to run */ 875 /* allow other tasks to run */
870 if (unlikely(time_after(jiffies, timeout))) { 876 if (unlikely(time_after(jiffies, timeout))) {
871 if (workqueue_congested(cpu, 877 if (!in_thread ||
872 ps.ppd->hfi1_wq)) { 878 workqueue_congested(
879 cpu,
880 ps.ppd->hfi1_wq)) {
873 spin_lock_irqsave( 881 spin_lock_irqsave(
874 &qp->s_lock, 882 &qp->s_lock,
875 ps.flags); 883 ps.flags);
@@ -882,11 +890,9 @@ void hfi1_do_send(struct rvt_qp *qp)
882 *ps.ppd->dd->send_schedule); 890 *ps.ppd->dd->send_schedule);
883 return; 891 return;
884 } 892 }
885 if (!irqs_disabled()) { 893 cond_resched();
886 cond_resched(); 894 this_cpu_inc(
887 this_cpu_inc( 895 *ps.ppd->dd->send_schedule);
888 *ps.ppd->dd->send_schedule);
889 }
890 timeout = jiffies + (timeout_int) / 8; 896 timeout = jiffies + (timeout_int) / 8;
891 } 897 }
892 spin_lock_irqsave(&qp->s_lock, ps.flags); 898 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 57036e545bdb..7174a18ebaac 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.
@@ -1820,7 +1820,7 @@ int hfi1_register_ib_device(struct hfi1_devdata *dd)
1820 dd->verbs_dev.rdi.driver_f.qp_priv_free = qp_priv_free; 1820 dd->verbs_dev.rdi.driver_f.qp_priv_free = qp_priv_free;
1821 dd->verbs_dev.rdi.driver_f.free_all_qps = free_all_qps; 1821 dd->verbs_dev.rdi.driver_f.free_all_qps = free_all_qps;
1822 dd->verbs_dev.rdi.driver_f.notify_qp_reset = notify_qp_reset; 1822 dd->verbs_dev.rdi.driver_f.notify_qp_reset = notify_qp_reset;
1823 dd->verbs_dev.rdi.driver_f.do_send = hfi1_do_send; 1823 dd->verbs_dev.rdi.driver_f.do_send = hfi1_do_send_from_rvt;
1824 dd->verbs_dev.rdi.driver_f.schedule_send = hfi1_schedule_send; 1824 dd->verbs_dev.rdi.driver_f.schedule_send = hfi1_schedule_send;
1825 dd->verbs_dev.rdi.driver_f.schedule_send_no_lock = _hfi1_schedule_send; 1825 dd->verbs_dev.rdi.driver_f.schedule_send_no_lock = _hfi1_schedule_send;
1826 dd->verbs_dev.rdi.driver_f.get_pmtu_from_attr = get_pmtu_from_attr; 1826 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 6c549e7a25e7..46b00ed9f2dc 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.
@@ -355,7 +355,9 @@ void hfi1_make_ruc_header(struct rvt_qp *qp, struct ib_other_headers *ohdr,
355 355
356void _hfi1_do_send(struct work_struct *work); 356void _hfi1_do_send(struct work_struct *work);
357 357
358void hfi1_do_send(struct rvt_qp *qp); 358void hfi1_do_send_from_rvt(struct rvt_qp *qp);
359
360void hfi1_do_send(struct rvt_qp *qp, bool in_thread);
359 361
360void hfi1_send_complete(struct rvt_qp *qp, struct rvt_swqe *wqe, 362void hfi1_send_complete(struct rvt_qp *qp, struct rvt_swqe *wqe,
361 enum ib_wc_status status); 363 enum ib_wc_status status);