skbufhead-raw-lock.patch
authorThomas Gleixner <tglx@linutronix.de>
Tue, 12 Jul 2011 13:38:34 +0000 (15:38 +0200)
committerClark Williams <williams@redhat.com>
Wed, 15 Feb 2012 16:33:00 +0000 (10:33 -0600)
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
include/linux/netdevice.h
include/linux/skbuff.h
net/core/dev.c

index a82ad4dd306a657565f5c9987f4b888468325ba2..a5bde7715be0ec484e70f71f2d4c6bee12f58d89 100644 (file)
@@ -1760,6 +1760,7 @@ struct softnet_data {
        unsigned                dropped;
        struct sk_buff_head     input_pkt_queue;
        struct napi_struct      backlog;
+       struct sk_buff_head     tofree_queue;
 };
 
 static inline void input_queue_head_incr(struct softnet_data *sd)
index fe864885c1edd5edbebc0504544e4950ebf2962f..cc32cceb612aa37a7b6937eeac9bda3544a75214 100644 (file)
@@ -124,6 +124,7 @@ struct sk_buff_head {
 
        __u32           qlen;
        spinlock_t      lock;
+       raw_spinlock_t  raw_lock;
 };
 
 struct sk_buff;
@@ -925,6 +926,12 @@ static inline void skb_queue_head_init(struct sk_buff_head *list)
        __skb_queue_head_init(list);
 }
 
+static inline void skb_queue_head_init_raw(struct sk_buff_head *list)
+{
+       raw_spin_lock_init(&list->raw_lock);
+       __skb_queue_head_init(list);
+}
+
 static inline void skb_queue_head_init_class(struct sk_buff_head *list,
                struct lock_class_key *class)
 {
index 1ecffbbc4137a01e2e0ec3a62134f1fcf6ac2c0f..3fde75bd0d81d9fe6c3f9bc30954354619b6798d 100644 (file)
@@ -222,14 +222,14 @@ static inline struct hlist_head *dev_index_hash(struct net *net, int ifindex)
 static inline void rps_lock(struct softnet_data *sd)
 {
 #ifdef CONFIG_RPS
-       spin_lock(&sd->input_pkt_queue.lock);
+       raw_spin_lock(&sd->input_pkt_queue.raw_lock);
 #endif
 }
 
 static inline void rps_unlock(struct softnet_data *sd)
 {
 #ifdef CONFIG_RPS
-       spin_unlock(&sd->input_pkt_queue.lock);
+       raw_spin_unlock(&sd->input_pkt_queue.raw_lock);
 #endif
 }
 
@@ -3407,7 +3407,7 @@ static void flush_backlog(void *arg)
        skb_queue_walk_safe(&sd->input_pkt_queue, skb, tmp) {
                if (skb->dev == dev) {
                        __skb_unlink(skb, &sd->input_pkt_queue);
-                       kfree_skb(skb);
+                       __skb_queue_tail(&sd->tofree_queue, skb);
                        input_queue_head_incr(sd);
                }
        }
@@ -3416,10 +3416,13 @@ static void flush_backlog(void *arg)
        skb_queue_walk_safe(&sd->process_queue, skb, tmp) {
                if (skb->dev == dev) {
                        __skb_unlink(skb, &sd->process_queue);
-                       kfree_skb(skb);
+                       __skb_queue_tail(&sd->tofree_queue, skb);
                        input_queue_head_incr(sd);
                }
        }
+
+       if (!skb_queue_empty(&sd->tofree_queue))
+               raise_softirq_irqoff(NET_RX_SOFTIRQ);
 }
 
 static int napi_gro_complete(struct sk_buff *skb)
@@ -3896,10 +3899,17 @@ static void net_rx_action(struct softirq_action *h)
        struct softnet_data *sd = &__get_cpu_var(softnet_data);
        unsigned long time_limit = jiffies + 2;
        int budget = netdev_budget;
+       struct sk_buff *skb;
        void *have;
 
        local_irq_disable();
 
+       while ((skb = __skb_dequeue(&sd->tofree_queue))) {
+               local_irq_enable();
+               kfree_skb(skb);
+               local_irq_disable();
+       }
+
        while (!list_empty(&sd->poll_list)) {
                struct napi_struct *n;
                int work, weight;
@@ -6365,6 +6375,9 @@ static int dev_cpu_callback(struct notifier_block *nfb,
                netif_rx(skb);
                input_queue_head_incr(oldsd);
        }
+       while ((skb = __skb_dequeue(&oldsd->tofree_queue))) {
+               kfree_skb(skb);
+       }
 
        return NOTIFY_OK;
 }
@@ -6631,8 +6644,9 @@ static int __init net_dev_init(void)
                struct softnet_data *sd = &per_cpu(softnet_data, i);
 
                memset(sd, 0, sizeof(*sd));
-               skb_queue_head_init(&sd->input_pkt_queue);
-               skb_queue_head_init(&sd->process_queue);
+               skb_queue_head_init_raw(&sd->input_pkt_queue);
+               skb_queue_head_init_raw(&sd->process_queue);
+               skb_queue_head_init_raw(&sd->tofree_queue);
                sd->completion_queue = NULL;
                INIT_LIST_HEAD(&sd->poll_list);
                sd->output_queue = NULL;