]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/net/bonding/bond_sysfs.c
Merge remote-tracking branch 'driver-core/driver-core-next'
[karo-tx-linux.git] / drivers / net / bonding / bond_sysfs.c
index ec9b6460a38dd0549b5b69f281b36f6cce0a3e7d..b9d8f1175ff500bd5cc290e676c5f1322fd7c72b 100644 (file)
@@ -159,41 +159,6 @@ static const struct class_attribute class_attr_bonding_masters = {
        .store = bonding_store_bonds,
 };
 
-int bond_create_slave_symlinks(struct net_device *master,
-                              struct net_device *slave)
-{
-       char linkname[IFNAMSIZ+7];
-       int ret = 0;
-
-       /* first, create a link from the slave back to the master */
-       ret = sysfs_create_link(&(slave->dev.kobj), &(master->dev.kobj),
-                               "master");
-       if (ret)
-               return ret;
-       /* next, create a link from the master to the slave */
-       sprintf(linkname, "slave_%s", slave->name);
-       ret = sysfs_create_link(&(master->dev.kobj), &(slave->dev.kobj),
-                               linkname);
-
-       /* free the master link created earlier in case of error */
-       if (ret)
-               sysfs_remove_link(&(slave->dev.kobj), "master");
-
-       return ret;
-
-}
-
-void bond_destroy_slave_symlinks(struct net_device *master,
-                                struct net_device *slave)
-{
-       char linkname[IFNAMSIZ+7];
-
-       sysfs_remove_link(&(slave->dev.kobj), "master");
-       sprintf(linkname, "slave_%s", slave->name);
-       sysfs_remove_link(&(master->dev.kobj), linkname);
-}
-
-
 /*
  * Show the slaves in the current bond.
  */
