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