diff options
| author | James Chapman <jchapman@katalix.com> | 2008-03-05 21:40:01 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2008-03-05 21:40:01 -0500 |
| commit | e653181dd6b3ad38ce14904351b03a5388f4b0f7 (patch) | |
| tree | 36703dfc6206863464a162f0a4a29a5901314e44 /drivers | |
| parent | cf3752e2d203bbbfc88d29e362e6938cef4339b3 (diff) | |
[PPPOL2TP]: Fix SMP issues in skb reorder queue handling
When walking a session's packet reorder queue, use
skb_queue_walk_safe() since the list could be modified inside the
loop.
Rearrange the unlinking skbs from the reorder queue such that it is
done while the queue lock is held in pppol2tp_recv_dequeue() when
walking the skb list.
A version of this patch was suggested by Jarek Poplawski.
Signed-off-by: James Chapman <jchapman@katalix.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/net/pppol2tp.c | 11 |
1 files changed, 8 insertions, 3 deletions
diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index 9a90cede0ecc..3d10ca050b79 100644 --- a/drivers/net/pppol2tp.c +++ b/drivers/net/pppol2tp.c | |||
| @@ -342,10 +342,11 @@ static struct pppol2tp_tunnel *pppol2tp_tunnel_find(u16 tunnel_id) | |||
| 342 | static void pppol2tp_recv_queue_skb(struct pppol2tp_session *session, struct sk_buff *skb) | 342 | static void pppol2tp_recv_queue_skb(struct pppol2tp_session *session, struct sk_buff *skb) |
| 343 | { | 343 | { |
| 344 | struct sk_buff *skbp; | 344 | struct sk_buff *skbp; |
| 345 | struct sk_buff *tmp; | ||
| 345 | u16 ns = PPPOL2TP_SKB_CB(skb)->ns; | 346 | u16 ns = PPPOL2TP_SKB_CB(skb)->ns; |
| 346 | 347 | ||
| 347 | spin_lock_bh(&session->reorder_q.lock); | 348 | spin_lock_bh(&session->reorder_q.lock); |
| 348 | skb_queue_walk(&session->reorder_q, skbp) { | 349 | skb_queue_walk_safe(&session->reorder_q, skbp, tmp) { |
| 349 | if (PPPOL2TP_SKB_CB(skbp)->ns > ns) { | 350 | if (PPPOL2TP_SKB_CB(skbp)->ns > ns) { |
| 350 | __skb_insert(skb, skbp->prev, skbp, &session->reorder_q); | 351 | __skb_insert(skb, skbp->prev, skbp, &session->reorder_q); |
| 351 | PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG, | 352 | PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG, |
| @@ -371,10 +372,9 @@ static void pppol2tp_recv_dequeue_skb(struct pppol2tp_session *session, struct s | |||
| 371 | int length = PPPOL2TP_SKB_CB(skb)->length; | 372 | int length = PPPOL2TP_SKB_CB(skb)->length; |
| 372 | struct sock *session_sock = NULL; | 373 | struct sock *session_sock = NULL; |
| 373 | 374 | ||
| 374 | /* We're about to requeue the skb, so unlink it and return resources | 375 | /* We're about to requeue the skb, so return resources |
| 375 | * to its current owner (a socket receive buffer). | 376 | * to its current owner (a socket receive buffer). |
| 376 | */ | 377 | */ |
| 377 | skb_unlink(skb, &session->reorder_q); | ||
| 378 | skb_orphan(skb); | 378 | skb_orphan(skb); |
| 379 | 379 | ||
| 380 | tunnel->stats.rx_packets++; | 380 | tunnel->stats.rx_packets++; |
| @@ -470,6 +470,11 @@ static void pppol2tp_recv_dequeue(struct pppol2tp_session *session) | |||
| 470 | goto out; | 470 | goto out; |
| 471 | } | 471 | } |
| 472 | } | 472 | } |
| 473 | __skb_unlink(skb, &session->reorder_q); | ||
| 474 | |||
| 475 | /* Process the skb. We release the queue lock while we | ||
| 476 | * do so to let other contexts process the queue. | ||
| 477 | */ | ||
| 473 | spin_unlock_bh(&session->reorder_q.lock); | 478 | spin_unlock_bh(&session->reorder_q.lock); |
| 474 | pppol2tp_recv_dequeue_skb(session, skb); | 479 | pppol2tp_recv_dequeue_skb(session, skb); |
| 475 | spin_lock_bh(&session->reorder_q.lock); | 480 | spin_lock_bh(&session->reorder_q.lock); |
