Skip to content

Commit ce7b149

Browse files
committed
netdev: depend on netdev->lock for qstats in ops locked drivers
We mostly needed rtnl_lock in qstat to make sure the queue count is stable while we work. For "ops locked" drivers the instance lock protects the queue count, so we don't have to take rtnl_lock. For currently ops-locked drivers: netdevsim and bnxt need the protection from netdev going down while we dump, which instance lock provides. gve doesn't care. Reviewed-by: Joe Damato <jdamato@fastly.com> Acked-by: Stanislav Fomichev <sdf@fomichev.me> Link: https://patch.msgid.link/20250408195956.412733-9-kuba@kernel.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
1 parent 87eba40 commit ce7b149

File tree

3 files changed

+26
-13
lines changed

3 files changed

+26
-13
lines changed

Documentation/networking/netdevices.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,12 @@ Similarly to ``ndos`` the instance lock is only held for select drivers.
356356
For "ops locked" drivers all ethtool ops without exceptions should
357357
be called under the instance lock.
358358

359+
struct netdev_stat_ops
360+
----------------------
361+
362+
"qstat" ops are invoked under the instance lock for "ops locked" drivers,
363+
and under rtnl_lock for all other drivers.
364+
359365
struct net_shaper_ops
360366
---------------------
361367

include/net/netdev_queues.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,9 +85,11 @@ struct netdev_queue_stats_tx {
8585
* for some of the events is not maintained, and reliable "total" cannot
8686
* be provided).
8787
*
88+
* Ops are called under the instance lock if netdev_need_ops_lock()
89+
* returns true, otherwise under rtnl_lock.
8890
* Device drivers can assume that when collecting total device stats,
8991
* the @get_base_stats and subsequent per-queue calls are performed
90-
* "atomically" (without releasing the rtnl_lock).
92+
* "atomically" (without releasing the relevant lock).
9193
*
9294
* Device drivers are encouraged to reset the per-queue statistics when
9395
* number of queues change. This is because the primary use case for

net/core/netdev-genl.c

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -795,26 +795,31 @@ int netdev_nl_qstats_get_dumpit(struct sk_buff *skb,
795795
if (info->attrs[NETDEV_A_QSTATS_IFINDEX])
796796
ifindex = nla_get_u32(info->attrs[NETDEV_A_QSTATS_IFINDEX]);
797797

798-
rtnl_lock();
799798
if (ifindex) {
800-
netdev = __dev_get_by_index(net, ifindex);
801-
if (netdev && netdev->stat_ops) {
802-
err = netdev_nl_qstats_get_dump_one(netdev, scope, skb,
803-
info, ctx);
804-
} else {
799+
netdev = netdev_get_by_index_lock_ops_compat(net, ifindex);
800+
if (!netdev) {
805801
NL_SET_BAD_ATTR(info->extack,
806802
info->attrs[NETDEV_A_QSTATS_IFINDEX]);
807-
err = netdev ? -EOPNOTSUPP : -ENODEV;
803+
return -ENODEV;
808804
}
809-
} else {
810-
for_each_netdev_dump(net, netdev, ctx->ifindex) {
805+
if (netdev->stat_ops) {
811806
err = netdev_nl_qstats_get_dump_one(netdev, scope, skb,
812807
info, ctx);
813-
if (err < 0)
814-
break;
808+
} else {
809+
NL_SET_BAD_ATTR(info->extack,
810+
info->attrs[NETDEV_A_QSTATS_IFINDEX]);
811+
err = -EOPNOTSUPP;
815812
}
813+
netdev_unlock_ops_compat(netdev);
814+
return err;
815+
}
816+
817+
for_each_netdev_lock_ops_compat_scoped(net, netdev, ctx->ifindex) {
818+
err = netdev_nl_qstats_get_dump_one(netdev, scope, skb,
819+
info, ctx);
820+
if (err < 0)
821+
break;
816822
}
817-
rtnl_unlock();
818823

819824
return err;
820825
}

0 commit comments

Comments
 (0)