@@ -201,11 +166,14 @@ static ssize_t bonding_show_slaves(struct device *d,
                                   struct device_attribute *attr, char *buf)
 {
        struct bonding *bond = to_bond(d);
+       struct list_head *iter;
        struct slave *slave;
        int res = 0;
 
-       read_lock(&bond->lock);
-       bond_for_each_slave(bond, slave) {
+       if (!rtnl_trylock())
+               return restart_syscall();
+
+       bond_for_each_slave(bond, slave, iter) {
                if (res > (PAGE_SIZE - IFNAMSIZ)) {
                        /* not enough space for another interface name */
                        if ((PAGE_SIZE - res) > 10)
@@ -215,7 +183,9 @@ static ssize_t bonding_show_slaves(struct device *d,
                }
                res += sprintf(buf + res, "%s ", slave->dev->name);
        }
-       read_unlock(&bond->lock);
+
+       rtnl_unlock();
+
        if (res)
                buf[res-1] = '\n'; /* eat the leftover space */
 
@@ -304,50 +274,26 @@ static ssize_t bonding_store_mode(struct device *d,
                                  struct device_attribute *attr,
                                  const char *buf, size_t count)
 {
-       int new_value, ret = count;
+       int new_value, ret;
        struct bonding *bond = to_bond(d);
 
-       if (!rtnl_trylock())
-               return restart_syscall();
-
-       if (bond->dev->flags & IFF_UP) {
-               pr_err("unable to update mode of %s because interface is up.\n",
-                      bond->dev->name);
-               ret = -EPERM;
-               goto out;
-       }
-
-       if (!list_empty(&bond->slave_list)) {
-               pr_err("unable to update mode of %s because it has slaves.\n",
-                       bond->dev->name);
-               ret = -EPERM;
-               goto out;
-       }
-
        new_value = bond_parse_parm(buf, bond_mode_tbl);
        if (new_value < 0)  {
                pr_err("%s: Ignoring invalid mode value %.*s.\n",
                       bond->dev->name, (int)strlen(buf) - 1, buf);
-               ret = -EINVAL;
-               goto out;
+               return -EINVAL;
        }
-       if ((new_value == BOND_MODE_ALB ||
-            new_value == BOND_MODE_TLB) &&
-           bond->params.arp_interval) {
-               pr_err("%s: %s mode is incompatible with arp monitoring.\n",
-                      bond->dev->name, bond_mode_tbl[new_value].modename);
-               ret = -EINVAL;
-               goto out;
+       if (!rtnl_trylock())
+               return restart_syscall();
+
+       ret = bond_option_mode_set(bond, new_value);
+       if (!ret) {
+               pr_info("%s: setting mode to %s (%d).\n",
+                       bond->dev->name, bond_mode_tbl[new_value].modename,
+                       new_value);
+               ret = count;
        }
 
-       /* don't cache arp_validate between modes */
-       bond->params.arp_validate = BOND_ARP_VALIDATE_NONE;
-       bond->params.mode = new_value;
-       bond_set_mode_ops(bond, bond->params.mode);
-       pr_info("%s: setting mode to %s (%d).\n",
-               bond->dev->name, bond_mode_tbl[new_value].modename,
-               new_value);
-out:
        rtnl_unlock();
        return ret;
 }
@@ -383,7 +329,6 @@ static ssize_t bonding_store_xmit_hash(struct device *d,
                ret = -EINVAL;
        } else {
                bond->params.xmit_policy = new_value;
-               bond_set_mode_ops(bond, bond->params.mode);
                pr_info("%s: setting xmit hash policy to %s (%d).\n",
                        bond->dev->name,
                        xmit_hashtype_tbl[new_value].modename, new_value);
@@ -513,7 +458,7 @@ static ssize_t bonding_store_fail_over_mac(struct device *d,
        if (!rtnl_trylock())
                return restart_syscall();
 
-       if (!list_empty(&bond->slave_list)) {
+       if (bond_has_slaves(bond)) {
                pr_err("%s: Can't alter fail_over_mac with slaves in bond.\n",
                       bond->dev->name);
                ret = -EPERM;
@@ -647,11 +592,15 @@ static ssize_t bonding_store_arp_targets(struct device *d,
                                         const char *buf, size_t count)
 {
        struct bonding *bond = to_bond(d);
+       struct list_head *iter;
        struct slave *slave;
        __be32 newtarget, *targets;
        unsigned long *targets_rx;
        int ind, i, j, ret = -EINVAL;
 
+       if (!rtnl_trylock())
+               return restart_syscall();
+
        targets = bond->params.arp_targets;
        newtarget = in_aton(buf + 1);
        /* look for adds */
@@ -679,7 +628,7 @@ static ssize_t bonding_store_arp_targets(struct device *d,
                         &newtarget);
                /* not to race with bond_arp_rcv */
                write_lock_bh(&bond->lock);
-               bond_for_each_slave(bond, slave)
+               bond_for_each_slave(bond, slave, iter)
                        slave->target_last_arp_rx[ind] = jiffies;
                targets[ind] = newtarget;
                write_unlock_bh(&bond->lock);
@@ -705,7 +654,7 @@ static ssize_t bonding_store_arp_targets(struct device *d,
                        &newtarget);
 
                write_lock_bh(&bond->lock);
-               bond_for_each_slave(bond, slave) {
+               bond_for_each_slave(bond, slave, iter) {
                        targets_rx = slave->target_last_arp_rx;
                        j = ind;
                        for (; (j < BOND_MAX_ARP_TARGETS-1) && targets[j+1]; j++)
@@ -725,6 +674,7 @@ static ssize_t bonding_store_arp_targets(struct device *d,
 
        ret = count;
 out:
+       rtnl_unlock();
        return ret;
 }
 static DEVICE_ATTR(arp_ip_target, S_IRUGO | S_IWUSR , bonding_show_arp_targets, bonding_store_arp_targets);
@@ -1102,6 +1052,7 @@ static ssize_t bonding_store_primary(struct device *d,
                                     const char *buf, size_t count)
 {
        struct bonding *bond = to_bond(d);
+       struct list_head *iter;
        char ifname[IFNAMSIZ];
        struct slave *slave;
 
@@ -1129,7 +1080,7 @@ static ssize_t bonding_store_primary(struct device *d,
                goto out;
        }
 
-       bond_for_each_slave(bond, slave) {
+       bond_for_each_slave(bond, slave, iter) {
                if (strncmp(slave->dev->name, ifname, IFNAMSIZ) == 0) {
                        pr_info("%s: Setting %s as primary slave.\n",
                                bond->dev->name, slave->dev->name);
@@ -1259,13 +1210,13 @@ static ssize_t bonding_show_active_slave(struct device *d,
                                         char *buf)
 {
        struct bonding *bond = to_bond(d);
-       struct slave *curr;
+       struct net_device *slave_dev;
        int count = 0;
 
        rcu_read_lock();
-       curr = rcu_dereference(bond->curr_active_slave);
-       if (USES_PRIMARY(bond->params.mode) && curr)
-               count = sprintf(buf, "%s\n", curr->dev->name);
+       slave_dev = bond_option_active_slave_get_rcu(bond);
+       if (slave_dev)
+               count = sprintf(buf, "%s\n", slave_dev->name);
        rcu_read_unlock();
 
        return count;
@@ -1275,80 +1226,33 @@ static ssize_t bonding_store_active_slave(struct device *d,
                                          struct device_attribute *attr,
                                          const char *buf, size_t count)
 {
-       struct slave *slave, *old_active, *new_active;
+       int ret;
        struct bonding *bond = to_bond(d);
        char ifname[IFNAMSIZ];
+       struct net_device *dev;
 
        if (!rtnl_trylock())
                return restart_syscall();
 
-       old_active = new_active = NULL;
-       block_netpoll_tx();
-       read_lock(&bond->lock);
-       write_lock_bh(&bond->curr_slave_lock);
-
-       if (!USES_PRIMARY(bond->params.mode)) {
-               pr_info("%s: Unable to change active slave; %s is in mode %d\n",
-                       bond->dev->name, bond->dev->name, bond->params.mode);
-               goto out;
-       }
-
        sscanf(buf, "%15s", ifname); /* IFNAMSIZ */
-
-       /* check to see if we are clearing active */
        if (!strlen(ifname) || buf[0] == '\n') {
-               pr_info("%s: Clearing current active slave.\n",
-                       bond->dev->name);
-               rcu_assign_pointer(bond->curr_active_slave, NULL);
-               bond_select_active_slave(bond);
-               goto out;
-       }
-
-       bond_for_each_slave(bond, slave) {
-               if (strncmp(slave->dev->name, ifname, IFNAMSIZ) == 0) {
-                       old_active = bond->curr_active_slave;
-                       new_active = slave;
-                       if (new_active == old_active) {
-                               /* do nothing */
-                               pr_info("%s: %s is already the current"
-                                       " active slave.\n",
-                                       bond->dev->name,
-                                       slave->dev->name);
-                               goto out;
-                       } else {
-                               if ((new_active) &&
-                                   (old_active) &&
-                                   (new_active->link == BOND_LINK_UP) &&
-                                   IS_UP(new_active->dev)) {
-                                       pr_info("%s: Setting %s as active"
-                                               " slave.\n",
-                                               bond->dev->name,
-                                               slave->dev->name);
-                                       bond_change_active_slave(bond,
-                                                                new_active);
-                               } else {
-                                       pr_info("%s: Could not set %s as"
-                                               " active slave; either %s is"
-                                               " down or the link is down.\n",
-                                               bond->dev->name,
-                                               slave->dev->name,
-                                               slave->dev->name);
-                               }
-                               goto out;
-                       }
+               dev = NULL;
+       } else {
+               dev = __dev_get_by_name(dev_net(bond->dev), ifname);
+               if (!dev) {
+                       ret = -ENODEV;
+                       goto out;
                }
        }
 
-       pr_info("%s: Unable to set %.*s as active slave.\n",
-               bond->dev->name, (int)strlen(buf) - 1, buf);
- out:
-       write_unlock_bh(&bond->curr_slave_lock);
-       read_unlock(&bond->lock);
-       unblock_netpoll_tx();
+       ret = bond_option_active_slave_set(bond, dev);
+       if (!ret)
+               ret = count;
 
+ out:
        rtnl_unlock();
 
-       return count;
+       return ret;
 
 }
 static DEVICE_ATTR(active_slave, S_IRUGO | S_IWUSR,
@@ -1484,14 +1388,14 @@ static ssize_t bonding_show_queue_id(struct device *d,
                                     char *buf)
 {
        struct bonding *bond = to_bond(d);
+       struct list_head *iter;
        struct slave *slave;
        int res = 0;
 
        if (!rtnl_trylock())
                return restart_syscall();
 
-       read_lock(&bond->lock);
-       bond_for_each_slave(bond, slave) {
+       bond_for_each_slave(bond, slave, iter) {
                if (res > (PAGE_SIZE - IFNAMSIZ - 6)) {
                        /* not enough space for another interface_name:queue_id pair */
                        if ((PAGE_SIZE - res) > 10)
@@ -1502,9 +1406,9 @@ static ssize_t bonding_show_queue_id(struct device *d,
                res += sprintf(buf + res, "%s:%d ",
                               slave->dev->name, slave->queue_id);
        }
-       read_unlock(&bond->lock);
        if (res)
                buf[res-1] = '\n'; /* eat the leftover space */
+
        rtnl_unlock();
 
        return res;
@@ -1520,6 +1424,7 @@ static ssize_t bonding_store_queue_id(struct device *d,
 {
        struct slave *slave, *update_slave;
        struct bonding *bond = to_bond(d);
+       struct list_head *iter;
        u16 qid;
        int ret = count;
        char *delim;
@@ -1552,11 +1457,9 @@ static ssize_t bonding_store_queue_id(struct device *d,
        if (!sdev)
                goto err_no_cmd;
 
-       read_lock(&bond->lock);
-
        /* Search for thes slave and check for duplicate qids */
        update_slave = NULL;
-       bond_for_each_slave(bond, slave) {
+       bond_for_each_slave(bond, slave, iter) {
                if (sdev == slave->dev)
                        /*
                         * We don't need to check the matching
@@ -1564,23 +1467,20 @@ static ssize_t bonding_store_queue_id(struct device *d,
                         */
                        update_slave = slave;
                else if (qid && qid == slave->queue_id) {
-                       goto err_no_cmd_unlock;
+                       goto err_no_cmd;
                }
        }
 
        if (!update_slave)
-               goto err_no_cmd_unlock;
+               goto err_no_cmd;
 
        /* Actually set the qids for the slave */
        update_slave->queue_id = qid;
 
-       read_unlock(&bond->lock);
 out:
        rtnl_unlock();
        return ret;
 
-err_no_cmd_unlock:
-       read_unlock(&bond->lock);
 err_no_cmd:
        pr_info("invalid input for queue_id set for %s.\n",
                bond->dev->name);
@@ -1610,8 +1510,12 @@ static ssize_t bonding_store_slaves_active(struct device *d,
 {
        struct bonding *bond = to_bond(d);
        int new_value, ret = count;
+       struct list_head *iter;
        struct slave *slave;
 
+       if (!rtnl_trylock())
+               return restart_syscall();
+
        if (sscanf(buf, "%d", &new_value) != 1) {
                pr_err("%s: no all_slaves_active value specified.\n",
                       bond->dev->name);
@@ -1631,8 +1535,7 @@ static ssize_t bonding_store_slaves_active(struct device *d,
                goto out;
        }
 
-       read_lock(&bond->lock);
-       bond_for_each_slave(bond, slave) {
+       bond_for_each_slave(bond, slave, iter) {
                if (!bond_is_active_slave(slave)) {
                        if (new_value)
                                slave->inactive = 0;
@@ -1640,8 +1543,8 @@ static ssize_t bonding_store_slaves_active(struct device *d,
                                slave->inactive = 1;
                }
        }
-       read_unlock(&bond->lock);
 out:
+       rtnl_unlock();
        return ret;
 }
 static DEVICE_ATTR(all_slaves_active, S_IRUGO | S_IWUSR,