]>
Commit | Line | Data |
---|---|---|
5032628c GKH |
1 | From b6eac931b9bb2bce4db7032c35b41e5e34ec22a5 Mon Sep 17 00:00:00 2001 |
2 | From: Mike Marciniszyn <mike.marciniszyn@intel.com> | |
3 | Date: Sun, 9 Apr 2017 10:16:35 -0700 | |
4 | Subject: IB/hfi1: Prevent kernel QP post send hard lockups | |
5 | ||
6 | From: Mike Marciniszyn <mike.marciniszyn@intel.com> | |
7 | ||
8 | commit b6eac931b9bb2bce4db7032c35b41e5e34ec22a5 upstream. | |
9 | ||
10 | The driver progress routines can call cond_resched() when | |
11 | a timeslice is exhausted and irqs are enabled. | |
12 | ||
13 | If the ULP had been holding a spin lock without disabling irqs and | |
14 | the post send directly called the progress routine, the cond_resched() | |
15 | could yield allowing another thread from the same ULP to deadlock | |
16 | on that same lock. | |
17 | ||
18 | Correct by replacing the current hfi1_do_send() calldown with a unique | |
19 | one for post send and adding an argument to hfi1_do_send() to indicate | |
20 | that the send engine is running in a thread. If the routine is not | |
21 | running in a thread, avoid calling cond_resched(). | |
22 | ||
23 | Fixes: Commit 831464ce4b74 ("IB/hfi1: Don't call cond_resched in atomic mode when sending packets") | |
24 | Reviewed-by: Dennis Dalessandro <dennis.dalessandro@intel.com> | |
25 | Signed-off-by: Mike Marciniszyn <mike.marciniszyn@intel.com> | |
26 | Signed-off-by: Dennis Dalessandro <dennis.dalessandro@intel.com> | |
27 | Signed-off-by: Doug Ledford <dledford@redhat.com> | |
28 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
29 | ||
30 | --- | |
31 | drivers/infiniband/hw/hfi1/ruc.c | 26 ++++++++++++++++---------- | |
32 | drivers/infiniband/hw/hfi1/verbs.c | 4 ++-- | |
33 | drivers/infiniband/hw/hfi1/verbs.h | 6 ++++-- | |
34 | 3 files changed, 22 insertions(+), 14 deletions(-) | |
35 | ||
36 | --- a/drivers/infiniband/hw/hfi1/ruc.c | |
37 | +++ b/drivers/infiniband/hw/hfi1/ruc.c | |
38 | @@ -1,5 +1,5 @@ | |
39 | /* | |
40 | - * Copyright(c) 2015, 2016 Intel Corporation. | |
41 | + * Copyright(c) 2015 - 2017 Intel Corporation. | |
42 | * | |
43 | * This file is provided under a dual BSD/GPLv2 license. When using or | |
44 | * redistributing this file, you may do so under either license. | |
45 | @@ -784,23 +784,29 @@ void hfi1_make_ruc_header(struct rvt_qp | |
46 | /* when sending, force a reschedule every one of these periods */ | |
47 | #define SEND_RESCHED_TIMEOUT (5 * HZ) /* 5s in jiffies */ | |
48 | ||
49 | +void hfi1_do_send_from_rvt(struct rvt_qp *qp) | |
50 | +{ | |
51 | + hfi1_do_send(qp, false); | |
52 | +} | |
53 | + | |
54 | void _hfi1_do_send(struct work_struct *work) | |
55 | { | |
56 | struct iowait *wait = container_of(work, struct iowait, iowork); | |
57 | struct rvt_qp *qp = iowait_to_qp(wait); | |
58 | ||
59 | - hfi1_do_send(qp); | |
60 | + hfi1_do_send(qp, true); | |
61 | } | |
62 | ||
63 | /** | |
64 | * hfi1_do_send - perform a send on a QP | |
65 | * @work: contains a pointer to the QP | |
66 | + * @in_thread: true if in a workqueue thread | |
67 | * | |
68 | * Process entries in the send work queue until credit or queue is | |
69 | * exhausted. Only allow one CPU to send a packet per QP. | |
70 | * Otherwise, two threads could send packets out of order. | |
71 | */ | |
72 | -void hfi1_do_send(struct rvt_qp *qp) | |
73 | +void hfi1_do_send(struct rvt_qp *qp, bool in_thread) | |
74 | { | |
75 | struct hfi1_pkt_state ps; | |
76 | struct hfi1_qp_priv *priv = qp->priv; | |
77 | @@ -868,8 +874,10 @@ void hfi1_do_send(struct rvt_qp *qp) | |
78 | qp->s_hdrwords = 0; | |
79 | /* allow other tasks to run */ | |
80 | if (unlikely(time_after(jiffies, timeout))) { | |
81 | - if (workqueue_congested(cpu, | |
82 | - ps.ppd->hfi1_wq)) { | |
83 | + if (!in_thread || | |
84 | + workqueue_congested( | |
85 | + cpu, | |
86 | + ps.ppd->hfi1_wq)) { | |
87 | spin_lock_irqsave( | |
88 | &qp->s_lock, | |
89 | ps.flags); | |
90 | @@ -882,11 +890,9 @@ void hfi1_do_send(struct rvt_qp *qp) | |
91 | *ps.ppd->dd->send_schedule); | |
92 | return; | |
93 | } | |
94 | - if (!irqs_disabled()) { | |
95 | - cond_resched(); | |
96 | - this_cpu_inc( | |
97 | - *ps.ppd->dd->send_schedule); | |
98 | - } | |
99 | + cond_resched(); | |
100 | + this_cpu_inc( | |
101 | + *ps.ppd->dd->send_schedule); | |
102 | timeout = jiffies + (timeout_int) / 8; | |
103 | } | |
104 | spin_lock_irqsave(&qp->s_lock, ps.flags); | |
105 | --- a/drivers/infiniband/hw/hfi1/verbs.c | |
106 | +++ b/drivers/infiniband/hw/hfi1/verbs.c | |
107 | @@ -1,5 +1,5 @@ | |
108 | /* | |
109 | - * Copyright(c) 2015, 2016 Intel Corporation. | |
110 | + * Copyright(c) 2015 - 2017 Intel Corporation. | |
111 | * | |
112 | * This file is provided under a dual BSD/GPLv2 license. When using or | |
113 | * redistributing this file, you may do so under either license. | |
114 | @@ -1751,7 +1751,7 @@ int hfi1_register_ib_device(struct hfi1_ | |
115 | dd->verbs_dev.rdi.driver_f.qp_priv_free = qp_priv_free; | |
116 | dd->verbs_dev.rdi.driver_f.free_all_qps = free_all_qps; | |
117 | dd->verbs_dev.rdi.driver_f.notify_qp_reset = notify_qp_reset; | |
118 | - dd->verbs_dev.rdi.driver_f.do_send = hfi1_do_send; | |
119 | + dd->verbs_dev.rdi.driver_f.do_send = hfi1_do_send_from_rvt; | |
120 | dd->verbs_dev.rdi.driver_f.schedule_send = hfi1_schedule_send; | |
121 | dd->verbs_dev.rdi.driver_f.schedule_send_no_lock = _hfi1_schedule_send; | |
122 | dd->verbs_dev.rdi.driver_f.get_pmtu_from_attr = get_pmtu_from_attr; | |
123 | --- a/drivers/infiniband/hw/hfi1/verbs.h | |
124 | +++ b/drivers/infiniband/hw/hfi1/verbs.h | |
125 | @@ -1,5 +1,5 @@ | |
126 | /* | |
127 | - * Copyright(c) 2015, 2016 Intel Corporation. | |
128 | + * Copyright(c) 2015 - 2017 Intel Corporation. | |
129 | * | |
130 | * This file is provided under a dual BSD/GPLv2 license. When using or | |
131 | * redistributing this file, you may do so under either license. | |
132 | @@ -350,7 +350,9 @@ void hfi1_make_ruc_header(struct rvt_qp | |
133 | ||
134 | void _hfi1_do_send(struct work_struct *work); | |
135 | ||
136 | -void hfi1_do_send(struct rvt_qp *qp); | |
137 | +void hfi1_do_send_from_rvt(struct rvt_qp *qp); | |
138 | + | |
139 | +void hfi1_do_send(struct rvt_qp *qp, bool in_thread); | |
140 | ||
141 | void hfi1_send_complete(struct rvt_qp *qp, struct rvt_swqe *wqe, | |
142 | enum ib_wc_status status); |