123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- From: Wei Wang <[email protected]>
- Date: Mon, 8 Feb 2021 11:34:10 -0800
- Subject: [PATCH] net: add sysfs attribute to control napi threaded mode
- This patch adds a new sysfs attribute to the network device class.
- Said attribute provides a per-device control to enable/disable the
- threaded mode for all the napi instances of the given network device,
- without the need for a device up/down.
- User sets it to 1 or 0 to enable or disable threaded mode.
- Note: when switching between threaded and the current softirq based mode
- for a napi instance, it will not immediately take effect if the napi is
- currently being polled. The mode switch will happen for the next time
- napi_schedule() is called.
- Co-developed-by: Paolo Abeni <[email protected]>
- Signed-off-by: Paolo Abeni <[email protected]>
- Co-developed-by: Hannes Frederic Sowa <[email protected]>
- Signed-off-by: Hannes Frederic Sowa <[email protected]>
- Co-developed-by: Felix Fietkau <[email protected]>
- Signed-off-by: Felix Fietkau <[email protected]>
- Signed-off-by: Wei Wang <[email protected]>
- Reviewed-by: Alexander Duyck <[email protected]>
- Signed-off-by: David S. Miller <[email protected]>
- ---
- --- a/Documentation/ABI/testing/sysfs-class-net
- +++ b/Documentation/ABI/testing/sysfs-class-net
- @@ -337,3 +337,18 @@ Contact: [email protected]
- Description:
- 32-bit unsigned integer counting the number of times the link has
- been down
- +
- +What: /sys/class/net/<iface>/threaded
- +Date: Jan 2021
- +KernelVersion: 5.12
- +Contact: [email protected]
- +Description:
- + Boolean value to control the threaded mode per device. User could
- + set this value to enable/disable threaded mode for all napi
- + belonging to this device, without the need to do device up/down.
- +
- + Possible values:
- + == ==================================
- + 0 threaded mode disabled for this dev
- + 1 threaded mode enabled for this dev
- + == ==================================
- --- a/include/linux/netdevice.h
- +++ b/include/linux/netdevice.h
- @@ -491,6 +491,8 @@ static inline bool napi_complete(struct
- return napi_complete_done(n, 0);
- }
-
- +int dev_set_threaded(struct net_device *dev, bool threaded);
- +
- /**
- * napi_disable - prevent NAPI from scheduling
- * @n: NAPI context
- --- a/net/core/dev.c
- +++ b/net/core/dev.c
- @@ -4280,8 +4280,9 @@ static inline void ____napi_schedule(str
-
- if (test_bit(NAPI_STATE_THREADED, &napi->state)) {
- /* Paired with smp_mb__before_atomic() in
- - * napi_enable(). Use READ_ONCE() to guarantee
- - * a complete read on napi->thread. Only call
- + * napi_enable()/dev_set_threaded().
- + * Use READ_ONCE() to guarantee a complete
- + * read on napi->thread. Only call
- * wake_up_process() when it's not NULL.
- */
- thread = READ_ONCE(napi->thread);
- @@ -6716,6 +6717,49 @@ static void init_gro_hash(struct napi_st
- napi->gro_bitmask = 0;
- }
-
- +int dev_set_threaded(struct net_device *dev, bool threaded)
- +{
- + struct napi_struct *napi;
- + int err = 0;
- +
- + if (dev->threaded == threaded)
- + return 0;
- +
- + if (threaded) {
- + list_for_each_entry(napi, &dev->napi_list, dev_list) {
- + if (!napi->thread) {
- + err = napi_kthread_create(napi);
- + if (err) {
- + threaded = false;
- + break;
- + }
- + }
- + }
- + }
- +
- + dev->threaded = threaded;
- +
- + /* Make sure kthread is created before THREADED bit
- + * is set.
- + */
- + smp_mb__before_atomic();
- +
- + /* Setting/unsetting threaded mode on a napi might not immediately
- + * take effect, if the current napi instance is actively being
- + * polled. In this case, the switch between threaded mode and
- + * softirq mode will happen in the next round of napi_schedule().
- + * This should not cause hiccups/stalls to the live traffic.
- + */
- + list_for_each_entry(napi, &dev->napi_list, dev_list) {
- + if (threaded)
- + set_bit(NAPI_STATE_THREADED, &napi->state);
- + else
- + clear_bit(NAPI_STATE_THREADED, &napi->state);
- + }
- +
- + return err;
- +}
- +
- void netif_napi_add(struct net_device *dev, struct napi_struct *napi,
- int (*poll)(struct napi_struct *, int), int weight)
- {
- --- a/net/core/net-sysfs.c
- +++ b/net/core/net-sysfs.c
- @@ -538,6 +538,45 @@ static ssize_t phys_switch_id_show(struc
- }
- static DEVICE_ATTR_RO(phys_switch_id);
-
- +static ssize_t threaded_show(struct device *dev,
- + struct device_attribute *attr, char *buf)
- +{
- + struct net_device *netdev = to_net_dev(dev);
- + ssize_t ret = -EINVAL;
- +
- + if (!rtnl_trylock())
- + return restart_syscall();
- +
- + if (dev_isalive(netdev))
- + ret = sprintf(buf, fmt_dec, netdev->threaded);
- +
- + rtnl_unlock();
- + return ret;
- +}
- +
- +static int modify_napi_threaded(struct net_device *dev, unsigned long val)
- +{
- + int ret;
- +
- + if (list_empty(&dev->napi_list))
- + return -EOPNOTSUPP;
- +
- + if (val != 0 && val != 1)
- + return -EOPNOTSUPP;
- +
- + ret = dev_set_threaded(dev, val);
- +
- + return ret;
- +}
- +
- +static ssize_t threaded_store(struct device *dev,
- + struct device_attribute *attr,
- + const char *buf, size_t len)
- +{
- + return netdev_store(dev, attr, buf, len, modify_napi_threaded);
- +}
- +static DEVICE_ATTR_RW(threaded);
- +
- static struct attribute *net_class_attrs[] __ro_after_init = {
- &dev_attr_netdev_group.attr,
- &dev_attr_type.attr,
- @@ -570,6 +609,7 @@ static struct attribute *net_class_attrs
- &dev_attr_proto_down.attr,
- &dev_attr_carrier_up_count.attr,
- &dev_attr_carrier_down_count.attr,
- + &dev_attr_threaded.attr,
- NULL,
- };
- ATTRIBUTE_GROUPS(net_class);
|