Commit 30b53668 authored by Guvenc Gulce's avatar Guvenc Gulce Committed by Litao Jiao
Browse files

net/smc: Add netlink support for SMC fallback statistics

mainline inclusion
from mainline-v5.14-rc1
commit f0dd7bf5
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I78IFM
CVE: NA

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit?id=f0dd7bf5e33066e554442c509ef6351728b95b51



--------------------------------

Add support to collect more detailed SMC fallback reason statistics and
provide these statistics to user space on the netlink interface.

Signed-off-by: default avatarGuvenc Gulce <guvenc@linux.ibm.com>
Signed-off-by: default avatarKarsten Graul <kgraul@linux.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarYingyu Zeng <zengyingyu@sangfor.com.cn>
parent 0ead8062
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@ enum {
	SMC_NETLINK_GET_DEV_SMCD,
	SMC_NETLINK_GET_DEV_SMCR,
	SMC_NETLINK_GET_STATS,
	SMC_NETLINK_GET_FBACK_STATS,
};

/* SMC_GENL_FAMILY top level attributes */
@@ -60,6 +61,7 @@ enum {
	SMC_GEN_DEV_SMCD,		/* nest */
	SMC_GEN_DEV_SMCR,		/* nest */
	SMC_GEN_STATS,			/* nest */
	SMC_GEN_FBACK_STATS,		/* nest */
	__SMC_GEN_MAX,
	SMC_GEN_MAX = __SMC_GEN_MAX - 1
};
@@ -228,4 +230,16 @@ enum {
	__SMC_NLA_STATS_MAX,
	SMC_NLA_STATS_MAX = __SMC_NLA_STATS_MAX - 1
};

/* SMC_GEN_FBACK_STATS attributes */
enum {
	SMC_NLA_FBACK_STATS_PAD,
	SMC_NLA_FBACK_STATS_TYPE,	/* u8 */
	SMC_NLA_FBACK_STATS_SRV_CNT,	/* u64 */
	SMC_NLA_FBACK_STATS_CLNT_CNT,	/* u64 */
	SMC_NLA_FBACK_STATS_RSN_CODE,	/* u32 */
	SMC_NLA_FBACK_STATS_RSN_CNT,	/* u16 */
	__SMC_NLA_FBACK_STATS_MAX,
	SMC_NLA_FBACK_STATS_MAX = __SMC_NLA_FBACK_STATS_MAX - 1
};
#endif /* _UAPI_LINUX_SMC_H */
+5 −0
Original line number Diff line number Diff line
@@ -61,6 +61,11 @@ static const struct genl_ops smc_gen_nl_ops[] = {
		/* can be retrieved by unprivileged users */
		.dumpit = smc_nl_get_stats,
	},
	{
		.cmd = SMC_NETLINK_GET_FBACK_STATS,
		/* can be retrieved by unprivileged users */
		.dumpit = smc_nl_get_fback_stats,
	},
};

static const struct nla_policy smc_gen_nl_policy[2] = {
+1 −1
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@
extern struct genl_family smc_gen_nl_family;

struct smc_nl_dmp_ctx {
	int pos[2];
	int pos[3];
};

static inline struct smc_nl_dmp_ctx *smc_nl_dmp_ctx(struct netlink_callback *c)
+92 −0
Original line number Diff line number Diff line
@@ -312,3 +312,95 @@ int smc_nl_get_stats(struct sk_buff *skb,
errmsg:
	return skb->len;
}

static int smc_nl_get_fback_details(struct sk_buff *skb,
				    struct netlink_callback *cb, int pos,
				    bool is_srv)
{
	struct smc_nl_dmp_ctx *cb_ctx = smc_nl_dmp_ctx(cb);
	int cnt_reported = cb_ctx->pos[2];
	struct smc_stats_fback *trgt_arr;
	struct nlattr *attrs;
	int rc = 0;
	void *nlh;

	if (is_srv)
		trgt_arr = &fback_rsn.srv[0];
	else
		trgt_arr = &fback_rsn.clnt[0];
	if (!trgt_arr[pos].fback_code)
		return -ENODATA;
	nlh = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
			  &smc_gen_nl_family, NLM_F_MULTI,
			  SMC_NETLINK_GET_FBACK_STATS);
	if (!nlh)
		goto errmsg;
	attrs = nla_nest_start(skb, SMC_GEN_FBACK_STATS);
	if (!attrs)
		goto errout;
	if (nla_put_u8(skb, SMC_NLA_FBACK_STATS_TYPE, is_srv))
		goto errattr;
	if (!cnt_reported) {
		if (nla_put_u64_64bit(skb, SMC_NLA_FBACK_STATS_SRV_CNT,
				      fback_rsn.srv_fback_cnt,
				      SMC_NLA_FBACK_STATS_PAD))
			goto errattr;
		if (nla_put_u64_64bit(skb, SMC_NLA_FBACK_STATS_CLNT_CNT,
				      fback_rsn.clnt_fback_cnt,
				      SMC_NLA_FBACK_STATS_PAD))
			goto errattr;
		cnt_reported = 1;
	}

	if (nla_put_u32(skb, SMC_NLA_FBACK_STATS_RSN_CODE,
			trgt_arr[pos].fback_code))
		goto errattr;
	if (nla_put_u16(skb, SMC_NLA_FBACK_STATS_RSN_CNT,
			trgt_arr[pos].count))
		goto errattr;

	cb_ctx->pos[2] = cnt_reported;
	nla_nest_end(skb, attrs);
	genlmsg_end(skb, nlh);
	return rc;

errattr:
	nla_nest_cancel(skb, attrs);
errout:
	genlmsg_cancel(skb, nlh);
errmsg:
	return -EMSGSIZE;
}

int smc_nl_get_fback_stats(struct sk_buff *skb, struct netlink_callback *cb)
{
	struct smc_nl_dmp_ctx *cb_ctx = smc_nl_dmp_ctx(cb);
	int rc_srv = 0, rc_clnt = 0, k;
	int skip_serv = cb_ctx->pos[1];
	int snum = cb_ctx->pos[0];
	bool is_srv = true;

	mutex_lock(&smc_stat_fback_rsn);
	for (k = 0; k < SMC_MAX_FBACK_RSN_CNT; k++) {
		if (k < snum)
			continue;
		if (!skip_serv) {
			rc_srv = smc_nl_get_fback_details(skb, cb, k, is_srv);
			if (rc_srv && rc_srv != ENODATA)
				break;
		} else {
			skip_serv = 0;
		}
		rc_clnt = smc_nl_get_fback_details(skb, cb, k, !is_srv);
		if (rc_clnt && rc_clnt != ENODATA) {
			skip_serv = 1;
			break;
		}
		if (rc_clnt == ENODATA && rc_srv == ENODATA)
			break;
	}
	mutex_unlock(&smc_stat_fback_rsn);
	cb_ctx->pos[1] = skip_serv;
	cb_ctx->pos[0] = k;
	return skb->len;
}
+1 −0
Original line number Diff line number Diff line
@@ -248,6 +248,7 @@ do { \
while (0)

int smc_nl_get_stats(struct sk_buff *skb, struct netlink_callback *cb);
int smc_nl_get_fback_stats(struct sk_buff *skb, struct netlink_callback *cb);
int smc_stats_init(void) __init;
void smc_stats_exit(void);