summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Chapman <jchapman@katalix.com>2008-04-06 23:41:29 -0700
committerChris Wright <chrisw@sous-sol.org>2008-04-18 18:53:25 -0700
commit43bee598bd747dc6849d3c4f32a3a912200073c0 (patch)
tree83045b57fb1c1defd8e267ffabb6a9dc00be4b3f
parent5998533a1a9aa7480329cca82bab577eec396679 (diff)
PPPOL2TP: Fix SMP issues in skb reorder queue handling
Upstream commit: e653181dd6b3ad38ce14904351b03a5388f4b0f7 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> Signed-off-by: Chris Wright <chrisw@sous-sol.org>
-rw-r--r--drivers/net/pppol2tp.c11
1 files changed, 8 insertions, 3 deletions
diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c
index ff4a94b29ec5..88a7e4e1cd03 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)
static void pppol2tp_recv_queue_skb(struct pppol2tp_session *session, struct sk_buff *skb)
{
struct sk_buff *skbp;
+ struct sk_buff *tmp;
u16 ns = PPPOL2TP_SKB_CB(skb)->ns;
spin_lock_bh(&session->reorder_q.lock);
- skb_queue_walk(&session->reorder_q, skbp) {
+ skb_queue_walk_safe(&session->reorder_q, skbp, tmp) {
if (PPPOL2TP_SKB_CB(skbp)->ns > ns) {
__skb_insert(skb, skbp->prev, skbp, &session->reorder_q);
PRINTK(session->debug, PPPOL2TP_MSG_SEQ, KERN_DEBUG,
@@ -371,10 +372,9 @@ static void pppol2tp_recv_dequeue_skb(struct pppol2tp_session *session, struct s
int length = PPPOL2TP_SKB_CB(skb)->length;
struct sock *session_sock = NULL;
- /* We're about to requeue the skb, so unlink it and return resources
+ /* We're about to requeue the skb, so return resources
* to its current owner (a socket receive buffer).
*/
- skb_unlink(skb, &session->reorder_q);
skb_orphan(skb);
tunnel->stats.rx_packets++;
@@ -469,6 +469,11 @@ static void pppol2tp_recv_dequeue(struct pppol2tp_session *session)
goto out;
}
}
+ __skb_unlink(skb, &session->reorder_q);
+
+ /* Process the skb. We release the queue lock while we
+ * do so to let other contexts process the queue.
+ */
spin_unlock_bh(&session->reorder_q.lock);
pppol2tp_recv_dequeue_skb(session, skb);
spin_lock_bh(&session->reorder_q.lock);