Linux 6.11-rc1
[linux-2.6-microblaze.git] / net / core / net-sysfs.c
index a09d507..0e2084c 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/of_net.h>
 #include <linux/cpu.h>
 #include <net/netdev_rx_queue.h>
+#include <net/rps.h>
 
 #include "dev.h"
 #include "net-sysfs.h"
@@ -34,10 +35,10 @@ static const char fmt_dec[] = "%d\n";
 static const char fmt_ulong[] = "%lu\n";
 static const char fmt_u64[] = "%llu\n";
 
-/* Caller holds RTNL or dev_base_lock */
+/* Caller holds RTNL or RCU */
 static inline int dev_isalive(const struct net_device *dev)
 {
-       return dev->reg_state <= NETREG_REGISTERED;
+       return READ_ONCE(dev->reg_state) <= NETREG_REGISTERED;
 }
 
 /* use same locking rules as GIF* ioctl's */
@@ -48,10 +49,10 @@ static ssize_t netdev_show(const struct device *dev,
        struct net_device *ndev = to_net_dev(dev);
        ssize_t ret = -EINVAL;
 
-       read_lock(&dev_base_lock);
+       rcu_read_lock();
        if (dev_isalive(ndev))
                ret = (*format)(ndev, buf);
-       read_unlock(&dev_base_lock);
+       rcu_read_unlock();
 
        return ret;
 }
@@ -60,7 +61,7 @@ static ssize_t netdev_show(const struct device *dev,
 #define NETDEVICE_SHOW(field, format_string)                           \
 static ssize_t format_##field(const struct net_device *dev, char *buf) \
 {                                                                      \
-       return sysfs_emit(buf, format_string, dev->field);              \
+       return sysfs_emit(buf, format_string, READ_ONCE(dev->field));           \
 }                                                                      \
 static ssize_t field##_show(struct device *dev,                                \
                            struct device_attribute *attr, char *buf)   \
