aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Chapman <jchapman@katalix.com>2008-03-05 21:39:08 -0500
committerDavid S. Miller <davem@davemloft.net>2008-03-05 21:39:08 -0500
commitcf3752e2d203bbbfc88d29e362e6938cef4339b3 (patch)
treef48f87708423899ca04590e0a004b3c4913443f9
parent5a346a10c0b1192e7eae52f0f3a332f1d3f11226 (diff)
[PPPOL2TP]: Make locking calls softirq-safe
Fix locking issues in the pppol2tp driver which can cause a kernel crash on SMP boxes. There were two problems:- 1. The driver was violating read_lock() and write_lock() scheduling rules because it wasn't using softirq-safe locks in softirq contexts. So we now consistently use the _bh variants of the lock functions. 2. The driver was calling sk_dst_get() in pppol2tp_xmit() which was taking sk_dst_lock in softirq context. We now call __sk_dst_get(). Signed-off-by: James Chapman <jchapman@katalix.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/pppol2tp.c58
1 files changed, 29 insertions, 29 deletions
diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c
index 86e5dba079fe..9a90cede0ecc 100644
--- a/drivers/net/pppol2tp.c
+++ b/drivers/net/pppol2tp.c
@@ -302,14 +302,14 @@ pppol2tp_session_find(struct pppol2tp_tunnel *tunnel, u16 session_id)
302 struct pppol2tp_session *session; 302 struct pppol2tp_session *session;
303 struct hlist_node *walk; 303 struct hlist_node *walk;
304 304
305 read_lock(&tunnel->hlist_lock); 305 read_lock_bh(&tunnel->hlist_lock);
306 hlist_for_each_entry(session, walk, session_list, hlist) { 306 hlist_for_each_entry(session, walk, session_list, hlist) {
307 if (session->tunnel_addr.s_session == session_id) { 307 if (session->tunnel_addr.s_session == session_id) {
308 read_unlock(&tunnel->hlist_lock); 308 read_unlock_bh(&tunnel->hlist_lock);
309 return session; 309 return session;
310 } 310 }
311 } 311 }
312 read_unlock(&tunnel->hlist_lock); 312 read_unlock_bh(&tunnel->hlist_lock);
313 313
314 return NULL; 314 return NULL;
315} 315}
@@ -320,14 +320,14 @@ static struct pppol2tp_tunnel *pppol2tp_tunnel_find(u16 tunnel_id)
320{ 320{
321 struct pppol2tp_tunnel *tunnel = NULL; 321 struct pppol2tp_tunnel *tunnel = NULL;
322 322
323 read_lock(&pppol2tp_tunnel_list_lock); 323 read_lock_bh(&pppol2tp_tunnel_list_lock);
324 list_for_each_entry(tunnel, &pppol2tp_tunnel_list, list) { 324 list_for_each_entry(tunnel, &pppol2tp_tunnel_list, list) {
325 if (tunnel->stats.tunnel_id == tunnel_id) { 325 if (tunnel->stats.tunnel_id == tunnel_id) {
326 read_unlock(&pppol2tp_tunnel_list_lock); 326 read_unlock_bh(&pppol2tp_tunnel_list_lock);
327 return tunnel; 327 return tunnel;
328 } 328 }
329 } 329 }
330 read_unlock(&pppol2tp_tunnel_list_lock); 330 read_unlock_bh(&pppol2tp_tunnel_list_lock);
331 331
332 return NULL; 332 return NULL;
333} 333}
@@ -344,7 +344,7 @@ static void pppol2tp_recv_queue_skb(struct pppol2tp_session *session, struct sk_
344 struct sk_buff *skbp; 344 struct sk_buff *skbp;
345 u16 ns = PPPOL2TP_SKB_CB(skb)->ns; 345 u16 ns = PPPOL2TP_SKB_CB(skb)->ns;
346 346
347 spin_lock(&session->reorder_q.lock); 347 spin_lock_bh(&session->reorder_q.lock);
348 skb_queue_walk(&session->reorder_q, skbp) { 348 skb_queue_walk(&session->reorder_q, skbp) {
349 if (PPPOL2TP_SKB_CB(skbp)->ns > ns) { 349 if (PPPOL2TP_SKB_CB(skbp)->ns > ns) {
350 __skb_insert(skb, skbp->prev, skbp, &session->reorder_q); 350 __skb_insert(skb, skbp->prev, skbp, &session->reorder_q);
@@ -360,7 +360,7 @@ static void pppol2tp_recv_queue_skb(struct pppol2tp_session *session, struct sk_
360 __skb_queue_tail(&session->reorder_q, skb); 360 __skb_queue_tail(&session->reorder_q, skb);
361 361
362out: 362out:
363 spin_unlock(&session->reorder_q.lock); 363 spin_unlock_bh(&session->reorder_q.lock);
364} 364}
365 365
366/* Dequeue a single skb. 366/* Dequeue a single skb.
@@ -442,7 +442,7 @@ static void pppol2tp_recv_dequeue(struct pppol2tp_session *session)
442 * expect to send up next, dequeue it and any other 442 * expect to send up next, dequeue it and any other
443 * in-sequence packets behind it. 443 * in-sequence packets behind it.
444 */ 444 */
445 spin_lock(&session->reorder_q.lock); 445 spin_lock_bh(&session->reorder_q.lock);
446 skb_queue_walk_safe(&session->reorder_q, skb, tmp) { 446 skb_queue_walk_safe(&session->reorder_q, skb, tmp) {
447 if (time_after(jiffies, PPPOL2TP_SKB_CB(skb)->expires)) { 447 if (time_after(jiffies, PPPOL2TP_SKB_CB(skb)->expires)) {
448 session->stats.rx_seq_discards++; 448 session->stats.rx_seq_discards++;
@@ -470,13 +470,13 @@ static void pppol2tp_recv_dequeue(struct pppol2tp_session *session)
470 goto out; 470 goto out;
471 } 471 }
472 } 472 }
473 spin_unlock(&session->reorder_q.lock); 473 spin_unlock_bh(&session->reorder_q.lock);
474 pppol2tp_recv_dequeue_skb(session, skb); 474 pppol2tp_recv_dequeue_skb(session, skb);
475 spin_lock(&session->reorder_q.lock); 475 spin_lock_bh(&session->reorder_q.lock);
476 } 476 }
477 477
478out: 478out:
479 spin_unlock(&session->reorder_q.lock); 479 spin_unlock_bh(&session->reorder_q.lock);
480} 480}
481 481
482/* Internal receive frame. Do the real work of receiving an L2TP data frame 482/* Internal receive frame. Do the real work of receiving an L2TP data frame
@@ -1059,7 +1059,7 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb)
1059 1059
1060 /* Get routing info from the tunnel socket */ 1060 /* Get routing info from the tunnel socket */
1061 dst_release(skb->dst); 1061 dst_release(skb->dst);
1062 skb->dst = sk_dst_get(sk_tun); 1062 skb->dst = dst_clone(__sk_dst_get(sk_tun));
1063 skb_orphan(skb); 1063 skb_orphan(skb);
1064 skb->sk = sk_tun; 1064 skb->sk = sk_tun;
1065 1065
@@ -1107,7 +1107,7 @@ static void pppol2tp_tunnel_closeall(struct pppol2tp_tunnel *tunnel)
1107 PRINTK(tunnel->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO, 1107 PRINTK(tunnel->debug, PPPOL2TP_MSG_CONTROL, KERN_INFO,
1108 "%s: closing all sessions...\n", tunnel->name); 1108 "%s: closing all sessions...\n", tunnel->name);
1109 1109
1110 write_lock(&tunnel->hlist_lock); 1110 write_lock_bh(&tunnel->hlist_lock);
1111 for (hash = 0; hash < PPPOL2TP_HASH_SIZE; hash++) { 1111 for (hash = 0; hash < PPPOL2TP_HASH_SIZE; hash++) {
1112again: 1112again:
1113 hlist_for_each_safe(walk, tmp, &tunnel->session_hlist[hash]) { 1113 hlist_for_each_safe(walk, tmp, &tunnel->session_hlist[hash]) {
@@ -1129,7 +1129,7 @@ again:
1129 * disappear as we're jumping between locks. 1129 * disappear as we're jumping between locks.
1130 */ 1130 */
1131 sock_hold(sk); 1131 sock_hold(sk);
1132 write_unlock(&tunnel->hlist_lock); 1132 write_unlock_bh(&tunnel->hlist_lock);
1133 lock_sock(sk); 1133 lock_sock(sk);
1134 1134
1135 if (sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND)) { 1135 if (sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND)) {
@@ -1154,11 +1154,11 @@ again:
1154 * list so we are guaranteed to make forward 1154 * list so we are guaranteed to make forward
1155 * progress. 1155 * progress.
1156 */ 1156 */
1157 write_lock(&tunnel->hlist_lock); 1157 write_lock_bh(&tunnel->hlist_lock);
1158 goto again; 1158 goto again;
1159 } 1159 }
1160 } 1160 }
1161 write_unlock(&tunnel->hlist_lock); 1161 write_unlock_bh(&tunnel->hlist_lock);
1162} 1162}
1163 1163
1164/* Really kill the tunnel. 1164/* Really kill the tunnel.
@@ -1167,9 +1167,9 @@ again:
1167static void pppol2tp_tunnel_free(struct pppol2tp_tunnel *tunnel) 1167static void pppol2tp_tunnel_free(struct pppol2tp_tunnel *tunnel)
1168{ 1168{
1169 /* Remove from socket list */ 1169 /* Remove from socket list */
1170 write_lock(&pppol2tp_tunnel_list_lock); 1170 write_lock_bh(&pppol2tp_tunnel_list_lock);
1171 list_del_init(&tunnel->list); 1171 list_del_init(&tunnel->list);
1172 write_unlock(&pppol2tp_tunnel_list_lock); 1172 write_unlock_bh(&pppol2tp_tunnel_list_lock);
1173 1173
1174 atomic_dec(&pppol2tp_tunnel_count); 1174 atomic_dec(&pppol2tp_tunnel_count);
1175 kfree(tunnel); 1175 kfree(tunnel);
@@ -1245,9 +1245,9 @@ static void pppol2tp_session_destruct(struct sock *sk)
1245 /* Delete the session socket from the 1245 /* Delete the session socket from the
1246 * hash 1246 * hash
1247 */ 1247 */
1248 write_lock(&tunnel->hlist_lock); 1248 write_lock_bh(&tunnel->hlist_lock);
1249 hlist_del_init(&session->hlist); 1249 hlist_del_init(&session->hlist);
1250 write_unlock(&tunnel->hlist_lock); 1250 write_unlock_bh(&tunnel->hlist_lock);
1251 1251
1252 atomic_dec(&pppol2tp_session_count); 1252 atomic_dec(&pppol2tp_session_count);
1253 } 1253 }
@@ -1392,9 +1392,9 @@ static struct sock *pppol2tp_prepare_tunnel_socket(int fd, u16 tunnel_id,
1392 1392
1393 /* Add tunnel to our list */ 1393 /* Add tunnel to our list */
1394 INIT_LIST_HEAD(&tunnel->list); 1394 INIT_LIST_HEAD(&tunnel->list);
1395 write_lock(&pppol2tp_tunnel_list_lock); 1395 write_lock_bh(&pppol2tp_tunnel_list_lock);
1396 list_add(&tunnel->list, &pppol2tp_tunnel_list); 1396 list_add(&tunnel->list, &pppol2tp_tunnel_list);
1397 write_unlock(&pppol2tp_tunnel_list_lock); 1397 write_unlock_bh(&pppol2tp_tunnel_list_lock);
1398 atomic_inc(&pppol2tp_tunnel_count); 1398 atomic_inc(&pppol2tp_tunnel_count);
1399 1399
1400 /* Bump the reference count. The tunnel context is deleted 1400 /* Bump the reference count. The tunnel context is deleted
@@ -1599,11 +1599,11 @@ static int pppol2tp_connect(struct socket *sock, struct sockaddr *uservaddr,
1599 sk->sk_user_data = session; 1599 sk->sk_user_data = session;
1600 1600
1601 /* Add session to the tunnel's hash list */ 1601 /* Add session to the tunnel's hash list */
1602 write_lock(&tunnel->hlist_lock); 1602 write_lock_bh(&tunnel->hlist_lock);
1603 hlist_add_head(&session->hlist, 1603 hlist_add_head(&session->hlist,
1604 pppol2tp_session_id_hash(tunnel, 1604 pppol2tp_session_id_hash(tunnel,
1605 session->tunnel_addr.s_session)); 1605 session->tunnel_addr.s_session));
1606 write_unlock(&tunnel->hlist_lock); 1606 write_unlock_bh(&tunnel->hlist_lock);
1607 1607
1608 atomic_inc(&pppol2tp_session_count); 1608 atomic_inc(&pppol2tp_session_count);
1609 1609
@@ -2205,7 +2205,7 @@ static struct pppol2tp_session *next_session(struct pppol2tp_tunnel *tunnel, str
2205 int next = 0; 2205 int next = 0;
2206 int i; 2206 int i;
2207 2207
2208 read_lock(&tunnel->hlist_lock); 2208 read_lock_bh(&tunnel->hlist_lock);
2209 for (i = 0; i < PPPOL2TP_HASH_SIZE; i++) { 2209 for (i = 0; i < PPPOL2TP_HASH_SIZE; i++) {
2210 hlist_for_each_entry(session, walk, &tunnel->session_hlist[i], hlist) { 2210 hlist_for_each_entry(session, walk, &tunnel->session_hlist[i], hlist) {
2211 if (curr == NULL) { 2211 if (curr == NULL) {
@@ -2223,7 +2223,7 @@ static struct pppol2tp_session *next_session(struct pppol2tp_tunnel *tunnel, str
2223 } 2223 }
2224 } 2224 }
2225out: 2225out:
2226 read_unlock(&tunnel->hlist_lock); 2226 read_unlock_bh(&tunnel->hlist_lock);
2227 if (!found) 2227 if (!found)
2228 session = NULL; 2228 session = NULL;
2229 2229
@@ -2234,13 +2234,13 @@ static struct pppol2tp_tunnel *next_tunnel(struct pppol2tp_tunnel *curr)
2234{ 2234{
2235 struct pppol2tp_tunnel *tunnel = NULL; 2235 struct pppol2tp_tunnel *tunnel = NULL;
2236 2236
2237 read_lock(&pppol2tp_tunnel_list_lock); 2237 read_lock_bh(&pppol2tp_tunnel_list_lock);
2238 if (list_is_last(&curr->list, &pppol2tp_tunnel_list)) { 2238 if (list_is_last(&curr->list, &pppol2tp_tunnel_list)) {
2239 goto out; 2239 goto out;
2240 } 2240 }
2241 tunnel = list_entry(curr->list.next, struct pppol2tp_tunnel, list); 2241 tunnel = list_entry(curr->list.next, struct pppol2tp_tunnel, list);
2242out: 2242out:
2243 read_unlock(&pppol2tp_tunnel_list_lock); 2243 read_unlock_bh(&pppol2tp_tunnel_list_lock);
2244 2244
2245 return tunnel; 2245 return tunnel;
2246} 2246}