xref: /freebsd-11-stable/sys/ofed/drivers/infiniband/ulp/sdp/sdp_proc.c (revision 3e8156e092749779c9ce85631f72a0ece7d06094)
1 /*
2  * Copyright (c) 2008 Mellanox Technologies Ltd.  All rights reserved.
3  *
4  * This software is available to you under a choice of one of two
5  * licenses.  You may choose to be licensed under the terms of the GNU
6  * General Public License (GPL) Version 2, available from the file
7  * COPYING in the main directory of this source tree, or the
8  * OpenIB.org BSD license below:
9  *
10  *     Redistribution and use in source and binary forms, with or
11  *     without modification, are permitted provided that the following
12  *     conditions are met:
13  *
14  *      - Redistributions of source code must retain the above
15  *        copyright notice, this list of conditions and the following
16  *        disclaimer.
17  *
18  *      - Redistributions in binary form must reproduce the above
19  *        copyright notice, this list of conditions and the following
20  *        disclaimer in the documentation and/or other materials
21  *        provided with the distribution.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30  * SOFTWARE.
31  */
32 
33 #include <linux/proc_fs.h>
34 #include "sdp.h"
35 
36 #ifdef CONFIG_PROC_FS
37 
38 #define PROC_SDP_STATS "sdpstats"
39 #define PROC_SDP_PERF "sdpprf"
40 
41 /* just like TCP fs */
42 struct sdp_seq_afinfo {
43 	struct module           *owner;
44 	char                    *name;
45 	sa_family_t             family;
46 	int                     (*seq_show) (struct seq_file *m, void *v);
47 	struct file_operations  *seq_fops;
48 };
49 
50 struct sdp_iter_state {
51 	sa_family_t             family;
52 	int                     num;
53 	struct seq_operations   seq_ops;
54 };
55 
sdp_get_idx(struct seq_file * seq,loff_t pos)56 static void *sdp_get_idx(struct seq_file *seq, loff_t pos)
57 {
58 	int i = 0;
59 	struct sdp_sock *ssk;
60 
61 	if (!list_empty(&sock_list))
62 		list_for_each_entry(ssk, &sock_list, sock_list) {
63 			if (i == pos)
64 				return ssk;
65 			i++;
66 		}
67 
68 	return NULL;
69 }
70 
sdp_seq_start(struct seq_file * seq,loff_t * pos)71 static void *sdp_seq_start(struct seq_file *seq, loff_t *pos)
72 {
73 	void *start = NULL;
74 	struct sdp_iter_state *st = seq->private;
75 
76 	st->num = 0;
77 
78 	if (!*pos)
79 		return SEQ_START_TOKEN;
80 
81 	spin_lock_irq(&sock_list_lock);
82 	start = sdp_get_idx(seq, *pos - 1);
83 	if (start)
84 		sock_hold((struct socket *)start, SOCK_REF_SEQ);
85 	spin_unlock_irq(&sock_list_lock);
86 
87 	return start;
88 }
89 
sdp_seq_next(struct seq_file * seq,void * v,loff_t * pos)90 static void *sdp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
91 {
92 	struct sdp_iter_state *st = seq->private;
93 	void *next = NULL;
94 
95 	spin_lock_irq(&sock_list_lock);
96 	if (v == SEQ_START_TOKEN)
97 		next = sdp_get_idx(seq, 0);
98 	else
99 		next = sdp_get_idx(seq, *pos);
100 	if (next)
101 		sock_hold((struct socket *)next, SOCK_REF_SEQ);
102 	spin_unlock_irq(&sock_list_lock);
103 
104 	*pos += 1;
105 	st->num++;
106 
107 	return next;
108 }
109 
sdp_seq_stop(struct seq_file * seq,void * v)110 static void sdp_seq_stop(struct seq_file *seq, void *v)
111 {
112 }
113 
114 #define TMPSZ 150
115 
sdp_seq_show(struct seq_file * seq,void * v)116 static int sdp_seq_show(struct seq_file *seq, void *v)
117 {
118 	struct sdp_iter_state *st;
119 	struct socket *sk = v;
120 	char tmpbuf[TMPSZ + 1];
121 	unsigned int dest;
122 	unsigned int src;
123 	int uid;
124 	unsigned long inode;
125 	__u16 destp;
126 	__u16 srcp;
127 	__u32 rx_queue, tx_queue;
128 
129 	if (v == SEQ_START_TOKEN) {
130 		seq_printf(seq, "%-*s\n", TMPSZ - 1,
131 				"  sl  local_address rem_address        "
132 				"uid inode   rx_queue tx_queue state");
133 		goto out;
134 	}
135 
136 	st = seq->private;
137 
138 	dest = inet_sk(sk)->daddr;
139 	src = inet_sk(sk)->rcv_saddr;
140 	destp = ntohs(inet_sk(sk)->dport);
141 	srcp = ntohs(inet_sk(sk)->sport);
142 	uid = sock_i_uid(sk);
143 	inode = sock_i_ino(sk);
144 	rx_queue = rcv_nxt(sdp_sk(sk)) - sdp_sk(sk)->copied_seq;
145 	tx_queue = sdp_sk(sk)->write_seq - sdp_sk(sk)->tx_ring.una_seq;
146 
147 	sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X %5d %lu	%08X:%08X %X",
148 		st->num, src, srcp, dest, destp, uid, inode,
149 		rx_queue, tx_queue, sk->sk_state);
150 
151 	seq_printf(seq, "%-*s\n", TMPSZ - 1, tmpbuf);
152 
153 	sock_put(sk, SOCK_REF_SEQ);
154 out:
155 	return 0;
156 }
157 
sdp_seq_open(struct inode * inode,struct file * file)158 static int sdp_seq_open(struct inode *inode, struct file *file)
159 {
160 	struct sdp_seq_afinfo *afinfo = PDE(inode)->data;
161 	struct seq_file *seq;
162 	struct sdp_iter_state *s;
163 	int rc;
164 
165 	if (unlikely(afinfo == NULL))
166 		return -EINVAL;
167 
168 /* Workaround bogus warning by memtrack */
169 #define _kzalloc(size,flags) kzalloc(size,flags)
170 #undef kzalloc
171 	s = kzalloc(sizeof(*s), GFP_KERNEL);
172 #define kzalloc(s,f) _kzalloc(s,f)
173 	if (!s)
174 		return -ENOMEM;
175 	s->family               = afinfo->family;
176 	s->seq_ops.start        = sdp_seq_start;
177 	s->seq_ops.next         = sdp_seq_next;
178 	s->seq_ops.show         = afinfo->seq_show;
179 	s->seq_ops.stop         = sdp_seq_stop;
180 
181 	rc = seq_open(file, &s->seq_ops);
182 	if (rc)
183 		goto out_kfree;
184 	seq          = file->private_data;
185 	seq->private = s;
186 out:
187 	return rc;
188 out_kfree:
189 	kfree(s);
190 	goto out;
191 }
192 
193 
194 static struct file_operations sdp_seq_fops;
195 static struct sdp_seq_afinfo sdp_seq_afinfo = {
196 	.owner          = THIS_MODULE,
197 	.name           = "sdp",
198 	.family         = AF_INET_SDP,
199 	.seq_show       = sdp_seq_show,
200 	.seq_fops       = &sdp_seq_fops,
201 };
202 
203 #ifdef SDPSTATS_ON
204 DEFINE_PER_CPU(struct sdpstats, sdpstats);
205 
sdpstats_seq_hist(struct seq_file * seq,char * str,u32 * h,int n,int is_log)206 static void sdpstats_seq_hist(struct seq_file *seq, char *str, u32 *h, int n,
207 		int is_log)
208 {
209 	int i;
210 	u32 max = 0;
211 
212 	seq_printf(seq, "%s:\n", str);
213 
214 	for (i = 0; i < n; i++) {
215 		if (h[i] > max)
216 			max = h[i];
217 	}
218 
219 	if (max == 0) {
220 		seq_printf(seq, " - all values are 0\n");
221 		return;
222 	}
223 
224 	for (i = 0; i < n; i++) {
225 		char s[51];
226 		int j = 50 * h[i] / max;
227 		int val = is_log ? (i == n-1 ? 0 : 1<<i) : i;
228 		memset(s, '*', j);
229 		s[j] = '\0';
230 
231 		seq_printf(seq, "%10d | %-50s - %d\n", val, s, h[i]);
232 	}
233 }
234 
235 #define SDPSTATS_COUNTER_GET(var) ({ \
236 	u32 __val = 0;						\
237 	unsigned int __i;                                       \
238 	for_each_possible_cpu(__i)                              \
239 		__val += per_cpu(sdpstats, __i).var;		\
240 	__val;							\
241 })
242 
243 #define SDPSTATS_HIST_GET(hist, hist_len, sum) ({ \
244 	unsigned int __i;                                       \
245 	for_each_possible_cpu(__i) {                            \
246 		unsigned int __j;				\
247 		u32 *h = per_cpu(sdpstats, __i).hist;		\
248 		for (__j = 0; __j < hist_len; __j++) { 		\
249 			sum[__j] += h[__j];			\
250 		} \
251 	} 							\
252 })
253 
254 #define __sdpstats_seq_hist(seq, msg, hist, is_log) ({		\
255 	u32 tmp_hist[SDPSTATS_MAX_HIST_SIZE];			\
256 	int hist_len = ARRAY_SIZE(__get_cpu_var(sdpstats).hist);\
257 	memset(tmp_hist, 0, sizeof(tmp_hist));			\
258 	SDPSTATS_HIST_GET(hist, hist_len, tmp_hist);	\
259 	sdpstats_seq_hist(seq, msg, tmp_hist, hist_len, is_log);\
260 })
261 
sdpstats_seq_show(struct seq_file * seq,void * v)262 static int sdpstats_seq_show(struct seq_file *seq, void *v)
263 {
264 	int i;
265 
266 	seq_printf(seq, "SDP statistics:\n");
267 
268 	__sdpstats_seq_hist(seq, "sendmsg_seglen", sendmsg_seglen, 1);
269 	__sdpstats_seq_hist(seq, "send_size", send_size, 1);
270 	__sdpstats_seq_hist(seq, "credits_before_update",
271 		credits_before_update, 0);
272 
273 	seq_printf(seq, "sdp_sendmsg() calls\t\t: %d\n",
274 		SDPSTATS_COUNTER_GET(sendmsg));
275 	seq_printf(seq, "bcopy segments     \t\t: %d\n",
276 		SDPSTATS_COUNTER_GET(sendmsg_bcopy_segment));
277 	seq_printf(seq, "bzcopy segments    \t\t: %d\n",
278 		SDPSTATS_COUNTER_GET(sendmsg_bzcopy_segment));
279 	seq_printf(seq, "zcopy segments    \t\t: %d\n",
280 		SDPSTATS_COUNTER_GET(sendmsg_zcopy_segment));
281 	seq_printf(seq, "post_send_credits  \t\t: %d\n",
282 		SDPSTATS_COUNTER_GET(post_send_credits));
283 	seq_printf(seq, "memcpy_count       \t\t: %u\n",
284 		SDPSTATS_COUNTER_GET(memcpy_count));
285 
286         for (i = 0; i < ARRAY_SIZE(__get_cpu_var(sdpstats).post_send); i++) {
287                 if (mid2str(i)) {
288                         seq_printf(seq, "post_send %-20s\t: %d\n",
289                                         mid2str(i),
290 					SDPSTATS_COUNTER_GET(post_send[i]));
291                 }
292         }
293 
294 	seq_printf(seq, "\n");
295 	seq_printf(seq, "post_recv         \t\t: %d\n",
296 		SDPSTATS_COUNTER_GET(post_recv));
297 	seq_printf(seq, "BZCopy poll miss  \t\t: %d\n",
298 		SDPSTATS_COUNTER_GET(bzcopy_poll_miss));
299 	seq_printf(seq, "send_wait_for_mem \t\t: %d\n",
300 		SDPSTATS_COUNTER_GET(send_wait_for_mem));
301 	seq_printf(seq, "send_miss_no_credits\t\t: %d\n",
302 		SDPSTATS_COUNTER_GET(send_miss_no_credits));
303 
304 	seq_printf(seq, "rx_poll_miss      \t\t: %d\n", SDPSTATS_COUNTER_GET(rx_poll_miss));
305 	seq_printf(seq, "tx_poll_miss      \t\t: %d\n", SDPSTATS_COUNTER_GET(tx_poll_miss));
306 	seq_printf(seq, "tx_poll_busy      \t\t: %d\n", SDPSTATS_COUNTER_GET(tx_poll_busy));
307 	seq_printf(seq, "tx_poll_hit       \t\t: %d\n", SDPSTATS_COUNTER_GET(tx_poll_hit));
308 
309 	seq_printf(seq, "CQ stats:\n");
310 	seq_printf(seq, "- RX interrupts\t\t: %d\n", SDPSTATS_COUNTER_GET(rx_int_count));
311 	seq_printf(seq, "- TX interrupts\t\t: %d\n", SDPSTATS_COUNTER_GET(tx_int_count));
312 
313 	seq_printf(seq, "ZCopy stats:\n");
314 	seq_printf(seq, "- TX timeout\t\t: %d\n", SDPSTATS_COUNTER_GET(zcopy_tx_timeout));
315 	seq_printf(seq, "- TX cross send\t\t: %d\n", SDPSTATS_COUNTER_GET(zcopy_cross_send));
316 	seq_printf(seq, "- TX aborted by peer\t: %d\n", SDPSTATS_COUNTER_GET(zcopy_tx_aborted));
317 	seq_printf(seq, "- TX error\t\t: %d\n", SDPSTATS_COUNTER_GET(zcopy_tx_error));
318 	return 0;
319 }
320 
sdpstats_write(struct file * file,const char __user * buf,size_t count,loff_t * offs)321 static ssize_t sdpstats_write(struct file *file, const char __user *buf,
322 			    size_t count, loff_t *offs)
323 {
324 	int i;
325 
326 	for_each_possible_cpu(i)
327 		memset(&per_cpu(sdpstats, i), 0, sizeof(struct sdpstats));
328 	printk(KERN_WARNING "Cleared sdp statistics\n");
329 
330 	return count;
331 }
332 
sdpstats_seq_open(struct inode * inode,struct file * file)333 static int sdpstats_seq_open(struct inode *inode, struct file *file)
334 {
335 	return single_open(file, sdpstats_seq_show, NULL);
336 }
337 
338 static struct file_operations sdpstats_fops = {
339 	.owner		= THIS_MODULE,
340 	.open		= sdpstats_seq_open,
341 	.read		= seq_read,
342 	.write		= sdpstats_write,
343 	.llseek		= seq_lseek,
344 	.release	= single_release,
345 };
346 
347 #endif
348 
349 #ifdef SDP_PROFILING
350 struct sdpprf_log sdpprf_log[SDPPRF_LOG_SIZE];
351 int sdpprf_log_count;
352 
353 static unsigned long long start_t;
354 
sdpprf_show(struct seq_file * m,void * v)355 static int sdpprf_show(struct seq_file *m, void *v)
356 {
357 	struct sdpprf_log *l = v;
358 	unsigned long nsec_rem, t;
359 
360 	if (!sdpprf_log_count) {
361 		seq_printf(m, "No performance logs\n");
362 		goto out;
363 	}
364 
365 	t = l->time - start_t;
366 	nsec_rem = do_div(t, 1000000000);
367 
368 	seq_printf(m, "%-6d: [%5lu.%06lu] %-50s - [%d{%d} %d:%d] "
369 			"mb: %p %s:%d\n",
370 			l->idx, (unsigned long)t, nsec_rem/1000,
371 			l->msg, l->pid, l->cpu, l->sk_num, l->sk_dport,
372 			l->mb, l->func, l->line);
373 out:
374 	return 0;
375 }
376 
sdpprf_start(struct seq_file * p,loff_t * pos)377 static void *sdpprf_start(struct seq_file *p, loff_t *pos)
378 {
379 	int idx = *pos;
380 
381 	if (!*pos) {
382 		if (!sdpprf_log_count)
383 			return SEQ_START_TOKEN;
384 	}
385 
386 	if (*pos >= MIN(sdpprf_log_count, SDPPRF_LOG_SIZE - 1))
387 		return NULL;
388 
389 	if (sdpprf_log_count >= SDPPRF_LOG_SIZE - 1) {
390 		int off = sdpprf_log_count & (SDPPRF_LOG_SIZE - 1);
391 		idx = (idx + off) & (SDPPRF_LOG_SIZE - 1);
392 
393 	}
394 
395 	if (!start_t)
396 		start_t = sdpprf_log[idx].time;
397 	return &sdpprf_log[idx];
398 }
399 
sdpprf_next(struct seq_file * p,void * v,loff_t * pos)400 static void *sdpprf_next(struct seq_file *p, void *v, loff_t *pos)
401 {
402 	struct sdpprf_log *l = v;
403 
404 	if (++*pos >= MIN(sdpprf_log_count, SDPPRF_LOG_SIZE - 1))
405 		return NULL;
406 
407 	++l;
408 	if (l - &sdpprf_log[0] >= SDPPRF_LOG_SIZE - 1)
409 		return &sdpprf_log[0];
410 
411 	return l;
412 }
413 
sdpprf_stop(struct seq_file * p,void * v)414 static void sdpprf_stop(struct seq_file *p, void *v)
415 {
416 }
417 
418 static struct seq_operations sdpprf_ops = {
419 	.start = sdpprf_start,
420 	.stop = sdpprf_stop,
421 	.next = sdpprf_next,
422 	.show = sdpprf_show,
423 };
424 
sdpprf_open(struct inode * inode,struct file * file)425 static int sdpprf_open(struct inode *inode, struct file *file)
426 {
427 	int res;
428 
429 	res = seq_open(file, &sdpprf_ops);
430 
431 	return res;
432 }
433 
sdpprf_write(struct file * file,const char __user * buf,size_t count,loff_t * offs)434 static ssize_t sdpprf_write(struct file *file, const char __user *buf,
435 			    size_t count, loff_t *offs)
436 {
437 	sdpprf_log_count = 0;
438 	printk(KERN_INFO "Cleared sdpprf statistics\n");
439 
440 	return count;
441 }
442 
443 static struct file_operations sdpprf_fops = {
444 	.open           = sdpprf_open,
445 	.read           = seq_read,
446 	.llseek         = seq_lseek,
447 	.release        = seq_release,
448 	.write		= sdpprf_write,
449 };
450 #endif /* SDP_PROFILING */
451 
sdp_proc_init(void)452 int __init sdp_proc_init(void)
453 {
454 	struct proc_dir_entry *p = NULL;
455 #ifdef SDPSTATS_ON
456 	struct proc_dir_entry *stats = NULL;
457 #endif
458 #ifdef SDP_PROFILING
459 	struct proc_dir_entry *prof = NULL;
460 #endif
461 
462 	sdp_seq_afinfo.seq_fops->owner         = sdp_seq_afinfo.owner;
463 	sdp_seq_afinfo.seq_fops->open          = sdp_seq_open;
464 	sdp_seq_afinfo.seq_fops->read          = seq_read;
465 	sdp_seq_afinfo.seq_fops->llseek        = seq_lseek;
466 	sdp_seq_afinfo.seq_fops->release       = seq_release_private;
467 
468 	p = proc_net_fops_create(&init_net, sdp_seq_afinfo.name, S_IRUGO,
469 				 sdp_seq_afinfo.seq_fops);
470 	if (p)
471 		p->data = &sdp_seq_afinfo;
472 	else
473 		goto no_mem;
474 
475 #ifdef SDPSTATS_ON
476 
477 	stats = proc_net_fops_create(&init_net, PROC_SDP_STATS,
478 			S_IRUGO | S_IWUGO, &sdpstats_fops);
479 	if (!stats)
480 		goto no_mem_stats;
481 
482 #endif
483 
484 #ifdef SDP_PROFILING
485 	prof = proc_net_fops_create(&init_net, PROC_SDP_PERF,
486 			S_IRUGO | S_IWUGO, &sdpprf_fops);
487 	if (!prof)
488 		goto no_mem_prof;
489 #endif
490 
491 	return 0;
492 
493 #ifdef SDP_PROFILING
494 no_mem_prof:
495 #endif
496 
497 #ifdef SDPSTATS_ON
498 	proc_net_remove(&init_net, PROC_SDP_STATS);
499 
500 no_mem_stats:
501 #endif
502 	proc_net_remove(&init_net, sdp_seq_afinfo.name);
503 
504 no_mem:
505 	return -ENOMEM;
506 }
507 
sdp_proc_unregister(void)508 void sdp_proc_unregister(void)
509 {
510 	proc_net_remove(&init_net, sdp_seq_afinfo.name);
511 	memset(sdp_seq_afinfo.seq_fops, 0, sizeof(*sdp_seq_afinfo.seq_fops));
512 
513 #ifdef SDPSTATS_ON
514 	proc_net_remove(&init_net, PROC_SDP_STATS);
515 #endif
516 #ifdef SDP_PROFILING
517 	proc_net_remove(&init_net, PROC_SDP_PERF);
518 #endif
519 }
520 
521 #else /* CONFIG_PROC_FS */
522 
sdp_proc_init(void)523 int __init sdp_proc_init(void)
524 {
525 	return 0;
526 }
527 
sdp_proc_unregister(void)528 void sdp_proc_unregister(void)
529 {
530 
531 }
532 #endif /* CONFIG_PROC_FS */
533