Whamcloud - gitweb
LU-6142 lnet: SPDX for lnet/lnet/
[fs/lustre-release.git] / lnet / lnet / lnet_debugfs.c
1 // SPDX-License-Identifier: GPL-2.0
2
3 /* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
4  *
5  * Copyright (c) 2011, 2017, Intel Corporation.
6  */
7
8 /* This file is part of Lustre, http://www.lustre.org/ */
9
10 #define DEBUG_SUBSYSTEM S_LNET
11
12 #include <linux/uaccess.h>
13
14 #include <libcfs/libcfs.h>
15 #include <lnet/lib-lnet.h>
16
17 #define LNET_LOFFT_BITS         (sizeof(loff_t) * 8)
18 /* NB: max allowed LNET_CPT_BITS is 8 on 64-bit system and 2 on 32-bit system
19  */
20 #define LNET_PROC_CPT_BITS      (LNET_CPT_BITS + 1)
21 /* change version, 16 bits or 8 bits */
22 #define LNET_PROC_VER_BITS              \
23         clamp_t(int, LNET_LOFFT_BITS / 4, 8, 16)
24
25 #define LNET_PROC_HASH_BITS     LNET_PEER_HASH_BITS
26 /* bits for peer hash offset
27  * NB: we don't use the highest bit of *ppos because it's signed
28  */
29 #define LNET_PROC_HOFF_BITS     (LNET_LOFFT_BITS -       \
30                                  LNET_PROC_CPT_BITS -    \
31                                  LNET_PROC_VER_BITS -    \
32                                  LNET_PROC_HASH_BITS - 1)
33 /* bits for hash index + position */
34 #define LNET_PROC_HPOS_BITS     (LNET_PROC_HASH_BITS + LNET_PROC_HOFF_BITS)
35 /* bits for peer hash table + hash version */
36 #define LNET_PROC_VPOS_BITS     (LNET_PROC_HPOS_BITS + LNET_PROC_VER_BITS)
37
38 #define LNET_PROC_CPT_MASK      ((1ULL << LNET_PROC_CPT_BITS) - 1)
39 #define LNET_PROC_VER_MASK      ((1ULL << LNET_PROC_VER_BITS) - 1)
40 #define LNET_PROC_HASH_MASK     ((1ULL << LNET_PROC_HASH_BITS) - 1)
41 #define LNET_PROC_HOFF_MASK     ((1ULL << LNET_PROC_HOFF_BITS) - 1)
42
43 #define LNET_PROC_CPT_GET(pos)                          \
44         (int)(((pos) >> LNET_PROC_VPOS_BITS) & LNET_PROC_CPT_MASK)
45
46 #define LNET_PROC_VER_GET(pos)                          \
47         (int)(((pos) >> LNET_PROC_HPOS_BITS) & LNET_PROC_VER_MASK)
48
49 #define LNET_PROC_HASH_GET(pos)                         \
50         (int)(((pos) >> LNET_PROC_HOFF_BITS) & LNET_PROC_HASH_MASK)
51
52 #define LNET_PROC_HOFF_GET(pos)                         \
53         (int)((pos) & LNET_PROC_HOFF_MASK)
54
55 #define LNET_PROC_POS_MAKE(cpt, ver, hash, off)         \
56         (((((loff_t)(cpt)) & LNET_PROC_CPT_MASK) << LNET_PROC_VPOS_BITS) |   \
57         ((((loff_t)(ver)) & LNET_PROC_VER_MASK) << LNET_PROC_HPOS_BITS) |   \
58         ((((loff_t)(hash)) & LNET_PROC_HASH_MASK) << LNET_PROC_HOFF_BITS) | \
59         ((off) & LNET_PROC_HOFF_MASK))
60
61 #define LNET_PROC_VERSION(v)    ((unsigned int)((v) & LNET_PROC_VER_MASK))
62
63 static int proc_cpt_table(struct ctl_table *table, int write,
64                           void __user *buffer, size_t *lenp, loff_t *ppos)
65 {
66         size_t nob = *lenp;
67         loff_t pos = *ppos;
68         char *buf = NULL;
69         int len = 4096;
70         int rc  = 0;
71
72         if (write)
73                 return -EPERM;
74
75         while (1) {
76                 LIBCFS_ALLOC(buf, len);
77                 if (!buf)
78                         return -ENOMEM;
79
80                 rc = cfs_cpt_table_print(cfs_cpt_tab, buf, len);
81                 if (rc >= 0)
82                         break;
83
84                 if (rc == -EFBIG) {
85                         LIBCFS_FREE(buf, len);
86                         len <<= 1;
87                         continue;
88                 }
89                 goto out;
90         }
91
92         if (pos >= rc) {
93                 rc = 0;
94                 goto out;
95         }
96
97         rc = cfs_trace_copyout_string(buffer, nob, buf + pos, NULL);
98 out:
99         if (buf)
100                 LIBCFS_FREE(buf, len);
101         return rc;
102 }
103
104 static int proc_cpt_distance(struct ctl_table *table, int write,
105                              void __user *buffer, size_t *lenp, loff_t *ppos)
106 {
107         size_t nob = *lenp;
108         loff_t pos = *ppos;
109         char *buf = NULL;
110         int len = 4096;
111         int rc  = 0;
112
113         if (write)
114                 return -EPERM;
115
116         while (1) {
117                 LIBCFS_ALLOC(buf, len);
118                 if (!buf)
119                         return -ENOMEM;
120
121                 rc = cfs_cpt_distance_print(cfs_cpt_tab, buf, len);
122                 if (rc >= 0)
123                         break;
124
125                 if (rc == -EFBIG) {
126                         LIBCFS_FREE(buf, len);
127                         len <<= 1;
128                         continue;
129                 }
130                 goto out;
131         }
132
133         if (pos >= rc) {
134                 rc = 0;
135                 goto out;
136         }
137
138         rc = cfs_trace_copyout_string(buffer, nob, buf + pos, NULL);
139 out:
140         if (buf)
141                 LIBCFS_FREE(buf, len);
142         return rc;
143 }
144
145 static int proc_lnet_stats(struct ctl_table *table, int write,
146                            void __user *buffer, size_t *lenp, loff_t *ppos)
147 {
148         int rc;
149         struct lnet_counters *ctrs;
150         struct lnet_counters_common common;
151         size_t nob = *lenp;
152         loff_t pos = *ppos;
153         int len;
154         char tmpstr[256]; /* 7 %u and 4 u64 */
155
156         if (write) {
157                 lnet_counters_reset();
158                 return 0;
159         }
160
161         /* read */
162
163         LIBCFS_ALLOC(ctrs, sizeof(*ctrs));
164         if (ctrs == NULL)
165                 return -ENOMEM;
166
167         rc = lnet_counters_get(ctrs);
168         if (rc)
169                 goto out_no_ctrs;
170
171         common = ctrs->lct_common;
172
173         len = scnprintf(tmpstr, sizeof(tmpstr),
174                         "%u %u %u %u %u %u %u %llu %llu "
175                         "%llu %llu",
176                         common.lcc_msgs_alloc, common.lcc_msgs_max,
177                         common.lcc_errors,
178                         common.lcc_send_count, common.lcc_recv_count,
179                         common.lcc_route_count, common.lcc_drop_count,
180                         common.lcc_send_length, common.lcc_recv_length,
181                         common.lcc_route_length, common.lcc_drop_length);
182
183         if (pos >= len)
184                 rc = 0;
185         else
186                 rc = cfs_trace_copyout_string(buffer, nob,
187                                               tmpstr + pos, "\n");
188 out_no_ctrs:
189         LIBCFS_FREE(ctrs, sizeof(*ctrs));
190         return rc;
191 }
192
193 static int
194 proc_lnet_routes(struct ctl_table *table, int write, void __user *buffer,
195                  size_t *lenp, loff_t *ppos)
196 {
197         const int       tmpsiz = 256;
198         char            *tmpstr;
199         char            *s;
200         int             rc = 0;
201         int             len;
202         int             ver;
203         int             off;
204
205         BUILD_BUG_ON(sizeof(loff_t) < 4);
206
207         off = LNET_PROC_HOFF_GET(*ppos);
208         ver = LNET_PROC_VER_GET(*ppos);
209
210         LASSERT(!write);
211
212         if (*lenp == 0)
213                 return 0;
214
215         LIBCFS_ALLOC(tmpstr, tmpsiz);
216         if (tmpstr == NULL)
217                 return -ENOMEM;
218
219         s = tmpstr; /* points to current position in tmpstr[] */
220
221         if (*ppos == 0) {
222                 s += scnprintf(s, tmpstr + tmpsiz - s, "Routing %s\n",
223                                the_lnet.ln_routing ? "enabled" : "disabled");
224                 LASSERT(tmpstr + tmpsiz - s > 0);
225
226                 s += scnprintf(s, tmpstr + tmpsiz - s, "%-8s %4s %8s %7s %s\n",
227                                "net", "hops", "priority", "state", "router");
228                 LASSERT(tmpstr + tmpsiz - s > 0);
229
230                 lnet_net_lock(0);
231                 ver = (unsigned int)the_lnet.ln_remote_nets_version;
232                 lnet_net_unlock(0);
233                 *ppos = LNET_PROC_POS_MAKE(0, ver, 0, off);
234         } else {
235                 struct list_head        *n;
236                 struct list_head        *r;
237                 struct lnet_route               *route = NULL;
238                 struct lnet_remotenet   *rnet  = NULL;
239                 int                     skip  = off - 1;
240                 struct list_head        *rn_list;
241                 int                     i;
242
243                 lnet_net_lock(0);
244
245                 if (ver != LNET_PROC_VERSION(the_lnet.ln_remote_nets_version)) {
246                         lnet_net_unlock(0);
247                         LIBCFS_FREE(tmpstr, tmpsiz);
248                         return -ESTALE;
249                 }
250
251                 for (i = 0; i < LNET_REMOTE_NETS_HASH_SIZE && route == NULL;
252                      i++) {
253                         rn_list = &the_lnet.ln_remote_nets_hash[i];
254
255                         n = rn_list->next;
256
257                         while (n != rn_list && route == NULL) {
258                                 rnet = list_entry(n, struct lnet_remotenet,
259                                                   lrn_list);
260
261                                 r = rnet->lrn_routes.next;
262
263                                 while (r != &rnet->lrn_routes) {
264                                         struct lnet_route *re =
265                                                 list_entry(r, struct lnet_route,
266                                                            lr_list);
267                                         if (skip == 0) {
268                                                 route = re;
269                                                 break;
270                                         }
271
272                                         skip--;
273                                         r = r->next;
274                                 }
275
276                                 n = n->next;
277                         }
278                 }
279
280                 if (route != NULL) {
281                         __u32 net = rnet->lrn_net;
282                         __u32 hops = route->lr_hops;
283                         unsigned int priority = route->lr_priority;
284                         int alive = lnet_is_route_alive(route);
285
286                         s += scnprintf(s, tmpstr + tmpsiz - s,
287                                        "%-8s %4d %8u %7s %s\n",
288                                        libcfs_net2str(net), hops,
289                                        priority,
290                                        alive ? "up" : "down",
291                                        libcfs_nidstr(&route->lr_nid));
292                         LASSERT(tmpstr + tmpsiz - s > 0);
293                 }
294
295                 lnet_net_unlock(0);
296         }
297
298         len = s - tmpstr;     /* how many bytes was written */
299
300         if (len > *lenp) {    /* linux-supplied buffer is too small */
301                 rc = -EINVAL;
302         } else if (len > 0) { /* wrote something */
303                 if (copy_to_user(buffer, tmpstr, len))
304                         rc = -EFAULT;
305                 else {
306                         off += 1;
307                         *ppos = LNET_PROC_POS_MAKE(0, ver, 0, off);
308                 }
309         }
310
311         LIBCFS_FREE(tmpstr, tmpsiz);
312
313         if (rc == 0)
314                 *lenp = len;
315
316         return rc;
317 }
318
319 static int
320 proc_lnet_routers(struct ctl_table *table, int write, void __user *buffer,
321                   size_t *lenp, loff_t *ppos)
322 {
323         int        rc = 0;
324         char      *tmpstr;
325         char      *s;
326         const int  tmpsiz = 256;
327         int        len;
328         int        ver;
329         int        off;
330
331         off = LNET_PROC_HOFF_GET(*ppos);
332         ver = LNET_PROC_VER_GET(*ppos);
333
334         LASSERT(!write);
335
336         if (*lenp == 0)
337                 return 0;
338
339         LIBCFS_ALLOC(tmpstr, tmpsiz);
340         if (tmpstr == NULL)
341                 return -ENOMEM;
342
343         s = tmpstr; /* points to current position in tmpstr[] */
344
345         if (*ppos == 0) {
346                 s += scnprintf(s, tmpstr + tmpsiz - s,
347                                "%-4s %7s %5s %s\n",
348                                "ref", "rtr_ref", "alive", "router");
349                 LASSERT(tmpstr + tmpsiz - s > 0);
350
351                 lnet_net_lock(0);
352                 ver = (unsigned int)the_lnet.ln_routers_version;
353                 lnet_net_unlock(0);
354                 *ppos = LNET_PROC_POS_MAKE(0, ver, 0, off);
355         } else {
356                 struct list_head *r;
357                 struct lnet_peer *peer = NULL;
358                 int               skip = off - 1;
359
360                 lnet_net_lock(0);
361
362                 if (ver != LNET_PROC_VERSION(the_lnet.ln_routers_version)) {
363                         lnet_net_unlock(0);
364
365                         LIBCFS_FREE(tmpstr, tmpsiz);
366                         return -ESTALE;
367                 }
368
369                 r = the_lnet.ln_routers.next;
370
371                 while (r != &the_lnet.ln_routers) {
372                         struct lnet_peer *lp =
373                           list_entry(r, struct lnet_peer,
374                                      lp_rtr_list);
375
376                         if (skip == 0) {
377                                 peer = lp;
378                                 break;
379                         }
380
381                         skip--;
382                         r = r->next;
383                 }
384
385                 if (peer != NULL) {
386                         struct lnet_nid *nid = &peer->lp_primary_nid;
387                         int nrefs     = atomic_read(&peer->lp_refcount);
388                         int nrtrrefs  = peer->lp_rtr_refcount;
389                         int alive     = lnet_is_gateway_alive(peer);
390
391                         s += scnprintf(s, tmpstr + tmpsiz - s,
392                                        "%-4d %7d %5s %s\n",
393                                        nrefs, nrtrrefs,
394                                        alive ? "up" : "down",
395                                        libcfs_nidstr(nid));
396                 }
397
398                 lnet_net_unlock(0);
399         }
400
401         len = s - tmpstr;     /* how many bytes was written */
402
403         if (len > *lenp) {    /* linux-supplied buffer is too small */
404                 rc = -EINVAL;
405         } else if (len > 0) { /* wrote something */
406                 if (copy_to_user(buffer, tmpstr, len))
407                         rc = -EFAULT;
408                 else {
409                         off += 1;
410                         *ppos = LNET_PROC_POS_MAKE(0, ver, 0, off);
411                 }
412         }
413
414         LIBCFS_FREE(tmpstr, tmpsiz);
415
416         if (rc == 0)
417                 *lenp = len;
418
419         return rc;
420 }
421
422 /* TODO: there should be no direct access to ptable. We should add a set
423  * of APIs that give access to the ptable and its members */
424 static int
425 proc_lnet_peers(struct ctl_table *table, int write, void __user *buffer,
426                 size_t *lenp, loff_t *ppos)
427 {
428         const int               tmpsiz  = 256;
429         struct lnet_peer_table  *ptable;
430         char                    *tmpstr = NULL;
431         char                    *s;
432         int                     cpt  = LNET_PROC_CPT_GET(*ppos);
433         int                     ver  = LNET_PROC_VER_GET(*ppos);
434         int                     hash = LNET_PROC_HASH_GET(*ppos);
435         int                     hoff = LNET_PROC_HOFF_GET(*ppos);
436         int                     rc = 0;
437         int                     len;
438
439         if (write) {
440                 int i;
441                 struct lnet_peer_ni *peer;
442
443                 cfs_percpt_for_each(ptable, i, the_lnet.ln_peer_tables) {
444                         lnet_net_lock(i);
445                         for (hash = 0; hash < LNET_PEER_HASH_SIZE; hash++) {
446                                 list_for_each_entry(peer,
447                                                     &ptable->pt_hash[hash],
448                                                     lpni_hashlist) {
449                                         peer->lpni_mintxcredits =
450                                                 peer->lpni_txcredits;
451                                         peer->lpni_minrtrcredits =
452                                                 peer->lpni_rtrcredits;
453                                 }
454                         }
455                         lnet_net_unlock(i);
456                 }
457                 *ppos += *lenp;
458                 return 0;
459         }
460
461         if (*lenp == 0)
462                 return 0;
463
464         BUILD_BUG_ON(LNET_PROC_HASH_BITS < LNET_PEER_HASH_BITS);
465
466         if (cpt >= LNET_CPT_NUMBER) {
467                 *lenp = 0;
468                 return 0;
469         }
470
471         LIBCFS_ALLOC(tmpstr, tmpsiz);
472         if (tmpstr == NULL)
473                 return -ENOMEM;
474
475         s = tmpstr; /* points to current position in tmpstr[] */
476
477         if (*ppos == 0) {
478                 s += scnprintf(s, tmpstr + tmpsiz - s,
479                                "%-24s %4s %5s %5s %5s %5s %5s %5s %5s %s\n",
480                                "nid", "refs", "state", "last", "max",
481                                "rtr", "min", "tx", "min", "queue");
482                 LASSERT(tmpstr + tmpsiz - s > 0);
483
484                 hoff++;
485         } else {
486                 struct lnet_peer_ni     *peer;
487                 struct list_head        *p;
488                 int                     skip;
489
490  again:
491                 p = NULL;
492                 peer = NULL;
493                 skip = hoff - 1;
494
495                 lnet_net_lock(cpt);
496                 ptable = the_lnet.ln_peer_tables[cpt];
497                 if (hoff == 1)
498                         ver = LNET_PROC_VERSION(ptable->pt_version);
499
500                 if (ver != LNET_PROC_VERSION(ptable->pt_version)) {
501                         lnet_net_unlock(cpt);
502                         LIBCFS_FREE(tmpstr, tmpsiz);
503                         return -ESTALE;
504                 }
505
506                 while (hash < LNET_PEER_HASH_SIZE) {
507                         if (p == NULL)
508                                 p = ptable->pt_hash[hash].next;
509
510                         while (p != &ptable->pt_hash[hash]) {
511                                 struct lnet_peer_ni *lp =
512                                   list_entry(p, struct lnet_peer_ni,
513                                              lpni_hashlist);
514                                 if (skip == 0) {
515                                         peer = lp;
516
517                                         /* minor optimization: start from idx+1
518                                          * on next iteration if we've just
519                                          * drained lpni_hashlist */
520                                         if (lp->lpni_hashlist.next ==
521                                             &ptable->pt_hash[hash]) {
522                                                 hoff = 1;
523                                                 hash++;
524                                         } else {
525                                                 hoff++;
526                                         }
527
528                                         break;
529                                 }
530
531                                 skip--;
532                                 p = lp->lpni_hashlist.next;
533                         }
534
535                         if (peer != NULL)
536                                 break;
537
538                         p = NULL;
539                         hoff = 1;
540                         hash++;
541                 }
542
543                 if (peer != NULL) {
544                         struct lnet_nid nid = peer->lpni_nid;
545                         int nrefs = kref_read(&peer->lpni_kref);
546                         time64_t lastalive = -1;
547                         char *aliveness = "NA";
548                         int maxcr = (peer->lpni_net) ?
549                           peer->lpni_net->net_tunables.lct_peer_tx_credits : 0;
550                         int txcr = peer->lpni_txcredits;
551                         int mintxcr = peer->lpni_mintxcredits;
552                         int rtrcr = peer->lpni_rtrcredits;
553                         int minrtrcr = peer->lpni_minrtrcredits;
554                         int txqnob = peer->lpni_txqnob;
555
556                         if (lnet_isrouter(peer) ||
557                             lnet_peer_aliveness_enabled(peer))
558                                 aliveness = lnet_is_peer_ni_alive(peer) ?
559                                         "up" : "down";
560
561                         lnet_net_unlock(cpt);
562
563                         s += scnprintf(s, tmpstr + tmpsiz - s,
564                                        "%-24s %4d %5s %5lld %5d %5d %5d %5d %5d %d\n",
565                                        libcfs_nidstr(&nid), nrefs, aliveness,
566                                        lastalive, maxcr, rtrcr, minrtrcr, txcr,
567                                        mintxcr, txqnob);
568                         LASSERT(tmpstr + tmpsiz - s > 0);
569
570                 } else { /* peer is NULL */
571                         lnet_net_unlock(cpt);
572                 }
573
574                 if (hash == LNET_PEER_HASH_SIZE) {
575                         cpt++;
576                         hash = 0;
577                         hoff = 1;
578                         if (peer == NULL && cpt < LNET_CPT_NUMBER)
579                                 goto again;
580                 }
581         }
582
583         len = s - tmpstr;     /* how many bytes was written */
584
585         if (len > *lenp) {    /* linux-supplied buffer is too small */
586                 rc = -EINVAL;
587         } else if (len > 0) { /* wrote something */
588                 if (copy_to_user(buffer, tmpstr, len))
589                         rc = -EFAULT;
590                 else
591                         *ppos = LNET_PROC_POS_MAKE(cpt, ver, hash, hoff);
592         }
593
594         LIBCFS_FREE(tmpstr, tmpsiz);
595
596         if (rc == 0)
597                 *lenp = len;
598
599         return rc;
600 }
601
602 static int proc_lnet_buffers(struct ctl_table *table, int write,
603                              void __user *buffer, size_t *lenp, loff_t *ppos)
604 {
605         size_t nob = *lenp;
606         loff_t pos = *ppos;
607         char            *s;
608         char            *tmpstr;
609         int             tmpsiz;
610         int             idx;
611         int             len;
612         int             rc;
613         int             i;
614
615         LASSERT(!write);
616
617         /* (4 %d) * 4 * LNET_CPT_NUMBER */
618         tmpsiz = 64 * (LNET_NRBPOOLS + 1) * LNET_CPT_NUMBER;
619         LIBCFS_ALLOC(tmpstr, tmpsiz);
620         if (tmpstr == NULL)
621                 return -ENOMEM;
622
623         s = tmpstr; /* points to current position in tmpstr[] */
624
625         s += scnprintf(s, tmpstr + tmpsiz - s,
626                        "%5s %5s %7s %7s\n",
627                        "pages", "count", "credits", "min");
628         LASSERT(tmpstr + tmpsiz - s > 0);
629
630         if (the_lnet.ln_rtrpools == NULL)
631                 goto out; /* I'm not a router */
632
633         for (idx = 0; idx < LNET_NRBPOOLS; idx++) {
634                 struct lnet_rtrbufpool *rbp;
635
636                 lnet_net_lock(LNET_LOCK_EX);
637                 cfs_percpt_for_each(rbp, i, the_lnet.ln_rtrpools) {
638                         s += scnprintf(s, tmpstr + tmpsiz - s,
639                                        "%5d %5d %7d %7d\n",
640                                        rbp[idx].rbp_npages,
641                                        rbp[idx].rbp_nbuffers,
642                                        rbp[idx].rbp_credits,
643                                        rbp[idx].rbp_mincredits);
644                         LASSERT(tmpstr + tmpsiz - s > 0);
645                 }
646                 lnet_net_unlock(LNET_LOCK_EX);
647         }
648
649  out:
650         len = s - tmpstr;
651
652         if (pos >= min_t(int, len, strlen(tmpstr)))
653                 rc = 0;
654         else
655                 rc = cfs_trace_copyout_string(buffer, nob,
656                                               tmpstr + pos, NULL);
657
658         LIBCFS_FREE(tmpstr, tmpsiz);
659         return rc;
660 }
661
662 static int
663 proc_lnet_nis(struct ctl_table *table, int write, void __user *buffer,
664               size_t *lenp, loff_t *ppos)
665 {
666         int     tmpsiz = 128 * LNET_CPT_NUMBER;
667         int     rc = 0;
668         char    *tmpstr;
669         char    *s;
670         int     len;
671
672         if (*lenp == 0)
673                 return 0;
674
675         if (write) {
676                 /* Just reset the min stat. */
677                 struct lnet_ni  *ni;
678                 struct lnet_net *net;
679
680                 lnet_net_lock(0);
681
682                 list_for_each_entry(net, &the_lnet.ln_nets, net_list) {
683                         list_for_each_entry(ni, &net->net_ni_list, ni_netlist) {
684                                 struct lnet_tx_queue *tq;
685                                 int i;
686                                 int j;
687
688                                 cfs_percpt_for_each(tq, i, ni->ni_tx_queues) {
689                                         for (j = 0; ni->ni_cpts != NULL &&
690                                              j < ni->ni_ncpts; j++) {
691                                                 if (i == ni->ni_cpts[j])
692                                                         break;
693                                         }
694
695                                         if (j == ni->ni_ncpts)
696                                                 continue;
697
698                                         if (i != 0)
699                                                 lnet_net_lock(i);
700                                         tq->tq_credits_min = tq->tq_credits;
701                                         if (i != 0)
702                                                 lnet_net_unlock(i);
703                                 }
704                         }
705                 }
706                 lnet_net_unlock(0);
707                 *ppos += *lenp;
708                 return 0;
709         }
710
711         LIBCFS_ALLOC(tmpstr, tmpsiz);
712         if (tmpstr == NULL)
713                 return -ENOMEM;
714
715         s = tmpstr; /* points to current position in tmpstr[] */
716
717         if (*ppos == 0) {
718                 s += scnprintf(s, tmpstr + tmpsiz - s,
719                                "%-24s %6s %5s %4s %4s %4s %5s %5s %5s\n",
720                                "nid", "status", "alive", "refs", "peer",
721                                "rtr", "max", "tx", "min");
722                 LASSERT (tmpstr + tmpsiz - s > 0);
723         } else {
724                 struct lnet_ni *ni   = NULL;
725                 int skip = *ppos - 1;
726
727                 lnet_net_lock(0);
728
729                 ni = lnet_get_ni_idx_locked(skip);
730
731                 if (ni != NULL) {
732                         struct lnet_tx_queue *tq;
733                         char *stat;
734                         time64_t now = ktime_get_seconds();
735                         time64_t last_alive = -1;
736                         int i;
737                         int j;
738
739                         if (the_lnet.ln_routing)
740                                 last_alive = now - ni->ni_net->net_last_alive;
741
742                         lnet_ni_lock(ni);
743                         LASSERT(ni->ni_status != NULL);
744                         stat = (lnet_ni_get_status_locked(ni) ==
745                                 LNET_NI_STATUS_UP) ? "up" : "down";
746                         lnet_ni_unlock(ni);
747
748                         /* @lo forever alive */
749                         if (ni->ni_net->net_lnd->lnd_type == LOLND) {
750                                 last_alive = 0;
751                                 stat = "up";
752                         }
753
754                         /* we actually output credits information for
755                          * TX queue of each partition */
756                         cfs_percpt_for_each(tq, i, ni->ni_tx_queues) {
757                                 for (j = 0; ni->ni_cpts != NULL &&
758                                      j < ni->ni_ncpts; j++) {
759                                         if (i == ni->ni_cpts[j])
760                                                 break;
761                                 }
762
763                                 if (j == ni->ni_ncpts)
764                                         continue;
765
766                                 if (i != 0)
767                                         lnet_net_lock(i);
768
769                                 s += scnprintf(s, tmpstr + tmpsiz - s,
770                                        "%-24s %6s %5lld %4d %4d %4d %5d %5d %5d\n",
771                                        libcfs_nidstr(&ni->ni_nid), stat,
772                                        last_alive, *ni->ni_refs[i],
773                                        ni->ni_net->net_tunables.lct_peer_tx_credits,
774                                        ni->ni_net->net_tunables.lct_peer_rtr_credits,
775                                        tq->tq_credits_max,
776                                        tq->tq_credits, tq->tq_credits_min);
777                                 if (i != 0)
778                                         lnet_net_unlock(i);
779                         }
780                         LASSERT(tmpstr + tmpsiz - s > 0);
781                 }
782
783                 lnet_net_unlock(0);
784         }
785
786         len = s - tmpstr;     /* how many bytes was written */
787
788         if (len > *lenp) {    /* linux-supplied buffer is too small */
789                 rc = -EINVAL;
790         } else if (len > 0) { /* wrote something */
791                 if (copy_to_user(buffer, tmpstr, len))
792                         rc = -EFAULT;
793                 else
794                         *ppos += 1;
795         }
796
797         LIBCFS_FREE(tmpstr, tmpsiz);
798
799         if (rc == 0)
800                 *lenp = len;
801
802         return rc;
803 }
804
805 struct lnet_portal_rotors {
806         int             pr_value;
807         const char      *pr_name;
808         const char      *pr_desc;
809 };
810
811 static struct lnet_portal_rotors        portal_rotors[] = {
812         {
813                 .pr_value = LNET_PTL_ROTOR_OFF,
814                 .pr_name  = "OFF",
815                 .pr_desc  = "Turn off message rotor for wildcard portals"
816         },
817         {
818                 .pr_value = LNET_PTL_ROTOR_ON,
819                 .pr_name  = "ON",
820                 .pr_desc  = "round-robin dispatch all PUT messages for "
821                             "wildcard portals"
822         },
823         {
824                 .pr_value = LNET_PTL_ROTOR_RR_RT,
825                 .pr_name  = "RR_RT",
826                 .pr_desc  = "round-robin dispatch routed PUT message for "
827                             "wildcard portals"
828         },
829         {
830                 .pr_value = LNET_PTL_ROTOR_HASH_RT,
831                 .pr_name  = "HASH_RT",
832                 .pr_desc  = "dispatch routed PUT message by hashing source "
833                             "NID for wildcard portals"
834         },
835         {
836                 .pr_value = -1,
837                 .pr_name  = NULL,
838                 .pr_desc  = NULL
839         },
840 };
841
842 static int proc_lnet_portal_rotor(struct ctl_table *table, int write,
843                                   void __user *buffer, size_t *lenp,
844                                   loff_t *ppos)
845 {
846         const int       buf_len = 128;
847         size_t nob = *lenp;
848         loff_t pos = *ppos;
849         char            *buf;
850         char            *tmp;
851         int             rc;
852         int             i;
853
854         if (!write) {
855                 LIBCFS_ALLOC(buf, buf_len);
856                 if (buf == NULL)
857                         return -ENOMEM;
858
859                 lnet_res_lock(0);
860
861                 for (i = 0; portal_rotors[i].pr_value >= 0; i++) {
862                         if (portal_rotors[i].pr_value == portal_rotor)
863                                 break;
864                 }
865
866                 LASSERT(portal_rotors[i].pr_value == portal_rotor);
867                 lnet_res_unlock(0);
868
869                 rc = scnprintf(buf, buf_len,
870                                "{\n\tportals: all\n"
871                                "\trotor: %s\n\tdescription: %s\n}",
872                                portal_rotors[i].pr_name,
873                                portal_rotors[i].pr_desc);
874
875                 if (pos >= min_t(int, rc, buf_len)) {
876                         rc = 0;
877                 } else {
878                         rc = cfs_trace_copyout_string(buffer, nob,
879                                                       buf + pos, "\n");
880                 }
881                 LIBCFS_FREE(buf, buf_len);
882
883                 return rc;
884         }
885
886         buf = memdup_user_nul(buffer, nob);
887         if (IS_ERR(buf))
888                 return PTR_ERR(buf);
889
890         tmp = strim(buf);
891
892         rc = -EINVAL;
893         lnet_res_lock(0);
894         for (i = 0; portal_rotors[i].pr_name != NULL; i++) {
895                 if (strncasecmp(portal_rotors[i].pr_name, tmp,
896                                 strlen(portal_rotors[i].pr_name)) == 0) {
897                         portal_rotor = portal_rotors[i].pr_value;
898                         rc = 0;
899                         break;
900                 }
901         }
902         lnet_res_unlock(0);
903         kfree(buf);
904
905         return rc;
906 }
907
908 static struct ctl_table lnet_table[] = {
909         /*
910          * NB No .strategy entries have been provided since sysctl(8) prefers
911          * to go via /proc for portability.
912          */
913         {
914                 .procname       = "cpu_partition_table",
915                 .maxlen         = 128,
916                 .mode           = 0444,
917                 .proc_handler   = &proc_cpt_table,
918         },
919         {
920                 .procname       = "cpu_partition_distance",
921                 .maxlen         = 128,
922                 .mode           = 0444,
923                 .proc_handler   = &proc_cpt_distance,
924         },
925         {
926                 .procname       = "stats",
927                 .mode           = 0644,
928                 .proc_handler   = &proc_lnet_stats,
929         },
930         {
931                 .procname       = "routes",
932                 .mode           = 0444,
933                 .proc_handler   = &proc_lnet_routes,
934         },
935         {
936                 .procname       = "routers",
937                 .mode           = 0444,
938                 .proc_handler   = &proc_lnet_routers,
939         },
940         {
941                 .procname       = "peers",
942                 .mode           = 0644,
943                 .proc_handler   = &proc_lnet_peers,
944         },
945         {
946                 .procname       = "buffers",
947                 .mode           = 0444,
948                 .proc_handler   = &proc_lnet_buffers,
949         },
950         {
951                 .procname       = "nis",
952                 .mode           = 0644,
953                 .proc_handler   = &proc_lnet_nis,
954         },
955         {
956                 .procname       = "portal_rotor",
957                 .mode           = 0644,
958                 .proc_handler   = &proc_lnet_portal_rotor,
959         },
960         {
961                 .procname       = "lnet_lnd_timeout",
962                 .data           = &lnet_lnd_timeout,
963                 .maxlen         = sizeof(lnet_lnd_timeout),
964                 .mode           = 0444,
965                 .proc_handler   = &debugfs_doint,
966         },
967         { .procname = NULL }
968 };
969
970 static void *debugfs_state;
971
972 void lnet_router_debugfs_init(void)
973 {
974         lnet_insert_debugfs(lnet_table, THIS_MODULE,
975                             &debugfs_state);
976 }
977
978 void lnet_router_debugfs_fini(void)
979 {
980         lnet_remove_debugfs(lnet_table);
981 }
982 void lnet_router_exit(void)
983 {
984         lnet_debugfs_fini(&debugfs_state);
985 }