Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=c15853f2c1c9baaa27bbc494cd183be96f6d9bb9
Commit:     c15853f2c1c9baaa27bbc494cd183be96f6d9bb9
Parent:     fa907895b7b776208a1406efe5ba7ffe0f49f507
Author:     Daniel Lezcano <[EMAIL PROTECTED]>
AuthorDate: Wed Feb 20 00:21:47 2008 -0800
Committer:  David S. Miller <[EMAIL PROTECTED]>
CommitDate: Wed Feb 20 00:21:47 2008 -0800

    veth: fix dev refcount race
    
    When deleting the veth driver, veth_close calls netif_carrier_off
    for the two extremities of the network device. netif_carrier_off on
    the peer device will fire an event and hold a reference on the peer
    device. Just after, the peer is unregistered taking the rtnl_lock while
    the linkwatch_event is scheduled. If __linkwatch_run_queue does not
    occurs before the unregistering, unregister_netdevice will wait for
    the dev refcount to reach zero holding the rtnl_lock and linkwatch_event
    will wait for the rtnl_lock and hold the dev refcount.
    
    Signed-off-by: Daniel Lezcano <[EMAIL PROTECTED]>
    Signed-off-by: David S. Miller <[EMAIL PROTECTED]>
---
 drivers/net/veth.c |   53 +++++++++++++++++++++++++++++++++++++++------------
 1 files changed, 40 insertions(+), 13 deletions(-)

diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 3f67a29..e2ad98b 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -244,18 +244,6 @@ static int veth_open(struct net_device *dev)
        return 0;
 }
 
-static int veth_close(struct net_device *dev)
-{
-       struct veth_priv *priv;
-
-       if (netif_carrier_ok(dev)) {
-               priv = netdev_priv(dev);
-               netif_carrier_off(dev);
-               netif_carrier_off(priv->peer);
-       }
-       return 0;
-}
-
 static int veth_dev_init(struct net_device *dev)
 {
        struct veth_net_stats *stats;
@@ -286,13 +274,50 @@ static void veth_setup(struct net_device *dev)
        dev->hard_start_xmit = veth_xmit;
        dev->get_stats = veth_get_stats;
        dev->open = veth_open;
-       dev->stop = veth_close;
        dev->ethtool_ops = &veth_ethtool_ops;
        dev->features |= NETIF_F_LLTX;
        dev->init = veth_dev_init;
        dev->destructor = veth_dev_free;
 }
 
+static void veth_change_state(struct net_device *dev)
+{
+       struct net_device *peer;
+       struct veth_priv *priv;
+
+       priv = netdev_priv(dev);
+       peer = priv->peer;
+
+       if (netif_carrier_ok(peer)) {
+               if (!netif_carrier_ok(dev))
+                       netif_carrier_on(dev);
+       } else {
+               if (netif_carrier_ok(dev))
+                       netif_carrier_off(dev);
+       }
+}
+
+static int veth_device_event(struct notifier_block *unused,
+                            unsigned long event, void *ptr)
+{
+       struct net_device *dev = ptr;
+
+       if (dev->open != veth_open)
+               goto out;
+
+       switch (event) {
+       case NETDEV_CHANGE:
+               veth_change_state(dev);
+               break;
+       }
+out:
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block veth_notifier_block __read_mostly = {
+       .notifier_call  = veth_device_event,
+};
+
 /*
  * netlink interface
  */
@@ -454,12 +479,14 @@ static struct rtnl_link_ops veth_link_ops = {
 
 static __init int veth_init(void)
 {
+       register_netdevice_notifier(&veth_notifier_block);
        return rtnl_link_register(&veth_link_ops);
 }
 
 static __exit void veth_exit(void)
 {
        rtnl_link_unregister(&veth_link_ops);
+       unregister_netdevice_notifier(&veth_notifier_block);
 }
 
 module_init(veth_init);
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to