net/smc: use the retry mechanism for netlink messages
authorGuvenc Gulce <guvenc@linux.ibm.com>
Thu, 10 Sep 2020 16:48:28 +0000 (18:48 +0200)
committerDavid S. Miller <davem@davemloft.net>
Thu, 10 Sep 2020 22:24:27 +0000 (15:24 -0700)
When the netlink messages to be sent to the userspace
are too big for a single netlink message, send them in
chunks using the netlink_dump infrastructure. Modify the
smc diag dump code so that it can signal to the netlink_dump
infrastructure that it needs to send more data.

Signed-off-by: Guvenc Gulce <guvenc@linux.ibm.com>
Signed-off-by: Karsten Graul <kgraul@linux.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/smc/smc_diag.c

index da9ba6d1679b7804f72ff3b3b8e222e1d3dfc833..f15fca59b4b2654251a375bc522d88a12b450ccc 100644 (file)
 #include "smc.h"
 #include "smc_core.h"
 
+struct smc_diag_dump_ctx {
+       int pos[2];
+};
+
+static struct smc_diag_dump_ctx *smc_dump_context(struct netlink_callback *cb)
+{
+       return (struct smc_diag_dump_ctx *)cb->ctx;
+}
+
 static void smc_gid_be16_convert(__u8 *buf, u8 *gid_raw)
 {
        sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
@@ -193,13 +202,15 @@ errout:
 }
 
 static int smc_diag_dump_proto(struct proto *prot, struct sk_buff *skb,
-                              struct netlink_callback *cb)
+                              struct netlink_callback *cb, int p_type)
 {
+       struct smc_diag_dump_ctx *cb_ctx = smc_dump_context(cb);
        struct net *net = sock_net(skb->sk);
+       int snum = cb_ctx->pos[p_type];
        struct nlattr *bc = NULL;
        struct hlist_head *head;
+       int rc = 0, num = 0;
        struct sock *sk;
-       int rc = 0;
 
        read_lock(&prot->h.smc_hash->lock);
        head = &prot->h.smc_hash->ht;
@@ -209,13 +220,18 @@ static int smc_diag_dump_proto(struct proto *prot, struct sk_buff *skb,
        sk_for_each(sk, head) {
                if (!net_eq(sock_net(sk), net))
                        continue;
+               if (num < snum)
+                       goto next;
                rc = __smc_diag_dump(sk, skb, cb, nlmsg_data(cb->nlh), bc);
-               if (rc)
-                       break;
+               if (rc < 0)
+                       goto out;
+next:
+               num++;
        }
 
 out:
        read_unlock(&prot->h.smc_hash->lock);
+       cb_ctx->pos[p_type] = num;
        return rc;
 }
 
@@ -223,10 +239,10 @@ static int smc_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
 {
        int rc = 0;
 
-       rc = smc_diag_dump_proto(&smc_proto, skb, cb);
+       rc = smc_diag_dump_proto(&smc_proto, skb, cb, SMCPROTO_SMC);
        if (!rc)
-               rc = smc_diag_dump_proto(&smc_proto6, skb, cb);
-       return rc;
+               smc_diag_dump_proto(&smc_proto6, skb, cb, SMCPROTO_SMC6);
+       return skb->len;
 }
 
 static int smc_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)