Hi, Here is my proposal of a solution based on dev->state flag, but intended mainly to prevent poll_napi from disturbing while net_rx_action is running and polling the device.
It doesn't look very nice or clean but I hope it could guard net_rx_action enough with some room for netpoll too. I'd be very glad if it could be verified and/or tested. Regards, Jarek P. PS: not tested! --- diff -Nurp 2.6.22-git9-/include/linux/netdevice.h 2.6.22-git9/include/linux/netdevice.h --- 2.6.22-git9-/include/linux/netdevice.h 2007-07-18 07:50:56.000000000 +0200 +++ 2.6.22-git9/include/linux/netdevice.h 2007-07-18 13:21:12.000000000 +0200 @@ -262,6 +262,8 @@ enum netdev_state_t __LINK_STATE_LINKWATCH_PENDING, __LINK_STATE_DORMANT, __LINK_STATE_QDISC_RUNNING, + /* Set by net_rx_action vs poll_napi */ + __LINK_STATE_POLL_LIST_FROZEN, }; diff -Nurp 2.6.22-git9-/net/core/dev.c 2.6.22-git9/net/core/dev.c --- 2.6.22-git9-/net/core/dev.c 2007-07-18 07:50:58.000000000 +0200 +++ 2.6.22-git9/net/core/dev.c 2007-07-18 13:18:23.000000000 +0200 @@ -2025,6 +2025,7 @@ static void net_rx_action(struct softirq unsigned long start_time = jiffies; int budget = netdev_budget; void *have; + struct net_device *dev_frozen = NULL; local_irq_disable(); @@ -2040,15 +2041,35 @@ static void net_rx_action(struct softirq struct net_device, poll_list); have = netpoll_poll_lock(dev); +#ifdef CONFIG_NETPOLL + /* prevent a race with poll_napi() */ + if (dev_frozen && dev_frozen != dev) { + clear_bit(__LINK_STATE_POLL_LIST_FROZEN, + &dev_frozen->state); + set_bit(__LINK_STATE_POLL_LIST_FROZEN, + &dev->state); + dev_frozen = dev; + } else if (!dev_frozen) { + set_bit(__LINK_STATE_POLL_LIST_FROZEN, + &dev->state); + dev_frozen = dev; + } +#endif if (dev->quota <= 0 || dev->poll(dev, &budget)) { netpoll_poll_unlock(have); local_irq_disable(); - list_move_tail(&dev->poll_list, &queue->poll_list); + list_move_tail(&dev->poll_list, + &queue->poll_list); if (dev->quota < 0) dev->quota += dev->weight; else dev->quota = dev->weight; } else { +#ifdef CONFIG_NETPOLL + clear_bit(__LINK_STATE_POLL_LIST_FROZEN, + &dev->state); + dev_frozen = NULL; +#endif netpoll_poll_unlock(have); dev_put(dev); local_irq_disable(); @@ -2056,6 +2077,14 @@ static void net_rx_action(struct softirq } out: local_irq_enable(); +#ifdef CONFIG_NETPOLL + if (dev_frozen) { + have = netpoll_poll_lock(dev_frozen); + clear_bit(__LINK_STATE_POLL_LIST_FROZEN, + &dev_frozen->state); + netpoll_poll_unlock(have); + } +#endif #ifdef CONFIG_NET_DMA /* * There may not be any more sk_buffs coming right now, so push diff -Nurp 2.6.22-git9-/net/core/netpoll.c 2.6.22-git9/net/core/netpoll.c --- 2.6.22-git9-/net/core/netpoll.c 2007-07-18 07:50:58.000000000 +0200 +++ 2.6.22-git9/net/core/netpoll.c 2007-07-18 12:09:43.000000000 +0200 @@ -124,13 +124,20 @@ 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)) { - npinfo->rx_flags |= NETPOLL_RX_DROP; - atomic_inc(&trapped); + /* + * If POLL_LIST_FROZEN is set net_rx_action + * is working with this device. + */ + if (!test_bit(__LINK_STATE_POLL_LIST_FROZEN, + &np->dev->state)) { + npinfo->rx_flags |= NETPOLL_RX_DROP; + atomic_inc(&trapped); - np->dev->poll(np->dev, &budget); + np->dev->poll(np->dev, &budget); - atomic_dec(&trapped); - npinfo->rx_flags &= ~NETPOLL_RX_DROP; + atomic_dec(&trapped); + npinfo->rx_flags &= ~NETPOLL_RX_DROP; + } spin_unlock(&npinfo->poll_lock); } } - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/