genetlink: fit NLMSG_DONE into same read() as families
authorJakub Kicinski <kuba@kernel.org>
Sun, 3 Mar 2024 05:24:08 +0000 (21:24 -0800)
committerDavid S. Miller <davem@davemloft.net>
Wed, 6 Mar 2024 08:07:45 +0000 (08:07 +0000)
Make sure ctrl_fill_info() returns sensible error codes and
propagate them out to netlink core. Let netlink core decide
when to return skb->len and when to treat the exit as an
error. Netlink core does better job at it, if we always
return skb->len the core doesn't know when we're done
dumping and NLMSG_DONE ends up in a separate read().

Reviewed-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/netlink/genetlink.c

index 50ec599a5cff57a9f138c8b6fbd966e63a64e275..3b7666944b11c12f605e48c13a932533f8c6c85d 100644 (file)
@@ -1232,7 +1232,7 @@ static int ctrl_fill_info(const struct genl_family *family, u32 portid, u32 seq,
 
        hdr = genlmsg_put(skb, portid, seq, &genl_ctrl, flags, cmd);
        if (hdr == NULL)
-               return -1;
+               return -EMSGSIZE;
 
        if (nla_put_string(skb, CTRL_ATTR_FAMILY_NAME, family->name) ||
            nla_put_u16(skb, CTRL_ATTR_FAMILY_ID, family->id) ||
@@ -1355,6 +1355,7 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb)
        struct net *net = sock_net(skb->sk);
        int fams_to_skip = cb->args[0];
        unsigned int id;
+       int err = 0;
 
        idr_for_each_entry(&genl_fam_idr, rt, id) {
                if (!rt->netnsok && !net_eq(net, &init_net))
@@ -1363,16 +1364,17 @@ static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb)
                if (n++ < fams_to_skip)
                        continue;
 
-               if (ctrl_fill_info(rt, NETLINK_CB(cb->skb).portid,
-                                  cb->nlh->nlmsg_seq, NLM_F_MULTI,
-                                  skb, CTRL_CMD_NEWFAMILY) < 0) {
+               err = ctrl_fill_info(rt, NETLINK_CB(cb->skb).portid,
+                                    cb->nlh->nlmsg_seq, NLM_F_MULTI,
+                                    skb, CTRL_CMD_NEWFAMILY);
+               if (err) {
                        n--;
                        break;
                }
        }
 
        cb->args[0] = n;
-       return skb->len;
+       return err;
 }
 
 static struct sk_buff *ctrl_build_family_msg(const struct genl_family *family,