.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * net-sysfs.c - network device class and attributes |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (c) 2003 Stephen Hemminger <shemminger@osdl.org> |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or |
---|
7 | | - * modify it under the terms of the GNU General Public License |
---|
8 | | - * as published by the Free Software Foundation; either version |
---|
9 | | - * 2 of the License, or (at your option) any later version. |
---|
10 | 6 | */ |
---|
11 | 7 | |
---|
12 | 8 | #include <linux/capability.h> |
---|
13 | 9 | #include <linux/kernel.h> |
---|
14 | 10 | #include <linux/netdevice.h> |
---|
15 | | -#include <net/switchdev.h> |
---|
16 | 11 | #include <linux/if_arp.h> |
---|
17 | 12 | #include <linux/slab.h> |
---|
18 | 13 | #include <linux/sched/signal.h> |
---|
| 14 | +#include <linux/sched/isolation.h> |
---|
19 | 15 | #include <linux/nsproxy.h> |
---|
20 | 16 | #include <net/sock.h> |
---|
21 | 17 | #include <net/net_namespace.h> |
---|
.. | .. |
---|
85 | 81 | struct net_device *netdev = to_net_dev(dev); |
---|
86 | 82 | struct net *net = dev_net(netdev); |
---|
87 | 83 | unsigned long new; |
---|
88 | | - int ret = -EINVAL; |
---|
| 84 | + int ret; |
---|
89 | 85 | |
---|
90 | 86 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
---|
91 | 87 | return -EPERM; |
---|
.. | .. |
---|
179 | 175 | static ssize_t carrier_store(struct device *dev, struct device_attribute *attr, |
---|
180 | 176 | const char *buf, size_t len) |
---|
181 | 177 | { |
---|
| 178 | + struct net_device *netdev = to_net_dev(dev); |
---|
| 179 | + |
---|
| 180 | + /* The check is also done in change_carrier; this helps returning early |
---|
| 181 | + * without hitting the trylock/restart in netdev_store. |
---|
| 182 | + */ |
---|
| 183 | + if (!netdev->netdev_ops->ndo_change_carrier) |
---|
| 184 | + return -EOPNOTSUPP; |
---|
| 185 | + |
---|
182 | 186 | return netdev_store(dev, attr, buf, len, change_carrier); |
---|
183 | 187 | } |
---|
184 | 188 | |
---|
.. | .. |
---|
200 | 204 | struct net_device *netdev = to_net_dev(dev); |
---|
201 | 205 | int ret = -EINVAL; |
---|
202 | 206 | |
---|
| 207 | + /* The check is also done in __ethtool_get_link_ksettings; this helps |
---|
| 208 | + * returning early without hitting the trylock/restart below. |
---|
| 209 | + */ |
---|
| 210 | + if (!netdev->ethtool_ops->get_link_ksettings) |
---|
| 211 | + return ret; |
---|
| 212 | + |
---|
203 | 213 | if (!rtnl_trylock()) |
---|
204 | 214 | return restart_syscall(); |
---|
205 | 215 | |
---|
206 | | - if (netif_running(netdev)) { |
---|
| 216 | + if (netif_running(netdev) && netif_device_present(netdev)) { |
---|
207 | 217 | struct ethtool_link_ksettings cmd; |
---|
208 | 218 | |
---|
209 | 219 | if (!__ethtool_get_link_ksettings(netdev, &cmd)) |
---|
.. | .. |
---|
219 | 229 | { |
---|
220 | 230 | struct net_device *netdev = to_net_dev(dev); |
---|
221 | 231 | int ret = -EINVAL; |
---|
| 232 | + |
---|
| 233 | + /* The check is also done in __ethtool_get_link_ksettings; this helps |
---|
| 234 | + * returning early without hitting the trylock/restart below. |
---|
| 235 | + */ |
---|
| 236 | + if (!netdev->ethtool_ops->get_link_ksettings) |
---|
| 237 | + return ret; |
---|
222 | 238 | |
---|
223 | 239 | if (!rtnl_trylock()) |
---|
224 | 240 | return restart_syscall(); |
---|
.. | .. |
---|
248 | 264 | } |
---|
249 | 265 | static DEVICE_ATTR_RO(duplex); |
---|
250 | 266 | |
---|
| 267 | +static ssize_t testing_show(struct device *dev, |
---|
| 268 | + struct device_attribute *attr, char *buf) |
---|
| 269 | +{ |
---|
| 270 | + struct net_device *netdev = to_net_dev(dev); |
---|
| 271 | + |
---|
| 272 | + if (netif_running(netdev)) |
---|
| 273 | + return sprintf(buf, fmt_dec, !!netif_testing(netdev)); |
---|
| 274 | + |
---|
| 275 | + return -EINVAL; |
---|
| 276 | +} |
---|
| 277 | +static DEVICE_ATTR_RO(testing); |
---|
| 278 | + |
---|
251 | 279 | static ssize_t dormant_show(struct device *dev, |
---|
252 | 280 | struct device_attribute *attr, char *buf) |
---|
253 | 281 | { |
---|
.. | .. |
---|
265 | 293 | "notpresent", /* currently unused */ |
---|
266 | 294 | "down", |
---|
267 | 295 | "lowerlayerdown", |
---|
268 | | - "testing", /* currently unused */ |
---|
| 296 | + "testing", |
---|
269 | 297 | "dormant", |
---|
270 | 298 | "up" |
---|
271 | 299 | }; |
---|
.. | .. |
---|
337 | 365 | |
---|
338 | 366 | static int change_flags(struct net_device *dev, unsigned long new_flags) |
---|
339 | 367 | { |
---|
340 | | - return dev_change_flags(dev, (unsigned int)new_flags); |
---|
| 368 | + return dev_change_flags(dev, (unsigned int)new_flags, NULL); |
---|
341 | 369 | } |
---|
342 | 370 | |
---|
343 | 371 | static ssize_t flags_store(struct device *dev, struct device_attribute *attr, |
---|
.. | .. |
---|
360 | 388 | |
---|
361 | 389 | static int change_gro_flush_timeout(struct net_device *dev, unsigned long val) |
---|
362 | 390 | { |
---|
363 | | - dev->gro_flush_timeout = val; |
---|
| 391 | + WRITE_ONCE(dev->gro_flush_timeout, val); |
---|
364 | 392 | return 0; |
---|
365 | 393 | } |
---|
366 | 394 | |
---|
.. | .. |
---|
374 | 402 | return netdev_store(dev, attr, buf, len, change_gro_flush_timeout); |
---|
375 | 403 | } |
---|
376 | 404 | NETDEVICE_SHOW_RW(gro_flush_timeout, fmt_ulong); |
---|
| 405 | + |
---|
| 406 | +static int change_napi_defer_hard_irqs(struct net_device *dev, unsigned long val) |
---|
| 407 | +{ |
---|
| 408 | + WRITE_ONCE(dev->napi_defer_hard_irqs, val); |
---|
| 409 | + return 0; |
---|
| 410 | +} |
---|
| 411 | + |
---|
| 412 | +static ssize_t napi_defer_hard_irqs_store(struct device *dev, |
---|
| 413 | + struct device_attribute *attr, |
---|
| 414 | + const char *buf, size_t len) |
---|
| 415 | +{ |
---|
| 416 | + if (!capable(CAP_NET_ADMIN)) |
---|
| 417 | + return -EPERM; |
---|
| 418 | + |
---|
| 419 | + return netdev_store(dev, attr, buf, len, change_napi_defer_hard_irqs); |
---|
| 420 | +} |
---|
| 421 | +NETDEVICE_SHOW_RW(napi_defer_hard_irqs, fmt_dec); |
---|
377 | 422 | |
---|
378 | 423 | static ssize_t ifalias_store(struct device *dev, struct device_attribute *attr, |
---|
379 | 424 | const char *buf, size_t len) |
---|
.. | .. |
---|
443 | 488 | struct device_attribute *attr, |
---|
444 | 489 | const char *buf, size_t len) |
---|
445 | 490 | { |
---|
| 491 | + struct net_device *netdev = to_net_dev(dev); |
---|
| 492 | + |
---|
| 493 | + /* The check is also done in change_proto_down; this helps returning |
---|
| 494 | + * early without hitting the trylock/restart in netdev_store. |
---|
| 495 | + */ |
---|
| 496 | + if (!netdev->netdev_ops->ndo_change_proto_down) |
---|
| 497 | + return -EOPNOTSUPP; |
---|
| 498 | + |
---|
446 | 499 | return netdev_store(dev, attr, buf, len, change_proto_down); |
---|
447 | 500 | } |
---|
448 | 501 | NETDEVICE_SHOW_RW(proto_down, fmt_dec); |
---|
.. | .. |
---|
452 | 505 | { |
---|
453 | 506 | struct net_device *netdev = to_net_dev(dev); |
---|
454 | 507 | ssize_t ret = -EINVAL; |
---|
| 508 | + |
---|
| 509 | + /* The check is also done in dev_get_phys_port_id; this helps returning |
---|
| 510 | + * early without hitting the trylock/restart below. |
---|
| 511 | + */ |
---|
| 512 | + if (!netdev->netdev_ops->ndo_get_phys_port_id) |
---|
| 513 | + return -EOPNOTSUPP; |
---|
455 | 514 | |
---|
456 | 515 | if (!rtnl_trylock()) |
---|
457 | 516 | return restart_syscall(); |
---|
.. | .. |
---|
475 | 534 | struct net_device *netdev = to_net_dev(dev); |
---|
476 | 535 | ssize_t ret = -EINVAL; |
---|
477 | 536 | |
---|
| 537 | + /* The checks are also done in dev_get_phys_port_name; this helps |
---|
| 538 | + * returning early without hitting the trylock/restart below. |
---|
| 539 | + */ |
---|
| 540 | + if (!netdev->netdev_ops->ndo_get_phys_port_name && |
---|
| 541 | + !netdev->netdev_ops->ndo_get_devlink_port) |
---|
| 542 | + return -EOPNOTSUPP; |
---|
| 543 | + |
---|
478 | 544 | if (!rtnl_trylock()) |
---|
479 | 545 | return restart_syscall(); |
---|
480 | 546 | |
---|
.. | .. |
---|
497 | 563 | struct net_device *netdev = to_net_dev(dev); |
---|
498 | 564 | ssize_t ret = -EINVAL; |
---|
499 | 565 | |
---|
| 566 | + /* The checks are also done in dev_get_phys_port_name; this helps |
---|
| 567 | + * returning early without hitting the trylock/restart below. This works |
---|
| 568 | + * because recurse is false when calling dev_get_port_parent_id. |
---|
| 569 | + */ |
---|
| 570 | + if (!netdev->netdev_ops->ndo_get_port_parent_id && |
---|
| 571 | + !netdev->netdev_ops->ndo_get_devlink_port) |
---|
| 572 | + return -EOPNOTSUPP; |
---|
| 573 | + |
---|
500 | 574 | if (!rtnl_trylock()) |
---|
501 | 575 | return restart_syscall(); |
---|
502 | 576 | |
---|
503 | 577 | if (dev_isalive(netdev)) { |
---|
504 | | - struct switchdev_attr attr = { |
---|
505 | | - .orig_dev = netdev, |
---|
506 | | - .id = SWITCHDEV_ATTR_ID_PORT_PARENT_ID, |
---|
507 | | - .flags = SWITCHDEV_F_NO_RECURSE, |
---|
508 | | - }; |
---|
| 578 | + struct netdev_phys_item_id ppid = { }; |
---|
509 | 579 | |
---|
510 | | - ret = switchdev_port_attr_get(netdev, &attr); |
---|
| 580 | + ret = dev_get_port_parent_id(netdev, &ppid, false); |
---|
511 | 581 | if (!ret) |
---|
512 | | - ret = sprintf(buf, "%*phN\n", attr.u.ppid.id_len, |
---|
513 | | - attr.u.ppid.id); |
---|
| 582 | + ret = sprintf(buf, "%*phN\n", ppid.id_len, ppid.id); |
---|
514 | 583 | } |
---|
515 | 584 | rtnl_unlock(); |
---|
516 | 585 | |
---|
.. | .. |
---|
534 | 603 | &dev_attr_speed.attr, |
---|
535 | 604 | &dev_attr_duplex.attr, |
---|
536 | 605 | &dev_attr_dormant.attr, |
---|
| 606 | + &dev_attr_testing.attr, |
---|
537 | 607 | &dev_attr_operstate.attr, |
---|
538 | 608 | &dev_attr_carrier_changes.attr, |
---|
539 | 609 | &dev_attr_ifalias.attr, |
---|
.. | .. |
---|
542 | 612 | &dev_attr_flags.attr, |
---|
543 | 613 | &dev_attr_tx_queue_len.attr, |
---|
544 | 614 | &dev_attr_gro_flush_timeout.attr, |
---|
| 615 | + &dev_attr_napi_defer_hard_irqs.attr, |
---|
545 | 616 | &dev_attr_phys_port_id.attr, |
---|
546 | 617 | &dev_attr_phys_port_name.attr, |
---|
547 | 618 | &dev_attr_phys_switch_id.attr, |
---|
.. | .. |
---|
720 | 791 | { |
---|
721 | 792 | struct rps_map *old_map, *map; |
---|
722 | 793 | cpumask_var_t mask; |
---|
723 | | - int err, cpu, i; |
---|
| 794 | + int err, cpu, i, hk_flags; |
---|
724 | 795 | static DEFINE_MUTEX(rps_map_mutex); |
---|
725 | 796 | |
---|
726 | 797 | if (!capable(CAP_NET_ADMIN)) |
---|
.. | .. |
---|
733 | 804 | if (err) { |
---|
734 | 805 | free_cpumask_var(mask); |
---|
735 | 806 | return err; |
---|
| 807 | + } |
---|
| 808 | + |
---|
| 809 | + if (!cpumask_empty(mask)) { |
---|
| 810 | + hk_flags = HK_FLAG_DOMAIN | HK_FLAG_WQ; |
---|
| 811 | + cpumask_and(mask, mask, housekeeping_cpumask(hk_flags)); |
---|
| 812 | + if (cpumask_empty(mask)) { |
---|
| 813 | + free_cpumask_var(mask); |
---|
| 814 | + return -EINVAL; |
---|
| 815 | + } |
---|
736 | 816 | } |
---|
737 | 817 | |
---|
738 | 818 | map = kzalloc(max_t(unsigned int, |
---|
.. | .. |
---|
760 | 840 | rcu_assign_pointer(queue->rps_map, map); |
---|
761 | 841 | |
---|
762 | 842 | if (map) |
---|
763 | | - static_key_slow_inc(&rps_needed); |
---|
| 843 | + static_branch_inc(&rps_needed); |
---|
764 | 844 | if (old_map) |
---|
765 | | - static_key_slow_dec(&rps_needed); |
---|
| 845 | + static_branch_dec(&rps_needed); |
---|
766 | 846 | |
---|
767 | 847 | mutex_unlock(&rps_map_mutex); |
---|
768 | 848 | |
---|
.. | .. |
---|
869 | 949 | #endif |
---|
870 | 950 | NULL |
---|
871 | 951 | }; |
---|
| 952 | +ATTRIBUTE_GROUPS(rx_queue_default); |
---|
872 | 953 | |
---|
873 | 954 | static void rx_queue_release(struct kobject *kobj) |
---|
874 | 955 | { |
---|
.. | .. |
---|
917 | 998 | static struct kobj_type rx_queue_ktype __ro_after_init = { |
---|
918 | 999 | .sysfs_ops = &rx_queue_sysfs_ops, |
---|
919 | 1000 | .release = rx_queue_release, |
---|
920 | | - .default_attrs = rx_queue_default_attrs, |
---|
| 1001 | + .default_groups = rx_queue_default_groups, |
---|
921 | 1002 | .namespace = rx_queue_namespace, |
---|
922 | 1003 | .get_ownership = rx_queue_get_ownership, |
---|
923 | 1004 | }; |
---|
.. | .. |
---|
953 | 1034 | kobject_put(kobj); |
---|
954 | 1035 | return error; |
---|
955 | 1036 | } |
---|
| 1037 | + |
---|
| 1038 | +static int rx_queue_change_owner(struct net_device *dev, int index, kuid_t kuid, |
---|
| 1039 | + kgid_t kgid) |
---|
| 1040 | +{ |
---|
| 1041 | + struct netdev_rx_queue *queue = dev->_rx + index; |
---|
| 1042 | + struct kobject *kobj = &queue->kobj; |
---|
| 1043 | + int error; |
---|
| 1044 | + |
---|
| 1045 | + error = sysfs_change_owner(kobj, kuid, kgid); |
---|
| 1046 | + if (error) |
---|
| 1047 | + return error; |
---|
| 1048 | + |
---|
| 1049 | + if (dev->sysfs_rx_queue_group) |
---|
| 1050 | + error = sysfs_group_change_owner( |
---|
| 1051 | + kobj, dev->sysfs_rx_queue_group, kuid, kgid); |
---|
| 1052 | + |
---|
| 1053 | + return error; |
---|
| 1054 | +} |
---|
956 | 1055 | #endif /* CONFIG_SYSFS */ |
---|
957 | 1056 | |
---|
958 | 1057 | int |
---|
.. | .. |
---|
982 | 1081 | if (dev->sysfs_rx_queue_group) |
---|
983 | 1082 | sysfs_remove_group(kobj, dev->sysfs_rx_queue_group); |
---|
984 | 1083 | kobject_put(kobj); |
---|
| 1084 | + } |
---|
| 1085 | + |
---|
| 1086 | + return error; |
---|
| 1087 | +#else |
---|
| 1088 | + return 0; |
---|
| 1089 | +#endif |
---|
| 1090 | +} |
---|
| 1091 | + |
---|
| 1092 | +static int net_rx_queue_change_owner(struct net_device *dev, int num, |
---|
| 1093 | + kuid_t kuid, kgid_t kgid) |
---|
| 1094 | +{ |
---|
| 1095 | +#ifdef CONFIG_SYSFS |
---|
| 1096 | + int error = 0; |
---|
| 1097 | + int i; |
---|
| 1098 | + |
---|
| 1099 | +#ifndef CONFIG_RPS |
---|
| 1100 | + if (!dev->sysfs_rx_queue_group) |
---|
| 1101 | + return 0; |
---|
| 1102 | +#endif |
---|
| 1103 | + for (i = 0; i < num; i++) { |
---|
| 1104 | + error = rx_queue_change_owner(dev, i, kuid, kgid); |
---|
| 1105 | + if (error) |
---|
| 1106 | + break; |
---|
985 | 1107 | } |
---|
986 | 1108 | |
---|
987 | 1109 | return error; |
---|
.. | .. |
---|
1085 | 1207 | * belongs to the root device it will be reported with just the |
---|
1086 | 1208 | * traffic class, so just "0" for TC 0 for example. |
---|
1087 | 1209 | */ |
---|
1088 | | - return dev->num_tc < 0 ? sprintf(buf, "%u%d\n", tc, dev->num_tc) : |
---|
1089 | | - sprintf(buf, "%u\n", tc); |
---|
| 1210 | + return dev->num_tc < 0 ? sprintf(buf, "%d%d\n", tc, dev->num_tc) : |
---|
| 1211 | + sprintf(buf, "%d\n", tc); |
---|
1090 | 1212 | } |
---|
1091 | 1213 | |
---|
1092 | 1214 | #ifdef CONFIG_XPS |
---|
.. | .. |
---|
1105 | 1227 | |
---|
1106 | 1228 | if (!capable(CAP_NET_ADMIN)) |
---|
1107 | 1229 | return -EPERM; |
---|
| 1230 | + |
---|
| 1231 | + /* The check is also done later; this helps returning early without |
---|
| 1232 | + * hitting the trylock/restart below. |
---|
| 1233 | + */ |
---|
| 1234 | + if (!dev->netdev_ops->ndo_set_tx_maxrate) |
---|
| 1235 | + return -EOPNOTSUPP; |
---|
1108 | 1236 | |
---|
1109 | 1237 | err = kstrtou32(buf, 10, &rate); |
---|
1110 | 1238 | if (err < 0) |
---|
.. | .. |
---|
1374 | 1502 | goto err_rtnl_unlock; |
---|
1375 | 1503 | } |
---|
1376 | 1504 | } |
---|
1377 | | - mask = kcalloc(BITS_TO_LONGS(dev->num_rx_queues), sizeof(long), |
---|
1378 | | - GFP_KERNEL); |
---|
| 1505 | + mask = bitmap_zalloc(dev->num_rx_queues, GFP_KERNEL); |
---|
1379 | 1506 | if (!mask) { |
---|
1380 | 1507 | ret = -ENOMEM; |
---|
1381 | 1508 | goto err_rtnl_unlock; |
---|
.. | .. |
---|
1408 | 1535 | rtnl_unlock(); |
---|
1409 | 1536 | |
---|
1410 | 1537 | len = bitmap_print_to_pagebuf(false, buf, mask, dev->num_rx_queues); |
---|
1411 | | - kfree(mask); |
---|
| 1538 | + bitmap_free(mask); |
---|
1412 | 1539 | |
---|
1413 | 1540 | return len < PAGE_SIZE ? len : -EINVAL; |
---|
1414 | 1541 | |
---|
.. | .. |
---|
1428 | 1555 | if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) |
---|
1429 | 1556 | return -EPERM; |
---|
1430 | 1557 | |
---|
1431 | | - mask = kcalloc(BITS_TO_LONGS(dev->num_rx_queues), sizeof(long), |
---|
1432 | | - GFP_KERNEL); |
---|
| 1558 | + mask = bitmap_zalloc(dev->num_rx_queues, GFP_KERNEL); |
---|
1433 | 1559 | if (!mask) |
---|
1434 | 1560 | return -ENOMEM; |
---|
1435 | 1561 | |
---|
.. | .. |
---|
1437 | 1563 | |
---|
1438 | 1564 | err = bitmap_parse(buf, len, mask, dev->num_rx_queues); |
---|
1439 | 1565 | if (err) { |
---|
1440 | | - kfree(mask); |
---|
| 1566 | + bitmap_free(mask); |
---|
1441 | 1567 | return err; |
---|
1442 | 1568 | } |
---|
1443 | 1569 | |
---|
.. | .. |
---|
1452 | 1578 | |
---|
1453 | 1579 | rtnl_unlock(); |
---|
1454 | 1580 | |
---|
1455 | | - kfree(mask); |
---|
| 1581 | + bitmap_free(mask); |
---|
1456 | 1582 | return err ? : len; |
---|
1457 | 1583 | } |
---|
1458 | 1584 | |
---|
.. | .. |
---|
1470 | 1596 | #endif |
---|
1471 | 1597 | NULL |
---|
1472 | 1598 | }; |
---|
| 1599 | +ATTRIBUTE_GROUPS(netdev_queue_default); |
---|
1473 | 1600 | |
---|
1474 | 1601 | static void netdev_queue_release(struct kobject *kobj) |
---|
1475 | 1602 | { |
---|
.. | .. |
---|
1502 | 1629 | static struct kobj_type netdev_queue_ktype __ro_after_init = { |
---|
1503 | 1630 | .sysfs_ops = &netdev_queue_sysfs_ops, |
---|
1504 | 1631 | .release = netdev_queue_release, |
---|
1505 | | - .default_attrs = netdev_queue_default_attrs, |
---|
| 1632 | + .default_groups = netdev_queue_default_groups, |
---|
1506 | 1633 | .namespace = netdev_queue_namespace, |
---|
1507 | 1634 | .get_ownership = netdev_queue_get_ownership, |
---|
1508 | 1635 | }; |
---|
.. | .. |
---|
1537 | 1664 | kobject_put(kobj); |
---|
1538 | 1665 | return error; |
---|
1539 | 1666 | } |
---|
| 1667 | + |
---|
| 1668 | +static int tx_queue_change_owner(struct net_device *ndev, int index, |
---|
| 1669 | + kuid_t kuid, kgid_t kgid) |
---|
| 1670 | +{ |
---|
| 1671 | + struct netdev_queue *queue = ndev->_tx + index; |
---|
| 1672 | + struct kobject *kobj = &queue->kobj; |
---|
| 1673 | + int error; |
---|
| 1674 | + |
---|
| 1675 | + error = sysfs_change_owner(kobj, kuid, kgid); |
---|
| 1676 | + if (error) |
---|
| 1677 | + return error; |
---|
| 1678 | + |
---|
| 1679 | +#ifdef CONFIG_BQL |
---|
| 1680 | + error = sysfs_group_change_owner(kobj, &dql_group, kuid, kgid); |
---|
| 1681 | +#endif |
---|
| 1682 | + return error; |
---|
| 1683 | +} |
---|
1540 | 1684 | #endif /* CONFIG_SYSFS */ |
---|
1541 | 1685 | |
---|
1542 | 1686 | int |
---|
.. | .. |
---|
1563 | 1707 | sysfs_remove_group(&queue->kobj, &dql_group); |
---|
1564 | 1708 | #endif |
---|
1565 | 1709 | kobject_put(&queue->kobj); |
---|
| 1710 | + } |
---|
| 1711 | + |
---|
| 1712 | + return error; |
---|
| 1713 | +#else |
---|
| 1714 | + return 0; |
---|
| 1715 | +#endif /* CONFIG_SYSFS */ |
---|
| 1716 | +} |
---|
| 1717 | + |
---|
| 1718 | +static int net_tx_queue_change_owner(struct net_device *dev, int num, |
---|
| 1719 | + kuid_t kuid, kgid_t kgid) |
---|
| 1720 | +{ |
---|
| 1721 | +#ifdef CONFIG_SYSFS |
---|
| 1722 | + int error = 0; |
---|
| 1723 | + int i; |
---|
| 1724 | + |
---|
| 1725 | + for (i = 0; i < num; i++) { |
---|
| 1726 | + error = tx_queue_change_owner(dev, i, kuid, kgid); |
---|
| 1727 | + if (error) |
---|
| 1728 | + break; |
---|
1566 | 1729 | } |
---|
1567 | 1730 | |
---|
1568 | 1731 | return error; |
---|
.. | .. |
---|
1603 | 1766 | kset_unregister(dev->queues_kset); |
---|
1604 | 1767 | #endif |
---|
1605 | 1768 | return error; |
---|
| 1769 | +} |
---|
| 1770 | + |
---|
| 1771 | +static int queue_change_owner(struct net_device *ndev, kuid_t kuid, kgid_t kgid) |
---|
| 1772 | +{ |
---|
| 1773 | + int error = 0, real_rx = 0, real_tx = 0; |
---|
| 1774 | + |
---|
| 1775 | +#ifdef CONFIG_SYSFS |
---|
| 1776 | + if (ndev->queues_kset) { |
---|
| 1777 | + error = sysfs_change_owner(&ndev->queues_kset->kobj, kuid, kgid); |
---|
| 1778 | + if (error) |
---|
| 1779 | + return error; |
---|
| 1780 | + } |
---|
| 1781 | + real_rx = ndev->real_num_rx_queues; |
---|
| 1782 | +#endif |
---|
| 1783 | + real_tx = ndev->real_num_tx_queues; |
---|
| 1784 | + |
---|
| 1785 | + error = net_rx_queue_change_owner(ndev, real_rx, kuid, kgid); |
---|
| 1786 | + if (error) |
---|
| 1787 | + return error; |
---|
| 1788 | + |
---|
| 1789 | + error = net_tx_queue_change_owner(ndev, real_tx, kuid, kgid); |
---|
| 1790 | + if (error) |
---|
| 1791 | + return error; |
---|
| 1792 | + |
---|
| 1793 | + return 0; |
---|
1606 | 1794 | } |
---|
1607 | 1795 | |
---|
1608 | 1796 | static void remove_queue_kobjects(struct net_device *dev) |
---|
.. | .. |
---|
1726 | 1914 | #ifdef CONFIG_OF_NET |
---|
1727 | 1915 | static int of_dev_node_match(struct device *dev, const void *data) |
---|
1728 | 1916 | { |
---|
1729 | | - int ret = 0; |
---|
| 1917 | + for (; dev; dev = dev->parent) { |
---|
| 1918 | + if (dev->of_node == data) |
---|
| 1919 | + return 1; |
---|
| 1920 | + } |
---|
1730 | 1921 | |
---|
1731 | | - if (dev->parent) |
---|
1732 | | - ret = dev->parent->of_node == data; |
---|
1733 | | - |
---|
1734 | | - return ret == 0 ? dev->of_node == data : ret; |
---|
| 1922 | + return 0; |
---|
1735 | 1923 | } |
---|
1736 | 1924 | |
---|
1737 | 1925 | /* |
---|
.. | .. |
---|
1821 | 2009 | return error; |
---|
1822 | 2010 | } |
---|
1823 | 2011 | |
---|
| 2012 | +/* Change owner for sysfs entries when moving network devices across network |
---|
| 2013 | + * namespaces owned by different user namespaces. |
---|
| 2014 | + */ |
---|
| 2015 | +int netdev_change_owner(struct net_device *ndev, const struct net *net_old, |
---|
| 2016 | + const struct net *net_new) |
---|
| 2017 | +{ |
---|
| 2018 | + kuid_t old_uid = GLOBAL_ROOT_UID, new_uid = GLOBAL_ROOT_UID; |
---|
| 2019 | + kgid_t old_gid = GLOBAL_ROOT_GID, new_gid = GLOBAL_ROOT_GID; |
---|
| 2020 | + struct device *dev = &ndev->dev; |
---|
| 2021 | + int error; |
---|
| 2022 | + |
---|
| 2023 | + net_ns_get_ownership(net_old, &old_uid, &old_gid); |
---|
| 2024 | + net_ns_get_ownership(net_new, &new_uid, &new_gid); |
---|
| 2025 | + |
---|
| 2026 | + /* The network namespace was changed but the owning user namespace is |
---|
| 2027 | + * identical so there's no need to change the owner of sysfs entries. |
---|
| 2028 | + */ |
---|
| 2029 | + if (uid_eq(old_uid, new_uid) && gid_eq(old_gid, new_gid)) |
---|
| 2030 | + return 0; |
---|
| 2031 | + |
---|
| 2032 | + error = device_change_owner(dev, new_uid, new_gid); |
---|
| 2033 | + if (error) |
---|
| 2034 | + return error; |
---|
| 2035 | + |
---|
| 2036 | + error = queue_change_owner(ndev, new_uid, new_gid); |
---|
| 2037 | + if (error) |
---|
| 2038 | + return error; |
---|
| 2039 | + |
---|
| 2040 | + return 0; |
---|
| 2041 | +} |
---|
| 2042 | + |
---|
1824 | 2043 | int netdev_class_create_file_ns(const struct class_attribute *class_attr, |
---|
1825 | 2044 | const void *ns) |
---|
1826 | 2045 | { |
---|