diff options
Diffstat (limited to 'drivers/net/bonding/bond_sysfs.c')
-rw-r--r-- | drivers/net/bonding/bond_sysfs.c | 264 |
1 files changed, 108 insertions, 156 deletions
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index ec9b6460a38d..bc8fd362a5aa 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include <net/net_namespace.h> | 40 | #include <net/net_namespace.h> |
41 | #include <net/netns/generic.h> | 41 | #include <net/netns/generic.h> |
42 | #include <linux/nsproxy.h> | 42 | #include <linux/nsproxy.h> |
43 | #include <linux/reciprocal_div.h> | ||
43 | 44 | ||
44 | #include "bonding.h" | 45 | #include "bonding.h" |
45 | 46 | ||
@@ -159,41 +160,6 @@ static const struct class_attribute class_attr_bonding_masters = { | |||
159 | .store = bonding_store_bonds, | 160 | .store = bonding_store_bonds, |
160 | }; | 161 | }; |
161 | 162 | ||
162 | int bond_create_slave_symlinks(struct net_device *master, | ||
163 | struct net_device *slave) | ||
164 | { | ||
165 | char linkname[IFNAMSIZ+7]; | ||
166 | int ret = 0; | ||
167 | |||
168 | /* first, create a link from the slave back to the master */ | ||
169 | ret = sysfs_create_link(&(slave->dev.kobj), &(master->dev.kobj), | ||
170 | "master"); | ||
171 | if (ret) | ||
172 | return ret; | ||
173 | /* next, create a link from the master to the slave */ | ||
174 | sprintf(linkname, "slave_%s", slave->name); | ||
175 | ret = sysfs_create_link(&(master->dev.kobj), &(slave->dev.kobj), | ||
176 | linkname); | ||
177 | |||
178 | /* free the master link created earlier in case of error */ | ||
179 | if (ret) | ||
180 | sysfs_remove_link(&(slave->dev.kobj), "master"); | ||
181 | |||
182 | return ret; | ||
183 | |||
184 | } | ||
185 | |||
186 | void bond_destroy_slave_symlinks(struct net_device *master, | ||
187 | struct net_device *slave) | ||
188 | { | ||
189 | char linkname[IFNAMSIZ+7]; | ||
190 | |||
191 | sysfs_remove_link(&(slave->dev.kobj), "master"); | ||
192 | sprintf(linkname, "slave_%s", slave->name); | ||
193 | sysfs_remove_link(&(master->dev.kobj), linkname); | ||
194 | } | ||
195 | |||
196 | |||
197 | /* | 163 | /* |
198 | * Show the slaves in the current bond. | 164 | * Show the slaves in the current bond. |
199 | */ | 165 | */ |
@@ -201,11 +167,14 @@ static ssize_t bonding_show_slaves(struct device *d, | |||
201 | struct device_attribute *attr, char *buf) | 167 | struct device_attribute *attr, char *buf) |
202 | { | 168 | { |
203 | struct bonding *bond = to_bond(d); | 169 | struct bonding *bond = to_bond(d); |
170 | struct list_head *iter; | ||
204 | struct slave *slave; | 171 | struct slave *slave; |
205 | int res = 0; | 172 | int res = 0; |
206 | 173 | ||
207 | read_lock(&bond->lock); | 174 | if (!rtnl_trylock()) |
208 | bond_for_each_slave(bond, slave) { | 175 | return restart_syscall(); |
176 | |||
177 | bond_for_each_slave(bond, slave, iter) { | ||
209 | if (res > (PAGE_SIZE - IFNAMSIZ)) { | 178 | if (res > (PAGE_SIZE - IFNAMSIZ)) { |
210 | /* not enough space for another interface name */ | 179 | /* not enough space for another interface name */ |
211 | if ((PAGE_SIZE - res) > 10) | 180 | if ((PAGE_SIZE - res) > 10) |
@@ -215,7 +184,9 @@ static ssize_t bonding_show_slaves(struct device *d, | |||
215 | } | 184 | } |
216 | res += sprintf(buf + res, "%s ", slave->dev->name); | 185 | res += sprintf(buf + res, "%s ", slave->dev->name); |
217 | } | 186 | } |
218 | read_unlock(&bond->lock); | 187 | |
188 | rtnl_unlock(); | ||
189 | |||
219 | if (res) | 190 | if (res) |
220 | buf[res-1] = '\n'; /* eat the leftover space */ | 191 | buf[res-1] = '\n'; /* eat the leftover space */ |
221 | 192 | ||
@@ -304,50 +275,26 @@ static ssize_t bonding_store_mode(struct device *d, | |||
304 | struct device_attribute *attr, | 275 | struct device_attribute *attr, |
305 | const char *buf, size_t count) | 276 | const char *buf, size_t count) |
306 | { | 277 | { |
307 | int new_value, ret = count; | 278 | int new_value, ret; |
308 | struct bonding *bond = to_bond(d); | 279 | struct bonding *bond = to_bond(d); |
309 | 280 | ||
310 | if (!rtnl_trylock()) | ||
311 | return restart_syscall(); | ||
312 | |||
313 | if (bond->dev->flags & IFF_UP) { | ||
314 | pr_err("unable to update mode of %s because interface is up.\n", | ||
315 | bond->dev->name); | ||
316 | ret = -EPERM; | ||
317 | goto out; | ||
318 | } | ||
319 | |||
320 | if (!list_empty(&bond->slave_list)) { | ||
321 | pr_err("unable to update mode of %s because it has slaves.\n", | ||
322 | bond->dev->name); | ||
323 | ret = -EPERM; | ||
324 | goto out; | ||
325 | } | ||
326 | |||
327 | new_value = bond_parse_parm(buf, bond_mode_tbl); | 281 | new_value = bond_parse_parm(buf, bond_mode_tbl); |
328 | if (new_value < 0) { | 282 | if (new_value < 0) { |
329 | pr_err("%s: Ignoring invalid mode value %.*s.\n", | 283 | pr_err("%s: Ignoring invalid mode value %.*s.\n", |
330 | bond->dev->name, (int)strlen(buf) - 1, buf); | 284 | bond->dev->name, (int)strlen(buf) - 1, buf); |
331 | ret = -EINVAL; | 285 | return -EINVAL; |
332 | goto out; | ||
333 | } | 286 | } |
334 | if ((new_value == BOND_MODE_ALB || | 287 | if (!rtnl_trylock()) |
335 | new_value == BOND_MODE_TLB) && | 288 | return restart_syscall(); |
336 | bond->params.arp_interval) { | 289 | |
337 | pr_err("%s: %s mode is incompatible with arp monitoring.\n", | 290 | ret = bond_option_mode_set(bond, new_value); |
338 | bond->dev->name, bond_mode_tbl[new_value].modename); | 291 | if (!ret) { |
339 | ret = -EINVAL; | 292 | pr_info("%s: setting mode to %s (%d).\n", |
340 | goto out; | 293 | bond->dev->name, bond_mode_tbl[new_value].modename, |
294 | new_value); | ||
295 | ret = count; | ||
341 | } | 296 | } |
342 | 297 | ||
343 | /* don't cache arp_validate between modes */ | ||
344 | bond->params.arp_validate = BOND_ARP_VALIDATE_NONE; | ||
345 | bond->params.mode = new_value; | ||
346 | bond_set_mode_ops(bond, bond->params.mode); | ||
347 | pr_info("%s: setting mode to %s (%d).\n", | ||
348 | bond->dev->name, bond_mode_tbl[new_value].modename, | ||
349 | new_value); | ||
350 | out: | ||
351 | rtnl_unlock(); | 298 | rtnl_unlock(); |
352 | return ret; | 299 | return ret; |
353 | } | 300 | } |
@@ -383,7 +330,6 @@ static ssize_t bonding_store_xmit_hash(struct device *d, | |||
383 | ret = -EINVAL; | 330 | ret = -EINVAL; |
384 | } else { | 331 | } else { |
385 | bond->params.xmit_policy = new_value; | 332 | bond->params.xmit_policy = new_value; |
386 | bond_set_mode_ops(bond, bond->params.mode); | ||
387 | pr_info("%s: setting xmit hash policy to %s (%d).\n", | 333 | pr_info("%s: setting xmit hash policy to %s (%d).\n", |
388 | bond->dev->name, | 334 | bond->dev->name, |
389 | xmit_hashtype_tbl[new_value].modename, new_value); | 335 | xmit_hashtype_tbl[new_value].modename, new_value); |
@@ -513,7 +459,7 @@ static ssize_t bonding_store_fail_over_mac(struct device *d, | |||
513 | if (!rtnl_trylock()) | 459 | if (!rtnl_trylock()) |
514 | return restart_syscall(); | 460 | return restart_syscall(); |
515 | 461 | ||
516 | if (!list_empty(&bond->slave_list)) { | 462 | if (bond_has_slaves(bond)) { |
517 | pr_err("%s: Can't alter fail_over_mac with slaves in bond.\n", | 463 | pr_err("%s: Can't alter fail_over_mac with slaves in bond.\n", |
518 | bond->dev->name); | 464 | bond->dev->name); |
519 | ret = -EPERM; | 465 | ret = -EPERM; |
@@ -647,11 +593,15 @@ static ssize_t bonding_store_arp_targets(struct device *d, | |||
647 | const char *buf, size_t count) | 593 | const char *buf, size_t count) |
648 | { | 594 | { |
649 | struct bonding *bond = to_bond(d); | 595 | struct bonding *bond = to_bond(d); |
596 | struct list_head *iter; | ||
650 | struct slave *slave; | 597 | struct slave *slave; |
651 | __be32 newtarget, *targets; | 598 | __be32 newtarget, *targets; |
652 | unsigned long *targets_rx; | 599 | unsigned long *targets_rx; |
653 | int ind, i, j, ret = -EINVAL; | 600 | int ind, i, j, ret = -EINVAL; |
654 | 601 | ||
602 | if (!rtnl_trylock()) | ||
603 | return restart_syscall(); | ||
604 | |||
655 | targets = bond->params.arp_targets; | 605 | targets = bond->params.arp_targets; |
656 | newtarget = in_aton(buf + 1); | 606 | newtarget = in_aton(buf + 1); |
657 | /* look for adds */ | 607 | /* look for adds */ |
@@ -679,7 +629,7 @@ static ssize_t bonding_store_arp_targets(struct device *d, | |||
679 | &newtarget); | 629 | &newtarget); |
680 | /* not to race with bond_arp_rcv */ | 630 | /* not to race with bond_arp_rcv */ |
681 | write_lock_bh(&bond->lock); | 631 | write_lock_bh(&bond->lock); |
682 | bond_for_each_slave(bond, slave) | 632 | bond_for_each_slave(bond, slave, iter) |
683 | slave->target_last_arp_rx[ind] = jiffies; | 633 | slave->target_last_arp_rx[ind] = jiffies; |
684 | targets[ind] = newtarget; | 634 | targets[ind] = newtarget; |
685 | write_unlock_bh(&bond->lock); | 635 | write_unlock_bh(&bond->lock); |
@@ -705,7 +655,7 @@ static ssize_t bonding_store_arp_targets(struct device *d, | |||
705 | &newtarget); | 655 | &newtarget); |
706 | 656 | ||
707 | write_lock_bh(&bond->lock); | 657 | write_lock_bh(&bond->lock); |
708 | bond_for_each_slave(bond, slave) { | 658 | bond_for_each_slave(bond, slave, iter) { |
709 | targets_rx = slave->target_last_arp_rx; | 659 | targets_rx = slave->target_last_arp_rx; |
710 | j = ind; | 660 | j = ind; |
711 | for (; (j < BOND_MAX_ARP_TARGETS-1) && targets[j+1]; j++) | 661 | for (; (j < BOND_MAX_ARP_TARGETS-1) && targets[j+1]; j++) |
@@ -725,6 +675,7 @@ static ssize_t bonding_store_arp_targets(struct device *d, | |||
725 | 675 | ||
726 | ret = count; | 676 | ret = count; |
727 | out: | 677 | out: |
678 | rtnl_unlock(); | ||
728 | return ret; | 679 | return ret; |
729 | } | 680 | } |
730 | static DEVICE_ATTR(arp_ip_target, S_IRUGO | S_IWUSR , bonding_show_arp_targets, bonding_store_arp_targets); | 681 | static DEVICE_ATTR(arp_ip_target, S_IRUGO | S_IWUSR , bonding_show_arp_targets, bonding_store_arp_targets); |
@@ -1102,6 +1053,7 @@ static ssize_t bonding_store_primary(struct device *d, | |||
1102 | const char *buf, size_t count) | 1053 | const char *buf, size_t count) |
1103 | { | 1054 | { |
1104 | struct bonding *bond = to_bond(d); | 1055 | struct bonding *bond = to_bond(d); |
1056 | struct list_head *iter; | ||
1105 | char ifname[IFNAMSIZ]; | 1057 | char ifname[IFNAMSIZ]; |
1106 | struct slave *slave; | 1058 | struct slave *slave; |
1107 | 1059 | ||
@@ -1129,7 +1081,7 @@ static ssize_t bonding_store_primary(struct device *d, | |||
1129 | goto out; | 1081 | goto out; |
1130 | } | 1082 | } |
1131 | 1083 | ||
1132 | bond_for_each_slave(bond, slave) { | 1084 | bond_for_each_slave(bond, slave, iter) { |
1133 | if (strncmp(slave->dev->name, ifname, IFNAMSIZ) == 0) { | 1085 | if (strncmp(slave->dev->name, ifname, IFNAMSIZ) == 0) { |
1134 | pr_info("%s: Setting %s as primary slave.\n", | 1086 | pr_info("%s: Setting %s as primary slave.\n", |
1135 | bond->dev->name, slave->dev->name); | 1087 | bond->dev->name, slave->dev->name); |
@@ -1259,13 +1211,13 @@ static ssize_t bonding_show_active_slave(struct device *d, | |||
1259 | char *buf) | 1211 | char *buf) |
1260 | { | 1212 | { |
1261 | struct bonding *bond = to_bond(d); | 1213 | struct bonding *bond = to_bond(d); |
1262 | struct slave *curr; | 1214 | struct net_device *slave_dev; |
1263 | int count = 0; | 1215 | int count = 0; |
1264 | 1216 | ||
1265 | rcu_read_lock(); | 1217 | rcu_read_lock(); |
1266 | curr = rcu_dereference(bond->curr_active_slave); | 1218 | slave_dev = bond_option_active_slave_get_rcu(bond); |
1267 | if (USES_PRIMARY(bond->params.mode) && curr) | 1219 | if (slave_dev) |
1268 | count = sprintf(buf, "%s\n", curr->dev->name); | 1220 | count = sprintf(buf, "%s\n", slave_dev->name); |
1269 | rcu_read_unlock(); | 1221 | rcu_read_unlock(); |
1270 | 1222 | ||
1271 | return count; | 1223 | return count; |
@@ -1275,80 +1227,33 @@ static ssize_t bonding_store_active_slave(struct device *d, | |||
1275 | struct device_attribute *attr, | 1227 | struct device_attribute *attr, |
1276 | const char *buf, size_t count) | 1228 | const char *buf, size_t count) |
1277 | { | 1229 | { |
1278 | struct slave *slave, *old_active, *new_active; | 1230 | int ret; |
1279 | struct bonding *bond = to_bond(d); | 1231 | struct bonding *bond = to_bond(d); |
1280 | char ifname[IFNAMSIZ]; | 1232 | char ifname[IFNAMSIZ]; |
1233 | struct net_device *dev; | ||
1281 | 1234 | ||
1282 | if (!rtnl_trylock()) | 1235 | if (!rtnl_trylock()) |
1283 | return restart_syscall(); | 1236 | return restart_syscall(); |
1284 | 1237 | ||
1285 | old_active = new_active = NULL; | ||
1286 | block_netpoll_tx(); | ||
1287 | read_lock(&bond->lock); | ||
1288 | write_lock_bh(&bond->curr_slave_lock); | ||
1289 | |||
1290 | if (!USES_PRIMARY(bond->params.mode)) { | ||
1291 | pr_info("%s: Unable to change active slave; %s is in mode %d\n", | ||
1292 | bond->dev->name, bond->dev->name, bond->params.mode); | ||
1293 | goto out; | ||
1294 | } | ||
1295 | |||
1296 | sscanf(buf, "%15s", ifname); /* IFNAMSIZ */ | 1238 | sscanf(buf, "%15s", ifname); /* IFNAMSIZ */ |
1297 | |||
1298 | /* check to see if we are clearing active */ | ||
1299 | if (!strlen(ifname) || buf[0] == '\n') { | 1239 | if (!strlen(ifname) || buf[0] == '\n') { |
1300 | pr_info("%s: Clearing current active slave.\n", | 1240 | dev = NULL; |
1301 | bond->dev->name); | 1241 | } else { |
1302 | rcu_assign_pointer(bond->curr_active_slave, NULL); | 1242 | dev = __dev_get_by_name(dev_net(bond->dev), ifname); |
1303 | bond_select_active_slave(bond); | 1243 | if (!dev) { |
1304 | goto out; | 1244 | ret = -ENODEV; |
1305 | } | 1245 | goto out; |
1306 | |||
1307 | bond_for_each_slave(bond, slave) { | ||
1308 | if (strncmp(slave->dev->name, ifname, IFNAMSIZ) == 0) { | ||
1309 | old_active = bond->curr_active_slave; | ||
1310 | new_active = slave; | ||
1311 | if (new_active == old_active) { | ||
1312 | /* do nothing */ | ||
1313 | pr_info("%s: %s is already the current" | ||
1314 | " active slave.\n", | ||
1315 | bond->dev->name, | ||
1316 | slave->dev->name); | ||
1317 | goto out; | ||
1318 | } else { | ||
1319 | if ((new_active) && | ||
1320 | (old_active) && | ||
1321 | (new_active->link == BOND_LINK_UP) && | ||
1322 | IS_UP(new_active->dev)) { | ||
1323 | pr_info("%s: Setting %s as active" | ||
1324 | " slave.\n", | ||
1325 | bond->dev->name, | ||
1326 | slave->dev->name); | ||
1327 | bond_change_active_slave(bond, | ||
1328 | new_active); | ||
1329 | } else { | ||
1330 | pr_info("%s: Could not set %s as" | ||
1331 | " active slave; either %s is" | ||
1332 | " down or the link is down.\n", | ||
1333 | bond->dev->name, | ||
1334 | slave->dev->name, | ||
1335 | slave->dev->name); | ||
1336 | } | ||
1337 | goto out; | ||
1338 | } | ||
1339 | } | 1246 | } |
1340 | } | 1247 | } |
1341 | 1248 | ||
1342 | pr_info("%s: Unable to set %.*s as active slave.\n", | 1249 | ret = bond_option_active_slave_set(bond, dev); |
1343 | bond->dev->name, (int)strlen(buf) - 1, buf); | 1250 | if (!ret) |
1344 | out: | 1251 | ret = count; |
1345 | write_unlock_bh(&bond->curr_slave_lock); | ||
1346 | read_unlock(&bond->lock); | ||
1347 | unblock_netpoll_tx(); | ||
1348 | 1252 | ||
1253 | out: | ||
1349 | rtnl_unlock(); | 1254 | rtnl_unlock(); |
1350 | 1255 | ||
1351 | return count; | 1256 | return ret; |
1352 | 1257 | ||
1353 | } | 1258 | } |
1354 | static DEVICE_ATTR(active_slave, S_IRUGO | S_IWUSR, | 1259 | static DEVICE_ATTR(active_slave, S_IRUGO | S_IWUSR, |
@@ -1484,14 +1389,14 @@ static ssize_t bonding_show_queue_id(struct device *d, | |||
1484 | char *buf) | 1389 | char *buf) |
1485 | { | 1390 | { |
1486 | struct bonding *bond = to_bond(d); | 1391 | struct bonding *bond = to_bond(d); |
1392 | struct list_head *iter; | ||
1487 | struct slave *slave; | 1393 | struct slave *slave; |
1488 | int res = 0; | 1394 | int res = 0; |
1489 | 1395 | ||
1490 | if (!rtnl_trylock()) | 1396 | if (!rtnl_trylock()) |
1491 | return restart_syscall(); | 1397 | return restart_syscall(); |
1492 | 1398 | ||
1493 | read_lock(&bond->lock); | 1399 | bond_for_each_slave(bond, slave, iter) { |
1494 | bond_for_each_slave(bond, slave) { | ||
1495 | if (res > (PAGE_SIZE - IFNAMSIZ - 6)) { | 1400 | if (res > (PAGE_SIZE - IFNAMSIZ - 6)) { |
1496 | /* not enough space for another interface_name:queue_id pair */ | 1401 | /* not enough space for another interface_name:queue_id pair */ |
1497 | if ((PAGE_SIZE - res) > 10) | 1402 | if ((PAGE_SIZE - res) > 10) |
@@ -1502,9 +1407,9 @@ static ssize_t bonding_show_queue_id(struct device *d, | |||
1502 | res += sprintf(buf + res, "%s:%d ", | 1407 | res += sprintf(buf + res, "%s:%d ", |
1503 | slave->dev->name, slave->queue_id); | 1408 | slave->dev->name, slave->queue_id); |
1504 | } | 1409 | } |
1505 | read_unlock(&bond->lock); | ||
1506 | if (res) | 1410 | if (res) |
1507 | buf[res-1] = '\n'; /* eat the leftover space */ | 1411 | buf[res-1] = '\n'; /* eat the leftover space */ |
1412 | |||
1508 | rtnl_unlock(); | 1413 | rtnl_unlock(); |
1509 | 1414 | ||
1510 | return res; | 1415 | return res; |
@@ -1520,6 +1425,7 @@ static ssize_t bonding_store_queue_id(struct device *d, | |||
1520 | { | 1425 | { |
1521 | struct slave *slave, *update_slave; | 1426 | struct slave *slave, *update_slave; |
1522 | struct bonding *bond = to_bond(d); | 1427 | struct bonding *bond = to_bond(d); |
1428 | struct list_head *iter; | ||
1523 | u16 qid; | 1429 | u16 qid; |
1524 | int ret = count; | 1430 | int ret = count; |
1525 | char *delim; | 1431 | char *delim; |
@@ -1552,11 +1458,9 @@ static ssize_t bonding_store_queue_id(struct device *d, | |||
1552 | if (!sdev) | 1458 | if (!sdev) |
1553 | goto err_no_cmd; | 1459 | goto err_no_cmd; |
1554 | 1460 | ||
1555 | read_lock(&bond->lock); | ||
1556 | |||
1557 | /* Search for thes slave and check for duplicate qids */ | 1461 | /* Search for thes slave and check for duplicate qids */ |
1558 | update_slave = NULL; | 1462 | update_slave = NULL; |
1559 | bond_for_each_slave(bond, slave) { | 1463 | bond_for_each_slave(bond, slave, iter) { |
1560 | if (sdev == slave->dev) | 1464 | if (sdev == slave->dev) |
1561 | /* | 1465 | /* |
1562 | * We don't need to check the matching | 1466 | * We don't need to check the matching |
@@ -1564,23 +1468,20 @@ static ssize_t bonding_store_queue_id(struct device *d, | |||
1564 | */ | 1468 | */ |
1565 | update_slave = slave; | 1469 | update_slave = slave; |
1566 | else if (qid && qid == slave->queue_id) { | 1470 | else if (qid && qid == slave->queue_id) { |
1567 | goto err_no_cmd_unlock; | 1471 | goto err_no_cmd; |
1568 | } | 1472 | } |
1569 | } | 1473 | } |
1570 | 1474 | ||
1571 | if (!update_slave) | 1475 | if (!update_slave) |
1572 | goto err_no_cmd_unlock; | 1476 | goto err_no_cmd; |
1573 | 1477 | ||
1574 | /* Actually set the qids for the slave */ | 1478 | /* Actually set the qids for the slave */ |
1575 | update_slave->queue_id = qid; | 1479 | update_slave->queue_id = qid; |
1576 | 1480 | ||
1577 | read_unlock(&bond->lock); | ||
1578 | out: | 1481 | out: |
1579 | rtnl_unlock(); | 1482 | rtnl_unlock(); |
1580 | return ret; | 1483 | return ret; |
1581 | 1484 | ||
1582 | err_no_cmd_unlock: | ||
1583 | read_unlock(&bond->lock); | ||
1584 | err_no_cmd: | 1485 | err_no_cmd: |
1585 | pr_info("invalid input for queue_id set for %s.\n", | 1486 | pr_info("invalid input for queue_id set for %s.\n", |
1586 | bond->dev->name); | 1487 | bond->dev->name); |
@@ -1610,8 +1511,12 @@ static ssize_t bonding_store_slaves_active(struct device *d, | |||
1610 | { | 1511 | { |
1611 | struct bonding *bond = to_bond(d); | 1512 | struct bonding *bond = to_bond(d); |
1612 | int new_value, ret = count; | 1513 | int new_value, ret = count; |
1514 | struct list_head *iter; | ||
1613 | struct slave *slave; | 1515 | struct slave *slave; |
1614 | 1516 | ||
1517 | if (!rtnl_trylock()) | ||
1518 | return restart_syscall(); | ||
1519 | |||
1615 | if (sscanf(buf, "%d", &new_value) != 1) { | 1520 | if (sscanf(buf, "%d", &new_value) != 1) { |
1616 | pr_err("%s: no all_slaves_active value specified.\n", | 1521 | pr_err("%s: no all_slaves_active value specified.\n", |
1617 | bond->dev->name); | 1522 | bond->dev->name); |
@@ -1631,8 +1536,7 @@ static ssize_t bonding_store_slaves_active(struct device *d, | |||
1631 | goto out; | 1536 | goto out; |
1632 | } | 1537 | } |
1633 | 1538 | ||
1634 | read_lock(&bond->lock); | 1539 | bond_for_each_slave(bond, slave, iter) { |
1635 | bond_for_each_slave(bond, slave) { | ||
1636 | if (!bond_is_active_slave(slave)) { | 1540 | if (!bond_is_active_slave(slave)) { |
1637 | if (new_value) | 1541 | if (new_value) |
1638 | slave->inactive = 0; | 1542 | slave->inactive = 0; |
@@ -1640,8 +1544,8 @@ static ssize_t bonding_store_slaves_active(struct device *d, | |||
1640 | slave->inactive = 1; | 1544 | slave->inactive = 1; |
1641 | } | 1545 | } |
1642 | } | 1546 | } |
1643 | read_unlock(&bond->lock); | ||
1644 | out: | 1547 | out: |
1548 | rtnl_unlock(); | ||
1645 | return ret; | 1549 | return ret; |
1646 | } | 1550 | } |
1647 | static DEVICE_ATTR(all_slaves_active, S_IRUGO | S_IWUSR, | 1551 | static DEVICE_ATTR(all_slaves_active, S_IRUGO | S_IWUSR, |
@@ -1728,6 +1632,53 @@ out: | |||
1728 | static DEVICE_ATTR(lp_interval, S_IRUGO | S_IWUSR, | 1632 | static DEVICE_ATTR(lp_interval, S_IRUGO | S_IWUSR, |
1729 | bonding_show_lp_interval, bonding_store_lp_interval); | 1633 | bonding_show_lp_interval, bonding_store_lp_interval); |
1730 | 1634 | ||
1635 | static ssize_t bonding_show_packets_per_slave(struct device *d, | ||
1636 | struct device_attribute *attr, | ||
1637 | char *buf) | ||
1638 | { | ||
1639 | struct bonding *bond = to_bond(d); | ||
1640 | int packets_per_slave = bond->params.packets_per_slave; | ||
1641 | |||
1642 | if (packets_per_slave > 1) | ||
1643 | packets_per_slave = reciprocal_value(packets_per_slave); | ||
1644 | |||
1645 | return sprintf(buf, "%d\n", packets_per_slave); | ||
1646 | } | ||
1647 | |||
1648 | static ssize_t bonding_store_packets_per_slave(struct device *d, | ||
1649 | struct device_attribute *attr, | ||
1650 | const char *buf, size_t count) | ||
1651 | { | ||
1652 | struct bonding *bond = to_bond(d); | ||
1653 | int new_value, ret = count; | ||
1654 | |||
1655 | if (sscanf(buf, "%d", &new_value) != 1) { | ||
1656 | pr_err("%s: no packets_per_slave value specified.\n", | ||
1657 | bond->dev->name); | ||
1658 | ret = -EINVAL; | ||
1659 | goto out; | ||
1660 | } | ||
1661 | if (new_value < 0 || new_value > USHRT_MAX) { | ||
1662 | pr_err("%s: packets_per_slave must be between 0 and %u\n", | ||
1663 | bond->dev->name, USHRT_MAX); | ||
1664 | ret = -EINVAL; | ||
1665 | goto out; | ||
1666 | } | ||
1667 | if (bond->params.mode != BOND_MODE_ROUNDROBIN) | ||
1668 | pr_warn("%s: Warning: packets_per_slave has effect only in balance-rr mode\n", | ||
1669 | bond->dev->name); | ||
1670 | if (new_value > 1) | ||
1671 | bond->params.packets_per_slave = reciprocal_value(new_value); | ||
1672 | else | ||
1673 | bond->params.packets_per_slave = new_value; | ||
1674 | out: | ||
1675 | return ret; | ||
1676 | } | ||
1677 | |||
1678 | static DEVICE_ATTR(packets_per_slave, S_IRUGO | S_IWUSR, | ||
1679 | bonding_show_packets_per_slave, | ||
1680 | bonding_store_packets_per_slave); | ||
1681 | |||
1731 | static struct attribute *per_bond_attrs[] = { | 1682 | static struct attribute *per_bond_attrs[] = { |
1732 | &dev_attr_slaves.attr, | 1683 | &dev_attr_slaves.attr, |
1733 | &dev_attr_mode.attr, | 1684 | &dev_attr_mode.attr, |
@@ -1759,6 +1710,7 @@ static struct attribute *per_bond_attrs[] = { | |||
1759 | &dev_attr_resend_igmp.attr, | 1710 | &dev_attr_resend_igmp.attr, |
1760 | &dev_attr_min_links.attr, | 1711 | &dev_attr_min_links.attr, |
1761 | &dev_attr_lp_interval.attr, | 1712 | &dev_attr_lp_interval.attr, |
1713 | &dev_attr_packets_per_slave.attr, | ||
1762 | NULL, | 1714 | NULL, |
1763 | }; | 1715 | }; |
1764 | 1716 | ||