diff options
| author | Mike Marciniszyn <mike.marciniszyn@intel.com> | 2017-04-09 13:16:35 -0400 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-05-20 08:28:38 -0400 |
| commit | e3cea38357ea66d63b1c42500c69ca88a3f0c44f (patch) | |
| tree | af3ebc979b7de6be128c985120ff26d29407ada5 /drivers/infiniband/hw | |
| parent | 43c54927f6f4e0dba5714dbcd53fea44114cd7cf (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>
Diffstat (limited to 'drivers/infiniband/hw')
| -rw-r--r-- | drivers/infiniband/hw/hfi1/ruc.c | 26 | ||||
| -rw-r--r-- | drivers/infiniband/hw/hfi1/verbs.c | 4 | ||||
| -rw-r--r-- | drivers/infiniband/hw/hfi1/verbs.h | 6 |
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 | ||
| 836 | void hfi1_do_send_from_rvt(struct rvt_qp *qp) | ||
| 837 | { | ||
| 838 | hfi1_do_send(qp, false); | ||
| 839 | } | ||
| 840 | |||
| 836 | void _hfi1_do_send(struct work_struct *work) | 841 | void _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 | */ |
| 852 | void hfi1_do_send(struct rvt_qp *qp) | 858 | void 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 | ||
| 373 | void _hfi1_do_send(struct work_struct *work); | 373 | void _hfi1_do_send(struct work_struct *work); |
| 374 | 374 | ||
| 375 | void hfi1_do_send(struct rvt_qp *qp); | 375 | void hfi1_do_send_from_rvt(struct rvt_qp *qp); |
| 376 | |||
| 377 | void hfi1_do_send(struct rvt_qp *qp, bool in_thread); | ||
| 376 | 378 | ||
| 377 | void hfi1_send_complete(struct rvt_qp *qp, struct rvt_swqe *wqe, | 379 | void hfi1_send_complete(struct rvt_qp *qp, struct rvt_swqe *wqe, |
| 378 | enum ib_wc_status status); | 380 | enum ib_wc_status status); |
