Path: blob/main/sys/ofed/drivers/infiniband/ulp/sdp/sdp_proc.c
39566 views
/*-1* SPDX-License-Identifier: BSD-2-Clause OR GPL-2.02*3* Copyright (c) 2008 Mellanox Technologies Ltd. All rights reserved.4*5* This software is available to you under a choice of one of two6* licenses. You may choose to be licensed under the terms of the GNU7* General Public License (GPL) Version 2, available from the file8* COPYING in the main directory of this source tree, or the9* OpenIB.org BSD license below:10*11* Redistribution and use in source and binary forms, with or12* without modification, are permitted provided that the following13* conditions are met:14*15* - Redistributions of source code must retain the above16* copyright notice, this list of conditions and the following17* disclaimer.18*19* - Redistributions in binary form must reproduce the above20* copyright notice, this list of conditions and the following21* disclaimer in the documentation and/or other materials22* provided with the distribution.23*24* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,25* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF26* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND27* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS28* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN29* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN30* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE31* SOFTWARE.32*/3334#include <linux/proc_fs.h>35#include "sdp.h"3637#ifdef CONFIG_PROC_FS3839#define PROC_SDP_STATS "sdpstats"40#define PROC_SDP_PERF "sdpprf"4142/* just like TCP fs */43struct sdp_seq_afinfo {44struct module *owner;45char *name;46sa_family_t family;47int (*seq_show) (struct seq_file *m, void *v);48struct file_operations *seq_fops;49};5051struct sdp_iter_state {52sa_family_t family;53int num;54struct seq_operations seq_ops;55};5657static void *sdp_get_idx(struct seq_file *seq, loff_t pos)58{59int i = 0;60struct sdp_sock *ssk;6162if (!list_empty(&sock_list))63list_for_each_entry(ssk, &sock_list, sock_list) {64if (i == pos)65return ssk;66i++;67}6869return NULL;70}7172static void *sdp_seq_start(struct seq_file *seq, loff_t *pos)73{74void *start = NULL;75struct sdp_iter_state *st = seq->private;7677st->num = 0;7879if (!*pos)80return SEQ_START_TOKEN;8182spin_lock_irq(&sock_list_lock);83start = sdp_get_idx(seq, *pos - 1);84if (start)85sock_hold((struct socket *)start, SOCK_REF_SEQ);86spin_unlock_irq(&sock_list_lock);8788return start;89}9091static void *sdp_seq_next(struct seq_file *seq, void *v, loff_t *pos)92{93struct sdp_iter_state *st = seq->private;94void *next = NULL;9596spin_lock_irq(&sock_list_lock);97if (v == SEQ_START_TOKEN)98next = sdp_get_idx(seq, 0);99else100next = sdp_get_idx(seq, *pos);101if (next)102sock_hold((struct socket *)next, SOCK_REF_SEQ);103spin_unlock_irq(&sock_list_lock);104105*pos += 1;106st->num++;107108return next;109}110111static void sdp_seq_stop(struct seq_file *seq, void *v)112{113}114115#define TMPSZ 150116117static int sdp_seq_show(struct seq_file *seq, void *v)118{119struct sdp_iter_state *st;120struct socket *sk = v;121char tmpbuf[TMPSZ + 1];122unsigned int dest;123unsigned int src;124int uid;125unsigned long inode;126__u16 destp;127__u16 srcp;128__u32 rx_queue, tx_queue;129130if (v == SEQ_START_TOKEN) {131seq_printf(seq, "%-*s\n", TMPSZ - 1,132" sl local_address rem_address "133"uid inode rx_queue tx_queue state");134goto out;135}136137st = seq->private;138139dest = inet_sk(sk)->daddr;140src = inet_sk(sk)->rcv_saddr;141destp = ntohs(inet_sk(sk)->dport);142srcp = ntohs(inet_sk(sk)->sport);143uid = sock_i_uid(sk);144inode = sock_i_ino(sk);145rx_queue = rcv_nxt(sdp_sk(sk)) - sdp_sk(sk)->copied_seq;146tx_queue = sdp_sk(sk)->write_seq - sdp_sk(sk)->tx_ring.una_seq;147148sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X %5d %lu %08X:%08X %X",149st->num, src, srcp, dest, destp, uid, inode,150rx_queue, tx_queue, sk->sk_state);151152seq_printf(seq, "%-*s\n", TMPSZ - 1, tmpbuf);153154sock_put(sk, SOCK_REF_SEQ);155out:156return 0;157}158159static int sdp_seq_open(struct inode *inode, struct file *file)160{161struct sdp_seq_afinfo *afinfo = PDE(inode)->data;162struct seq_file *seq;163struct sdp_iter_state *s;164int rc;165166if (unlikely(afinfo == NULL))167return -EINVAL;168169/* Workaround bogus warning by memtrack */170#define _kzalloc(size,flags) kzalloc(size,flags)171#undef kzalloc172s = kzalloc(sizeof(*s), GFP_KERNEL);173#define kzalloc(s,f) _kzalloc(s,f)174if (!s)175return -ENOMEM;176s->family = afinfo->family;177s->seq_ops.start = sdp_seq_start;178s->seq_ops.next = sdp_seq_next;179s->seq_ops.show = afinfo->seq_show;180s->seq_ops.stop = sdp_seq_stop;181182rc = seq_open(file, &s->seq_ops);183if (rc)184goto out_kfree;185seq = file->private_data;186seq->private = s;187out:188return rc;189out_kfree:190kfree(s);191goto out;192}193194195static struct file_operations sdp_seq_fops;196static struct sdp_seq_afinfo sdp_seq_afinfo = {197.owner = THIS_MODULE,198.name = "sdp",199.family = AF_INET_SDP,200.seq_show = sdp_seq_show,201.seq_fops = &sdp_seq_fops,202};203204#ifdef SDPSTATS_ON205DEFINE_PER_CPU(struct sdpstats, sdpstats);206207static void sdpstats_seq_hist(struct seq_file *seq, char *str, u32 *h, int n,208int is_log)209{210int i;211u32 max = 0;212213seq_printf(seq, "%s:\n", str);214215for (i = 0; i < n; i++) {216if (h[i] > max)217max = h[i];218}219220if (max == 0) {221seq_printf(seq, " - all values are 0\n");222return;223}224225for (i = 0; i < n; i++) {226char s[51];227int j = 50 * h[i] / max;228int val = is_log ? (i == n-1 ? 0 : 1<<i) : i;229memset(s, '*', j);230s[j] = '\0';231232seq_printf(seq, "%10d | %-50s - %d\n", val, s, h[i]);233}234}235236#define SDPSTATS_COUNTER_GET(var) ({ \237u32 __val = 0; \238unsigned int __i; \239for_each_possible_cpu(__i) \240__val += per_cpu(sdpstats, __i).var; \241__val; \242})243244#define SDPSTATS_HIST_GET(hist, hist_len, sum) ({ \245unsigned int __i; \246for_each_possible_cpu(__i) { \247unsigned int __j; \248u32 *h = per_cpu(sdpstats, __i).hist; \249for (__j = 0; __j < hist_len; __j++) { \250sum[__j] += h[__j]; \251} \252} \253})254255#define __sdpstats_seq_hist(seq, msg, hist, is_log) ({ \256u32 tmp_hist[SDPSTATS_MAX_HIST_SIZE]; \257int hist_len = ARRAY_SIZE(__get_cpu_var(sdpstats).hist);\258memset(tmp_hist, 0, sizeof(tmp_hist)); \259SDPSTATS_HIST_GET(hist, hist_len, tmp_hist); \260sdpstats_seq_hist(seq, msg, tmp_hist, hist_len, is_log);\261})262263static int sdpstats_seq_show(struct seq_file *seq, void *v)264{265int i;266267seq_printf(seq, "SDP statistics:\n");268269__sdpstats_seq_hist(seq, "sendmsg_seglen", sendmsg_seglen, 1);270__sdpstats_seq_hist(seq, "send_size", send_size, 1);271__sdpstats_seq_hist(seq, "credits_before_update",272credits_before_update, 0);273274seq_printf(seq, "sdp_sendmsg() calls\t\t: %d\n",275SDPSTATS_COUNTER_GET(sendmsg));276seq_printf(seq, "bcopy segments \t\t: %d\n",277SDPSTATS_COUNTER_GET(sendmsg_bcopy_segment));278seq_printf(seq, "bzcopy segments \t\t: %d\n",279SDPSTATS_COUNTER_GET(sendmsg_bzcopy_segment));280seq_printf(seq, "zcopy segments \t\t: %d\n",281SDPSTATS_COUNTER_GET(sendmsg_zcopy_segment));282seq_printf(seq, "post_send_credits \t\t: %d\n",283SDPSTATS_COUNTER_GET(post_send_credits));284seq_printf(seq, "memcpy_count \t\t: %u\n",285SDPSTATS_COUNTER_GET(memcpy_count));286287for (i = 0; i < ARRAY_SIZE(__get_cpu_var(sdpstats).post_send); i++) {288if (mid2str(i)) {289seq_printf(seq, "post_send %-20s\t: %d\n",290mid2str(i),291SDPSTATS_COUNTER_GET(post_send[i]));292}293}294295seq_printf(seq, "\n");296seq_printf(seq, "post_recv \t\t: %d\n",297SDPSTATS_COUNTER_GET(post_recv));298seq_printf(seq, "BZCopy poll miss \t\t: %d\n",299SDPSTATS_COUNTER_GET(bzcopy_poll_miss));300seq_printf(seq, "send_wait_for_mem \t\t: %d\n",301SDPSTATS_COUNTER_GET(send_wait_for_mem));302seq_printf(seq, "send_miss_no_credits\t\t: %d\n",303SDPSTATS_COUNTER_GET(send_miss_no_credits));304305seq_printf(seq, "rx_poll_miss \t\t: %d\n", SDPSTATS_COUNTER_GET(rx_poll_miss));306seq_printf(seq, "tx_poll_miss \t\t: %d\n", SDPSTATS_COUNTER_GET(tx_poll_miss));307seq_printf(seq, "tx_poll_busy \t\t: %d\n", SDPSTATS_COUNTER_GET(tx_poll_busy));308seq_printf(seq, "tx_poll_hit \t\t: %d\n", SDPSTATS_COUNTER_GET(tx_poll_hit));309310seq_printf(seq, "CQ stats:\n");311seq_printf(seq, "- RX interrupts\t\t: %d\n", SDPSTATS_COUNTER_GET(rx_int_count));312seq_printf(seq, "- TX interrupts\t\t: %d\n", SDPSTATS_COUNTER_GET(tx_int_count));313314seq_printf(seq, "ZCopy stats:\n");315seq_printf(seq, "- TX timeout\t\t: %d\n", SDPSTATS_COUNTER_GET(zcopy_tx_timeout));316seq_printf(seq, "- TX cross send\t\t: %d\n", SDPSTATS_COUNTER_GET(zcopy_cross_send));317seq_printf(seq, "- TX aborted by peer\t: %d\n", SDPSTATS_COUNTER_GET(zcopy_tx_aborted));318seq_printf(seq, "- TX error\t\t: %d\n", SDPSTATS_COUNTER_GET(zcopy_tx_error));319return 0;320}321322static ssize_t sdpstats_write(struct file *file, const char __user *buf,323size_t count, loff_t *offs)324{325int i;326327for_each_possible_cpu(i)328memset(&per_cpu(sdpstats, i), 0, sizeof(struct sdpstats));329printk(KERN_WARNING "Cleared sdp statistics\n");330331return count;332}333334static int sdpstats_seq_open(struct inode *inode, struct file *file)335{336return single_open(file, sdpstats_seq_show, NULL);337}338339static struct file_operations sdpstats_fops = {340.owner = THIS_MODULE,341.open = sdpstats_seq_open,342.read = seq_read,343.write = sdpstats_write,344.llseek = seq_lseek,345.release = single_release,346};347348#endif349350#ifdef SDP_PROFILING351struct sdpprf_log sdpprf_log[SDPPRF_LOG_SIZE];352int sdpprf_log_count;353354static unsigned long long start_t;355356static int sdpprf_show(struct seq_file *m, void *v)357{358struct sdpprf_log *l = v;359unsigned long nsec_rem, t;360361if (!sdpprf_log_count) {362seq_printf(m, "No performance logs\n");363goto out;364}365366t = l->time - start_t;367nsec_rem = do_div(t, 1000000000);368369seq_printf(m, "%-6d: [%5lu.%06lu] %-50s - [%d{%d} %d:%d] "370"mb: %p %s:%d\n",371l->idx, (unsigned long)t, nsec_rem/1000,372l->msg, l->pid, l->cpu, l->sk_num, l->sk_dport,373l->mb, l->func, l->line);374out:375return 0;376}377378static void *sdpprf_start(struct seq_file *p, loff_t *pos)379{380int idx = *pos;381382if (!*pos) {383if (!sdpprf_log_count)384return SEQ_START_TOKEN;385}386387if (*pos >= MIN(sdpprf_log_count, SDPPRF_LOG_SIZE - 1))388return NULL;389390if (sdpprf_log_count >= SDPPRF_LOG_SIZE - 1) {391int off = sdpprf_log_count & (SDPPRF_LOG_SIZE - 1);392idx = (idx + off) & (SDPPRF_LOG_SIZE - 1);393394}395396if (!start_t)397start_t = sdpprf_log[idx].time;398return &sdpprf_log[idx];399}400401static void *sdpprf_next(struct seq_file *p, void *v, loff_t *pos)402{403struct sdpprf_log *l = v;404405if (++*pos >= MIN(sdpprf_log_count, SDPPRF_LOG_SIZE - 1))406return NULL;407408++l;409if (l - &sdpprf_log[0] >= SDPPRF_LOG_SIZE - 1)410return &sdpprf_log[0];411412return l;413}414415static void sdpprf_stop(struct seq_file *p, void *v)416{417}418419static struct seq_operations sdpprf_ops = {420.start = sdpprf_start,421.stop = sdpprf_stop,422.next = sdpprf_next,423.show = sdpprf_show,424};425426static int sdpprf_open(struct inode *inode, struct file *file)427{428int res;429430res = seq_open(file, &sdpprf_ops);431432return res;433}434435static ssize_t sdpprf_write(struct file *file, const char __user *buf,436size_t count, loff_t *offs)437{438sdpprf_log_count = 0;439printk(KERN_INFO "Cleared sdpprf statistics\n");440441return count;442}443444static struct file_operations sdpprf_fops = {445.open = sdpprf_open,446.read = seq_read,447.llseek = seq_lseek,448.release = seq_release,449.write = sdpprf_write,450};451#endif /* SDP_PROFILING */452453int __init sdp_proc_init(void)454{455struct proc_dir_entry *p = NULL;456#ifdef SDPSTATS_ON457struct proc_dir_entry *stats = NULL;458#endif459#ifdef SDP_PROFILING460struct proc_dir_entry *prof = NULL;461#endif462463sdp_seq_afinfo.seq_fops->owner = sdp_seq_afinfo.owner;464sdp_seq_afinfo.seq_fops->open = sdp_seq_open;465sdp_seq_afinfo.seq_fops->read = seq_read;466sdp_seq_afinfo.seq_fops->llseek = seq_lseek;467sdp_seq_afinfo.seq_fops->release = seq_release_private;468469p = proc_net_fops_create(&init_net, sdp_seq_afinfo.name, S_IRUGO,470sdp_seq_afinfo.seq_fops);471if (p)472p->data = &sdp_seq_afinfo;473else474goto no_mem;475476#ifdef SDPSTATS_ON477478stats = proc_net_fops_create(&init_net, PROC_SDP_STATS,479S_IRUGO | S_IWUGO, &sdpstats_fops);480if (!stats)481goto no_mem_stats;482483#endif484485#ifdef SDP_PROFILING486prof = proc_net_fops_create(&init_net, PROC_SDP_PERF,487S_IRUGO | S_IWUGO, &sdpprf_fops);488if (!prof)489goto no_mem_prof;490#endif491492return 0;493494#ifdef SDP_PROFILING495no_mem_prof:496#endif497498#ifdef SDPSTATS_ON499proc_net_remove(&init_net, PROC_SDP_STATS);500501no_mem_stats:502#endif503proc_net_remove(&init_net, sdp_seq_afinfo.name);504505no_mem:506return -ENOMEM;507}508509void sdp_proc_unregister(void)510{511proc_net_remove(&init_net, sdp_seq_afinfo.name);512memset(sdp_seq_afinfo.seq_fops, 0, sizeof(*sdp_seq_afinfo.seq_fops));513514#ifdef SDPSTATS_ON515proc_net_remove(&init_net, PROC_SDP_STATS);516#endif517#ifdef SDP_PROFILING518proc_net_remove(&init_net, PROC_SDP_PERF);519#endif520}521522#else /* CONFIG_PROC_FS */523524int __init sdp_proc_init(void)525{526return 0;527}528529void sdp_proc_unregister(void)530{531532}533#endif /* CONFIG_PROC_FS */534535536