Use for_each_netdev_dump() instead of for_each_netdev(). This is more scalable, and will ease RCU conversion. This also offer better behavior when other threads are adding or deleting netevices concurrently. This enables dumping qdiscs for a single device at user space request in the following patch. Signed-off-by: Eric Dumazet --- net/sched/sch_api.c | 62 ++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 32 deletions(-) diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 029e0f87ea9c61cc757432a07a6af92c90c551ef..641f5a01aca167dd230173078f2db5801dca58da 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -1877,18 +1877,18 @@ static int tc_dump_qdisc_root(struct Qdisc *root, struct sk_buff *skb, static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb) { - struct net *net = sock_net(skb->sk); - int idx, q_idx; - int s_idx, s_q_idx; - struct net_device *dev; const struct nlmsghdr *nlh = cb->nlh; + struct net *net = sock_net(skb->sk); struct nlattr *tca[TCA_MAX + 1]; + struct { + unsigned long ifindex; + int q_idx; + } *ctx = (void *)cb->ctx; + unsigned long s_ifindex; + struct net_device *dev; + int s_q_idx, q_idx; int err; - s_idx = cb->args[0]; - s_q_idx = q_idx = cb->args[1]; - - idx = 0; ASSERT_RTNL(); err = nlmsg_parse_deprecated(nlh, sizeof(struct tcmsg), tca, TCA_MAX, @@ -1896,42 +1896,40 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb) if (err < 0) return err; - for_each_netdev(net, dev) { + s_ifindex = ctx->ifindex; + s_q_idx = ctx->q_idx; + + for_each_netdev_dump(net, dev, ctx->ifindex) { struct netdev_queue *dev_queue; + struct Qdisc *q; - if (idx < s_idx) - goto cont; - if (idx > s_idx) - s_q_idx = 0; q_idx = 0; netdev_lock_ops(dev); - if (tc_dump_qdisc_root(rtnl_dereference(dev->qdisc), - skb, cb, &q_idx, s_q_idx, - true, tca[TCA_DUMP_INVISIBLE]) < 0) { - netdev_unlock_ops(dev); - goto done; - } + q = rtnl_dereference(dev->qdisc); + err = tc_dump_qdisc_root(q, skb, cb, &q_idx, s_q_idx, + true, tca[TCA_DUMP_INVISIBLE]); + if (err < 0) + goto error_unlock; dev_queue = dev_ingress_queue(dev); - if (dev_queue && - tc_dump_qdisc_root(rtnl_dereference(dev_queue->qdisc_sleeping), - skb, cb, &q_idx, s_q_idx, false, - tca[TCA_DUMP_INVISIBLE]) < 0) { - netdev_unlock_ops(dev); - goto done; + if (dev_queue) { + q = rtnl_dereference(dev_queue->qdisc_sleeping); + err = tc_dump_qdisc_root(q, skb, cb, &q_idx, s_q_idx, + false, tca[TCA_DUMP_INVISIBLE]); + if (err < 0) + goto error_unlock; } netdev_unlock_ops(dev); - -cont: - idx++; + s_q_idx = 0; } + return skb->len; -done: - cb->args[0] = idx; - cb->args[1] = q_idx; +error_unlock: + netdev_unlock_ops(dev); + ctx->q_idx = q_idx; - return skb->len; + return err; } -- 2.54.0.545.g6539524ca2-goog