]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/3.1.5/ib-fix-rcu-lockdep-splats.patch
4.9-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 3.1.5 / ib-fix-rcu-lockdep-splats.patch
CommitLineData
7c598465
GKH
1From 580da35a31f91a594f3090b7a2c39b85cb051a12 Mon Sep 17 00:00:00 2001
2From: Eric Dumazet <eric.dumazet@gmail.com>
3Date: Tue, 29 Nov 2011 22:31:23 +0100
4Subject: IB: Fix RCU lockdep splats
5
6From: Eric Dumazet <eric.dumazet@gmail.com>
7
8commit 580da35a31f91a594f3090b7a2c39b85cb051a12 upstream.
9
10Commit f2c31e32b37 ("net: fix NULL dereferences in check_peer_redir()")
11forgot to take care of infiniband uses of dst neighbours.
12
13Many thanks to Marc Aurele who provided a nice bug report and feedback.
14
15Reported-by: Marc Aurele La France <tsi@ualberta.ca>
16Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
17Cc: David Miller <davem@davemloft.net>
18Signed-off-by: Roland Dreier <roland@purestorage.com>
19
20---
21 drivers/infiniband/core/addr.c | 9 ++++++---
22 drivers/infiniband/hw/cxgb3/iwch_cm.c | 4 ++++
23 drivers/infiniband/hw/cxgb4/cm.c | 4 ++++
24 drivers/infiniband/hw/mlx4/qp.c | 2 +-
25 drivers/infiniband/hw/nes/nes_cm.c | 6 ++++--
26 drivers/infiniband/ulp/ipoib/ipoib_main.c | 18 +++++++++++-------
27 drivers/infiniband/ulp/ipoib/ipoib_multicast.c | 6 ++++--
28 7 files changed, 34 insertions(+), 15 deletions(-)
29
30--- a/drivers/infiniband/core/addr.c
31+++ b/drivers/infiniband/core/addr.c
32@@ -215,7 +215,9 @@ static int addr4_resolve(struct sockaddr
33
34 neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, rt->dst.dev);
35 if (!neigh || !(neigh->nud_state & NUD_VALID)) {
36+ rcu_read_lock();
37 neigh_event_send(dst_get_neighbour(&rt->dst), NULL);
38+ rcu_read_unlock();
39 ret = -ENODATA;
40 if (neigh)
41 goto release;
42@@ -273,15 +275,16 @@ static int addr6_resolve(struct sockaddr
43 goto put;
44 }
45
46+ rcu_read_lock();
47 neigh = dst_get_neighbour(dst);
48 if (!neigh || !(neigh->nud_state & NUD_VALID)) {
49 if (neigh)
50 neigh_event_send(neigh, NULL);
51 ret = -ENODATA;
52- goto put;
53+ } else {
54+ ret = rdma_copy_addr(addr, dst->dev, neigh->ha);
55 }
56-
57- ret = rdma_copy_addr(addr, dst->dev, neigh->ha);
58+ rcu_read_unlock();
59 put:
60 dst_release(dst);
61 return ret;
62--- a/drivers/infiniband/hw/cxgb3/iwch_cm.c
63+++ b/drivers/infiniband/hw/cxgb3/iwch_cm.c
64@@ -1365,8 +1365,10 @@ static int pass_accept_req(struct t3cdev
65 goto reject;
66 }
67 dst = &rt->dst;
68+ rcu_read_lock();
69 neigh = dst_get_neighbour(dst);
70 l2t = t3_l2t_get(tdev, neigh, neigh->dev);
71+ rcu_read_unlock();
72 if (!l2t) {
73 printk(KERN_ERR MOD "%s - failed to allocate l2t entry!\n",
74 __func__);
75@@ -1936,10 +1938,12 @@ int iwch_connect(struct iw_cm_id *cm_id,
76 }
77 ep->dst = &rt->dst;
78
79+ rcu_read_lock();
80 neigh = dst_get_neighbour(ep->dst);
81
82 /* get a l2t entry */
83 ep->l2t = t3_l2t_get(ep->com.tdev, neigh, neigh->dev);
84+ rcu_read_unlock();
85 if (!ep->l2t) {
86 printk(KERN_ERR MOD "%s - cannot alloc l2e.\n", __func__);
87 err = -ENOMEM;
88--- a/drivers/infiniband/hw/cxgb4/cm.c
89+++ b/drivers/infiniband/hw/cxgb4/cm.c
90@@ -1358,6 +1358,7 @@ static int pass_accept_req(struct c4iw_d
91 goto reject;
92 }
93 dst = &rt->dst;
94+ rcu_read_lock();
95 neigh = dst_get_neighbour(dst);
96 if (neigh->dev->flags & IFF_LOOPBACK) {
97 pdev = ip_dev_find(&init_net, peer_ip);
98@@ -1384,6 +1385,7 @@ static int pass_accept_req(struct c4iw_d
99 rss_qid = dev->rdev.lldi.rxq_ids[
100 cxgb4_port_idx(neigh->dev) * step];
101 }
102+ rcu_read_unlock();
103 if (!l2t) {
104 printk(KERN_ERR MOD "%s - failed to allocate l2t entry!\n",
105 __func__);
106@@ -1909,6 +1911,7 @@ int c4iw_connect(struct iw_cm_id *cm_id,
107 }
108 ep->dst = &rt->dst;
109
110+ rcu_read_lock();
111 neigh = dst_get_neighbour(ep->dst);
112
113 /* get a l2t entry */
114@@ -1945,6 +1948,7 @@ int c4iw_connect(struct iw_cm_id *cm_id,
115 ep->rss_qid = ep->com.dev->rdev.lldi.rxq_ids[
116 cxgb4_port_idx(neigh->dev) * step];
117 }
118+ rcu_read_unlock();
119 if (!ep->l2t) {
120 printk(KERN_ERR MOD "%s - cannot alloc l2e.\n", __func__);
121 err = -ENOMEM;
122--- a/drivers/infiniband/hw/mlx4/qp.c
123+++ b/drivers/infiniband/hw/mlx4/qp.c
124@@ -1309,7 +1309,7 @@ static int build_mlx_header(struct mlx4_
125 int is_eth;
126 int is_vlan = 0;
127 int is_grh;
128- u16 vlan;
129+ u16 vlan = 0;
130
131 send_size = 0;
132 for (i = 0; i < wr->num_sge; ++i)
133--- a/drivers/infiniband/hw/nes/nes_cm.c
134+++ b/drivers/infiniband/hw/nes/nes_cm.c
135@@ -1150,9 +1150,11 @@ static int nes_addr_resolve_neigh(struct
136 neigh_release(neigh);
137 }
138
139- if ((neigh == NULL) || (!(neigh->nud_state & NUD_VALID)))
140+ if ((neigh == NULL) || (!(neigh->nud_state & NUD_VALID))) {
141+ rcu_read_lock();
142 neigh_event_send(dst_get_neighbour(&rt->dst), NULL);
143-
144+ rcu_read_unlock();
145+ }
146 ip_rt_put(rt);
147 return rc;
148 }
149--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
150+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
151@@ -555,6 +555,7 @@ static int path_rec_start(struct net_dev
152 return 0;
153 }
154
155+/* called with rcu_read_lock */
156 static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
157 {
158 struct ipoib_dev_priv *priv = netdev_priv(dev);
159@@ -636,6 +637,7 @@ err_drop:
160 spin_unlock_irqrestore(&priv->lock, flags);
161 }
162
163+/* called with rcu_read_lock */
164 static void ipoib_path_lookup(struct sk_buff *skb, struct net_device *dev)
165 {
166 struct ipoib_dev_priv *priv = netdev_priv(skb->dev);
167@@ -720,13 +722,14 @@ static int ipoib_start_xmit(struct sk_bu
168 struct neighbour *n = NULL;
169 unsigned long flags;
170
171+ rcu_read_lock();
172 if (likely(skb_dst(skb)))
173 n = dst_get_neighbour(skb_dst(skb));
174
175 if (likely(n)) {
176 if (unlikely(!*to_ipoib_neigh(n))) {
177 ipoib_path_lookup(skb, dev);
178- return NETDEV_TX_OK;
179+ goto unlock;
180 }
181
182 neigh = *to_ipoib_neigh(n);
183@@ -749,17 +752,17 @@ static int ipoib_start_xmit(struct sk_bu
184 ipoib_neigh_free(dev, neigh);
185 spin_unlock_irqrestore(&priv->lock, flags);
186 ipoib_path_lookup(skb, dev);
187- return NETDEV_TX_OK;
188+ goto unlock;
189 }
190
191 if (ipoib_cm_get(neigh)) {
192 if (ipoib_cm_up(neigh)) {
193 ipoib_cm_send(dev, skb, ipoib_cm_get(neigh));
194- return NETDEV_TX_OK;
195+ goto unlock;
196 }
197 } else if (neigh->ah) {
198 ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(n->ha));
199- return NETDEV_TX_OK;
200+ goto unlock;
201 }
202
203 if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) {
204@@ -793,13 +796,14 @@ static int ipoib_start_xmit(struct sk_bu
205 phdr->hwaddr + 4);
206 dev_kfree_skb_any(skb);
207 ++dev->stats.tx_dropped;
208- return NETDEV_TX_OK;
209+ goto unlock;
210 }
211
212 unicast_arp_send(skb, dev, phdr);
213 }
214 }
215-
216+unlock:
217+ rcu_read_unlock();
218 return NETDEV_TX_OK;
219 }
220
221@@ -837,7 +841,7 @@ static int ipoib_hard_header(struct sk_b
222 dst = skb_dst(skb);
223 n = NULL;
224 if (dst)
225- n = dst_get_neighbour(dst);
226+ n = dst_get_neighbour_raw(dst);
227 if ((!dst || !n) && daddr) {
228 struct ipoib_pseudoheader *phdr =
229 (struct ipoib_pseudoheader *) skb_push(skb, sizeof *phdr);
230--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
231+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
232@@ -265,7 +265,7 @@ static int ipoib_mcast_join_finish(struc
233
234 skb->dev = dev;
235 if (dst)
236- n = dst_get_neighbour(dst);
237+ n = dst_get_neighbour_raw(dst);
238 if (!dst || !n) {
239 /* put pseudoheader back on for next time */
240 skb_push(skb, sizeof (struct ipoib_pseudoheader));
241@@ -721,6 +721,8 @@ out:
242 if (mcast && mcast->ah) {
243 struct dst_entry *dst = skb_dst(skb);
244 struct neighbour *n = NULL;
245+
246+ rcu_read_lock();
247 if (dst)
248 n = dst_get_neighbour(dst);
249 if (n && !*to_ipoib_neigh(n)) {
250@@ -733,7 +735,7 @@ out:
251 list_add_tail(&neigh->list, &mcast->neigh_list);
252 }
253 }
254-
255+ rcu_read_unlock();
256 spin_unlock_irqrestore(&priv->lock, flags);
257 ipoib_send(dev, skb, mcast->ah, IB_MULTICAST_QPN);
258 return;