bonding: register slave pointer for rx_handler
authorJiri Pirko <jpirko@redhat.com>
Sat, 12 Mar 2011 03:14:35 +0000 (03:14 +0000)
committerDavid S. Miller <davem@davemloft.net>
Wed, 16 Mar 2011 19:51:19 +0000 (12:51 -0700)
Register slave pointer as rx_handler data. That would eventually prevent
need to loop over slave devices to find the right slave.

Use synchronize_net to ensure that bond_handle_frame does not get slave
structure freed when working with that.

Signed-off-by: Jiri Pirko <jpirko@redhat.com>
Reviewed-by: Nicolas de Pesloüan <nicolas.2p.debian@free.fr>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/bonding/bond_main.c
drivers/net/bonding/bonding.h

index 66c98e61f0b77389a910f2441519c391b892873b..b047d75c28d43495b82743ba3636e1c6f330f8c7 100644 (file)
@@ -1482,21 +1482,22 @@ static bool bond_should_deliver_exact_match(struct sk_buff *skb,
 
 static struct sk_buff *bond_handle_frame(struct sk_buff *skb)
 {
-       struct net_device *slave_dev;
+       struct slave *slave;
        struct net_device *bond_dev;
 
        skb = skb_share_check(skb, GFP_ATOMIC);
        if (unlikely(!skb))
                return NULL;
-       slave_dev = skb->dev;
-       bond_dev = ACCESS_ONCE(slave_dev->master);
+
+       slave = bond_slave_get_rcu(skb->dev);
+       bond_dev = ACCESS_ONCE(slave->dev->master);
        if (unlikely(!bond_dev))
                return skb;
 
        if (bond_dev->priv_flags & IFF_MASTER_ARPMON)
-               slave_dev->last_rx = jiffies;
+               slave->dev->last_rx = jiffies;
 
-       if (bond_should_deliver_exact_match(skb, slave_dev, bond_dev)) {
+       if (bond_should_deliver_exact_match(skb, slave->dev, bond_dev)) {
                skb->deliver_no_wcard = 1;
                return skb;
        }
@@ -1694,7 +1695,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
                pr_debug("Error %d calling netdev_set_bond_master\n", res);
                goto err_restore_mac;
        }
-       res = netdev_rx_handler_register(slave_dev, bond_handle_frame, NULL);
+       res = netdev_rx_handler_register(slave_dev, bond_handle_frame,
+                                        new_slave);
        if (res) {
                pr_debug("Error %d calling netdev_rx_handler_register\n", res);
                goto err_unset_master;
@@ -1916,6 +1918,7 @@ err_close:
 
 err_unreg_rxhandler:
        netdev_rx_handler_unregister(slave_dev);
+       synchronize_net();
 
 err_unset_master:
        netdev_set_bond_master(slave_dev, NULL);
@@ -2099,6 +2102,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
        }
 
        netdev_rx_handler_unregister(slave_dev);
+       synchronize_net();
        netdev_set_bond_master(slave_dev, NULL);
 
        slave_disable_netpoll(slave);
@@ -2213,6 +2217,7 @@ static int bond_release_all(struct net_device *bond_dev)
                }
 
                netdev_rx_handler_unregister(slave_dev);
+               synchronize_net();
                netdev_set_bond_master(slave_dev, NULL);
 
                slave_disable_netpoll(slave);
index c4e2343bb0b7a24d30ae25d402358d4c3781b594..ff9af31e8c5b4f4fe66cf4d3abd63357f2a5539e 100644 (file)
@@ -266,6 +266,9 @@ struct bonding {
 #endif /* CONFIG_DEBUG_FS */
 };
 
+#define bond_slave_get_rcu(dev) \
+       ((struct slave *) rcu_dereference(dev->rx_handler_data))
+
 /**
  * Returns NULL if the net_device does not belong to any of the bond's slaves
  *