net: consolidate and fix ethtool_ops->get_settings calling
authorJiri Pirko <jpirko@redhat.com>
Sat, 3 Sep 2011 03:34:30 +0000 (03:34 +0000)
committerDavid S. Miller <davem@davemloft.net>
Thu, 15 Sep 2011 21:32:26 +0000 (17:32 -0400)
This patch does several things:
- introduces __ethtool_get_settings which is called from ethtool code and
  from drivers as well. Put ASSERT_RTNL there.
- dev_ethtool_get_settings() is replaced by __ethtool_get_settings()
- changes calling in drivers so rtnl locking is respected. In
  iboe_get_rate was previously ->get_settings() called unlocked. This
  fixes it. Also prb_calc_retire_blk_tmo() in af_packet.c had the same
  problem. Also fixed by calling __dev_get_by_index() instead of
  dev_get_by_index() and holding rtnl_lock for both calls.
- introduces rtnl_lock in bnx2fc_vport_create() and fcoe_vport_create()
  so bnx2fc_if_create() and fcoe_if_create() are called locked as they
  are from other places.
- use __ethtool_get_settings() in bonding code

Signed-off-by: Jiri Pirko <jpirko@redhat.com>
v2->v3:
-removed dev_ethtool_get_settings()
-added ASSERT_RTNL into __ethtool_get_settings()
-prb_calc_retire_blk_tmo - use __dev_get_by_index() and lock
 around it and __ethtool_get_settings() call
v1->v2:
        add missing export_symbol
Reviewed-by: Ben Hutchings <bhutchings@solarflare.com> [except FCoE bits]
Acked-by: Ralf Baechle <ralf@linux-mips.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
14 files changed:
arch/mips/txx9/generic/setup_tx4939.c
drivers/net/bonding/bond_main.c
drivers/net/macvlan.c
drivers/scsi/bnx2fc/bnx2fc_fcoe.c
drivers/scsi/fcoe/fcoe.c
include/linux/ethtool.h
include/linux/netdevice.h
include/rdma/ib_addr.h
net/8021q/vlan_dev.c
net/bridge/br_if.c
net/core/dev.c
net/core/ethtool.c
net/core/net-sysfs.c
net/packet/af_packet.c

