net/smc: use the retry mechanism for netlink messages

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>
This commit is contained in:
Guvenc Gulce 2020-09-10 18:48:28 +02:00 committed by David S. Miller
parent 219d9aef6d
commit 8418cb4065

View file

@ -22,6 +22,15 @@
#include "smc.h" #include "smc.h"
#include "smc_core.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) static void smc_gid_be16_convert(__u8 *buf, u8 *gid_raw)
{ {
sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", 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, 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); struct net *net = sock_net(skb->sk);
int snum = cb_ctx->pos[p_type];
struct nlattr *bc = NULL; struct nlattr *bc = NULL;
struct hlist_head *head; struct hlist_head *head;
int rc = 0, num = 0;
struct sock *sk; struct sock *sk;
int rc = 0;
read_lock(&prot->h.smc_hash->lock); read_lock(&prot->h.smc_hash->lock);
head = &prot->h.smc_hash->ht; 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) { sk_for_each(sk, head) {
if (!net_eq(sock_net(sk), net)) if (!net_eq(sock_net(sk), net))
continue; continue;
if (num < snum)
goto next;
rc = __smc_diag_dump(sk, skb, cb, nlmsg_data(cb->nlh), bc); rc = __smc_diag_dump(sk, skb, cb, nlmsg_data(cb->nlh), bc);
if (rc) if (rc < 0)
break; goto out;
next:
num++;
} }
out: out:
read_unlock(&prot->h.smc_hash->lock); read_unlock(&prot->h.smc_hash->lock);
cb_ctx->pos[p_type] = num;
return rc; return rc;
} }
@ -223,10 +239,10 @@ static int smc_diag_dump(struct sk_buff *skb, struct netlink_callback *cb)
{ {
int rc = 0; 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) if (!rc)
rc = smc_diag_dump_proto(&smc_proto6, skb, cb); smc_diag_dump_proto(&smc_proto6, skb, cb, SMCPROTO_SMC6);
return rc; return skb->len;
} }
static int smc_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h) static int smc_diag_handler_dump(struct sk_buff *skb, struct nlmsghdr *h)