@@ -125,7 +126,7 @@ static DEVICE_ATTR_RO(iflink);
 
 static ssize_t format_name_assign_type(const struct net_device *dev, char *buf)
 {
-       return sysfs_emit(buf, fmt_dec, dev->name_assign_type);
+       return sysfs_emit(buf, fmt_dec, READ_ONCE(dev->name_assign_type));
 }
 
 static ssize_t name_assign_type_show(struct device *dev,
@@ -135,24 +136,28 @@ static ssize_t name_assign_type_show(struct device *dev,
        struct net_device *ndev = to_net_dev(dev);
        ssize_t ret = -EINVAL;
 
-       if (ndev->name_assign_type != NET_NAME_UNKNOWN)
+       if (READ_ONCE(ndev->name_assign_type) != NET_NAME_UNKNOWN)
                ret = netdev_show(dev, attr, buf, format_name_assign_type);
 
        return ret;
 }
 static DEVICE_ATTR_RO(name_assign_type);
 
-/* use same locking rules as GIFHWADDR ioctl's */
+/* use same locking rules as GIFHWADDR ioctl's (dev_get_mac_address()) */
 static ssize_t address_show(struct device *dev, struct device_attribute *attr,
                            char *buf)
 {
        struct net_device *ndev = to_net_dev(dev);
        ssize_t ret = -EINVAL;
 
-       read_lock(&dev_base_lock);
+       down_read(&dev_addr_sem);
+
+       rcu_read_lock();
        if (dev_isalive(ndev))
                ret = sysfs_format_mac(buf, ndev->dev_addr, ndev->addr_len);
-       read_unlock(&dev_base_lock);
+       rcu_read_unlock();
+
+       up_read(&dev_addr_sem);
        return ret;
 }
 static DEVICE_ATTR_RO(address);
@@ -161,10 +166,13 @@ static ssize_t broadcast_show(struct device *dev,
                              struct device_attribute *attr, char *buf)
 {
        struct net_device *ndev = to_net_dev(dev);
+       int ret = -EINVAL;
 
+       rcu_read_lock();
        if (dev_isalive(ndev))
-               return sysfs_format_mac(buf, ndev->broadcast, ndev->addr_len);
-       return -EINVAL;
+               ret = sysfs_format_mac(buf, ndev->broadcast, ndev->addr_len);
+       rcu_read_unlock();
+       return ret;
 }
 static DEVICE_ATTR_RO(broadcast);
 
@@ -318,11 +326,9 @@ static ssize_t operstate_show(struct device *dev,
        const struct net_device *netdev = to_net_dev(dev);
        unsigned char operstate;
 
-       read_lock(&dev_base_lock);
-       operstate = netdev->operstate;
+       operstate = READ_ONCE(netdev->operstate);
        if (!netif_running(netdev))
                operstate = IF_OPER_DOWN;
-       read_unlock(&dev_base_lock);
 
        if (operstate >= ARRAY_SIZE(operstates))
                return -EINVAL; /* should not happen */
@@ -599,13 +605,13 @@ static ssize_t threaded_show(struct device *dev,
        struct net_device *netdev = to_net_dev(dev);
        ssize_t ret = -EINVAL;
 
-       if (!rtnl_trylock())
-               return restart_syscall();
+       rcu_read_lock();
 
        if (dev_isalive(netdev))
-               ret = sysfs_emit(buf, fmt_dec, netdev->threaded);
+               ret = sysfs_emit(buf, fmt_dec, READ_ONCE(netdev->threaded));
+
+       rcu_read_unlock();
 
-       rtnl_unlock();
        return ret;
 }
 
@@ -680,14 +686,14 @@ static ssize_t netstat_show(const struct device *d,
        WARN_ON(offset > sizeof(struct rtnl_link_stats64) ||
                offset % sizeof(u64) != 0);
 
-       read_lock(&dev_base_lock);
+       rcu_read_lock();
        if (dev_isalive(dev)) {
                struct rtnl_link_stats64 temp;
                const struct rtnl_link_stats64 *stats = dev_get_stats(dev, &temp);
 
                ret = sysfs_emit(buf, fmt_u64, *(u64 *)(((u8 *)stats) + offset));
        }
-       read_unlock(&dev_base_lock);
+       rcu_read_unlock();
        return ret;
 }
 
@@ -1409,6 +1415,65 @@ static struct netdev_queue_attribute bql_hold_time_attribute __ro_after_init
        = __ATTR(hold_time, 0644,
                 bql_show_hold_time, bql_set_hold_time);
 
+static ssize_t bql_show_stall_thrs(struct netdev_queue *queue, char *buf)
+{
+       struct dql *dql = &queue->dql;
+
+       return sysfs_emit(buf, "%u\n", jiffies_to_msecs(dql->stall_thrs));
+}
+
+static ssize_t bql_set_stall_thrs(struct netdev_queue *queue,
+                                 const char *buf, size_t len)
+{
+       struct dql *dql = &queue->dql;
+       unsigned int value;
+       int err;
+
+       err = kstrtouint(buf, 10, &value);
+       if (err < 0)
+               return err;
+
+       value = msecs_to_jiffies(value);
+       if (value && (value < 4 || value > 4 / 2 * BITS_PER_LONG))
+               return -ERANGE;
+
+       if (!dql->stall_thrs && value)
+               dql->last_reap = jiffies;
+       /* Force last_reap to be live */
+       smp_wmb();
+       dql->stall_thrs = value;
+
+       return len;
+}
+
+static struct netdev_queue_attribute bql_stall_thrs_attribute __ro_after_init =
+       __ATTR(stall_thrs, 0644, bql_show_stall_thrs, bql_set_stall_thrs);
+
+static ssize_t bql_show_stall_max(struct netdev_queue *queue, char *buf)
+{
+       return sysfs_emit(buf, "%u\n", READ_ONCE(queue->dql.stall_max));
+}
+
+static ssize_t bql_set_stall_max(struct netdev_queue *queue,
+                                const char *buf, size_t len)
+{
+       WRITE_ONCE(queue->dql.stall_max, 0);
+       return len;
+}
+
+static struct netdev_queue_attribute bql_stall_max_attribute __ro_after_init =
+       __ATTR(stall_max, 0644, bql_show_stall_max, bql_set_stall_max);
+
+static ssize_t bql_show_stall_cnt(struct netdev_queue *queue, char *buf)
+{
+       struct dql *dql = &queue->dql;
+
+       return sysfs_emit(buf, "%lu\n", dql->stall_cnt);
+}
+
+static struct netdev_queue_attribute bql_stall_cnt_attribute __ro_after_init =
+       __ATTR(stall_cnt, 0444, bql_show_stall_cnt, NULL);
+
 static ssize_t bql_show_inflight(struct netdev_queue *queue,
                                 char *buf)
 {
@@ -1447,6 +1512,9 @@ static struct attribute *dql_attrs[] __ro_after_init = {
        &bql_limit_min_attribute.attr,
        &bql_hold_time_attribute.attr,
        &bql_inflight_attribute.attr,
+       &bql_stall_thrs_attribute.attr,
+       &bql_stall_cnt_attribute.attr,
+       &bql_stall_max_attribute.attr,
        NULL
 };
 
@@ -1454,6 +1522,9 @@ static const struct attribute_group dql_group = {
        .name  = "byte_queue_limits",
        .attrs  = dql_attrs,
 };
+#else
+/* Fake declaration, all the code using it should be dead */
+extern const struct attribute_group dql_group;
 #endif /* CONFIG_BQL */
 
 #ifdef CONFIG_XPS
@@ -1691,6 +1762,15 @@ static const struct kobj_type netdev_queue_ktype = {
        .get_ownership = netdev_queue_get_ownership,
 };
 
+static bool netdev_uses_bql(const struct net_device *dev)
+{
+       if (dev->features & NETIF_F_LLTX ||
+           dev->priv_flags & IFF_NO_QUEUE)
+               return false;
+
+       return IS_ENABLED(CONFIG_BQL);
+}
+
 static int netdev_queue_add_kobject(struct net_device *dev, int index)
 {
        struct netdev_queue *queue = dev->_tx + index;
@@ -1708,11 +1788,11 @@ static int netdev_queue_add_kobject(struct net_device *dev, int index)
        if (error)
                goto err;
 
-#ifdef CONFIG_BQL
-       error = sysfs_create_group(kobj, &dql_group);
-       if (error)
-               goto err;
-#endif
+       if (netdev_uses_bql(dev)) {
+               error = sysfs_create_group(kobj, &dql_group);
+               if (error)
+                       goto err;
+       }
 
        kobject_uevent(kobj, KOBJ_ADD);
        return 0;
@@ -1733,9 +1813,9 @@ static int tx_queue_change_owner(struct net_device *ndev, int index,
        if (error)
                return error;
 
-#ifdef CONFIG_BQL
-       error = sysfs_group_change_owner(kobj, &dql_group, kuid, kgid);
-#endif
+       if (netdev_uses_bql(ndev))
+               error = sysfs_group_change_owner(kobj, &dql_group, kuid, kgid);
+
        return error;
 }
 #endif /* CONFIG_SYSFS */
@@ -1767,9 +1847,10 @@ netdev_queue_update_kobjects(struct net_device *dev, int old_num, int new_num)
 
                if (!refcount_read(&dev_net(dev)->ns.count))
                        queue->kobj.uevent_suppress = 1;
-#ifdef CONFIG_BQL
-               sysfs_remove_group(&queue->kobj, &dql_group);
-#endif
+
+               if (netdev_uses_bql(dev))
+                       sysfs_remove_group(&queue->kobj, &dql_group);
+
                kobject_put(&queue->kobj);
        }
 
@@ -1947,7 +2028,7 @@ static void netdev_release(struct device *d)
         * device is dead and about to be freed.
         */
        kfree(rcu_access_pointer(dev->ifalias));
-       netdev_freemem(dev);
+       kvfree(dev);
 }
 
 static const void *net_namespace(const struct device *d)
@@ -1965,7 +2046,7 @@ static void net_get_ownership(const struct device *d, kuid_t *uid, kgid_t *gid)
        net_ns_get_ownership(net, uid, gid);
 }
 
-static struct class net_class __ro_after_init = {
+static const struct class net_class = {
        .name = "net",
        .dev_release = netdev_release,
        .dev_groups = net_class_groups,