index e9f95dc..ba3cec3 100644 (file)
@@ -321,7 +321,7 @@ void __init tx4939_sio_init(unsigned int sclk, unsigned int cts_mask)
 static u32 tx4939_get_eth_speed(struct net_device *dev)
 {
        struct ethtool_cmd cmd;
-       if (dev_ethtool_get_settings(dev, &cmd))
+       if (__ethtool_get_settings(dev, &cmd))
                return 100;     /* default 100Mbps */
 
        return ethtool_cmd_speed(&cmd);
index 8cb75a6..1dcb07c 100644 (file)
@@ -557,7 +557,7 @@ down:
 static int bond_update_speed_duplex(struct slave *slave)
 {
        struct net_device *slave_dev = slave->dev;
-       struct ethtool_cmd etool = { .cmd = ETHTOOL_GSET };
+       struct ethtool_cmd ecmd;
        u32 slave_speed;
        int res;
 
@@ -565,18 +565,15 @@ static int bond_update_speed_duplex(struct slave *slave)
        slave->speed = SPEED_100;
        slave->duplex = DUPLEX_FULL;
 
-       if (!slave_dev->ethtool_ops || !slave_dev->ethtool_ops->get_settings)
-               return -1;
-
-       res = slave_dev->ethtool_ops->get_settings(slave_dev, &etool);
+       res = __ethtool_get_settings(slave_dev, &ecmd);
        if (res < 0)
                return -1;
 
-       slave_speed = ethtool_cmd_speed(&etool);
+       slave_speed = ethtool_cmd_speed(&ecmd);
        if (slave_speed == 0 || slave_speed == ((__u32) -1))
                return -1;
 
-       switch (etool.duplex) {
+       switch (ecmd.duplex) {
        case DUPLEX_FULL:
        case DUPLEX_HALF:
                break;
@@ -585,7 +582,7 @@ static int bond_update_speed_duplex(struct slave *slave)
        }
 
        slave->speed = slave_speed;
-       slave->duplex = etool.duplex;
+       slave->duplex = ecmd.duplex;
 
        return 0;
 }
index 836e13f..b100c90 100644 (file)
@@ -543,7 +543,8 @@ static int macvlan_ethtool_get_settings(struct net_device *dev,
                                        struct ethtool_cmd *cmd)
 {
        const struct macvlan_dev *vlan = netdev_priv(dev);
-       return dev_ethtool_get_settings(vlan->lowerdev, cmd);
+
+       return __ethtool_get_settings(vlan->lowerdev, cmd);
 }
 
 static const struct ethtool_ops macvlan_ethtool_ops = {
index 2c780a7..820a184 100644 (file)
@@ -673,7 +673,7 @@ static void bnx2fc_link_speed_update(struct fc_lport *lport)
        struct net_device *netdev = interface->netdev;
        struct ethtool_cmd ecmd;
 
-       if (!dev_ethtool_get_settings(netdev, &ecmd)) {
+       if (!__ethtool_get_settings(netdev, &ecmd)) {
                lport->link_supported_speeds &=
                        ~(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT);
                if (ecmd.supported & (SUPPORTED_1000baseT_Half |
@@ -1001,9 +1001,11 @@ static int bnx2fc_vport_create(struct fc_vport *vport, bool disabled)
                        "this interface\n");
                return -EIO;
        }
+       rtnl_lock();
        mutex_lock(&bnx2fc_dev_lock);
        vn_port = bnx2fc_if_create(interface, &vport->dev, 1);
        mutex_unlock(&bnx2fc_dev_lock);
+       rtnl_unlock();
 
        if (IS_ERR(vn_port)) {
                printk(KERN_ERR PFX "bnx2fc_vport_create (%s) failed\n",
index 3416ab6..83aa3ac 100644 (file)
@@ -2043,7 +2043,7 @@ int fcoe_link_speed_update(struct fc_lport *lport)
        struct net_device *netdev = fcoe_netdev(lport);
        struct ethtool_cmd ecmd;
 
-       if (!dev_ethtool_get_settings(netdev, &ecmd)) {
+       if (!__ethtool_get_settings(netdev, &ecmd)) {
                lport->link_supported_speeds &=
                        ~(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT);
                if (ecmd.supported & (SUPPORTED_1000baseT_Half |
@@ -2452,7 +2452,9 @@ static int fcoe_vport_create(struct fc_vport *vport, bool disabled)
        }
 
        mutex_lock(&fcoe_config_mutex);
+       rtnl_lock();
        vn_port = fcoe_if_create(fcoe, &vport->dev, 1);
+       rtnl_unlock();
        mutex_unlock(&fcoe_config_mutex);
 
        if (IS_ERR(vn_port)) {
index 3829712..8571f18 100644 (file)
@@ -728,6 +728,9 @@ enum ethtool_sfeatures_retval_bits {
 /* needed by dev_disable_lro() */
 extern int __ethtool_set_flags(struct net_device *dev, u32 flags);
 
+extern int __ethtool_get_settings(struct net_device *dev,
+                                 struct ethtool_cmd *cmd);
+
 /**
  * enum ethtool_phys_id_state - indicator state for physical identification
  * @ETHTOOL_ID_INACTIVE: Physical ID indicator should be deactivated
index 0a7f619..43b3298 100644 (file)
@@ -2589,9 +2589,6 @@ static inline int netif_is_bond_slave(struct net_device *dev)
 
 extern struct pernet_operations __net_initdata loopback_net_ops;
 
-int dev_ethtool_get_settings(struct net_device *dev,
-                            struct ethtool_cmd *cmd);
-
 static inline u32 dev_ethtool_get_rx_csum(struct net_device *dev)
 {
        if (dev->features & NETIF_F_RXCSUM)
index ae8c68f..639a449 100644 (file)
@@ -218,8 +218,12 @@ static inline int iboe_get_rate(struct net_device *dev)
 {
        struct ethtool_cmd cmd;
        u32 speed;
+       int err;
 
-       if (dev_ethtool_get_settings(dev, &cmd))
+       rtnl_lock();
+       err = __ethtool_get_settings(dev, &cmd);
+       rtnl_unlock();
+       if (err)
                return IB_RATE_PORT_CURRENT;
 
        speed = ethtool_cmd_speed(&cmd);
index eba705b..c8cf939 100644 (file)
@@ -610,7 +610,8 @@ static int vlan_ethtool_get_settings(struct net_device *dev,
                                     struct ethtool_cmd *cmd)
 {
        const struct vlan_dev_info *vlan = vlan_dev_info(dev);
-       return dev_ethtool_get_settings(vlan->real_dev, cmd);
+
+       return __ethtool_get_settings(vlan->real_dev, cmd);
 }
 
 static void vlan_ethtool_get_drvinfo(struct net_device *dev,
index b365bba..043a5eb 100644 (file)
@@ -35,7 +35,7 @@ static int port_cost(struct net_device *dev)
 {
        struct ethtool_cmd ecmd;
 
-       if (!dev_ethtool_get_settings(dev, &ecmd)) {
+       if (!__ethtool_get_settings(dev, &ecmd)) {
                switch (ethtool_cmd_speed(&ecmd)) {
                case SPEED_10000:
                        return 2;
index b2e262e..4b9981c 100644 (file)
@@ -4565,30 +4565,6 @@ void dev_set_rx_mode(struct net_device *dev)
        netif_addr_unlock_bh(dev);
 }
 
-/**
- *     dev_ethtool_get_settings - call device's ethtool_ops::get_settings()
- *     @dev: device
- *     @cmd: memory area for ethtool_ops::get_settings() result
- *
- *      The cmd arg is initialized properly (cleared and
- *      ethtool_cmd::cmd field set to ETHTOOL_GSET).
- *
- *     Return device's ethtool_ops::get_settings() result value or
- *     -EOPNOTSUPP when device doesn't expose
- *     ethtool_ops::get_settings() operation.
- */
-int dev_ethtool_get_settings(struct net_device *dev,
-                            struct ethtool_cmd *cmd)
-{
-       if (!dev->ethtool_ops || !dev->ethtool_ops->get_settings)
-               return -EOPNOTSUPP;
-
-       memset(cmd, 0, sizeof(struct ethtool_cmd));
-       cmd->cmd = ETHTOOL_GSET;
-       return dev->ethtool_ops->get_settings(dev, cmd);
-}
-EXPORT_SYMBOL(dev_ethtool_get_settings);
-
 /**
  *     dev_get_flags - get flags reported to userspace
  *     @dev: device
index 6cdba5f..f444817 100644 (file)
@@ -569,15 +569,25 @@ int __ethtool_set_flags(struct net_device *dev, u32 data)
        return 0;
 }
 
-static int ethtool_get_settings(struct net_device *dev, void __user *useraddr)
+int __ethtool_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-       struct ethtool_cmd cmd = { .cmd = ETHTOOL_GSET };
-       int err;
+       ASSERT_RTNL();
 
-       if (!dev->ethtool_ops->get_settings)
+       if (!dev->ethtool_ops || !dev->ethtool_ops->get_settings)
                return -EOPNOTSUPP;
 
-       err = dev->ethtool_ops->get_settings(dev, &cmd);
+       memset(cmd, 0, sizeof(struct ethtool_cmd));
+       cmd->cmd = ETHTOOL_GSET;
+       return dev->ethtool_ops->get_settings(dev, cmd);
+}
+EXPORT_SYMBOL(__ethtool_get_settings);
+
+static int ethtool_get_settings(struct net_device *dev, void __user *useraddr)
+{
+       int err;
+       struct ethtool_cmd cmd;
+
+       err = __ethtool_get_settings(dev, &cmd);
        if (err < 0)
                return err;
 
index 56e42ab..7604a63 100644 (file)
@@ -147,7 +147,7 @@ static ssize_t show_speed(struct device *dev,
 
        if (netif_running(netdev)) {
                struct ethtool_cmd cmd;
-               if (!dev_ethtool_get_settings(netdev, &cmd))
+               if (!__ethtool_get_settings(netdev, &cmd))
                        ret = sprintf(buf, fmt_udec, ethtool_cmd_speed(&cmd));
        }
        rtnl_unlock();
@@ -165,7 +165,7 @@ static ssize_t show_duplex(struct device *dev,
 
        if (netif_running(netdev)) {
                struct ethtool_cmd cmd;
-               if (!dev_ethtool_get_settings(netdev, &cmd))
+               if (!__ethtool_get_settings(netdev, &cmd))
                        ret = sprintf(buf, "%s\n",
                                      cmd.duplex ? "full" : "half");
        }
index 2ea3d63..25e68f5 100644 (file)
@@ -530,33 +530,35 @@ static int prb_calc_retire_blk_tmo(struct packet_sock *po,
 {
        struct net_device *dev;
        unsigned int mbits = 0, msec = 0, div = 0, tmo = 0;
+       struct ethtool_cmd ecmd;
+       int err;
 
-       dev = dev_get_by_index(sock_net(&po->sk), po->ifindex);
-       if (unlikely(dev == NULL))
+       rtnl_lock();
+       dev = __dev_get_by_index(sock_net(&po->sk), po->ifindex);
+       if (unlikely(!dev)) {
+               rtnl_unlock();
                return DEFAULT_PRB_RETIRE_TOV;
-
-       if (dev->ethtool_ops && dev->ethtool_ops->get_settings) {
-               struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET, };
-
-               if (!dev->ethtool_ops->get_settings(dev, &ecmd)) {
-                       switch (ecmd.speed) {
-                       case SPEED_10000:
-                               msec = 1;
-                               div = 10000/1000;
-                               break;
-                       case SPEED_1000:
-                               msec = 1;
-                               div = 1000/1000;
-                               break;
-                       /*
-                        * If the link speed is so slow you don't really
-                        * need to worry about perf anyways
-                        */
-                       case SPEED_100:
-                       case SPEED_10:
-                       default:
-                               return DEFAULT_PRB_RETIRE_TOV;
-                       }
+       }
+       err = __ethtool_get_settings(dev, &ecmd);
+       rtnl_unlock();
+       if (!err) {
+               switch (ecmd.speed) {
+               case SPEED_10000:
+                       msec = 1;
+                       div = 10000/1000;
+                       break;
+               case SPEED_1000:
+                       msec = 1;
+                       div = 1000/1000;
+                       break;
+               /*
+                * If the link speed is so slow you don't really
+                * need to worry about perf anyways
+                */
+               case SPEED_100:
+               case SPEED_10:
+               default:
+                       return DEFAULT_PRB_RETIRE_TOV;
                }
        }