[PATCH net-next 3/4] netdev: avoid skipping objects on race with device disappearance
From: Jakub Kicinski <kuba@kernel.org>
Date: 2026-06-09 19:08:11
Subsystem:
networking [general], the rest · Maintainers:
"David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
If the currently dumped device disappears while we were mid-dump we will get the next device without resetting the sub-object ID. This is quite unlikely, it was reported by an AI tool not a real user. Let's fix it for better dump consistency. Signed-off-by: Jakub Kicinski <kuba@kernel.org> --- net/core/netdev-genl.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/net/core/netdev-genl.c b/net/core/netdev-genl.c
index d35af460e886..18046ad0f883 100644
--- a/net/core/netdev-genl.c
+++ b/net/core/netdev-genl.c@@ -310,11 +310,14 @@ int netdev_nl_napi_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) err = -ENODEV; } } else { + unsigned long start_ifindex = ctx->ifindex; + for_each_netdev_lock_scoped(net, netdev, ctx->ifindex) { + if (ctx->ifindex != start_ifindex) + ctx->napi_id = 0; err = netdev_nl_napi_dump_one(netdev, skb, info, ctx); if (err < 0) break; - ctx->napi_id = 0; } }
@@ -634,13 +637,17 @@ int netdev_nl_queue_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb) err = -ENODEV; } } else { + unsigned long start_ifindex = ctx->ifindex; + for_each_netdev_lock_ops_compat_scoped(net, netdev, ctx->ifindex) { + if (ctx->ifindex != start_ifindex) { + ctx->rxq_idx = 0; + ctx->txq_idx = 0; + } err = netdev_nl_queue_dump_one(netdev, skb, info, ctx); if (err < 0) break; - ctx->rxq_idx = 0; - ctx->txq_idx = 0; } }
@@ -786,8 +793,6 @@ netdev_nl_stats_by_queue(struct net_device *netdev, struct sk_buff *rsp, ctx->txq_idx = ++i; } - ctx->rxq_idx = 0; - ctx->txq_idx = 0; return 0; }
@@ -902,6 +907,7 @@ int netdev_nl_qstats_get_dumpit(struct sk_buff *skb, struct netdev_nl_dump_ctx *ctx = netdev_dump_ctx(cb); const struct genl_info *info = genl_info_dump(cb); struct net *net = sock_net(skb->sk); + unsigned long start_ifindex; struct net_device *netdev; unsigned int ifindex; unsigned int scope;
@@ -934,7 +940,13 @@ int netdev_nl_qstats_get_dumpit(struct sk_buff *skb, return err; } + start_ifindex = ctx->ifindex; + for_each_netdev_lock_ops_compat_scoped(net, netdev, ctx->ifindex) { + if (ctx->ifindex != start_ifindex) { + ctx->rxq_idx = 0; + ctx->txq_idx = 0; + } err = netdev_nl_qstats_get_dump_one(netdev, scope, skb, info, ctx); if (err < 0)
--
2.54.0