]> err.no Git - linux-2.6/blobdiff - net/core/netpoll.c
netpoll info leak
[linux-2.6] / net / core / netpoll.c
index 6589adb14cbfe5d80401b5384671a599bb05e1f4..c66df2f45d268e3a477cd2d4c0b5450dde92423d 100644 (file)
@@ -36,9 +36,7 @@
 #define MAX_QUEUE_DEPTH (MAX_SKBS / 2)
 #define MAX_RETRIES 20000
 
-static DEFINE_SPINLOCK(skb_list_lock);
-static int nr_skbs;
-static struct sk_buff *skbs;
+static struct sk_buff_head skb_pool;
 
 static DEFINE_SPINLOCK(queue_lock);
 static int queue_depth;
@@ -190,17 +188,15 @@ static void refill_skbs(void)
        struct sk_buff *skb;
        unsigned long flags;
 
-       spin_lock_irqsave(&skb_list_lock, flags);
-       while (nr_skbs < MAX_SKBS) {
+       spin_lock_irqsave(&skb_pool.lock, flags);
+       while (skb_pool.qlen < MAX_SKBS) {
                skb = alloc_skb(MAX_SKB_SIZE, GFP_ATOMIC);
                if (!skb)
                        break;
 
-               skb->next = skbs;
-               skbs = skb;
-               nr_skbs++;
+               __skb_queue_tail(&skb_pool, skb);
        }
-       spin_unlock_irqrestore(&skb_list_lock, flags);
+       spin_unlock_irqrestore(&skb_pool.lock, flags);
 }
 
 static void zap_completion_queue(void)
@@ -229,38 +225,25 @@ static void zap_completion_queue(void)
        put_cpu_var(softnet_data);
 }
 
-static struct sk_buff * find_skb(struct netpoll *np, int len, int reserve)
+static struct sk_buff *find_skb(struct netpoll *np, int len, int reserve)
 {
-       int once = 1, count = 0;
-       unsigned long flags;
-       struct sk_buff *skb = NULL;
+       int count = 0;
+       struct sk_buff *skb;
 
        zap_completion_queue();
+       refill_skbs();
 repeat:
-       if (nr_skbs < MAX_SKBS)
-               refill_skbs();
 
        skb = alloc_skb(len, GFP_ATOMIC);
-
-       if (!skb) {
-               spin_lock_irqsave(&skb_list_lock, flags);
-               skb = skbs;
-               if (skb) {
-                       skbs = skb->next;
-                       skb->next = NULL;
-                       nr_skbs--;
-               }
-               spin_unlock_irqrestore(&skb_list_lock, flags);
-       }
+       if (!skb)
+               skb = skb_dequeue(&skb_pool);
 
        if(!skb) {
-               count++;
-               if (once && (count == 1000000)) {
-                       printk("out of netpoll skbs!\n");
-                       once = 0;
+               if (++count < 10) {
+                       netpoll_poll(np);
+                       goto repeat;
                }
-               netpoll_poll(np);
-               goto repeat;
+               return NULL;
        }
 
        atomic_set(&skb->users, 1);
@@ -675,8 +658,11 @@ int netpoll_setup(struct netpoll *np)
                npinfo->tries = MAX_RETRIES;
                spin_lock_init(&npinfo->rx_lock);
                skb_queue_head_init(&npinfo->arp_tx);
-       } else
+               atomic_set(&npinfo->refcnt, 1);
+       } else {
                npinfo = ndev->npinfo;
+               atomic_inc(&npinfo->refcnt);
+       }
 
        if (!ndev->poll_controller) {
                printk(KERN_ERR "%s: %s doesn't support polling, aborting.\n",
@@ -770,6 +756,12 @@ int netpoll_setup(struct netpoll *np)
        return -1;
 }
 
+static int __init netpoll_init(void) {
+       skb_queue_head_init(&skb_pool);
+       return 0;
+}
+core_initcall(netpoll_init);
+
 void netpoll_cleanup(struct netpoll *np)
 {
        struct netpoll_info *npinfo;
@@ -777,12 +769,22 @@ void netpoll_cleanup(struct netpoll *np)
 
        if (np->dev) {
                npinfo = np->dev->npinfo;
-               if (npinfo && npinfo->rx_np == np) {
-                       spin_lock_irqsave(&npinfo->rx_lock, flags);
-                       npinfo->rx_np = NULL;
-                       npinfo->rx_flags &= ~NETPOLL_RX_ENABLED;
-                       spin_unlock_irqrestore(&npinfo->rx_lock, flags);
+               if (npinfo) {
+                       if (npinfo->rx_np == np) {
+                               spin_lock_irqsave(&npinfo->rx_lock, flags);
+                               npinfo->rx_np = NULL;
+                               npinfo->rx_flags &= ~NETPOLL_RX_ENABLED;
+                               spin_unlock_irqrestore(&npinfo->rx_lock, flags);
+                       }
+
+                       np->dev->npinfo = NULL;
+                       if (atomic_dec_and_test(&npinfo->refcnt)) {
+                               skb_queue_purge(&npinfo->arp_tx);
+
+                               kfree(npinfo);
+                       }
                }
+
                dev_put(np->dev);
        }