mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	net/smc: Add netlink support for SMC fallback statistics
Add support to collect more detailed SMC fallback reason statistics and provide these statistics to user space on the netlink interface. 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:
		
							parent
							
								
									8c40602b4b
								
							
						
					
					
						commit
						f0dd7bf5e3
					
				
					 5 changed files with 113 additions and 1 deletions
				
			
		| 
						 | 
					@ -48,6 +48,7 @@ enum {
 | 
				
			||||||
	SMC_NETLINK_GET_DEV_SMCD,
 | 
						SMC_NETLINK_GET_DEV_SMCD,
 | 
				
			||||||
	SMC_NETLINK_GET_DEV_SMCR,
 | 
						SMC_NETLINK_GET_DEV_SMCR,
 | 
				
			||||||
	SMC_NETLINK_GET_STATS,
 | 
						SMC_NETLINK_GET_STATS,
 | 
				
			||||||
 | 
						SMC_NETLINK_GET_FBACK_STATS,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* SMC_GENL_FAMILY top level attributes */
 | 
					/* SMC_GENL_FAMILY top level attributes */
 | 
				
			||||||
| 
						 | 
					@ -60,6 +61,7 @@ enum {
 | 
				
			||||||
	SMC_GEN_DEV_SMCD,		/* nest */
 | 
						SMC_GEN_DEV_SMCD,		/* nest */
 | 
				
			||||||
	SMC_GEN_DEV_SMCR,		/* nest */
 | 
						SMC_GEN_DEV_SMCR,		/* nest */
 | 
				
			||||||
	SMC_GEN_STATS,			/* nest */
 | 
						SMC_GEN_STATS,			/* nest */
 | 
				
			||||||
 | 
						SMC_GEN_FBACK_STATS,		/* nest */
 | 
				
			||||||
	__SMC_GEN_MAX,
 | 
						__SMC_GEN_MAX,
 | 
				
			||||||
	SMC_GEN_MAX = __SMC_GEN_MAX - 1
 | 
						SMC_GEN_MAX = __SMC_GEN_MAX - 1
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -228,4 +230,16 @@ enum {
 | 
				
			||||||
	__SMC_NLA_STATS_MAX,
 | 
						__SMC_NLA_STATS_MAX,
 | 
				
			||||||
	SMC_NLA_STATS_MAX = __SMC_NLA_STATS_MAX - 1
 | 
						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 */
 | 
					#endif /* _UAPI_LINUX_SMC_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -61,6 +61,11 @@ static const struct genl_ops smc_gen_nl_ops[] = {
 | 
				
			||||||
		/* can be retrieved by unprivileged users */
 | 
							/* can be retrieved by unprivileged users */
 | 
				
			||||||
		.dumpit = smc_nl_get_stats,
 | 
							.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] = {
 | 
					static const struct nla_policy smc_gen_nl_policy[2] = {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,7 +18,7 @@
 | 
				
			||||||
extern struct genl_family smc_gen_nl_family;
 | 
					extern struct genl_family smc_gen_nl_family;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct smc_nl_dmp_ctx {
 | 
					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)
 | 
					static inline struct smc_nl_dmp_ctx *smc_nl_dmp_ctx(struct netlink_callback *c)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -312,3 +312,95 @@ int smc_nl_get_stats(struct sk_buff *skb,
 | 
				
			||||||
errmsg:
 | 
					errmsg:
 | 
				
			||||||
	return skb->len;
 | 
						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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -248,6 +248,7 @@ do { \
 | 
				
			||||||
while (0)
 | 
					while (0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int smc_nl_get_stats(struct sk_buff *skb, struct netlink_callback *cb);
 | 
					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;
 | 
					int smc_stats_init(void) __init;
 | 
				
			||||||
void smc_stats_exit(void);
 | 
					void smc_stats_exit(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue