The new lidx argument allows the current dumping device to save a private state counter which would enable it to continue dumping from where it left off.
Signed-off-by: Nikolay Aleksandrov <niko...@cumulusnetworks.com> --- net/core/rtnetlink.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 5ec059d52823..aeb2fa9b1cda 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -3446,11 +3446,13 @@ out: static int rtnl_fill_statsinfo(struct sk_buff *skb, struct net_device *dev, int type, u32 pid, u32 seq, u32 change, - unsigned int flags, unsigned int filter_mask) + unsigned int flags, unsigned int filter_mask, + int *lidx) { struct if_stats_msg *ifsm; struct nlmsghdr *nlh; struct nlattr *attr; + int s_lidx = *lidx; ASSERT_RTNL(); @@ -3480,7 +3482,11 @@ static int rtnl_fill_statsinfo(struct sk_buff *skb, struct net_device *dev, return 0; nla_put_failure: - nlmsg_cancel(skb, nlh); + /* If we haven't made progress, it's a real error */ + if (s_lidx == *lidx) + nlmsg_cancel(skb, nlh); + else + nlmsg_end(skb, nlh); return -EMSGSIZE; } @@ -3507,6 +3513,7 @@ static int rtnl_stats_get(struct sk_buff *skb, struct nlmsghdr *nlh) struct net_device *dev = NULL; struct sk_buff *nskb; u32 filter_mask; + int lidx = 0; int err; ifsm = nlmsg_data(nlh); @@ -3528,7 +3535,7 @@ static int rtnl_stats_get(struct sk_buff *skb, struct nlmsghdr *nlh) err = rtnl_fill_statsinfo(nskb, dev, RTM_NEWSTATS, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0, - 0, filter_mask); + 0, filter_mask, &lidx); if (err < 0) { /* -EMSGSIZE implies BUG in if_nlmsg_stats_size */ WARN_ON(err == -EMSGSIZE); @@ -3545,7 +3552,7 @@ static int rtnl_stats_dump(struct sk_buff *skb, struct netlink_callback *cb) struct net *net = sock_net(skb->sk); struct if_stats_msg *ifsm; int h, s_h; - int idx = 0, s_idx; + int idx = 0, s_idx, s_lidx; struct net_device *dev; struct hlist_head *head; unsigned int flags = NLM_F_MULTI; @@ -3554,6 +3561,7 @@ static int rtnl_stats_dump(struct sk_buff *skb, struct netlink_callback *cb) s_h = cb->args[0]; s_idx = cb->args[1]; + s_lidx = cb->args[2]; cb->seq = net->dev_base_seq; @@ -3571,7 +3579,7 @@ static int rtnl_stats_dump(struct sk_buff *skb, struct netlink_callback *cb) err = rtnl_fill_statsinfo(skb, dev, RTM_NEWSTATS, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, 0, - flags, filter_mask); + flags, filter_mask, &s_lidx); /* If we ran out of room on the first message, * we're in trouble */ @@ -3579,13 +3587,14 @@ static int rtnl_stats_dump(struct sk_buff *skb, struct netlink_callback *cb) if (err < 0) goto out; - + s_lidx = 0; nl_dump_check_consistent(cb, nlmsg_hdr(skb)); cont: idx++; } } out: + cb->args[2] = s_lidx; cb->args[1] = idx; cb->args[0] = h; -- 2.4.11