summaryrefslogtreecommitdiff
path: root/include/net/gro_cells.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/net/gro_cells.h')
-rw-r--r--include/net/gro_cells.h23
1 files changed, 19 insertions, 4 deletions
diff --git a/include/net/gro_cells.h b/include/net/gro_cells.h
index 2a1abbf8da74..6db0e8534127 100644
--- a/include/net/gro_cells.h
+++ b/include/net/gro_cells.h
@@ -18,22 +18,36 @@ static inline int gro_cells_receive(struct gro_cells *gcells, struct sk_buff *sk
{
struct gro_cell *cell;
struct net_device *dev = skb->dev;
+ int res;
- if (!gcells->cells || skb_cloned(skb) || !(dev->features & NETIF_F_GRO))
- return netif_rx(skb);
+ rcu_read_lock();
+ if (unlikely(!(dev->flags & IFF_UP)))
+ goto drop;
+
+ if (!gcells->cells || skb_cloned(skb) || !(dev->features & NETIF_F_GRO)) {
+ res = netif_rx(skb);
+ goto unlock;
+ }
cell = this_cpu_ptr(gcells->cells);
if (skb_queue_len(&cell->napi_skbs) > netdev_max_backlog) {
+drop:
atomic_long_inc(&dev->rx_dropped);
kfree_skb(skb);
- return NET_RX_DROP;
+ res = NET_RX_DROP;
+ goto unlock;
}
__skb_queue_tail(&cell->napi_skbs, skb);
if (skb_queue_len(&cell->napi_skbs) == 1)
napi_schedule(&cell->napi);
- return NET_RX_SUCCESS;
+
+ res = NET_RX_SUCCESS;
+
+unlock:
+ rcu_read_unlock();
+ return res;
}
/* called under BH context */
@@ -86,6 +100,7 @@ static inline void gro_cells_destroy(struct gro_cells *gcells)
for_each_possible_cpu(i) {
struct gro_cell *cell = per_cpu_ptr(gcells->cells, i);
+ napi_disable(&cell->napi);
netif_napi_del(&cell->napi);
__skb_queue_purge(&cell->napi_skbs);
}