]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.7-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 17 Dec 2012 20:58:19 +0000 (12:58 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 17 Dec 2012 20:58:19 +0000 (12:58 -0800)
added patches:
net-fix-a-race-in-gro_cell_poll.patch

queue-3.7/net-fix-a-race-in-gro_cell_poll.patch [new file with mode: 0644]
queue-3.7/series [new file with mode: 0644]

diff --git a/queue-3.7/net-fix-a-race-in-gro_cell_poll.patch b/queue-3.7/net-fix-a-race-in-gro_cell_poll.patch
new file mode 100644 (file)
index 0000000..c365e45
--- /dev/null
@@ -0,0 +1,88 @@
+From 168b60069f773eb662e26ad23e7e8e274ae8cbba Mon Sep 17 00:00:00 2001
+From: Eric Dumazet <edumazet@google.com>
+Date: Mon, 10 Dec 2012 12:32:03 +0000
+Subject: net: fix a race in gro_cell_poll()
+
+
+From: Eric Dumazet <edumazet@google.com>
+
+[ Upstream commit f8e8f97c11d5ff3cc47d85b97c7c35e443dcf490 ]
+
+Dmitry Kravkov reported packet drops for GRE packets since GRO support
+was added.
+
+There is a race in gro_cell_poll() because we call napi_complete()
+without any synchronization with a concurrent gro_cells_receive()
+
+Once bug was triggered, we queued packets but did not schedule NAPI
+poll.
+
+We can fix this issue using the spinlock protected the napi_skbs queue,
+as we have to hold it to perform skb dequeue anyway.
+
+As we open-code skb_dequeue(), we no longer need to mask IRQS, as both
+producer and consumer run under BH context.
+
+Bug added in commit c9e6bc644e (net: add gro_cells infrastructure)
+
+Reported-by: Dmitry Kravkov <dmitry@broadcom.com>
+Signed-off-by: Eric Dumazet <edumazet@google.com>
+Tested-by: Dmitry Kravkov <dmitry@broadcom.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/net/gro_cells.h |   14 +++++++++-----
+ 1 file changed, 9 insertions(+), 5 deletions(-)
+
+--- a/include/net/gro_cells.h
++++ b/include/net/gro_cells.h
+@@ -17,7 +17,6 @@ struct gro_cells {
+ static inline void gro_cells_receive(struct gro_cells *gcells, struct sk_buff *skb)
+ {
+-      unsigned long flags;
+       struct gro_cell *cell = gcells->cells;
+       struct net_device *dev = skb->dev;
+@@ -35,32 +34,37 @@ static inline void gro_cells_receive(str
+               return;
+       }
+-      spin_lock_irqsave(&cell->napi_skbs.lock, flags);
++      /* We run in BH context */
++      spin_lock(&cell->napi_skbs.lock);
+       __skb_queue_tail(&cell->napi_skbs, skb);
+       if (skb_queue_len(&cell->napi_skbs) == 1)
+               napi_schedule(&cell->napi);
+-      spin_unlock_irqrestore(&cell->napi_skbs.lock, flags);
++      spin_unlock(&cell->napi_skbs.lock);
+ }
++/* called unser BH context */
+ static inline int gro_cell_poll(struct napi_struct *napi, int budget)
+ {
+       struct gro_cell *cell = container_of(napi, struct gro_cell, napi);
+       struct sk_buff *skb;
+       int work_done = 0;
++      spin_lock(&cell->napi_skbs.lock);
+       while (work_done < budget) {
+-              skb = skb_dequeue(&cell->napi_skbs);
++              skb = __skb_dequeue(&cell->napi_skbs);
+               if (!skb)
+                       break;
+-
++              spin_unlock(&cell->napi_skbs.lock);
+               napi_gro_receive(napi, skb);
+               work_done++;
++              spin_lock(&cell->napi_skbs.lock);
+       }
+       if (work_done < budget)
+               napi_complete(napi);
++      spin_unlock(&cell->napi_skbs.lock);
+       return work_done;
+ }
diff --git a/queue-3.7/series b/queue-3.7/series
new file mode 100644 (file)
index 0000000..f9f610d
--- /dev/null
@@ -0,0 +1 @@
+net-fix-a-race-in-gro_cell_poll.patch