]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
[NET]: Fix races in net_rx_action vs netpoll.
authorOlaf Kirch <olaf.kirch@oracle.com>
Thu, 12 Jul 2007 02:32:02 +0000 (19:32 -0700)
committerDavid S. Miller <davem@davemloft.net>
Thu, 12 Jul 2007 02:32:02 +0000 (19:32 -0700)
Keep netpoll/poll_napi from messing with the poll_list.
Only net_rx_action is allowed to manipulate the list.

Signed-off-by: Olaf Kirch <olaf.kirch@oracle.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/netdevice.h
net/core/netpoll.c

index 8590d685d9351089df84ce6e1304369ce1ab154d..79cc3dab4be7e8e743dbc3f87f821407effebc99 100644 (file)
@@ -261,6 +261,8 @@ enum netdev_state_t
        __LINK_STATE_LINKWATCH_PENDING,
        __LINK_STATE_DORMANT,
        __LINK_STATE_QDISC_RUNNING,
+       /* Set by the netpoll NAPI code */
+       __LINK_STATE_POLL_LIST_FROZEN,
 };
 
 
@@ -1014,6 +1016,14 @@ static inline void netif_rx_complete(struct net_device *dev)
 {
        unsigned long flags;
 
+#ifdef CONFIG_NETPOLL
+       /* Prevent race with netpoll - yes, this is a kludge.
+        * But at least it doesn't penalize the non-netpoll
+        * code path. */
+       if (test_bit(__LINK_STATE_POLL_LIST_FROZEN, &dev->state))
+               return;
+#endif
+
        local_irq_save(flags);
        __netif_rx_complete(dev);
        local_irq_restore(flags);
index de1b26aa5720f011616413d87d852f94d46f9c52..d1264e9a50a8afe71abd41dc7805770df2e2ff2c 100644 (file)
@@ -124,6 +124,13 @@ static void poll_napi(struct netpoll *np)
        if (test_bit(__LINK_STATE_RX_SCHED, &np->dev->state) &&
            npinfo->poll_owner != smp_processor_id() &&
            spin_trylock(&npinfo->poll_lock)) {
+               /* When calling dev->poll from poll_napi, we may end up in
+                * netif_rx_complete. However, only the CPU to which the
+                * device was queued is allowed to remove it from poll_list.
+                * Setting POLL_LIST_FROZEN tells netif_rx_complete
+                * to leave the NAPI state alone.
+                */
+               set_bit(__LINK_STATE_POLL_LIST_FROZEN, &np->dev->state);
                npinfo->rx_flags |= NETPOLL_RX_DROP;
                atomic_inc(&trapped);
 
@@ -131,6 +138,7 @@ static void poll_napi(struct netpoll *np)
 
                atomic_dec(&trapped);
                npinfo->rx_flags &= ~NETPOLL_RX_DROP;
+               clear_bit(__LINK_STATE_POLL_LIST_FROZEN, &np->dev->state);
                spin_unlock(&npinfo->poll_lock);
        }
 }