Whamcloud - gitweb
LU-56 lnet: cleanup for rtrpool and LNet counter
[fs/lustre-release.git] / lnet / lnet / router_proc.c
1 /*
2  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
3  *
4  * Copyright (c) 2011, Whamcloud, Inc.
5  *
6  *   This file is part of Portals
7  *   http://sourceforge.net/projects/sandiaportals/
8  *
9  *   Portals is free software; you can redistribute it and/or
10  *   modify it under the terms of version 2 of the GNU General Public
11  *   License as published by the Free Software Foundation.
12  *
13  *   Portals is distributed in the hope that it will be useful,
14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *   GNU General Public License for more details.
17  *
18  *   You should have received a copy of the GNU General Public License
19  *   along with Portals; if not, write to the Free Software
20  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  *
22  */
23
24 #define DEBUG_SUBSYSTEM S_LNET
25 #include <libcfs/libcfs.h>
26 #include <lnet/lib-lnet.h>
27
28 #if defined(__KERNEL__) && defined(LNET_ROUTER)
29
30 /* This is really lnet_proc.c. You might need to update sanity test 215
31  * if any file format is changed. */
32
33 static cfs_sysctl_table_header_t *lnet_table_header = NULL;
34
35 #ifndef HAVE_SYSCTL_UNNUMBERED
36 #define CTL_LNET         (0x100)
37 enum {
38         PSDEV_LNET_STATS = 100,
39         PSDEV_LNET_ROUTES,
40         PSDEV_LNET_ROUTERS,
41         PSDEV_LNET_PEERS,
42         PSDEV_LNET_BUFFERS,
43         PSDEV_LNET_NIS,
44 };
45 #else
46 #define CTL_LNET           CTL_UNNUMBERED
47 #define PSDEV_LNET_STATS   CTL_UNNUMBERED
48 #define PSDEV_LNET_ROUTES  CTL_UNNUMBERED
49 #define PSDEV_LNET_ROUTERS CTL_UNNUMBERED
50 #define PSDEV_LNET_PEERS   CTL_UNNUMBERED
51 #define PSDEV_LNET_BUFFERS CTL_UNNUMBERED
52 #define PSDEV_LNET_NIS     CTL_UNNUMBERED
53 #endif
54
55 /*
56  * NB: we don't use the highest bit of *ppos because it's signed;
57  *     next 9 bits is used to stash idx (assuming that
58  *     LNET_PEER_HASHSIZE < 512)
59  */
60 #define LNET_LOFFT_BITS        (sizeof(loff_t) * 8)
61 #define LNET_VERSION_BITS      MAX(((MIN(LNET_LOFFT_BITS, 64)) / 4), 8)
62 #define LNET_PHASH_IDX_BITS    9
63 #define LNET_PHASH_NUM_BITS    (LNET_LOFFT_BITS - 1 -\
64                                 LNET_VERSION_BITS - LNET_PHASH_IDX_BITS)
65 #define LNET_PHASH_BITS        (LNET_PHASH_IDX_BITS + LNET_PHASH_NUM_BITS)
66
67 #define LNET_VERSION_BITMASK   ((1ULL << LNET_VERSION_BITS) - 1)
68 #define LNET_PHASH_IDX_BITMASK ((1ULL << LNET_PHASH_IDX_BITS) - 1)
69 #define LNET_PHASH_NUM_BITMASK ((1ULL << LNET_PHASH_NUM_BITS) - 1)
70
71 #define LNET_VERSION_MASK      (LNET_VERSION_BITMASK << LNET_PHASH_BITS)
72 #define LNET_PHASH_IDX_MASK    (LNET_PHASH_IDX_BITMASK << LNET_PHASH_NUM_BITS)
73 #define LNET_PHASH_NUM_MASK    (LNET_PHASH_NUM_BITMASK)
74
75 #define LNET_VERSION_GET(pos)   (int)(((pos) & LNET_VERSION_MASK) >> \
76                                      LNET_PHASH_BITS)
77 #define LNET_PHASH_IDX_GET(pos) (int)(((pos) & LNET_PHASH_IDX_MASK) >> \
78                                       LNET_PHASH_NUM_BITS)
79 #define LNET_PHASH_NUM_GET(pos) (int)((pos) & LNET_PHASH_NUM_MASK)
80 #define LNET_VERSION_VALID_MASK(ver) \
81                                 (unsigned int)((ver) & \
82                                  LNET_VERSION_BITMASK)
83 #define LNET_PHASH_POS_MAKE(ver, idx, num)                                     \
84                                 (((((loff_t)(ver)) & LNET_VERSION_BITMASK) <<  \
85                                    LNET_PHASH_BITS) |                          \
86                                  ((((loff_t)(idx)) & LNET_PHASH_IDX_BITMASK) <<\
87                                    LNET_PHASH_NUM_BITS) |                      \
88                                  ((num) & LNET_PHASH_NUM_BITMASK))
89
90 static int __proc_lnet_stats(void *data, int write,
91                              loff_t pos, void *buffer, int nob)
92 {
93         int              rc;
94         lnet_counters_t *ctrs;
95         int              len;
96         char            *tmpstr;
97         const int        tmpsiz = 256; /* 7 %u and 4 LPU64 */
98
99         if (write) {
100                 lnet_counters_reset();
101                 return 0;
102         }
103
104         /* read */
105
106         LIBCFS_ALLOC(ctrs, sizeof(*ctrs));
107         if (ctrs == NULL)
108                 return -ENOMEM;
109
110         LIBCFS_ALLOC(tmpstr, tmpsiz);
111         if (tmpstr == NULL) {
112                 LIBCFS_FREE(ctrs, sizeof(*ctrs));
113                 return -ENOMEM;
114         }
115
116         lnet_counters_get(ctrs);
117
118         len = snprintf(tmpstr, tmpsiz,
119                        "%u %u %u %u %u %u %u "LPU64" "LPU64" "
120                        LPU64" "LPU64,
121                        ctrs->msgs_alloc, ctrs->msgs_max,
122                        ctrs->errors,
123                        ctrs->send_count, ctrs->recv_count,
124                        ctrs->route_count, ctrs->drop_count,
125                        ctrs->send_length, ctrs->recv_length,
126                        ctrs->route_length, ctrs->drop_length);
127
128         if (pos >= min_t(int, len, strlen(tmpstr)))
129                 rc = 0;
130         else
131                 rc = cfs_trace_copyout_string(buffer, nob,
132                                               tmpstr + pos, "\n");
133
134         LIBCFS_FREE(tmpstr, tmpsiz);
135         LIBCFS_FREE(ctrs, sizeof(*ctrs));
136         return rc;
137 }
138
139 DECLARE_PROC_HANDLER(proc_lnet_stats);
140
141 int LL_PROC_PROTO(proc_lnet_routes)
142 {
143         int        rc     = 0;
144         char      *tmpstr;
145         char      *s;
146         const int  tmpsiz = 256;
147         int        len;
148         int        ver;
149         int        num;
150
151         DECLARE_LL_PROC_PPOS_DECL;
152
153         num = LNET_PHASH_NUM_GET(*ppos);
154         ver = LNET_VERSION_GET(*ppos);
155
156         LASSERT (!write);
157
158         if (*lenp == 0)
159                 return 0;
160
161         LIBCFS_ALLOC(tmpstr, tmpsiz);
162         if (tmpstr == NULL)
163                 return -ENOMEM;
164
165         s = tmpstr; /* points to current position in tmpstr[] */
166
167         if (*ppos == 0) {
168                 s += snprintf(s, tmpstr + tmpsiz - s, "Routing %s\n",
169                               the_lnet.ln_routing ? "enabled" : "disabled");
170                 LASSERT (tmpstr + tmpsiz - s > 0);
171
172                 s += snprintf(s, tmpstr + tmpsiz - s, "%-8s %4s %7s %s\n",
173                               "net", "hops", "state", "router");
174                 LASSERT (tmpstr + tmpsiz - s > 0);
175
176                 LNET_LOCK();
177                 ver = (unsigned int)the_lnet.ln_remote_nets_version;
178                 LNET_UNLOCK();
179                 *ppos = LNET_PHASH_POS_MAKE(ver, 0, num);
180         } else {
181                 cfs_list_t        *n;
182                 cfs_list_t        *r;
183                 lnet_route_t      *route = NULL;
184                 lnet_remotenet_t  *rnet  = NULL;
185                 int                skip  = num - 1;
186
187                 LNET_LOCK();
188
189                 if (ver != LNET_VERSION_VALID_MASK(the_lnet.ln_remote_nets_version)) {
190                         LNET_UNLOCK();
191                         LIBCFS_FREE(tmpstr, tmpsiz);
192                         return -ESTALE;
193                 }
194
195                 n = the_lnet.ln_remote_nets.next;
196
197                 while (n != &the_lnet.ln_remote_nets && route == NULL) {
198                         rnet = cfs_list_entry(n, lnet_remotenet_t, lrn_list);
199
200                         r = rnet->lrn_routes.next;
201
202                         while (r != &rnet->lrn_routes) {
203                                 lnet_route_t *re =
204                                         cfs_list_entry(r, lnet_route_t,
205                                                        lr_list);
206                                 if (skip == 0) {
207                                         route = re;
208                                         break;
209                                 }
210
211                                 skip--;
212                                 r = r->next;
213                         }
214
215                         n = n->next;
216                 }
217
218                 if (route != NULL) {
219                         __u32        net   = rnet->lrn_net;
220                         unsigned int hops  = route->lr_hops;
221                         lnet_nid_t   nid   = route->lr_gateway->lp_nid;
222                         int          alive = route->lr_gateway->lp_alive;
223
224                         s += snprintf(s, tmpstr + tmpsiz - s, "%-8s %4u %7s %s\n",
225                                       libcfs_net2str(net), hops,
226                                       alive ? "up" : "down", libcfs_nid2str(nid));
227                         LASSERT (tmpstr + tmpsiz - s > 0);
228                 }
229
230                 LNET_UNLOCK();
231         }
232
233         len = s - tmpstr;     /* how many bytes was written */
234
235         if (len > *lenp) {    /* linux-supplied buffer is too small */
236                 rc = -EINVAL;
237         } else if (len > 0) { /* wrote something */
238                 if (cfs_copy_to_user(buffer, tmpstr, len))
239                         rc = -EFAULT;
240                 else {
241                         num += 1;
242                         *ppos = LNET_PHASH_POS_MAKE(ver, 0, num);
243                 }
244         }
245
246         LIBCFS_FREE(tmpstr, tmpsiz);
247
248         if (rc == 0)
249                 *lenp = len;
250
251         return rc;
252 }
253
254 int LL_PROC_PROTO(proc_lnet_routers)
255 {
256         int        rc = 0;
257         char      *tmpstr;
258         char      *s;
259         const int  tmpsiz = 256;
260         int        len;
261         int        ver;
262         int        num;
263
264         DECLARE_LL_PROC_PPOS_DECL;
265
266         num = LNET_PHASH_NUM_GET(*ppos);
267         ver = LNET_VERSION_GET(*ppos);
268
269         LASSERT (!write);
270
271         if (*lenp == 0)
272                 return 0;
273
274         LIBCFS_ALLOC(tmpstr, tmpsiz);
275         if (tmpstr == NULL)
276                 return -ENOMEM;
277
278         s = tmpstr; /* points to current position in tmpstr[] */
279
280         if (*ppos == 0) {
281                 s += snprintf(s, tmpstr + tmpsiz - s,
282                               "%-4s %7s %9s %6s %12s %9s %8s %7s %s\n",
283                               "ref", "rtr_ref", "alive_cnt", "state", "last_ping",
284                               "ping_sent", "deadline", "down_ni", "router");
285                 LASSERT (tmpstr + tmpsiz - s > 0);
286
287                 LNET_LOCK();
288                 ver = (unsigned int)the_lnet.ln_routers_version;
289                 LNET_UNLOCK();
290                 *ppos = LNET_PHASH_POS_MAKE(ver, 0, num);
291         } else {
292                 cfs_list_t        *r;
293                 lnet_peer_t       *peer = NULL;
294                 int                skip = num - 1;
295
296                 LNET_LOCK();
297
298                 if (ver != LNET_VERSION_VALID_MASK(the_lnet.ln_routers_version)) {
299                         LNET_UNLOCK();
300                         LIBCFS_FREE(tmpstr, tmpsiz);
301                         return -ESTALE;
302                 }
303
304                 r = the_lnet.ln_routers.next;
305
306                 while (r != &the_lnet.ln_routers) {
307                         lnet_peer_t *lp = cfs_list_entry(r, lnet_peer_t,
308                                                          lp_rtr_list);
309
310                         if (skip == 0) {
311                                 peer = lp;
312                                 break;
313                         }
314
315                         skip--;
316                         r = r->next;
317                 }
318
319                 if (peer != NULL) {
320                         lnet_nid_t nid = peer->lp_nid;
321                         cfs_time_t now = cfs_time_current();
322                         cfs_time_t deadline = peer->lp_ping_deadline;
323                         int nrefs     = peer->lp_refcount;
324                         int nrtrrefs  = peer->lp_rtr_refcount;
325                         int alive_cnt = peer->lp_alive_count;
326                         int alive     = peer->lp_alive;
327                         int pingsent  = !peer->lp_ping_notsent;
328                         int last_ping = cfs_duration_sec(cfs_time_sub(now,
329                                                      peer->lp_ping_timestamp));
330                         int down_ni   = 0;
331                         lnet_route_t *rtr;
332
333                         if (peer->lp_ping_version == LNET_PROTO_PING_VERSION) {
334                                 cfs_list_for_each_entry(rtr, &peer->lp_routes,
335                                                         lr_gwlist) {
336                                         /* downis on any route should be the
337                                          * number of downis on the gateway */
338                                         if (rtr->lr_downis != 0) {
339                                                 down_ni = rtr->lr_downis;
340                                                 break;
341                                         }
342                                 }
343                         }
344
345                         if (deadline == 0)
346                                 s += snprintf(s, tmpstr + tmpsiz - s,
347                                               "%-4d %7d %9d %6s %12d %9d %8s %7d %s\n",
348                                               nrefs, nrtrrefs, alive_cnt,
349                                               alive ? "up" : "down", last_ping,
350                                               pingsent, "NA", down_ni,
351                                               libcfs_nid2str(nid));
352                         else
353                                 s += snprintf(s, tmpstr + tmpsiz - s,
354                                               "%-4d %7d %9d %6s %12d %9d %8lu %7d %s\n",
355                                               nrefs, nrtrrefs, alive_cnt,
356                                               alive ? "up" : "down", last_ping,
357                                               pingsent,
358                                               cfs_duration_sec(cfs_time_sub(deadline, now)),
359                                               down_ni, libcfs_nid2str(nid));
360                         LASSERT (tmpstr + tmpsiz - s > 0);
361                 }
362
363                 LNET_UNLOCK();
364         }
365
366         len = s - tmpstr;     /* how many bytes was written */
367
368         if (len > *lenp) {    /* linux-supplied buffer is too small */
369                 rc = -EINVAL;
370         } else if (len > 0) { /* wrote something */
371                 if (cfs_copy_to_user(buffer, tmpstr, len))
372                         rc = -EFAULT;
373                 else {
374                         num += 1;
375                         *ppos = LNET_PHASH_POS_MAKE(ver, 0, num);
376                 }
377         }
378
379         LIBCFS_FREE(tmpstr, tmpsiz);
380
381         if (rc == 0)
382                 *lenp = len;
383
384         return rc;
385 }
386
387 int LL_PROC_PROTO(proc_lnet_peers)
388 {
389         struct lnet_peer_table  *ptable = the_lnet.ln_peer_table;
390         int        rc = 0;
391         char      *tmpstr;
392         char      *s;
393         const int  tmpsiz      = 256;
394         int        len;
395         int        ver;
396         int        idx;
397         int        num;
398
399         DECLARE_LL_PROC_PPOS_DECL;
400
401         idx = LNET_PHASH_IDX_GET(*ppos);
402         num = LNET_PHASH_NUM_GET(*ppos);
403         ver = LNET_VERSION_GET(*ppos);
404
405         CLASSERT ((1ULL << LNET_PHASH_BITS) > LNET_PEER_HASHSIZE);
406
407         LASSERT (!write);
408
409         if (*lenp == 0)
410                 return 0;
411
412         LIBCFS_ALLOC(tmpstr, tmpsiz);
413         if (tmpstr == NULL)
414                 return -ENOMEM;
415
416         s = tmpstr; /* points to current position in tmpstr[] */
417
418         if (*ppos == 0) {
419                 s += snprintf(s, tmpstr + tmpsiz - s,
420                               "%-24s %4s %5s %5s %5s %5s %5s %5s %5s %s\n",
421                               "nid", "refs", "state", "last", "max",
422                               "rtr", "min", "tx", "min", "queue");
423                 LASSERT (tmpstr + tmpsiz - s > 0);
424
425                 LNET_LOCK();
426                 ver = (unsigned int)ptable->pt_version;
427                 LNET_UNLOCK();
428                 *ppos = LNET_PHASH_POS_MAKE(ver, idx, num);
429
430                 num++;
431         } else {
432                 cfs_list_t        *p    = NULL;
433                 lnet_peer_t       *peer = NULL;
434                 int                skip = num - 1;
435
436                 LNET_LOCK();
437
438                 if (ver != LNET_VERSION_VALID_MASK(ptable->pt_version)) {
439                         LNET_UNLOCK();
440                         LIBCFS_FREE(tmpstr, tmpsiz);
441                         return -ESTALE;
442                 }
443
444                 while (idx < LNET_PEER_HASHSIZE) {
445                         if (p == NULL)
446                                 p = ptable->pt_hash[idx].next;
447
448                         while (p != &ptable->pt_hash[idx]) {
449                                 lnet_peer_t *lp = cfs_list_entry(p, lnet_peer_t,
450                                                                  lp_hashlist);
451                                 if (skip == 0) {
452                                         peer = lp;
453
454                                         /* minor optimization: start from idx+1
455                                          * on next iteration if we've just
456                                          * drained lp_hashlist */
457                                         if (lp->lp_hashlist.next ==
458                                             &ptable->pt_hash[idx]) {
459                                                 num = 1;
460                                                 idx++;
461                                         } else {
462                                                 num++;
463                                         }
464
465                                         break;
466                                 }
467
468                                 skip--;
469                                 p = lp->lp_hashlist.next;
470                         }
471
472                         if (peer != NULL)
473                                 break;
474
475                         p = NULL;
476                         num = 1;
477                         idx++;
478                 }
479
480                 if (peer != NULL) {
481                         lnet_nid_t nid       = peer->lp_nid;
482                         int        nrefs     = peer->lp_refcount;
483                         int        lastalive = -1;
484                         char      *aliveness = "NA";
485                         int        maxcr     = peer->lp_ni->ni_peertxcredits;
486                         int        txcr      = peer->lp_txcredits;
487                         int        mintxcr   = peer->lp_mintxcredits;
488                         int        rtrcr     = peer->lp_rtrcredits;
489                         int        minrtrcr  = peer->lp_minrtrcredits;
490                         int        txqnob    = peer->lp_txqnob;
491
492                         if (lnet_isrouter(peer) ||
493                             lnet_peer_aliveness_enabled(peer))
494                                 aliveness = peer->lp_alive ? "up" : "down";
495
496                         if (lnet_peer_aliveness_enabled(peer)) {
497                                 cfs_time_t     now = cfs_time_current();
498                                 cfs_duration_t delta;
499
500                                 delta = cfs_time_sub(now, peer->lp_last_alive);
501                                 lastalive = cfs_duration_sec(delta);
502
503                                 /* No need to mess up peers contents with
504                                  * arbitrarily long integers - it suffices to
505                                  * know that lastalive is more than 10000s old
506                                  */
507                                 if (lastalive >= 10000)
508                                         lastalive = 9999;
509                         }
510
511                         s += snprintf(s, tmpstr + tmpsiz - s,
512                                       "%-24s %4d %5s %5d %5d %5d %5d %5d %5d %d\n",
513                                       libcfs_nid2str(nid), nrefs, aliveness,
514                                       lastalive, maxcr, rtrcr, minrtrcr, txcr,
515                                       mintxcr, txqnob);
516                         LASSERT (tmpstr + tmpsiz - s > 0);
517                 }
518
519                 LNET_UNLOCK();
520         }
521
522         len = s - tmpstr;     /* how many bytes was written */
523
524         if (len > *lenp) {    /* linux-supplied buffer is too small */
525                 rc = -EINVAL;
526         } else if (len > 0) { /* wrote something */
527                 if (cfs_copy_to_user(buffer, tmpstr, len))
528                         rc = -EFAULT;
529                 else
530                         *ppos = LNET_PHASH_POS_MAKE(ver, idx, num);
531         }
532
533         LIBCFS_FREE(tmpstr, tmpsiz);
534
535         if (rc == 0)
536                 *lenp = len;
537
538         return rc;
539 }
540
541 static int __proc_lnet_buffers(void *data, int write,
542                                loff_t pos, void *buffer, int nob)
543 {
544
545         int              rc;
546         int              len;
547         char            *s;
548         char            *tmpstr;
549         const int        tmpsiz = 64 * (LNET_NRBPOOLS + 1); /* (4 %d) * 4 */
550         int              idx;
551
552         LASSERT (!write);
553
554         LIBCFS_ALLOC(tmpstr, tmpsiz);
555         if (tmpstr == NULL)
556                 return -ENOMEM;
557
558         s = tmpstr; /* points to current position in tmpstr[] */
559
560         s += snprintf(s, tmpstr + tmpsiz - s,
561                       "%5s %5s %7s %7s\n",
562                       "pages", "count", "credits", "min");
563         LASSERT (tmpstr + tmpsiz - s > 0);
564
565         if (the_lnet.ln_rtrpools == NULL)
566                 goto out; /* I'm not a router */
567
568         LNET_LOCK();
569
570         for (idx = 0; idx < LNET_NRBPOOLS; idx++) {
571                 lnet_rtrbufpool_t *rbp = &the_lnet.ln_rtrpools[idx];
572
573                 int npages = rbp->rbp_npages;
574                 int nbuf   = rbp->rbp_nbuffers;
575                 int cr     = rbp->rbp_credits;
576                 int mincr  = rbp->rbp_mincredits;
577
578                 s += snprintf(s, tmpstr + tmpsiz - s,
579                               "%5d %5d %7d %7d\n",
580                               npages, nbuf, cr, mincr);
581                 LASSERT (tmpstr + tmpsiz - s > 0);
582         }
583
584         LNET_UNLOCK();
585
586  out:
587         len = s - tmpstr;
588
589         if (pos >= min_t(int, len, strlen(tmpstr)))
590                 rc = 0;
591         else
592                 rc = cfs_trace_copyout_string(buffer, nob,
593                                               tmpstr + pos, NULL);
594
595         LIBCFS_FREE(tmpstr, tmpsiz);
596         return rc;
597 }
598
599 DECLARE_PROC_HANDLER(proc_lnet_buffers);
600
601 int LL_PROC_PROTO(proc_lnet_nis)
602 {
603         int        rc = 0;
604         char      *tmpstr;
605         char      *s;
606         const int  tmpsiz = 256;
607         int        len;
608
609         DECLARE_LL_PROC_PPOS_DECL;
610
611         LASSERT (!write);
612
613         if (*lenp == 0)
614                 return 0;
615
616         LIBCFS_ALLOC(tmpstr, tmpsiz);
617         if (tmpstr == NULL)
618                 return -ENOMEM;
619
620         s = tmpstr; /* points to current position in tmpstr[] */
621
622         if (*ppos == 0) {
623                 s += snprintf(s, tmpstr + tmpsiz - s,
624                               "%-24s %6s %5s %4s %4s %4s %5s %5s %5s\n",
625                               "nid", "status", "alive", "refs", "peer",
626                               "rtr", "max", "tx", "min");
627                 LASSERT (tmpstr + tmpsiz - s > 0);
628         } else {
629                 cfs_list_t        *n;
630                 lnet_ni_t         *ni   = NULL;
631                 int                skip = *ppos - 1;
632
633                 LNET_LOCK();
634
635                 n = the_lnet.ln_nis.next;
636
637                 while (n != &the_lnet.ln_nis) {
638                         lnet_ni_t *a_ni = cfs_list_entry(n, lnet_ni_t, ni_list);
639
640                         if (skip == 0) {
641                                 ni = a_ni;
642                                 break;
643                         }
644
645                         skip--;
646                         n = n->next;
647                 }
648
649                 if (ni != NULL) {
650                         cfs_time_t now = cfs_time_current();
651                         int        last_alive = -1;
652                         int        maxtxcr = ni->ni_maxtxcredits;
653                         int        txcr = ni->ni_txcredits;
654                         int        mintxcr = ni->ni_mintxcredits;
655                         int        npeertxcr = ni->ni_peertxcredits;
656                         int        npeerrtrcr = ni->ni_peerrtrcredits;
657                         lnet_nid_t nid = ni->ni_nid;
658                         int        nref = ni->ni_refcount;
659                         char      *stat;
660
661                         if (the_lnet.ln_routing)
662                                 last_alive = cfs_duration_sec(cfs_time_sub(now,
663                                                             ni->ni_last_alive));
664                         if (ni->ni_lnd->lnd_type == LOLND)  /* @lo forever alive */
665                                 last_alive = 0;
666
667                         LASSERT (ni->ni_status != NULL);
668                         stat = (ni->ni_status->ns_status == LNET_NI_STATUS_UP) ?
669                                                                   "up" : "down";
670
671                         s += snprintf(s, tmpstr + tmpsiz - s,
672                                       "%-24s %6s %5d %4d %4d %4d %5d %5d %5d\n",
673                                       libcfs_nid2str(nid), stat, last_alive, nref,
674                                       npeertxcr, npeerrtrcr, maxtxcr,
675                                       txcr, mintxcr);
676                         LASSERT (tmpstr + tmpsiz - s > 0);
677                 }
678
679                 LNET_UNLOCK();
680         }
681
682         len = s - tmpstr;     /* how many bytes was written */
683
684         if (len > *lenp) {    /* linux-supplied buffer is too small */
685                 rc = -EINVAL;
686         } else if (len > 0) { /* wrote something */
687                 if (cfs_copy_to_user(buffer, tmpstr, len))
688                         rc = -EFAULT;
689                 else
690                         *ppos += 1;
691         }
692
693         LIBCFS_FREE(tmpstr, tmpsiz);
694
695         if (rc == 0)
696                 *lenp = len;
697
698         return rc;
699 }
700
701 static cfs_sysctl_table_t lnet_table[] = {
702         /*
703          * NB No .strategy entries have been provided since sysctl(8) prefers
704          * to go via /proc for portability.
705          */
706         {
707                 INIT_CTL_NAME(PSDEV_LNET_STATS)
708                 .procname = "stats",
709                 .mode     = 0644,
710                 .proc_handler = &proc_lnet_stats,
711         },
712         {
713                 INIT_CTL_NAME(PSDEV_LNET_ROUTES)
714                 .procname = "routes",
715                 .mode     = 0444,
716                 .proc_handler = &proc_lnet_routes,
717         },
718         {
719                 INIT_CTL_NAME(PSDEV_LNET_ROUTERS)
720                 .procname = "routers",
721                 .mode     = 0444,
722                 .proc_handler = &proc_lnet_routers,
723         },
724         {
725                 INIT_CTL_NAME(PSDEV_LNET_PEERS)
726                 .procname = "peers",
727                 .mode     = 0444,
728                 .proc_handler = &proc_lnet_peers,
729         },
730         {
731                 INIT_CTL_NAME(PSDEV_LNET_PEERS)
732                 .procname = "buffers",
733                 .mode     = 0444,
734                 .proc_handler = &proc_lnet_buffers,
735         },
736         {
737                 INIT_CTL_NAME(PSDEV_LNET_NIS)
738                 .procname = "nis",
739                 .mode     = 0444,
740                 .proc_handler = &proc_lnet_nis,
741         },
742         {
743                 INIT_CTL_NAME(0)
744         }
745 };
746
747 static cfs_sysctl_table_t top_table[] = {
748         {
749                 INIT_CTL_NAME(CTL_LNET)
750                 .procname = "lnet",
751                 .mode     = 0555,
752                 .data     = NULL,
753                 .maxlen   = 0,
754                 .child    = lnet_table,
755         },
756         {
757                 INIT_CTL_NAME(0)
758         }
759 };
760
761 void
762 lnet_proc_init(void)
763 {
764 #ifdef CONFIG_SYSCTL
765         if (lnet_table_header == NULL)
766                 lnet_table_header = cfs_register_sysctl_table(top_table, 0);
767 #endif
768 }
769
770 void
771 lnet_proc_fini(void)
772 {
773 #ifdef CONFIG_SYSCTL
774         if (lnet_table_header != NULL)
775                 cfs_unregister_sysctl_table(lnet_table_header);
776
777         lnet_table_header = NULL;
778 #endif
779 }
780
781 #else
782
783 void
784 lnet_proc_init(void)
785 {
786 }
787
788 void
789 lnet_proc_fini(void)
790 {
791 }
792
793 #endif